socket.ioで通信してみる

June 18, 2016

iPod touchとサーバ(hubot)間の通信をsocket.ioで行うように実装しました。これにより、直接双方向でボットとiPhoneアプリ間でメッセージのやり取りができるようになります。

まずhubotはボットがメッセージに応答したり、自律的に何らかのアクションを実行するためのプログラム(hubot scripts)と、チャット等の外部サービス間とデータをやり取りするためのプログラム(hubot adapters)が必要です。今回はこのアダプター部分を実装してみました。下記がそのソースです。割とシンプルに書けますね。ちなみに、コメント中のMBEDというのは、iPhoneアプリのことを指しています(前回を参照)。このアプリとのメッセージのやり取りを、Socket.ioを使って行っています。やり取りするデータは適当です。

{Robot, Adapter, TextMessage, Response} = require 'hubot'
{EventEmitter} = require 'events'

class MbedAdapter extends Adapter
  run: ->
    options = {}
    bot = new MbedStreaming options, @robot
    bot.on 'message', (userId, userData, message) =>
      user = @robot.brain.userForId userId, userData
      @receive new TextMessage user, message

    # ここでサービスに接続し、継続的にメッセージを待ち受けるハンドラを作成
    bot.listen()
    @bot = bot
    @emit 'connected'

  send: (envelope, strings...) =>
    @bot.send str for str in strings
    
  reply: (envelope, strings...) ->


exports.use = (robot) ->
  new MbedAdapter robot

class MbedStreaming extends EventEmitter
  constructor: (options, @robot) ->

  send: (message) ->
    # ここでMBEDにメッセージを送信する
    @io?.sockets.emit 'message', message

  listen: ->
    self = @
    http = require 'http'
    io = require 'socket.io'
    htserver = http.createServer (req,res) ->
      res.write 'Test'
      res.end()
    io = io.listen htserver      
    htserver.listen 7799 

    io.sockets.on 'connection', (socket) ->
      #接続された時の処理
      socket.on 'message', (data) ->
        # MBEDからのメッセージを取得する
        # data = JSON.parse data
        usr_id = data.uid
        usr_data =
          name:data.uname
          room:data.room
        self.emit 'message', 100, usr_data, data.text
    @io = io

今回初めてCoffeeScriptでコードを書いたのですが、確かにコードが書きやすくなりました。あと、ベースはJavascriptなので、特に新しい概念を覚える必要がなくて学習コストも少なそうです。ちょっとだけハマったのはインデントですかね。基本、スペースだけでインデントしてますが、たまにタブが混じったりするとエラーになって、何が原因かわからなくなることがありました(見た目は全く問題ないわけですから)。

次はiPhoneアプリの方です。Socket.ioでデータをやり取りするため、Socket.IO-Client-Swiftというライブラリを使いました。ユーザーIDとかは適当です。

import UIKit
import SocketIOClientSwift

class ViewController: UIViewController {
    let SocketURL = NSURL(string:"http://192.168.1.7:7799")
    var socket: SocketIOClient!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        socket = SocketIOClient(socketURL: SocketURL!, options:[.Log(true), .ForcePolling(true)])
        socket.on("connect") { data, ack in
            print("socket connected!!")
            let msg : Dictionary<String, String> = [ "uid":"123", "uname":"nanasi", "room":"myhouse", "text":"mbedbot HELLO"]
            self.socket.emit("message", msg)
        }
        socket.on("disconnect") { data, ack in
            print("socket disconnected!!")
        }
        
        socket.on("message") { data, emitter in
            if let message = data as? [String] {
                print(message[0])
            }
        }
        socket.connect()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}