async-websocket 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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.