読者です 読者をやめる 読者になる 読者になる

Swift で MessagePack-RPC

ねこじゃらしの y-okubo と申します。

今回は、Swift で MessagePack-RPC を実現するライブラリの使い方を紹介します。

MessagePack-RPC については、こちらをご覧ください。

www.slideshare.net

ひとことで言えば、MessagePack (JSON) を使った RPC です。

各言語にライブラリが用意されており、異なる言語で作ったアプリ間でプロセス間通信をするのに便利です。

github.com

なぜか公式にはリストアップされていないのですが、Objective-C 版もあります(CocoaPods 対応がありがたい)。

github.com

今回は、コレを Swift から使ってみることにしました。

プロジェクトの作成

まず、Xcode で適当なプロジェクトを作成します。 今回は OS X - Application - Command Line Tool のプロジェクトを作成します。

f:id:nekojarashi-Inc:20160810182458p:plain

ターミナルでそのディレクトリまで移動して、以下のコマンドで CocoaPods をインストールします。

pod init

この後は、作成された Podfile に使用するライブラリを追加していきます。 Podfile を編集して、以下の内容を追加します。

pod 'MPMessagePack'

以下のコマンドを実行してライブラリをインストールします。

pod install

CocoaPods のライブラリを Xcode で使うには、先のコマンドで生成された .xcworkspace ファイルを開きます。

サンプルコード

簡単なコードを書いて動作確認をしてみます。

まずはサーバのリクエストハンドラを追加します。

RPC が呼び出されると必ずこのコードが実行されます。

メソッド名で分岐することで RPC 呼出しに対応したコードを記述できます。

今回は実験的なコードなので、そのような分岐はせず同じような戻り値を返しています。

func serverRequestHandler(messageId: NSNumber?, method: String?, params: [AnyObject]?, completion: (MPRequestCompletion)?) {
    if let method = method, let params = params {
        print("(Server) method:", method)
        print("(Server) params:", params)
    }
    
    completion!(nil, "Return from server(\(method))")
}

サーバを起動するコードを追加します。

リクエストハンドラを設定して、ポート 5001 番でサーバを起動してみます。

// Server

var server: MPMessagePackServer = MPMessagePackServer()

server.requestHandler = serverRequestHandler

do {
    try server.openWithPort(5001)
}
catch let error as NSError {
    print(error)
}

クライアントのコードを追加します。

こちらは非同期実行のコードになります。

var client: MPMessagePackClient = MPMessagePackClient()

client.openWithHost("127.0.0.1", port: 5001, completion: {error in
    client.sendRequestWithMethod("method_hoge", params: ["hoge", "42"], messageId: 1, completion: {error, result in
        if let error = error {
            print("Error:", error)
        }
    })
})

同期実行のコードは以下になります。 こちらは Exception を throw するので do ~ try ~ catch で例外ハンドリングをする必要があります。

client.openWithHost("127.0.0.1", port: 5001, completion: {error in
    do {
        try print(client.sendRequestWithMethod("method_fuga", params: [], messageId: 1, timeout: 2.0))
    } catch let error as NSError {
        print("Error:", error)
    }
})

注意点として、Command Line Tool でプロジェクトを作成している場合は、以下のコードも追加してください(このコードを追加しないと動きません)。

このコードで無限ループを回してクライアントからのリクエストを待ちます。

NSRunLoop.currentRunLoop().run()

では、コードを実行してみます。

2016-08-12 15:35:40.222 MsgpackRpcSwiftExample[11273:1429215] -[MPMessagePackServer connectionWithInputStream:outputStream:]:38: [Server] Client connected
(Server) method: method_fuga
(Server) params: []
(Server) method: method_hoge
(Server) params: [hoge, 42]

クライアントからの RPC 呼出しに対してサーバが値を受け取っているのがおわかりいただけるかと思います。

まとめ

MessagePack-RPC を Swift から使う方法について簡単に紹介いたしました。

他の言語についてもライブラリが存在するので、異なる言語間でプロセス間通信を行うような処理が必要になったとき、気軽に使えて便利です。

最近はマイクロサービス化によりコンポーネント疎結合化が加速しており、設計の都合やチームのスキルセットによって言語を使い分けるシーンも増えているのではないでしょうか。

そのようなときに、それらコンポーネントを繋ぐ方法として MessagePack-RPC は有力な選択肢になり得ると思います。

MessagePack-RPC を使う上でこの記事がお役に立てば幸いです。

お知らせ

ねこじゃらしでは Swift に限らず RubyJavaScriptプログラマ、UI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com