• Stars
    star
    1,690
  • Rank 26,467 (Top 0.6 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 14 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

EventMachine based WebSocket server

EM-WebSocket

Gem Version Analytics

EventMachine based, async, Ruby WebSocket server. Take a look at examples directory, or check out the blog post: Ruby & Websockets: TCP for the Web.

Simple server example

require 'em-websocket'

EM.run {
  EM::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws|
    ws.onopen { |handshake|
      puts "WebSocket connection open"

      # Access properties on the EM::WebSocket::Handshake object, e.g.
      # path, query_string, origin, headers

      # Publish message to the client
      ws.send "Hello Client, you connected to #{handshake.path}"
    }

    ws.onclose { puts "Connection closed" }

    ws.onmessage { |msg|
      puts "Recieved message: #{msg}"
      ws.send "Pong: #{msg}"
    }
  end
}

Protocols supported, and protocol specific functionality

Supports all WebSocket protocols in use in the wild (and a few that are not): drafts 75, 76, 1-17, rfc.

While some of the changes between protocols are unimportant from the point of view of application developers, a few drafts did introduce new functionality. It's possible to easily test for this functionality by using

Ping & pong supported

Call ws.pingable? to check whether ping & pong is supported by the protocol in use.

It's possible to send a ping frame (ws.ping(body = '')), which the client must respond to with a pong, or the server can send an unsolicited pong frame (ws.pong(body = '')) which the client should not respond to. These methods can be used regardless of protocol version; they return true if the protocol supports ping&pong or false otherwise.

When receiving a ping, the server will automatically respond with a pong as the spec requires (so you should not write an onping handler that replies with a pong), however it is possible to bind to ping & pong events if desired by using the onping and onpong methods.

Healthchecks

It's possible to send a regular HTTP GET request to the /healthcheck endpoint and receive a 200 response from the server.

Close codes and reasons

A WebSocket connection can be closed cleanly, regardless of protocol, by calling ws.close(code = nil, body = nil).

Early protocols just close the TCP connection, draft 3 introduced a close handshake, and draft 6 added close codes and reasons to the close handshake. Call ws.supports_close_codes? to check whether close codes are supported (i.e. the protocol version is 6 or above).

The onclose callback is passed a hash which may contain following keys (depending on the protocol version):

  • was_clean: boolean indicating whether the connection was closed via the close handshake.
  • code: the close code. There are two special close codes which the server may set (as defined in the WebSocket spec):
    • 1005: no code was supplied
    • 1006: abnormal closure (the same as was_clean: false)
  • reason: the close reason

Acceptable close codes are defined in the WebSocket rfc (http://tools.ietf.org/html/rfc6455#section-7.4). The following codes can be supplies when calling ws.close(code):

  • 1000: a generic normal close
  • range 3xxx: reserved for libraries, frameworks, and applications (and can be registered with IANA)
  • range 4xxx: for private use

If unsure use a code in the 4xxx range. em-websocket may also close a connection with one of the following close codes:

  • 1002: WebSocket protocol error.
  • 1009: Message too big to process. By default em-websocket will accept frames up to 10MB in size. If a frame is larger than this the connection will be closed without reading the frame data. The limit can be overriden globally (EM::WebSocket.max_frame_size = bytes) or on a specific connection (ws.max_frame_size = bytes).

Secure server

It is possible to accept secure wss:// connections by passing :secure => true when opening the connection. Pass a :tls_options hash containing keys as described in http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine/Connection:start_tls

Warning: Safari 5 does not currently support prompting on untrusted SSL certificates therefore using a self signed certificate may leave you scratching your head.

EM::WebSocket.start({
  :host => "0.0.0.0",
  :port => 443,
  :secure => true,
  :tls_options => {
    :private_key_file => "/private/key",
    :cert_chain_file => "/ssl/certificate"
  }
}) do |ws|
  # ...
end

It's possible to check whether an incoming connection is secure by reading handshake.secure? in the onopen callback.

Running behind an SSL Proxy/Terminator, like Stunnel

The :secure_proxy => true option makes it possible to use em-websocket behind a secure SSL proxy/terminator like Stunnel which does the actual encryption & decryption.

Note that this option is only required to support drafts 75 & 76 correctly (e.g. Safari 5.1.x & earlier, and Safari on iOS 5.x & earlier).

EM::WebSocket.start({
  :host => "0.0.0.0",
  :port => 8080,
  :secure_proxy => true
}) do |ws|
  # ...
end

Handling errors

There are two kinds of errors that need to be handled -- WebSocket protocol errors and errors in application code.

WebSocket protocol errors (for example invalid data in the handshake or invalid message frames) raise errors which descend from EM::WebSocket::WebSocketError. Such errors are rescued internally and the WebSocket connection will be closed immediately or an error code sent to the browser in accordance to the WebSocket specification. It is possible to be notified in application code of such errors by including an onerror callback.

ws.onerror { |error|
  if error.kind_of?(EM::WebSocket::WebSocketError)
    # ...
  end
}

Application errors are treated differently. If no onerror callback has been defined these errors will propagate to the EventMachine reactor, typically causing your program to terminate. If you wish to handle exceptions, simply supply an onerror callback and check for exceptions which are not descendant from EM::WebSocket::WebSocketError.

It is also possible to log all errors when developing by including the :debug => true option when initialising the WebSocket server.

Emulating WebSockets in older browsers

It is possible to emulate WebSockets in older browsers using flash emulation. For example take a look at the web-socket-js project.

Using flash emulation does require some minimal support from em-websocket which is enabled by default. If flash connects to the WebSocket port and requests a policy file (which it will do if it fails to receive a policy file on port 843 after a timeout), em-websocket will return one. Also see #61 for an example policy file server which you can run on port 843.

Examples & Projects using em-websocket

  • Pusher - Realtime Messaging Service
  • Livereload - LiveReload applies CSS/JS changes to Safari or Chrome w/o reloading
  • Twitter AMQP WebSocket Example
  • examples/multicast.rb - broadcast all ruby tweets to all subscribers
  • examples/echo.rb - server <> client exchange via a websocket

More Repositories

1

videospeed

HTML5 video speed controller (for Google Chrome)
JavaScript
3,654
star
2

ga-beacon

Google Analytics collector-as-a-service (using GA measurement protocol).
Go
3,527
star
3

gharchive.org

GH Archive is a project to record the public GitHub timeline, archive it, and make it easily accessible for further analysis.
Ruby
2,567
star
4

decisiontree

ID3-based implementation of the ML Decision Tree algorithm
Ruby
1,414
star
5

em-http-request

Asynchronous HTTP Client (EventMachine + Ruby)
Ruby
1,216
star
6

em-synchrony

Fiber aware EventMachine clients and convenience classes
Ruby
1,040
star
7

http-2

Pure Ruby implementation of HTTP/2 protocol
Ruby
876
star
8

bugspots

Implementation of simple bug prediction hotspot heuristic
Ruby
841
star
9

agent

Agent is an attempt at modelling Go-like concurrency, in Ruby
Ruby
729
star
10

em-proxy

EventMachine Proxy DSL for writing high-performance transparent / intercepting proxies in Ruby
Ruby
664
star
11

vimgolf

Real Vim ninjas count every keystroke - do you?
Ruby
632
star
12

node-spdyproxy

SPDY forwarding proxy - fast and secure
JavaScript
528
star
13

bloomfilter-rb

BloomFilter(s) in Ruby: Native counting filter + Redis counting/non-counting filters
C
468
star
14

async-rails

async Rails 3 stack demo
Ruby
467
star
15

hackernews-button

Embeddable Hacker News button + vote counter for your site
Go
417
star
16

istlsfastyet.com

Is TLS fast yet? Yes, yes it is.
HTML
417
star
17

http-client-hints

Ruby
401
star
18

spdy

SPDY is a protocol designed to reduce latency of web pages
Ruby
317
star
19

hpbn.co

High Performance Browser Networking (O'Reilly)
HTML
286
star
20

webp-detect

WebP with Accept negotiation
C++
242
star
21

zeroconf-router

Zero-config reverse proxies: let's get there!
Ruby
205
star
22

autoperf

Ruby driver for httperf - automated load and performance testing
Ruby
179
star
23

PubSubHubbub

Asynchronous PubSubHubbub Ruby Client
Ruby
174
star
24

heroku-buildpack-dart

Heroku buildpack for Dart
Shell
166
star
25

rack-speedtracer

SpeedTracer middleware for server side debugging
Ruby
156
star
26

textquery

Evaluate any text against a collection of match rules
Ruby
145
star
27

tokyo-recipes

Lean & mean Tokyo Cabinet recipes (with Lua)
Lua
144
star
28

slowgrowl

Surface slow code paths in your Rails 3 app via Growl
Ruby
117
star
29

mneme

Mneme is an HTTP web-service for recording and identifying previously seen records - aka, duplicate detection.
Ruby
108
star
30

RRRDTool

Round robin database pattern via Redis sorted sets
Ruby
79
star
31

pregel

Single-node implementation of Google's Pregel framework for graph processing.
Ruby
72
star
32

gmetric

Pure Ruby interface for generating Ganglia gmetric packets
Ruby
70
star
33

rack-aggregate

Rack response-time statistics aggregator middleware
Ruby
67
star
34

em-jack

An Evented Beanstalk Client
Ruby
65
star
35

rb-pagerank

Code from RailsConf '09 pres: Building Mini Google in Ruby
Ruby
54
star
36

closure-sprockets

Sprockets processor for Google's Closure tools
Python
54
star
37

netinfo-monitor

Displays network quality as reported by Network Information API.
JavaScript
48
star
38

shopify-core-web-vitals

This embedded app provides a report on how real-world Google Chrome users experience the Shopify-powered storefront, as captured by the Chrome UX Report, and enables the site owner to benchmark their site against a custom list of competitors.
Ruby
48
star
39

libsnappy

Snappy, a fast compressor/decompressor (courtesy of Google)
Ruby
45
star
40

hydra5

Load-balanced (multi-headed) SOCKS5 proxy
Ruby
42
star
41

zdevice

ZDevice is a Ruby DSL for assembling ZeroMQ routing devices, with support for the ZDCF configuration syntax
Ruby
42
star
42

ruby2lolz

Ruby to Lolcode translator, kthnxbai.
Ruby
38
star
43

bmr-wordcount

Browser Map-Reduce: distributed word count example
Ruby
33
star
44

em-socksify

Transparent proxy support for any EventMachine protocol
Ruby
32
star
45

resource-hints

Moved to...
JavaScript
32
star
46

gitter

XML history generator for CodeSwarm
31
star
47

em-handlersocket

EventMachine HandlerSocket MySQL plugin for direct read/write of InnoDB tables
Ruby
29
star
48

canicrawl

Hosted robots.txt permissions verifier
Go
23
star
49

udacity-webperf

JavaScript
17
star
50

omnipipe

web pipes for your browser's omnibar!
Ruby
12
star
51

issue-tracker

W3C webperf issue tracker
JavaScript
11
star
52

contextual

runtime contextual HTML autoescaper
Ruby
10
star
53

presentations

Slides, notes, code examples from some of the bigger conferences & talks.
9
star
54

performance-observer

JavaScript
7
star
55

libgeohash

Ruby FFI wrapper for libgeohash
Ruby
7
star
56

ImageQuote

Convert text quotes to images
Ruby
7
star
57

resourcehints.info

HTML
2
star
58

igrigorik

1
star