websocket-eventmachine-client 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +5 -0
- data/README.md +208 -0
- data/Rakefile +16 -0
- data/autobahn.json +11 -0
- data/examples/autobahn_client.rb +50 -0
- data/examples/echo_client.rb +42 -0
- data/lib/websocket-eventmachine-client.rb +1 -0
- data/lib/websocket/eventmachine/client.rb +134 -0
- data/lib/websocket/eventmachine/client/version.rb +7 -0
- data/websocket-eventmachine-client.gemspec +21 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
# WebSocket Client for Ruby
|
2
|
+
|
3
|
+
WebSocket-EventMachine-Client is Ruby WebSocket client based on EventMachine.
|
4
|
+
|
5
|
+
- [Autobahn tests](http://imanel.github.com/websocket-ruby/autobahn/client)
|
6
|
+
- [Docs](http://rdoc.info/github/imanel/websocket-eventmachine-client/master/frames)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
``` bash
|
11
|
+
gem install websocket-eventmachine-client
|
12
|
+
```
|
13
|
+
|
14
|
+
or in Gemfile
|
15
|
+
|
16
|
+
``` ruby
|
17
|
+
gem 'websocket-eventmachine-client'
|
18
|
+
```
|
19
|
+
|
20
|
+
## Simple client example
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
EM.run do
|
24
|
+
|
25
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => 'ws://localhost:8080')
|
26
|
+
|
27
|
+
ws.onopen do
|
28
|
+
puts "Connected"
|
29
|
+
end
|
30
|
+
|
31
|
+
ws.onmessage do |msg, type|
|
32
|
+
puts "Received message: #{msg}"
|
33
|
+
end
|
34
|
+
|
35
|
+
ws.onclose do
|
36
|
+
puts "Disconnected"
|
37
|
+
end
|
38
|
+
|
39
|
+
ws.send "Hello Server!"
|
40
|
+
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
## Options
|
45
|
+
|
46
|
+
Following options can be passed to WebSocket::EventMachine::Client initializer:
|
47
|
+
|
48
|
+
- `[String] :host` - IP or host of server to connect
|
49
|
+
- `[Integer] :port` - Port of server to connect
|
50
|
+
- `[String] :uri` - Full URI for server(optional - use instead of host/port combination)
|
51
|
+
- `[Integer] :version` - Version of WebSocket to use. Default: 13
|
52
|
+
|
53
|
+
## Methods
|
54
|
+
|
55
|
+
Following methods are available for WebSocket::EventMachine::Client object:
|
56
|
+
|
57
|
+
### onopen
|
58
|
+
|
59
|
+
Called after successfully connecting.
|
60
|
+
|
61
|
+
Example:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
ws.onopen do
|
65
|
+
puts "Client connected"
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
### onclose
|
70
|
+
|
71
|
+
Called after closing connection.
|
72
|
+
|
73
|
+
Example:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
ws.onclose do
|
77
|
+
puts "Client disconnected"
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
### onmessage
|
82
|
+
|
83
|
+
Called when client receive message.
|
84
|
+
|
85
|
+
Parameters:
|
86
|
+
|
87
|
+
- `[String] message` - content of message
|
88
|
+
- `[Symbol] type` - type is type of message(:text or :binary)
|
89
|
+
|
90
|
+
Example:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
ws.onmessage do |msg, type|
|
94
|
+
puts "Received message: #{msg} or type: #{type}"
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
### onerror
|
99
|
+
|
100
|
+
Called when client discovers error.
|
101
|
+
|
102
|
+
Parameters:
|
103
|
+
|
104
|
+
- `[String] error` - error reason.
|
105
|
+
|
106
|
+
Example:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
ws.onerror do |error|
|
110
|
+
puts "Error occured: #{error}"
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
### onping
|
115
|
+
|
116
|
+
Called when client receive ping request. Pong request is sent automatically.
|
117
|
+
|
118
|
+
Parameters:
|
119
|
+
|
120
|
+
- `[String] message` - message for ping request.
|
121
|
+
|
122
|
+
Example:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
ws.onping do |message|
|
126
|
+
puts "Ping received: #{message}"
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
### onpong
|
131
|
+
|
132
|
+
Called when client receive pong response.
|
133
|
+
|
134
|
+
Parameters:
|
135
|
+
|
136
|
+
- `[String] message` - message for pong response.
|
137
|
+
|
138
|
+
Example:
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
ws.onpong do |message|
|
142
|
+
puts "Pong received: #{message}"
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
### send
|
147
|
+
|
148
|
+
Sends message to server.
|
149
|
+
|
150
|
+
Parameters:
|
151
|
+
|
152
|
+
- `[String] message` - message that should be sent to client
|
153
|
+
- `[Hash] params` - params for message(optional)
|
154
|
+
- `[Symbol] :type` - type of message. Valid values are :text, :binary(default is :text)
|
155
|
+
|
156
|
+
Example:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
ws.send "Hello Server!"
|
160
|
+
ws.send "binary data", :type => :binary
|
161
|
+
```
|
162
|
+
|
163
|
+
### close
|
164
|
+
|
165
|
+
Closes connection and optionally send close frame to server.
|
166
|
+
|
167
|
+
Parameters:
|
168
|
+
|
169
|
+
- `[Integer] code` - code of closing, according to WebSocket specification(optional)
|
170
|
+
- `[String] data` - data to send in closing frame(optional)
|
171
|
+
|
172
|
+
Example:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
ws.close
|
176
|
+
```
|
177
|
+
|
178
|
+
### ping
|
179
|
+
|
180
|
+
Sends ping request.
|
181
|
+
|
182
|
+
Parameters:
|
183
|
+
|
184
|
+
- `[String] data` - data to send in ping request(optional)
|
185
|
+
|
186
|
+
Example:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
ws.ping 'Hi'
|
190
|
+
```
|
191
|
+
|
192
|
+
### pong
|
193
|
+
|
194
|
+
Sends pong request. Usually there should be no need to send this request, as pong responses are sent automatically by client.
|
195
|
+
|
196
|
+
Parameters:
|
197
|
+
|
198
|
+
- `[String] data` - data to send in pong request(optional)
|
199
|
+
|
200
|
+
Example:
|
201
|
+
|
202
|
+
``` ruby
|
203
|
+
ws.pong 'Hello'
|
204
|
+
```
|
205
|
+
|
206
|
+
## License
|
207
|
+
|
208
|
+
The MIT License - Copyright (c) 2012 Bernard Potocki
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
# require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
# RSpec::Core::RakeTask.new do |t|
|
7
|
+
# t.rspec_opts = ["-c", "-f progress"]
|
8
|
+
# t.pattern = 'spec/**/*_spec.rb'
|
9
|
+
# end
|
10
|
+
|
11
|
+
# task :default => :spec
|
12
|
+
|
13
|
+
desc "Run autobahn tests for client"
|
14
|
+
task :autobahn do
|
15
|
+
system('wstest --mode=fuzzingserver --spec=autobahn.json')
|
16
|
+
end
|
data/autobahn.json
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path('../../lib/websocket-eventmachine-client', __FILE__)
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
EM.epoll
|
6
|
+
EM.run do
|
7
|
+
|
8
|
+
host = 'ws://localhost:9001'
|
9
|
+
agent = "WebSocket-EventMachine-Client (1.0.0)"
|
10
|
+
cases = 0
|
11
|
+
skip = []
|
12
|
+
|
13
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/getCaseCount")
|
14
|
+
|
15
|
+
ws.onmessage do |msg, type|
|
16
|
+
puts "$ Total cases to run: #{msg}"
|
17
|
+
cases = msg.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
ws.onclose do
|
21
|
+
|
22
|
+
run_case = lambda do |n|
|
23
|
+
|
24
|
+
if n > cases
|
25
|
+
puts "$ Requesting report"
|
26
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/updateReports?agent=#{CGI.escape agent}")
|
27
|
+
ws.onclose do
|
28
|
+
EM.stop
|
29
|
+
end
|
30
|
+
|
31
|
+
elsif skip.include?(n)
|
32
|
+
EM.next_tick { run_case.call(n+1) }
|
33
|
+
|
34
|
+
else
|
35
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/runCase?case=#{n}&agent=#{CGI.escape agent}")
|
36
|
+
|
37
|
+
ws.onmessage do |msg, type|
|
38
|
+
ws.send(msg, :type => type)
|
39
|
+
end
|
40
|
+
|
41
|
+
ws.onclose do |msg|
|
42
|
+
EM.add_timer(0.1) { run_case.call(n + 1) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
run_case.call(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('../../lib/websocket-eventmachine-client', __FILE__)
|
2
|
+
|
3
|
+
EM.epoll
|
4
|
+
EM.run do
|
5
|
+
|
6
|
+
trap("TERM") { stop }
|
7
|
+
trap("INT") { stop }
|
8
|
+
|
9
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "ws://localhost:9001");
|
10
|
+
|
11
|
+
ws.onopen do
|
12
|
+
puts "Connected"
|
13
|
+
ws.send "Hello"
|
14
|
+
end
|
15
|
+
|
16
|
+
ws.onmessage do |msg, type|
|
17
|
+
puts "Received message: #{msg}"
|
18
|
+
ws.send msg, :type => type
|
19
|
+
end
|
20
|
+
|
21
|
+
ws.onclose do
|
22
|
+
puts "Disconnected"
|
23
|
+
end
|
24
|
+
|
25
|
+
ws.onerror do |e|
|
26
|
+
puts "Error: #{e}"
|
27
|
+
end
|
28
|
+
|
29
|
+
ws.onping do |msg|
|
30
|
+
puts "Receied ping: #{msg}"
|
31
|
+
end
|
32
|
+
|
33
|
+
ws.onpong do |msg|
|
34
|
+
puts "Received pong: #{msg}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
puts "Terminating connection"
|
39
|
+
EventMachine.stop
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path('../websocket/eventmachine/client', __FILE__)
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'websocket-eventmachine-base'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module WebSocket
|
5
|
+
module EventMachine
|
6
|
+
|
7
|
+
# WebSocket Client (using EventMachine)
|
8
|
+
# @example
|
9
|
+
# ws = WebSocket::EventMachine::Client.connect(:host => "0.0.0.0", :port => 8080)
|
10
|
+
# ws.onmessage { |msg| ws.send "Pong: #{msg}" }
|
11
|
+
# ws.send "data"
|
12
|
+
class Client < Base
|
13
|
+
|
14
|
+
###########
|
15
|
+
### API ###
|
16
|
+
###########
|
17
|
+
|
18
|
+
# Connect to websocket server
|
19
|
+
# @param args [Hash] The request arguments
|
20
|
+
# @option args [String] :host The host IP/DNS name
|
21
|
+
# @option args [Integer] :port The port to connect too(default = 80)
|
22
|
+
# @option args [Integer] :version Version of protocol to use(default = 13)
|
23
|
+
def self.connect(args = {})
|
24
|
+
host = nil
|
25
|
+
port = nil
|
26
|
+
if args[:uri]
|
27
|
+
uri = URI.parse(args[:uri])
|
28
|
+
host = uri.host
|
29
|
+
port = uri.port
|
30
|
+
end
|
31
|
+
host = args[:host] if args[:host]
|
32
|
+
port = args[:port] if args[:port]
|
33
|
+
port ||= 80
|
34
|
+
|
35
|
+
::EventMachine.connect host, port, self, args
|
36
|
+
end
|
37
|
+
|
38
|
+
# Initialize connection
|
39
|
+
# @param args [Hash] Arguments for connection
|
40
|
+
# @option args [String] :host The host IP/DNS name
|
41
|
+
# @option args [Integer] :port The port to connect too(default = 80)
|
42
|
+
# @option args [Integer] :version Version of protocol to use(default = 13)
|
43
|
+
def initialize(args)
|
44
|
+
@args = args
|
45
|
+
end
|
46
|
+
|
47
|
+
############################
|
48
|
+
### EventMachine methods ###
|
49
|
+
############################
|
50
|
+
|
51
|
+
# Called after initialize of connection, but before connecting to server
|
52
|
+
# Eventmachine internal
|
53
|
+
# @private
|
54
|
+
def post_init
|
55
|
+
@state = :connecting
|
56
|
+
@handshake = WebSocket::Handshake::Client.new(@args)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Called by EventMachine after connecting.
|
60
|
+
# Sends handshake to server
|
61
|
+
# Eventmachine internal
|
62
|
+
# @private
|
63
|
+
def connection_completed
|
64
|
+
send(@handshake.to_s, :type => :plain)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def incoming_frame
|
70
|
+
WebSocket::Frame::Incoming::Client
|
71
|
+
end
|
72
|
+
|
73
|
+
def outgoing_frame
|
74
|
+
WebSocket::Frame::Outgoing::Client
|
75
|
+
end
|
76
|
+
|
77
|
+
public
|
78
|
+
|
79
|
+
#########################
|
80
|
+
### Inherited methods ###
|
81
|
+
#########################
|
82
|
+
|
83
|
+
# Called when connection is opened.
|
84
|
+
# No parameters are passed to block
|
85
|
+
def onopen(&blk); super; end
|
86
|
+
|
87
|
+
# Called when connection is closed.
|
88
|
+
# No parameters are passed to block
|
89
|
+
def onclose(&blk); super; end
|
90
|
+
|
91
|
+
# Called when error occurs.
|
92
|
+
# One parameter passed to block:
|
93
|
+
# error - string with error message
|
94
|
+
def onerror(&blk); super; end
|
95
|
+
|
96
|
+
# Called when message is received.
|
97
|
+
# Two parameters passed to block:
|
98
|
+
# message - string with received message
|
99
|
+
# type - type of message. Valid values are :text and :binary
|
100
|
+
def onmessage(&blk); super; end
|
101
|
+
|
102
|
+
# Called when ping message is received
|
103
|
+
# One parameter passed to block:
|
104
|
+
# message - string with ping message
|
105
|
+
def onping(&blk); super; end
|
106
|
+
|
107
|
+
# Called when pond message is received
|
108
|
+
# One parameter passed to block:
|
109
|
+
# message - string with pong message
|
110
|
+
def onpong(&blk); super; end
|
111
|
+
|
112
|
+
# Send data
|
113
|
+
# @param data [String] Data to send
|
114
|
+
# @param args [Hash] Arguments for send
|
115
|
+
# @option args [String] :type Type of frame to send - available types are "text", "binary", "ping", "pong" and "close"
|
116
|
+
# @option args [Integer] :code Code for close frame
|
117
|
+
# @return [Boolean] true if data was send, otherwise call on_error if needed
|
118
|
+
def send(data, args = {}); super; end
|
119
|
+
|
120
|
+
# Close connection
|
121
|
+
# @return [Boolean] true if connection is closed immediately, false if waiting for other side to close connection
|
122
|
+
def close(code = 1000, data = nil); super; end
|
123
|
+
|
124
|
+
# Send ping message
|
125
|
+
# @return [Boolean] false if protocol version is not supporting ping requests
|
126
|
+
def ping(data = ''); super; end
|
127
|
+
|
128
|
+
# Send pong message
|
129
|
+
# @return [Boolean] false if protocol version is not supporting pong requests
|
130
|
+
def pong(data = ''); super; end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "websocket/eventmachine/client/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "websocket-eventmachine-client"
|
7
|
+
s.version = WebSocket::EventMachine::Client::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Bernard Potocki"]
|
10
|
+
s.email = ["bernard.potocki@imanel.org"]
|
11
|
+
s.homepage = "http://github.com/imanel/websocket-eventmachine-client"
|
12
|
+
s.summary = %q{WebSocket client for Ruby}
|
13
|
+
s.description = %q{WebSocket client for Ruby}
|
14
|
+
|
15
|
+
s.add_dependency 'websocket-eventmachine-base', '~> 1.0'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: websocket-eventmachine-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bernard Potocki
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: websocket-eventmachine-base
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
description: WebSocket client for Ruby
|
31
|
+
email:
|
32
|
+
- bernard.potocki@imanel.org
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- CHANGELOG.md
|
39
|
+
- Gemfile
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- autobahn.json
|
43
|
+
- examples/autobahn_client.rb
|
44
|
+
- examples/echo_client.rb
|
45
|
+
- lib/websocket-eventmachine-client.rb
|
46
|
+
- lib/websocket/eventmachine/client.rb
|
47
|
+
- lib/websocket/eventmachine/client/version.rb
|
48
|
+
- websocket-eventmachine-client.gemspec
|
49
|
+
homepage: http://github.com/imanel/websocket-eventmachine-client
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: WebSocket client for Ruby
|
73
|
+
test_files: []
|