async-websocket 0.13.1 → 0.18.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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/websocket/adapters/rack.rb +7 -1
  3. data/{spec/async/websocket/upgrade.rb → lib/async/websocket/adapters/rails.rb} +20 -19
  4. data/lib/async/websocket/client.rb +39 -17
  5. data/lib/async/websocket/connect_request.rb +31 -16
  6. data/lib/async/websocket/connect_response.rb +2 -2
  7. data/lib/async/websocket/connection.rb +21 -2
  8. data/lib/async/websocket/request.rb +1 -1
  9. data/lib/async/websocket/response.rb +1 -1
  10. data/lib/async/websocket/server.rb +2 -0
  11. data/lib/async/websocket/upgrade_request.rb +9 -9
  12. data/lib/async/websocket/upgrade_response.rb +3 -3
  13. data/lib/async/websocket/version.rb +1 -1
  14. metadata +36 -103
  15. data/.editorconfig +0 -6
  16. data/.gitignore +0 -13
  17. data/.rspec +0 -3
  18. data/.travis.yml +0 -18
  19. data/Gemfile +0 -12
  20. data/README.md +0 -129
  21. data/Rakefile +0 -6
  22. data/async-websocket.gemspec +0 -29
  23. data/examples/chat/README.md +0 -3
  24. data/examples/chat/client.rb +0 -32
  25. data/examples/chat/config.ru +0 -113
  26. data/examples/chat/multi-client.rb +0 -81
  27. data/examples/mud/client.rb +0 -34
  28. data/examples/mud/config.ru +0 -142
  29. data/examples/rack/client.rb +0 -20
  30. data/examples/rack/config.ru +0 -14
  31. data/examples/utopia/.bowerrc +0 -4
  32. data/examples/utopia/.gitignore +0 -9
  33. data/examples/utopia/.rspec +0 -4
  34. data/examples/utopia/Gemfile +0 -33
  35. data/examples/utopia/Guardfile +0 -29
  36. data/examples/utopia/README.md +0 -16
  37. data/examples/utopia/Rakefile +0 -8
  38. data/examples/utopia/config.ru +0 -47
  39. data/examples/utopia/config/README.md +0 -7
  40. data/examples/utopia/config/environment.rb +0 -8
  41. data/examples/utopia/lib/readme.txt +0 -1
  42. data/examples/utopia/pages/_heading.xnode +0 -2
  43. data/examples/utopia/pages/_page.xnode +0 -30
  44. data/examples/utopia/pages/client/client.js +0 -28
  45. data/examples/utopia/pages/client/index.xnode +0 -8
  46. data/examples/utopia/pages/errors/exception.xnode +0 -5
  47. data/examples/utopia/pages/errors/file-not-found.xnode +0 -5
  48. data/examples/utopia/pages/links.yaml +0 -2
  49. data/examples/utopia/pages/server/controller.rb +0 -26
  50. data/examples/utopia/public/_static/icon.png +0 -0
  51. data/examples/utopia/public/_static/site.css +0 -205
  52. data/examples/utopia/public/_static/utopia-background.svg +0 -1
  53. data/examples/utopia/public/_static/utopia.svg +0 -1
  54. data/examples/utopia/public/readme.txt +0 -1
  55. data/examples/utopia/spec/spec_helper.rb +0 -31
  56. data/examples/utopia/spec/website_context.rb +0 -11
  57. data/examples/utopia/spec/website_spec.rb +0 -56
  58. data/examples/utopia/tasks/bower.rake +0 -45
  59. data/examples/utopia/tasks/deploy.rake +0 -13
  60. data/examples/utopia/tasks/development.rake +0 -34
  61. data/examples/utopia/tasks/environment.rake +0 -17
  62. data/examples/utopia/tasks/log.rake +0 -17
  63. data/examples/utopia/tasks/static.rake +0 -43
  64. data/spec/async/websocket/adapters/rack/client.rb +0 -38
  65. data/spec/async/websocket/adapters/rack/config.ru +0 -23
  66. data/spec/async/websocket/adapters/rack_spec.rb +0 -84
  67. data/spec/async/websocket/client_spec.rb +0 -48
  68. data/spec/async/websocket/connection_spec.rb +0 -34
  69. data/spec/async/websocket/server_examples.rb +0 -81
  70. data/spec/async/websocket/server_spec.rb +0 -31
  71. data/spec/spec_helper.rb +0 -16
