scalaのRedisクライアントbrandoを使ってみる

ちょっとはまったのでメモ。

scalaのRedisクライアントには何種類か有ります。

http://redis.io/clients

当初scala-redisを使っていたのですが、Pub/Subする際に、内部的にスレッドを生成しているようで、大量のPub/Subを作成したい場合(数千)にはOutOfMemoryで落ちてしまいます。

そこでActorモデルのbrandoを使用してみました。

ネット上にはほとんど情報もなくちょっとはまってしまったので記録しておきます

https://github.com/chrisdinn/brando

こちらからダウンロードしてsbt packageでJarを作成します。

あとakkaが必要なので2.3をダウンロードしておきます。

いろいろと試行錯誤し以下のコードでとれました

Pub/Subとかこれから確かめます

package brandoTest

import akka.actor._
import akka.util._
import akka.pattern.ask
import scala.concurrent._
import brando._

object Main {

	def main(args: Array[String]): Unit = {
		implicit val timeout= Timeout(5000)
		val system=ActorSystem("brando")
		val brando = system.actorOf(Brando("localhost", 6379,None,None))
		val future=brando.ask (Request("GET","key")).mapTo[Some[ByteString]]
		val res=Await.result(future,timeout.duration)
		res match{
			case Some(x)=>println(x.decodeString("UTF-8"))
		}

	}
}

C言語でStringBufferもどきを作成してみる

c言語は速いのはいいのですが、いかんせん標準ライブラリ群が貧弱な面は否めません。

文字列周りの処理だとC++のSTLあたりを使用すれば簡単ですが、純粋にCで簡単に作成してみました

  • string_buffer.h
#ifndef _STRING_BUFFER_H
#define _STRING_BUFFER_H
#include 

struct string_buffer {
	unsigned int item_size;
	char *item;
	unsigned int max_item_size; // 実際のメモリ確保量
};


extern struct string_buffer *create_string_buffer();
extern void delete_string_buffer(struct string_buffer *buf);
extern int append_string_buffer(struct string_buffer *buf, char *val, unsigned int val_len);


#endif
  • string_buffer.c
#include "string_buffer.h"
#define ITEM_SIZE 1024
struct string_buffer *create_string_buffer(){
				struct string_buffer *buf;
				buf=(struct string_buffer *)malloc(sizeof(struct string_buffer));
				if(buf==NULL)return NULL;
				buf->item=(char*)malloc(sizeof(char)*ITEM_SIZE);
				if(buf->item==NULL){
								free(buf);
								return NULL;
				}
				buf->item[0]='\0';
				buf->item_size=0;
				buf->max_item_size=ITEM_SIZE;
				return buf;
}
void delete_string_buffer(struct string_buffer *buf){
				if(buf!=NULL){
								if(buf->item!=NULL) free(buf->item);
								free(buf);
				}
}
int append_string_buffer(struct string_buffer *buf, char *val, unsigned int val_len){
				int size;
				char *newbuf;
				int diff=buf->max_item_size-buf->item_size;
				if(diff>val_len){
								strncat(buf->item,val,val_len);
								buf->item_size+=val_len;
				}else{
								size=buf->max_item_size+ITEM_SIZE;
								newbuf=(char*)malloc(sizeof(char)*size);
								if(newbuf==NULL) return -1;
								newbuf[0]='\0';
								strncpy(newbuf,buf->item,buf->item_size);
								free(buf->item);
								buf->item=newbuf;
								buf->max_item_size=size;
								return append_string_buffer(buf,val,val_len);
				}
				return 0;
}

実行してみます

  • main.c

static void print_string_buffer(char *header,struct string_buffer *buf){
				printf("%s:item_size=%d,char=%s,max_item_size=%d\n",header,buf->item_size,buf->item,buf->max_item_size);
}
int main(){
				struct string_buffer *buf;
				buf=create_string_buffer();
				if(buf==NULL)exit(0);

				append_string_buffer(buf,"test",sizeof("test"));
				print_string_buffer("1",buf);

				append_string_buffer(buf," 1111",sizeof(" 1111"));
				print_string_buffer("2",buf);

				append_string_buffer(buf,"",sizeof(""));
				print_string_buffer("3",buf);

				append_string_buffer(buf,"a",sizeof("a"));
				print_string_buffer("4",buf);

				append_string_buffer(buf,"12345678901234567890",12);
				print_string_buffer("5",buf);

				append_string_buffer(buf,"123",sizeof("123"));
				print_string_buffer("6",buf);
				delete_string_buffer(buf);
}
  • 実行結果
