EventMachine – WebSocket + AngularJS

One more EventMachine. Just tried to write a simple chat server using “em-websocket” gem (WebSocket server written over EventMachine). Client part is a simple HTML with AngularJS. It’s just wrapped around the native WebSocket object (couldn’t provide strong interaction with AngularJS).

Screenshot

websocket_example

Code

The following is the result of my trial.

Server (server.rb)

require 'em-websocket'

index = 1
connections = {}

def login_names(connections)
  connections.map {|ws, name| name}.join(", ")
end

EM.run do
  EM::WebSocket.run(:host => "0.0.0.0", :port => 8000) do |ws|
    ws.onopen do |handshake|
      name  = "Guest#{index}"
      connections[ws] = name
      index += 1

      ws.send "[Server] Hello #{name}"
      ws.send "[Server] Members are: #{login_names(connections)}"
    end

    ws.onclose do
      connections.delete(ws)
    end

    ws.onmessage do |msg|
      sender = connections[ws]

      connections.each do |cws, name|
        cws.send "[#{sender}] #{msg}"
      end
    end
  end
end

Client (client.js)

var app = angular.module('app', []);

app.factory('ChatService', function() {
  var service = {};

  service.connect = function() {
    if(service.ws) { return; }

    var ws = new WebSocket("ws://localhost:8000/socket/");

    ws.onopen = function() {
      service.callback("Succeeded to open a connection");
    };

    ws.onerror = function() {
      service.callback("Failed to open a connection");
    }

    ws.onmessage = function(message) {
      service.callback(message.data);
    };

    service.ws = ws;
  }

  service.send = function(message) {
    service.ws.send(message);
  }

  service.subscribe = function(callback) {
    service.callback = callback;
  }

  return service;
});


function AppCtrl($scope, ChatService) {
  $scope.messages = [];

  ChatService.subscribe(function(message) {
    $scope.messages.push(message);
    $scope.$apply();
  });

  $scope.connect = function() {
    ChatService.connect();
  }

  $scope.send = function() {
    ChatService.send($scope.text);
    $scope.text = "";
  }
}

Client (client.html)

<html ng-app="app">
  <head>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
    <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">

    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="client.js"></script>

    <style>
      body { margin-top: 10px; }
      input.message { height: 30px; }
    </style>
  </head>
  <body ng-controller="AppCtrl">
    <form class="form-inline">
      <button ng-click="connect()" class="btn">Connect</button>
      <input type="text" ng-model="text" placeholder="input message to send" class="message"></input>
      <button ng-click="send()" class="btn">send</button>
    </form>

    <table class="table table-striped">
      <tr ng-repeat="message in messages">
        <td>{{message}}</td>
      </tr
    </table>
  </body>
</html>

Referenced Documents

Advertisements

Posted on July 15, 2013, in JavaScript, Ruby, Web. Bookmark the permalink. 5 Comments.

  1. most useful example I have found on the net. thanks!

  2. finally a non-socket.io factory example for angular :D
    thanks for the help, it really helped me.

  3. Thank you very much!! :D :D

  1. Pingback: Create your first real-time AngularJS application | J talks about…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: