async-websocket 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8954f1e1bb06c1e4188f6b248f2c78ee7b79ced5
4
- data.tar.gz: 3dc3b81c1c475d07cab9281ace55bc7c4ec265f1
2
+ SHA256:
3
+ metadata.gz: '0158791283f1da9ef7fe755bd019899508f3d647fc9f18984e2b7ef77a3074db'
4
+ data.tar.gz: 22b4fcb061a87637d7c108e465e65ae3388379850a85f1f65e8661f7d1867b1c
5
5
  SHA512:
6
- metadata.gz: d452579efb8559353825d4e4771112ed5a25cc0d0abac7e3f508431a2c65795250767dddc824d1c9cd297e0e1bbff20d9d5ccc5d119be50657cb6386ce717b7e
7
- data.tar.gz: 67d57f3cb2202e527ddd35493700612db4e166692cc7f880f2dbcaa908766bb4c711a47b0c3fa281fb463f89280c40486c54680be0179c3538957ed014a9f69b
6
+ metadata.gz: b6ec6a61a6b1c63545739a2dec75455a1a9a68addde791deb339f4190246e5469875f13e8fa84f45505d579073668d45dd4bdc28c833fba3f5164a8f21a4afd7
7
+ data.tar.gz: f37bf0833c8c894fc5d0f71248abf4c1cac83bf4a4f6b70676d6f044217ba9ac2ccb6edc60ead20dfa53c6c8c47e872eb0db559e0c2229faf6e85f03c139c049
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async/reactor'
4
+ require 'async/io/stream'
5
+ require 'async/http/url_endpoint'
6
+ require 'async/websocket/client'
7
+
8
+ URL = ARGV.pop
9
+ USER = ARGV.pop
10
+
11
+ Async::Reactor.run do |task|
12
+ endpoint = Async::HTTP::URLEndpoint.parse(URL)
13
+
14
+ endpoint.connect do |socket|
15
+ connection = Async::WebSocket::Client.new(socket, URL)
16
+
17
+ connection.send_message({
18
+ user: USER,
19
+ status: "connected",
20
+ })
21
+
22
+ task.async do
23
+ stdin = Async::IO::Stream.new(
24
+ Async::IO::Generic.new($stdin)
25
+ )
26
+
27
+ puts "Waiting for input..."
28
+ while line = stdin.read_until("\n")
29
+ puts "Sending text: #{line}"
30
+ connection.send_message({
31
+ user: USER,
32
+ text: line,
33
+ })
34
+ end
35
+ end
36
+
37
+ while message = connection.next_message
38
+ puts "Message from server: #{message.inspect}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env falcon serve --concurrency 1 -c
2
+
3
+ require 'async/websocket/server'
4
+
5
+ Message = Struct.new(:user, :contents, :created_at)
6
+
7
+ $connections = []
8
+
9
+ run lambda {|env|
10
+ Async::WebSocket::Server.open(env) do |connection|
11
+ $connections << connection
12
+
13
+ while message = connection.next_message
14
+ $connections.each do |connection|
15
+ connection.send_message(message)
16
+ end
17
+ end
18
+ end
19
+
20
+ [200, {}, ["Hello World"]]
21
+ }
@@ -19,67 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require_relative 'websocket/version'
22
- require 'websocket/driver'
23
-
24
- module Async
25
- def self.WebSocket?(env)
26
- ::WebSocket::Driver.websocket?(env)
27
- end
28
-
29
- module WebSocket
30
- class Connection
31
- READ_BUFFER_SIZE = 1024*8
32
-
33
- attr_reader :env, :url
34
-
35
- def initialize(env, io)
36
- @env = env
37
- @io = io
38
-
39
- scheme = Rack::Request.new(env).ssl? ? 'wss:' : 'ws:'
40
- @url = "#{scheme}//#{env['HTTP_HOST']}#{env['REQUEST_URI']}"
41
-
42
- @driver = ::WebSocket::Driver.rack(self)
43
- @running = false
44
- end
45
-
46
- def write(string)
47
- @io.write(string)
48
- end
49
-
50
- def read
51
- @driver.parse(@io.read(READ_BUFFER_SIZE))
52
- end
53
-
54
- def run(&handler)
55
- @running = true
56
-
57
- @driver.on(:close) do
58
- @running = false
59
- end
60
-
61
- @driver.on(:open) do
62
- yield @driver if block_given?
63
- end
64
-
65
- @driver.start
66
-
67
- while @running
68
- self.read
69
- end
70
- end
71
- end
72
-
73
- def self.open(env)
74
- if ::WebSocket::Driver.websocket?(env)
75
- env['rack.hijack'].call
76
-
77
- connection = Connection.new(env, env['rack.hijack_io'])
78
-
79
- connection.run do |driver|
80
- yield driver
81
- end
82
- end
83
- end
84
- end
85
- end
22
+ require_relative 'websocket/server'
23
+ require_relative 'websocket/client'
@@ -18,71 +18,16 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'websocket/driver'
22
- require 'json'
21
+ require_relative 'connection'
23
22
 