$ a.out
1:item_size=5,char=test,max_item_size=1024
2:item_size=11,char=test 1111,max_item_size=1024
3:item_size=12,char=test 1111,max_item_size=1024
4:item_size=14,char=test 1111a,max_item_size=1024
5:item_size=26,char=test 1111a123456789012,max_item_size=1024
6:item_size=30,char=test 1111a123456789012123,max_item_size=1024

StringからEnumの作成

文字列からEnum型へ変換するサンプルです

public class test{ 
 
	public static enum Channel{PC,WEB; 
		static Channel get(String s){ 
			Channel[] channels=Channel.values(); 
			for(Channel channel:channels){ 
				if(channel.toString().equals(s))return channel; 
			} 
			return null; 
		} 
}; 
 
	public static void main(String[] argv){ 
		System.out.println(Channel.WEB); // Enumをそのまま出力
		System.out.println(Channel.get("PC")); // 文字列からEnumを取得してみる
	} 
} 

Linuxでミリ秒まで取得

ansiのC言語で用意されているtime関数では現在時刻をミリ秒まで取得できません。そこでLinuxならではの取得方法の覚え書きです

gettimeofday関数を用いてミリ秒を取得します

以下のサンプルではミリ秒単位で現在時刻を取得し、2つの時間の差を求めています

#include
#include
#include
#include
#include

struct my_tm {
	time_t tim; // yyyymmddhhmmss
	long msec;	// milli sec
};

static struct my_tm *get_now_tm(){
	struct my_tm *qt;
	struct tm *tmp;
	struct timeval tv;

	qt=(struct my_tm*)malloc(sizeof(struct my_tm));
	if(qt == NULL)return NULL;
	gettimeofday(&tv,NULL);
	tmp=localtime(&tv.tv_sec);
	qt->tim=mktime(tmp);
	qt->msec=tv.tv_usec/1000;
	printf("%04d/%02d/%02d %02d:%02d:%02d:%3d\n",
		tmp->tm_year + 1900, tmp->tm_mon + 1,
		tmp->tm_mday, tmp->tm_hour,
		tmp->tm_min, tmp->tm_sec,
		tv.tv_usec/1000);
	return qt;
}

// return milli second
static inline long my_tm_cmptime(struct my_tm* now_t,struct my_tm* prev_t){
	long diff_sec;
	long diff_msec;
	diff_sec=difftime(now_t->tim,prev_t->tim);
	diff_msec=now_t->msec-prev_t->msec;
	return diff_sec*1000+diff_msec;
}

int main(){
	int i,b;
	struct my_tm *q1;
	struct my_tm *q2;
	long dif;

	q1=get_now_tm();
	sleep(2); // 2秒あける
	b=0;
	for(i=0;i<1000000;i++) b++; // +αあける
	q2=get_now_tm();
	dif=my_tm_cmptime(q2,q1);
	printf("%d\n",dif);

	free(q1);
	free(q2);
}

PlayFramework+Redis+websocketでプッシュ配信(データ圧縮編)

Websocketに最近はまっています。

前回プッシュ配信をRedisのPub/Subを用いて実現した訳ですが、データ量が増えてくるとどうしても配信するデータを圧縮したくなります。

特にAWSなんかだと、従量課金となっていますので、データ転送量は少なければ少ないほど○

Websocket自体はまだデータの圧縮はサポートされていないとのことですので、自前でデータの圧縮伸長を実装してみました。

また、それだけではつまらないので、Reidsにチャンネルを作成し、ReidsのチャンネルごとにPub/Subする仕組みを入れています

図解するとちょっとわかりにくいですがこんな感じ

			user1							userActor			 redisActor	 sub		Redis
		|code1,code2| ---	|	 user1	 | ---	|	code1	| --- |
											 |					 |			|				 |
			user2						|					 | ---	|	code2	| --- |
		|code2,code3| ---	|	 user2	 | ---	|	code3	| --- |

User別に作成したActorと、ユーザが選択したチャンネル(code1,code2,code3)別に作成したActorを別々に作成し、チャンネルがReidsから更新された際には、購読しているUserのActorへ更新をかけるという感じです

こうすることにより、チャンネル数がユーザ数より圧倒的に少ない場合には、Reidsに対するコネクションも削減でき、効率が良くなります。

  • route