data/.editorconfig DELETED
@@ -1,6 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = tab
5
- indent_size = 2
6
-
data/.gitignore DELETED
@@ -1,13 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
12
- Gemfile.lock
13
- .covered.db
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --warnings
3
- --require spec_helper
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- language: ruby
2
- dist: xenial
3
- cache: bundler
4
-
5
- matrix:
6
- include:
7
- - rvm: 2.4
8
- - rvm: 2.5
9
- - rvm: 2.6
10
- - rvm: 2.6
11
- env: COVERAGE=PartialSummary,Coveralls
12
- - rvm: truffleruby
13
- - rvm: jruby-head
14
- env: JRUBY_OPTS="--debug -X+O"
15
- - rvm: ruby-head
16
- allow_failures:
17
- - rvm: ruby-head
18
- - rvm: jruby-head
data/Gemfile DELETED
@@ -1,12 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :test do
6
- gem 'rack-test'
7
- gem 'pry'
8
- end
9
-
10
- group :development do
11
- gem 'tty-progressbar'
12
- end
data/README.md DELETED
@@ -1,129 +0,0 @@
1
- # Async::WebSocket
2
-
3
- A simple asynchronous websocket client/server implementation for [HTTP/1](https://tools.ietf.org/html/rfc6455) and [HTTP/2](https://tools.ietf.org/html/rfc8441).
4
-
5
- [![Build Status](https://secure.travis-ci.org/socketry/async-websocket.svg)](http://travis-ci.org/socketry/async-websocket)
6
- [![Code Climate](https://codeclimate.com/github/socketry/async-websocket.svg)](https://codeclimate.com/github/socketry/async-websocket)
7
- [![Coverage Status](https://coveralls.io/repos/socketry/async-websocket/badge.svg)](https://coveralls.io/r/socketry/async-websocket)
8
-
9
- ## Installation
10
-
11
- Add this line to your application's Gemfile:
12
-
13
- gem 'async-websocket'
14
-
15
- And then execute:
16
-
17
- $ bundle
18
-
19
- Or install it yourself as:
20
-
21
- $ gem install async-websocket
22
-
23
- ## Usage
24
-
25
- There are [examples](examples/) which include:
26
-
27
- - [A command line chat client/server](examples/chat) which can read input from `stdin` and send messages to the server.
28
- - [A small MUD client/server](examples/mud) which uses JSON for communation between client/server.
29
- - [A utopia-based web application](examples/utopia) which uses a JavaScript client to connect to a web application server.
30
-
31
- ### Client Side with Async
32
-
33
- ```ruby
34
- #!/usr/bin/env ruby
35
-
36
- require 'async'
37
- require 'async/io/stream'
38
- require 'async/http/endpoint'
39
- require 'async/websocket/client'
40
-
41
- USER = ARGV.pop || "anonymous"
42
- URL = ARGV.pop || "http://localhost:7070"
43
-
44
- Async do |task|
45
- stdin = Async::IO::Stream.new(
46
- Async::IO::Generic.new($stdin)
47
- )
48
-
49
- endpoint = Async::HTTP::Endpoint.parse(URL)
50
-
51
- Async::WebSocket::Client.open(endpoint) do |connection|
52
- input_task = task.async do
53
- while line = stdin.read_until("\n")
54
- connection.write({user: USER, text: line})
55
- connection.flush
56
- end
57
- end
58
-
59
- connection.write({
60
- user: USER,
61
- status: "connected",
62
- })
63
-
64
- while message = connection.read
65
- puts message.inspect
66
- end
67
- ensure
68
- input_task&.stop
69
- end
70
- end
71
- ```
72
-
73
- ### Server Side with Rack & Falcon
74
-
75
- ```ruby
76
- #!/usr/bin/env -S falcon serve --bind http://localhost:7070 --count 1 -c
77
-
78
- require 'async/websocket/adapters/rack'
79
- require 'set'
80
-
81
- $connections = Set.new
82
-
83
- run lambda {|env|
84
- Async::WebSocket::Adapters::Rack.open(env, protocols: ['ws']) do |connection|
85
- $connections << connection
86
-
87
- while message = connection.read
88
- $connections.each do |connection|
89
- connection.write(message)
90
- connection.flush
91
- end
92
- end
93
- ensure
94
- $connections.delete(connection)
95
- end or [200, {}, ["Hello World"]]
96
- }
97
- ```
98
-
99
- ## Contributing
100
-
101
- 1. Fork it
102
- 2. Create your feature branch (`git checkout -b my-new-feature`)
103
- 3. Commit your changes (`git commit -am 'Add some feature'`)
104
- 4. Push to the branch (`git push origin my-new-feature`)
105
- 5. Create new Pull Request
106
-
107
- ## License
108
-
109
- Released under the MIT license.
110
-
111
- Copyright, 2015, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
112
-
113
- Permission is hereby granted, free of charge, to any person obtaining a copy
114
- of this software and associated documentation files (the "Software"), to deal
115
- in the Software without restriction, including without limitation the rights
116
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
117
- copies of the Software, and to permit persons to whom the Software is
118
- furnished to do so, subject to the following conditions:
119
-
120
- The above copyright notice and this permission notice shall be included in
121
- all copies or substantial portions of the Software.
122
-
123
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
124
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
125
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
126
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
127
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
128
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
129
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
@@ -1,29 +0,0 @@
1
-
2
- require_relative 'lib/async/websocket/version'
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-websocket"
6
- spec.version = Async::WebSocket::VERSION
7
- spec.authors = ["Samuel Williams"]
8
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
- spec.summary = %q{An async websocket library on top of websocket-driver.}
10
- spec.homepage = ""
11
- spec.license = "MIT"
12
-
13
- spec.files = `git ls-files -z`.split("\x0")
14
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
- spec.require_paths = ["lib"]
17
-
18
- spec.add_dependency "async-io", "~> 1.23"
19
- spec.add_dependency "async-http", "~> 0.43"
20
- spec.add_dependency "protocol-websocket", "~> 0.7.0"
21
-
22
- spec.add_development_dependency "async-rspec"
23
- spec.add_development_dependency "falcon", "~> 0.32"
24
-
25
- spec.add_development_dependency "covered"
26
- spec.add_development_dependency "bundler"
27
- spec.add_development_dependency "rspec", "~> 3.6"
28
- spec.add_development_dependency "rake"
29
- end
@@ -1,3 +0,0 @@
1
- # The Journey to One Million
2
-
3
-
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/io/stream'
5
- require 'async/http/endpoint'
6
- require_relative '../../lib/async/websocket/client'
7
-
8
- USER = ARGV.pop || "anonymous"
9
- URL = ARGV.pop || "https://localhost:8080"
10
- ENDPOINT = Async::HTTP::Endpoint.parse(URL)
11
-
12
- Async do |task|
13
- stdin = Async::IO::Stream.new(
14
- Async::IO::Generic.new($stdin)
15
- )
16
-
17
- Async::WebSocket::Client.connect(ENDPOINT) do |connection|
18
- input_task = task.async do
19
- while line = stdin.read_until("\n")
20
- connection.write({text: line})
21
- connection.flush
22
- end
23
- end
24
-
25
- puts "Connected..."
26
- while message = connection.read
27
- puts "> #{message.inspect}"
28
- end
29
- ensure
30
- input_task&.stop
31
- end
32
- end
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env -S falcon serve --bind https://localhost:8080 --count 1 -c
2
-
3
- require_relative '../../lib/async/websocket/adapters/rack'
4
- require 'async/clock'
5
- require 'async/semaphore'
6
- require 'async/logger'
7
-
8
- require 'set'
9
-
10
- GC.disable
11
-
12
- class Room
13
- def initialize
14
- @connections = Set.new
15
- @semaphore = Async::Semaphore.new(512)
16
- end
17
-
18
- def connect connection
19
- @connections << connection
20
- end
21
-
22
- def disconnect connection
23
- @connections.delete(connection)
24
- end
25
-
26
- def each(&block)
27
- @connections.each(&block)
28
- end
29
-
30
- def allocations
31
- counts = Hash.new{|h,k| h[k] = 0}
32
-
33
- ObjectSpace.each_object do |object|
34
- counts[object.class] += 1
35
- end
36
-
37
- return counts
38
- end
39
-
40
- def show_allocations(key, limit = 1000)
41
- Async.logger.info(self) do |buffer|
42
- ObjectSpace.each_object(key).each do |object|
43
- buffer.puts object
44
- end
45
- end
46
- end
47
-
48
- def print_allocations(minimum = @connections.count)
49
- count = 0
50
-
51
- Async.logger.info(self) do |buffer|
52
- allocations.select{|k,v| v >= minimum}.sort_by{|k,v| -v}.each do |key, value|
53
- count += value
54
- buffer.puts "#{key}: #{value} allocations"
55
- end
56
-
57
- buffer.puts "** #{count.to_f / @connections.count} objects per connection."
58
- end
59
- end
60
-
61
- def command(code)
62
- Async.logger.warn self, "eval(#{code})"
63
-
64
- eval(code)
65
- end
66
-
67
- def broadcast(message)
68
- Async.logger.info "Broadcast: #{message.inspect}"
69
- start_time = Async::Clock.now
70
-
71
- @connections.each do |connection|
72
- @semaphore.async do
73
- connection.write(message)
74
- connection.flush
75
- end
76
- end
77
-
78
- end_time = Async::Clock.now
79
- Async.logger.info "Duration: #{(end_time - start_time).round(3)}s for #{@connections.count} connected clients."
80
- end
81
-
82
- def open(connection)
83
- self.connect(connection)
84
-
85
- while message = connection.read
86
- if message[:text] =~ /^\/(.*?)$/
87
- begin
88
- result = self.command($1)
89
-
90
- if result.is_a? Hash
91
- connection.write(result)
92
- else
93
- connection.write({result: result.inspect})
94
- end
95
- rescue
96
- connection.write({error: $!.inspect})
97
- end
98
- else
99
- self.broadcast(message)
100
- end
101
- end
102
-
103
- connection.close
104
- ensure
105
- self.disconnect(connection)
106
- end
107
-
108
- def call(env)
109
- Async::WebSocket::Adapters::Rack.open(env, &self.method(:open))
110
- end
111
- end
112
-
113
- run Room.new
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async'
4
- require 'async/semaphore'
5
- require 'async/clock'
6
- require 'async/io/stream'
7
- require 'async/http/endpoint'
8
- require_relative '../../lib/async/websocket/client'
9
-
10
- require 'samovar'
11
- require 'ruby-prof'
12
-
13
- require 'tty/progressbar'
14
-
15
- GC.disable
16
-
17
- class Command < Samovar::Command
18
- options do
19
- option "-c/--count <integer>", "The total number of connections to make.", default: 1000, type: Integer
20
- option "--bind <address>", "The local address to bind to before making a connection."
21
- option "--connect <string>", "The remote server to connect to.", default: "https://localhost:8080"
22
-
23
- option "-s/--semaphore <integer>", "The number of simultaneous connections to perform."
24
- end
25
-
26
- def local_address
27
- if bind = @options[:bind]
28
- Async::IO::Address.tcp(bind, 0)
29
- end
30
- end
31
-
32
- def call
33
- endpoint = Async::HTTP::Endpoint.parse(@options[:connect], local_address: self.local_address)
34
- count = @options[:count]
35
-
36
- connections = Async::Queue.new
37
- progress = TTY::ProgressBar.new(":rate connection/s [:bar] :current/:total (:eta/:elapsed)", total: count)
38
-
39
- # profile = RubyProf::Profile.new(merge_fibers: true)
40
- # profile.start
41
-
42
- Async do |task|
43
- task.logger.info!
44
-
45
- task.async do |subtask|
46
- while connection = connections.dequeue
47
- subtask.async(connection) do |subtask, connection|
48
- pp connection.read
49
-
50
- while message = connection.read
51
- pp message
52
- end
53
- ensure
54
- connection.close
55
- end
56
- end
57
-
58
- # subtask.children.each(&:stop)
59
- end
60
-
61
- client = Async::WebSocket::Client.open(endpoint)
62
-
63
- count.times do |i|
64
- connections.enqueue(client.connect(endpoint.path))
65
- progress.advance(1)
66
- end
67
-
68
- connections.enqueue(nil)
69
- end
70
-
71
- # ensure
72
- # result = profile.stop
73
- # printer = RubyProf::FlatPrinter.new(result)
74
- # printer.print(STDOUT, min_percent: 0.5)
75
- #
76
- # printer = RubyProf::GraphPrinter.new(result)
77
- # printer.print(STDOUT, min_percent: 0.5)
78
- end
79
- end
80
-
81
- Command.call