24
23
  module Async
25
24
  module WebSocket
26
25
  # This is a basic synchronous websocket client:
27
- class Client
28
- EVENTS = [:open, :message, :close]
29
-
30
- def initialize(socket, url: "ws://.")
31
- @socket = socket
26
+ class Client < Connection
27
+ def initialize(socket, url = "ws://.")
32
28
  @url = url
33
29
 
34
- @driver = ::WebSocket::Driver.client(self)
35
-
36
- @queue = []
37
-
38
- @driver.on(:error) do |error|
39
- raise error
40
- end
41
-
42
- EVENTS.each do |event|
43
- @driver.on(event) do |data|
44
- @queue.push(data)
45
- end
46
- end
47
-
48
- @driver.start
49
- end
50
-
51
- attr :driver
52
- attr :url
53
-
54
- def next_event
55
- while @queue.empty?
56
- data = @socket.read(1024)
57
-
58
- if data and !data.empty?
59
- @driver.parse(data)
60
- else
61
- return nil
62
- end
63
- end
64
-
65
- @queue.shift
66
- rescue EOFError
67
- return nil
68
- end
69
-
70
- def next_message
71
- while event = next_event
72
- if event.is_a? ::WebSocket::Driver::MessageEvent
73
- return JSON.parse(event.data)
74
- elsif event.is_a? ::WebSocket::Driver::CloseEvent
75
- return nil
76
- end
77
- end
78
- end
79
-
80
- def write(data)
81
- @socket.write(data)
82
- end
83
-
84
- def close
85
- @driver.close
30
+ super socket, ::WebSocket::Driver.client(self)
86
31
  end
87
32
  end
88
33
  end
@@ -0,0 +1,91 @@
1
+ # Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'websocket/driver'
22
+ require 'json'
23
+
24
+ module Async
25
+ module WebSocket
26
+ # This is a basic synchronous websocket client:
27
+ class Connection
28
+ EVENTS = [:open, :message, :close]
29
+
30
+ def initialize(socket, driver)
31
+ @socket = socket
32
+ @driver = driver
33
+
34
+ @queue = []
35
+
36
+ @driver.on(:error) do |error|
37
+ raise error
38
+ end
39
+
40
+ EVENTS.each do |event|
41
+ @driver.on(event) do |data|
42
+ @queue.push(data)
43
+ end
44
+ end
45
+
46
+ @driver.start
47
+ end
48
+
49
+ attr :driver
50
+ attr :url
51
+
52
+ def next_event
53
+ while @queue.empty?
54
+ data = @socket.read(1024)
55
+
56
+ if data and !data.empty?
57
+ @driver.parse(data)
58
+ else
59
+ return nil
60
+ end
61
+ end
62
+
63
+ @queue.shift
64
+ rescue EOFError
65
+ return nil
66
+ end
67
+
68
+ def next_message
69
+ while event = next_event
70
+ if event.is_a? ::WebSocket::Driver::MessageEvent
71
+ return JSON.parse(event.data)
72
+ elsif event.is_a? ::WebSocket::Driver::CloseEvent
73
+ return nil
74
+ end
75
+ end
76
+ end
77
+
78
+ def send_message(message)
79
+ @driver.text(JSON.dump(message))
80
+ end
81
+
82
+ def write(data)
83
+ @socket.write(data)
84
+ end
85
+
86
+ def close
87
+ @driver.close
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'connection'
22
+
23
+ module Async
24
+ module WebSocket
25
+ class Server < Connection
26
+ def initialize(env, socket)
27
+ scheme = env['rack.url_scheme'] == 'https' ? 'wss' : 'ws'
28
+ @url = "#{scheme}://#{env['HTTP_HOST']}#{env['REQUEST_URI']}"
29
+
30
+ @env = env
31
+
32
+ super socket, ::WebSocket::Driver.rack(self)
33
+ end
34
+
35
+ attr :env
36
+ attr :url
37
+
38
+ def self.open(env)
39
+ if ::WebSocket::Driver.websocket?(env)
40
+ env['rack.hijack'].call
41
+
42
+ connection = self.new(env, env['rack.hijack_io'])
43
+
44
+ if block_given?
45
+ begin
46
+ yield(connection) || true
47
+ ensure
48
+ connection.close
49
+ end
50
+ else
51
+ return connection
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module WebSocket
23
- VERSION = "0.2.0"
23
+ VERSION = "0.3.0"
24
24
  end