GET		 /board													 controllers.Application.board(code:Option[String])	 # 画面作成用
GET		 /board/data											controllers.Application.data(code) #WSでデータ取得用
GET		 /asset/javascripts/board.js		 #Javascript controllers.Application.boardJs(code:String)
  • Compress.scala

データ圧縮用に作成します。String型をZIP圧縮し、BASE64でエンコードします

package models

import java.util.zip._
import java.io._
import org.apache.commons.codec.binary._

object Compress {
	def encode(str:String):String={
		val out = new ByteArrayOutputStream()
		val defl = new DeflaterOutputStream(out, new Deflater(Deflater.BEST_COMPRESSION, true))
		defl.write(str.getBytes())
		defl.close()
		val compressed = Base64.encodeBase64(out.toByteArray())
		new String(compressed)		
	}
}
  • UserActor.scala
...
	
	def notifyAll(code:String,data:String){
		// 実際にWebSocketでブラウザに送るデータ
		val msg=JsObject(
				Seq(
						"code"->JsString(code),
						"data"->JsString(Compress.encode(data)) // JSONの一部データ部分のみ圧縮
..
  • Javascriptで解凍

JavaScriptでZIP解凍、Base64でコードするために↓からinfrate.js,base64.js,utf.jsなどをダウンロードしておきます。

http://www.onicos.com/staff/iz/amuse/javascript/expert/

@(code:String)(implicit r: RequestHeader)

$(function() {

		var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket
		var socket = new WS("@routes.Application.data(code).webSocketURL()")

		
		var receiveEvent = function(event) {
				var data = JSON.parse(event.data)

				var bs=base64decode(data.data) // Base64デコード
				var dec=zip_inflate(bs)				// ZIP解凍
				var p=JSON.parse(dec)
				$("#data").text(p.data);
			 
		}

		socket.onmessage = receiveEvent

})

サンプルの一式は以下においておきました

https://github.com/anagotan/play_websocket_compressed

PlayFramework+Redis+websocketでプッシュ配信を作成してみる

Websocketを使ったサンプルだとチャットが多いのですが、実際にはチャットのアプリを作ることはあまり有りません。

どちらかというとサーバ側から配信するというような用途が多いのではないでしょうか?

PlayframeworkのサンプルにはWebsocketを使ったサンプルが付属しています。

これを改造してサーバ側から配信できるように改造してみました

  • 環境
    • MacOS10.9
    • jdk1.7
    • playframework2.2
    • redis2.8.4
    • scala2.10
  • playframeworkのチャットサンプル

brewでインストールした場合にはこちらに入っているので、作業エリアにコピーしておきます

/usr/local/Cellar/play/2.2.1/libexec/samples/scala/websocket-chat/

  • unicast

一斉配信したい場合にはサンプルで採用されているbroadcastをそのまま使用してもいいのですが、今回は一対一通信で配信したいのでunicastを使用します。サンプルはこちらを参考にしました。

http://satoshi-m8a.github.io/blog/2013/05/18/scala-concurrent-unicast/

  • build.sbt

scalaからredisに接続するためにはscala-redisライブラリを使用します。そのためbuild.sbtに以下を記述します

import play.Project._

name := "websocket-chat"

version := "1.0"

libraryDependencies ++= Seq(
	cache,
	"net.debasishg" % "redisclient_2.10" % "2.11"
)

playScalaSettings
  • conf/logger.xml

ログ出力用に追加します


		
	
	
	
		 ${application.home}/logs/application.log
		 
			 %date - [%level] - from %logger in %thread %n%message%n%xException%n
		 
	 

	
		
			%coloredLevel %d{HH:mm:ss.SSS} [%thread] %logger{15} - %message%n%xException{5}
		
	
	
	
	

	
		
		
	
	

  • conf/application.conf

redisの接続先をconfに書いておきます


redis.uri="http://localhost:6379/"
  • models/ChatRoom.scala

モデルをscala-redisのテストコードを参考に修正します

package models

import akka.actor._
import scala.concurrent.duration._

import play.api._
import play.api.libs.json._
import play.api.libs.iteratee._
import play.api.libs.concurrent._

import akka.util.Timeout
import akka.pattern.ask

import play.api.Play.current
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.iteratee.Concurrent.Channel

import com.redis._
import akka.actor.{ Actor, ActorSystem, Props }
case class PublishMessage(channel: String, message: String)
case class SubscribeMessage(channels: Array[String])
case class UnsubscribeMessage(channels: Array[String])
case object GoDown



object Robot {

	def apply(chatRoom: ActorRef) {

		// Create an Iteratee that logs all messages to the console.
		val loggerIteratee = Iteratee.foreach[JsValue](event => Logger("robot").info(event.toString))

		implicit val timeout = Timeout(1 second)
		// Make the robot join the room
		chatRoom ? (Join("Robot")) map {
			case Connected(robotChannel) =>
				// Apply this Enumerator on the logger.
				robotChannel |>> loggerIteratee
		}

		// Make the robot talk every 30 seconds
		Akka.system.scheduler.schedule(
			30 seconds,
			30 seconds,
			chatRoom,
			Talk("Robot", "I'm still alive")
		)
	}

}

object ChatRoom {

	implicit val timeout = Timeout(1 second)

	// username split ","	ex. "6758,9997"
	def join(username: String): scala.concurrent.Future[(Iteratee[JsValue, _], Enumerator[JsValue])] = {
		val roomActor = Akka.system.actorOf(Props[ChatRoom])
		
		roomActor ! SubscribeMessage(username.split(","))

		Robot(roomActor)

		(roomActor ? Join(username)).map {

			case Connected(enumerator) =>

				// Create an Iteratee to consume the feed
				val iteratee = Iteratee.foreach[JsValue] {
					event =>
						roomActor ! Talk(username, (event \ "text").as[String])
				}.mapDone {
					_ =>
						roomActor ! Quit(username)
				}

				(iteratee, enumerator)

			case CannotConnect(error) =>

				// Connection error

				// A finished Iteratee sending EOF
				val iteratee = Done[JsValue, Unit]((), Input.EOF)

				// Send an error and close the socket
				val enumerator = Enumerator[JsValue](JsObject(Seq("error" -> JsString(error)))).andThen(Enumerator.enumInput(Input.EOF))

				(iteratee, enumerator)

		}
	}
}

class ChatRoom extends Actor {
	println("starting subscription service ..")
	val system = ActorSystem("sub")
	val uri = new java.net.URI(Play.configuration.getString("redis.uri").get)
	val r = new RedisClient(uri.getHost,uri.getPort)
	val s = system.actorOf(Props(new Subscriber(r)))
	s ! Register(callback)
	
	def receive = {
		case SubscribeMessage(chs) => sub(chs)
		case UnsubscribeMessage(chs) => unsub(chs)
		case GoDown =>
			r.quit
			system.shutdown()
			system.awaitTermination()

		//case x => println("Got in Sub " + x)
		
		
		
		case Join(username) => {
			sender ! Connected(chatEnumerator)
		}

		case NotifyJoin(username) => {
			notifyAll("join", username, "has entered the room")
		}

		case Talk(username, text) => {
			notifyAll("talk", username, text)
		}

		case Quit(username) => {
			notifyAll("quit", username, "has left the room")
		}
	}

	def sub(channels: Array[String]) = {
		s ! Subscribe(channels.toArray)
	}

	def unsub(channels: Array[String]) = {
		s ! Unsubscribe(channels.toArray)
	}

	def callback(pubsub: PubSubMessage) = pubsub match {
		case E(exception) => println("Fatal error caused consumer dead. Please init new consumer reconnecting to master or connect to backup")
		case S(channel, no) => println("subscribed to " + channel + " and count = " + no)
		case U(channel, no) => println("unsubscribed from " + channel + " and count = " + no)
		case M(channel, msg) =>
			msg match {
				// exit will unsubscribe from all channels and stop subscription service
				case "exit" =>
					println("unsubscribe all ..")
					r.unsubscribe

				// message "+x" will subscribe to channel x
				case x if x startsWith "+" =>
					val s: Seq[Char] = x
					s match {
						case Seq('+', rest @ _*) => r.subscribe(rest.toString){ m => }
					}

				// message "-x" will unsubscribe from channel x
				case x if x startsWith "-" =>
					val s: Seq[Char] = x
					s match {
						case Seq('-', rest @ _*) => r.unsubscribe(rest.toString)
					}

				// other message receive
				case x =>
					println("received message on channel " + channel + " as : " + x)
					notifyAll("talk", channel, x)
			}
	}
	

	var chatChannel: Option[Channel[JsValue]] = None

	def onStart: Channel[JsValue] => Unit = {
		channel =>
			chatChannel = Some(channel)
			println("start")
			self ! NotifyJoin("you")
	}

	def onError: (String, Input[JsValue]) => Unit = {
		(message, input) =>
			println("onError " + message)
	}

	def onComplete = println("onComplete")

	val chatEnumerator = Concurrent.unicast[JsValue](onStart, onComplete, onError)
/*
	def receive = {

		case Join(username) => {
			sender ! Connected(chatEnumerator)
		}

		case NotifyJoin(username) => {
			notifyAll("join", username, "has entered the room")
		}

		case Talk(username, text) => {
			notifyAll("talk", username, text)
		}

		case Quit(username) => {
			notifyAll("quit", username, "has left the room")
		}

	}
	* 
	*/

	def notifyAll(kind: String, user: String, text: String) {
		val msg = JsObject(
			Seq(
				"kind" -> JsString(kind),
				"user" -> JsString(user),
				"message" -> JsString(text)
			)
		)
		chatChannel match {
			case Some(channel) => channel.push(msg)
			case _ => println("nothing")
		}
	}
}

case class Join(username: String)
case class Quit(username: String)
case class Talk(username: String, text: String)
case class NotifyJoin(username: String)
case class Connected(enumerator: Enumerator[JsValue])
case class CannotConnect(msg: String)

これで準備完了

  • 実行

play runで実行し、ユーザ名部分にカンマ区切りでキーを入力します。このキーはカンマ区切りで複数入力可能で、このキーがredisのキーとなります。

play run

画面が起動したら、a,b でログインしてみます

その後Reidsのコマンドで値を送ってみます

redis-cli publish a test

画面にa test が表示されます

CocoaのFrameworkでSTLを使ってみる

最近Cocoaにはまっています。Windows用に作成したライブラリをMacへ移植してみたのですが意外とはまったのでメモ

環境

  • MacOX10.9
  • XCode 5

TestAppという単純なアプリを作成しその中からSTLで作成したFrameworkを呼ぶことにするサンプルです。

UtilsというなのFramework

まず、ライブラリの作成です。XCodeでOSX用のCocoaFrameworkを作成します。

作成した後にファイルの追加で以下のヘッダファイルとC++ファイルを追加します

  • Test.h
#ifndef Utils_Test_h
#define Utils_Test_h
#include 
// 値を保持するクラス
class Bean{
public:
		int a;
		int b;

		Bean();
		void set(int a,int b);
		std::string to_s();
};
// 値を操作するクラス
class Test{
public:
		int add(int a,int b);
		std::shared_ptr add(std::shared_ptr a ,std::shared_ptr b);
};
#endif
  • Test.cpp
#include "Test.h"
#include 
Bean::Bean(){
		a=0;
		b=0;
}
void Bean::set(int a_,int b_){
		a=a_;
		b=b_;
}
std::string Bean::to_s(){
		char buf[1000];
		sprintf(buf,"a=%d,b=%d",a,b);
		return std::string(buf);
}
int Test::add(int a, int b){
		return a+b;
}
std::shared_ptr Test::add(std::shared_ptr a ,std::shared_ptr b){
		std::shared_ptr ret=std::shared_ptr(new Bean());
		int va=a->a+b->a;
		int vb=b->b+b->b;
		ret->set(va,vb);
		return ret;
}

ついでにObjective-Cのクラスも追加します。こちらを参考に

  • Utils.h
#import 

@interface Utils : NSObject
+(NSString*)addBrackets:(NSString*)string;
@end
  • Utils.m
#import "Utils.h"

@implementation Utils
+(NSString *)addBrackets:(NSString *)string
{
		return [NSString stringWithFormat:@"[-- %@ --]", string];
}
@end

それぞれのヘッダファイルをPublickにしたのちに、コンパイルするのですが、Build Rulesの Apple LLVM 5.0 Language C++のC++ Language Dialect を -std=c++11へ、C++ Standard Libraryを libc++(LLVM C++ standard library with C++ 11 supportへ変更します。また Apple LLVM 5.0 Language のCompile Source As をObjective-C++へと変更しておきます。

これでコンパイルOKのはず

TestAppというアプリ作成

OSXのApplicationのCocoaApplicationからプロジェクトを作成し、テキストボックスとボタンを配置しておきます。また、プロジェクトのFrameworksに先ほど作成したUtilsのフレームワークを追加しておきます。

  • AppDelegate.h
#import 

@interface AppDelegate : NSObject 

@property (assign) IBOutlet NSWindow *window;

@property IBOutlet NSButton *button;
@property IBOutlet NSTextField *text;

-(IBAction)pushButton:(id)sender;
@end
  • AppDelegate.m
#import "AppDelegate.h"

#import 
#import 
#include 

@implementation AppDelegate
@synthesize button;
@synthesize text;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
		// Insert code here to initialize your application
}

-(IBAction)pushButton:(id)sender{
		std::shared_ptr a=std::shared_ptr(new Bean());
		std::shared_ptr b=std::shared_ptr(new Bean());
		std::shared_ptr t=std::shared_ptr(new Test());

		a->set(1,2);
		b->set(10,20);
		std::shared_ptr tt=t->add(a,b);
		NSString* swk=[NSString stringWithCString:tt->to_s().c_str() encoding:[NSString defaultCStringEncoding]];
		NSString* str=[Utils addBrackets:swk];
		[text setStringValue:str];
}
@end

先ほどのライブラリと同様にBuildSettingを変更しておきます。

これでコンパイルとリンクがOKのはず。。

ボタンを押すとライブラリで計算した値がテキストボックスに出るはずです

Mac用アプリの自動テスト

最近自動テストツールにはまっています。

さすがにはやりというかiOSやAndroid用のテストツールは山ほど(というほどでもありませんが)有るのですが、Macのアプリ用のテストツールはほとんど有りません。

ちなみにこちらにまとめて書いてあるので参考になります

http://iphone-dev.g.hatena.ne.jp/laiso/20120111/1326280021

KIFのMac版が有るとのことなのでちょっと試してみました。

こちらのサイトを参考に

http://d.hatena.ne.jp/laiso+iphone/20121013/1350134198

環境

  • MacOS10.9
  • Xcode 5

この組み合わせで少しはまりました。

http://d.hatena.ne.jp/laiso+iphone/20121013/1350134198

こちらのサイトのサンプルであるGITHubからダウンロードします

https://github.com/laiso/Mac-Samples/tree/master/KIFMac01

git clone https://github.com/laiso/Mac-Samples.git

このままではKIFがとれないので別途取得します

mkdir work
cd work
git init
mkdir Vendor
git submodule add https://github.com/joshaber/KIF.git	Vendors/KIF-Mac

先ほど取得したサンプルに上書きします

mv Vendors/KIF-Mac ../../Mac-Sample/.

Xcodeを起動しプロジェクトを取り込みます

IntegrationTestのターゲットを選んで実行。しても止まってしまいます。

ログを見ると、

System Preferences => Universal Access => Enable access for assistive devices

どうやらアクセシビリティがだめな模様。

システム環境設定のアクセシビリティを見ても設定項目なし。。

http://www.tekrevue.com/how-to-enable-access-for-assistive-devices-in-os-x-mavericks/

こちらに答えが書いていました。

システム環境設定のセキュリティとプライバシーの中から、プライバシータグのアクセシビリティにXCodeのチェックボックスをオン

これでサンプル通りに動きました

npmコマンドのproxy設定

iOSとAndroidのアプリのテストが自動でできるというappiumを試そうとしたときの話。

  • 環境
    • MacOS 10.9
  • インストール
$ brew install node
Warning: node-0.10.24 already installed
$ sudo npm install -g appium
Password:
npm http GET https://registry.npmjs.org/appium
npm http GET https://registry.npmjs.org/appium
npm http GET https://registry.npmjs.org/appium
npm ERR! network read ECONNRESET
npm ERR! network This is most likely not a problem with npm itself
npm ERR! network and is related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.	See: 'npm help config'
npm ERR! System Darwin 13.0.0
npm ERR! command "/usr/local/Cellar/node/0.10.24/bin/node" "/usr/local/bin/npm" "install" "-g" "appium"
npm ERR! cwd /private/tmp
npm ERR! node -v v0.10.24
npm ERR! npm -v 1.3.21
npm ERR! syscall read
npm ERR! code ECONNRESET
npm ERR! errno ECONNRESET
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!		 /private/tmp/npm-debug.log
npm ERR! not ok code 0

こんな感じでおこられてしまった

proxyの設定はbashの環境変数とは別の様でconfigで設定する必要が有ります

$ npm config set proxy http://proxyhost:8080

再度実行

$ sudo npm install -g appium
Password:
npm http GET https://registry.npmjs.org/appium
npm http 200 https://registry.npmjs.org/appium
npm http GET https://registry.npmjs.org/appium/-/appium-0.13.0.tgz
npm http 200 https://registry.npmjs.org/appium/-/appium-0.13.0.tgz
npm http GET https://registry.npmjs.org/grunt
npm http GET https://registry.npmjs.org/argparse
npm http GET https://registry.npmjs.org/uuid-js
npm http GET https://registry.npmjs.org/rimraf
..