25
25
  end
@@ -26,12 +26,13 @@ require 'falcon/server'
26
26
 
27
27
  RSpec.describe Async::WebSocket::Connection do
28
28
  include_context Async::RSpec::Reactor
29
+
29
30
  let(:server_address) {Async::IO::Endpoint.tcp('0.0.0.0', 9000)}
30
31
  let(:app) {Rack::Builder.parse_file(File.expand_path('../connection_spec.ru', __FILE__)).first}
31
32
  let(:server) {Falcon::Server.new(app, [server_address])}
32
33
 
33
34
  it "should connect to the websocket server" do
34
- server_task = Async::Reactor.run do
35
+ server_task = reactor.async do
35
36
  server.run
36
37
  end
37
38
 
@@ -1,5 +1,5 @@
1
1
 
2
- require 'async/websocket'
2
+ require 'async/websocket/server'
3
3
 
4
4
  class Upgrade
5
5
  def initialize(app)
@@ -7,22 +7,16 @@ class Upgrade
7
7
  end
8
8
 
9
9
  def call(env)
10
- if Async::WebSocket?(env)
11
- Async::WebSocket.open(env) do |connection|
12
- read, write = IO.pipe
13
-
14
- Process.spawn("ls -lah", :out => write)
15
- write.close
16
-
17
- read.each_line do |line|
18
- connection.text(line)
19
- end
20
-
21
- connection.close
10
+ Async::WebSocket::Server.open(env) do |server|
11
+ read, write = IO.pipe
12
+
13
+ Process.spawn("ls -lah", :out => write)
14
+ write.close
15
+
16
+ read.each_line do |line|
17
+ server.driver.text(line)
22
18
  end
23
- else
24
- @app.call(env)
25
- end
19
+ end or @app.call(env)
26
20
  end
27
21
  end
28
22
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-02 00:00:00.000000000 Z
11
+ date: 2018-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-driver
@@ -122,8 +122,12 @@ files:
122
122
  - README.md
123
123
  - Rakefile
124
124
  - async-websocket.gemspec
125
+ - chat/client.rb
126
+ - chat/config.ru
125
127
  - lib/async/websocket.rb
126
128
  - lib/async/websocket/client.rb
129
+ - lib/async/websocket/connection.rb
130
+ - lib/async/websocket/server.rb
127
131
  - lib/async/websocket/version.rb
128
132
  - spec/async/websocket/connection_spec.rb
129
133
  - spec/async/websocket/connection_spec.ru
@@ -148,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
152
  version: '0'
149
153
  requirements: []
150
154
  rubyforge_project:
151
- rubygems_version: 2.6.12
155
+ rubygems_version: 2.7.6
152
156
  signing_key:
153
157
  specification_version: 4
154
158
  summary: An async websocket library on top of websocket-driver.