wands 0.1.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 +7 -0
- data/.idea/.gitignore +3 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/wands.iml +25 -0
- data/.rubocop.yml +20 -0
- data/LICENSE +21 -0
- data/README.md +50 -0
- data/Rakefile +12 -0
- data/lib/wands/http_response.rb +71 -0
- data/lib/wands/response_exception.rb +17 -0
- data/lib/wands/upgrade_request.rb +40 -0
- data/lib/wands/version.rb +5 -0
- data/lib/wands/web_socket.rb +65 -0
- data/lib/wands/web_socket_server.rb +93 -0
- data/lib/wands.rb +5 -0
- data/sig/wands.rbs +30 -0
- metadata +90 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ed955880d15ca35b40902f4be003d4615c049b113f7408873a64a0553a1a9e78
|
|
4
|
+
data.tar.gz: da44bcd5f0c393bf14ff2c55d16acd1eef21ac2073ad60f3e58b5d267fbc4db7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e75f52070180a29dee8a4d2a0dbfa0d7bf077cf09d917948610f6db0c06b4be21c5ad3a91adb62f5d2992746488e08580d0e9780e09d7d528dc4b111055ba35d
|
|
7
|
+
data.tar.gz: c2dcf0cc618b07e62f79f5113c4596b848a77122cb97e60457bebf108404122898261a7610de4fc0c119c3aa629c9705a630f4fc17d2d6308be98d625de4041c
|
data/.idea/.gitignore
ADDED
data/.idea/misc.xml
ADDED
data/.idea/modules.xml
ADDED
data/.idea/vcs.xml
ADDED
data/.idea/wands.iml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="RUBY_MODULE" version="4">
|
|
3
|
+
<component name="ModuleRunConfigurationManager">
|
|
4
|
+
<shared />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="NewModuleRootManager">
|
|
7
|
+
<content url="file://$MODULE_DIR$">
|
|
8
|
+
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
|
|
9
|
+
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
|
10
|
+
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
11
|
+
</content>
|
|
12
|
+
<orderEntry type="inheritedJdk" />
|
|
13
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
14
|
+
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, rbenv: 3.3.5) [gem]" level="application" />
|
|
15
|
+
<orderEntry type="library" scope="PROVIDED" name="fiber-annotation (v0.2.0, rbenv: 3.3.5) [gem]" level="application" />
|
|
16
|
+
<orderEntry type="library" scope="PROVIDED" name="fiber-local (v1.1.0, rbenv: 3.3.5) [gem]" level="application" />
|
|
17
|
+
<orderEntry type="library" scope="PROVIDED" name="fiber-storage (v1.0.0, rbenv: 3.3.5) [gem]" level="application" />
|
|
18
|
+
<orderEntry type="library" scope="PROVIDED" name="language_server-protocol (v3.17.0.3, rbenv: 3.3.5) [gem]" level="application" />
|
|
19
|
+
<orderEntry type="library" scope="PROVIDED" name="protocol-websocket (v0.20.1, rbenv: 3.3.5) [gem]" level="application" />
|
|
20
|
+
<orderEntry type="library" scope="PROVIDED" name="racc (v1.8.1, rbenv: 3.3.5) [gem]" level="application" />
|
|
21
|
+
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, rbenv: 3.3.5) [gem]" level="application" />
|
|
22
|
+
<orderEntry type="library" scope="PROVIDED" name="rake (v13.2.1, rbenv: 3.3.5) [gem]" level="application" />
|
|
23
|
+
<orderEntry type="library" scope="PROVIDED" name="stringio (v3.1.2, rbenv: 3.3.5) [gem]" level="application" />
|
|
24
|
+
</component>
|
|
25
|
+
</module>
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.1
|
|
3
|
+
NewCops: enable
|
|
4
|
+
|
|
5
|
+
Metrics/MethodLength:
|
|
6
|
+
Max: 15
|
|
7
|
+
|
|
8
|
+
Style/StringLiterals:
|
|
9
|
+
EnforcedStyle: double_quotes
|
|
10
|
+
|
|
11
|
+
Style/StringLiteralsInInterpolation:
|
|
12
|
+
EnforcedStyle: double_quotes
|
|
13
|
+
|
|
14
|
+
Layout/LineLength:
|
|
15
|
+
Exclude:
|
|
16
|
+
- wands.gemspec
|
|
17
|
+
|
|
18
|
+
require:
|
|
19
|
+
- rubocop-minitest
|
|
20
|
+
- rubocop-rake
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 shigeru.nakajima
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Wands
|
|
2
|
+
|
|
3
|
+
A low-level WebSocket library compatible with Ruby's TCPSocket.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle add wands
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
gem install wands
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Server
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
server = Wands::WebSocketServer.open('localhost', 2345)
|
|
25
|
+
|
|
26
|
+
loop do
|
|
27
|
+
client = server.accept
|
|
28
|
+
client.write("Hello World!")
|
|
29
|
+
client.close
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Client
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
web_socket = Wands::WebSocket.open('localhost', 2345)
|
|
37
|
+
web_socket.write("Hello World!")
|
|
38
|
+
puts web_socket.gets
|
|
39
|
+
web_socket.close
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Development
|
|
43
|
+
|
|
44
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
45
|
+
|
|
46
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
47
|
+
|
|
48
|
+
## Contributing
|
|
49
|
+
|
|
50
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ledsun/wands.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wands
|
|
4
|
+
# This is a class that parses the response from the server and stores the headers in a hash.
|
|
5
|
+
# The parse and header methods in this class are modeled on WEBrick::HTTPRequest.
|
|
6
|
+
#
|
|
7
|
+
# The expected HTTP response string is:
|
|
8
|
+
#
|
|
9
|
+
# HTTP/1.1 101 Switching Protocols
|
|
10
|
+
# Upgrade: websocket
|
|
11
|
+
# Connection: Upgrade
|
|
12
|
+
# Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
|
13
|
+
# Sec-WebSocket-Protocol: chat
|
|
14
|
+
# Sec-WebSocket-Version: 13
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
# Example usage:
|
|
18
|
+
#
|
|
19
|
+
# response = HTTPResponse.new
|
|
20
|
+
# response.parse(socket)
|
|
21
|
+
# response.header["upgrade"] # => ["websocket"]
|
|
22
|
+
# response.header["connection"] # => ["Upgrade"]
|
|
23
|
+
# response.header["sec-websocket-accept"] # => ["s3pPLMBiTxaQ9kYGzzhZRbK+xOo="]
|
|
24
|
+
#
|
|
25
|
+
class HTTPResponse
|
|
26
|
+
attr_reader :status, :header
|
|
27
|
+
|
|
28
|
+
def parse(stream)
|
|
29
|
+
@response = read_from stream
|
|
30
|
+
@status, @header = headers_of @response
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_s
|
|
34
|
+
@response
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def read_from(stream)
|
|
40
|
+
response_string = ""
|
|
41
|
+
while (line = stream.gets) != "\r\n"
|
|
42
|
+
response_string += line
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
response_string
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Parse the headers from the HTTP response string.
|
|
49
|
+
def headers_of(response_string)
|
|
50
|
+
# Split the response string into headers and body.
|
|
51
|
+
headers, _body = response_string.split("\r\n\r\n", 2)
|
|
52
|
+
|
|
53
|
+
# Split the headers into lines.
|
|
54
|
+
headers_lines = headers.split("\r\n")
|
|
55
|
+
|
|
56
|
+
# The first line is the status line.
|
|
57
|
+
# We don't need it, so we remove it from the headers.
|
|
58
|
+
status_line = headers_lines.shift
|
|
59
|
+
status_code = status_line.split[1]
|
|
60
|
+
|
|
61
|
+
# Parse the headers into a hash.
|
|
62
|
+
headers = headers_lines.to_h do |line|
|
|
63
|
+
# Split the line into header name and value.
|
|
64
|
+
header_name, value = line.split(": ", 2)
|
|
65
|
+
[header_name.downcase, [value.strip]]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
[status_code, headers]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wands
|
|
4
|
+
# This exception is raised when the response from the server is not as expected.
|
|
5
|
+
class ResponseException < StandardError
|
|
6
|
+
attr_reader :response
|
|
7
|
+
|
|
8
|
+
def initialize(message, response)
|
|
9
|
+
super(message)
|
|
10
|
+
@response = response
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
"#{super} from '#{response}'"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
require "protocol/websocket/headers"
|
|
5
|
+
require_relative "response_exception"
|
|
6
|
+
|
|
7
|
+
module Wands
|
|
8
|
+
# The request is used to upgrade the HTTP connection to a WebSocket connection.
|
|
9
|
+
class UpgradeRequest
|
|
10
|
+
include ::Protocol::WebSocket::Headers
|
|
11
|
+
|
|
12
|
+
# The Host header is required in HTTP 1.1.
|
|
13
|
+
TEMPLATE = <<~REQUEST
|
|
14
|
+
GET / HTTP/1.1
|
|
15
|
+
Host: <%= @host %>:<%= @port %>
|
|
16
|
+
Connection: Upgrade
|
|
17
|
+
Upgrade: websocket
|
|
18
|
+
Sec-WebSocket-Version: 13
|
|
19
|
+
Sec-WebSocket-Key: <%= @key %>
|
|
20
|
+
|
|
21
|
+
REQUEST
|
|
22
|
+
|
|
23
|
+
ERB = ERB.new(TEMPLATE).freeze
|
|
24
|
+
|
|
25
|
+
def initialize(host, port)
|
|
26
|
+
@host = host
|
|
27
|
+
@port = port
|
|
28
|
+
@key = Nounce.generate_key
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
ERB.result(binding).gsub(/\r?\n/, "\r\n")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def verify(response)
|
|
36
|
+
accept_digest = response.header[SEC_WEBSOCKET_ACCEPT].first
|
|
37
|
+
accept_digest == Nounce.accept_digest(@key) || raise(ResponseException.new("Invalid accept digest", response))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "socket"
|
|
4
|
+
require "forwardable"
|
|
5
|
+
require "protocol/websocket/headers"
|
|
6
|
+
require "protocol/websocket/framer"
|
|
7
|
+
require "protocol/websocket/text_frame"
|
|
8
|
+
require_relative "upgrade_request"
|
|
9
|
+
require_relative "http_response"
|
|
10
|
+
require_relative "response_exception"
|
|
11
|
+
|
|
12
|
+
module Wands
|
|
13
|
+
# This is a class that represents WebSocket, which has the same interface as TCPSocket.
|
|
14
|
+
#
|
|
15
|
+
# The WebSocket class is responsible for reading and writing messages to the server.
|
|
16
|
+
#
|
|
17
|
+
# Example usage:
|
|
18
|
+
#
|
|
19
|
+
# web_socket = WebSocket.open('localhost', 2345)
|
|
20
|
+
# web_socket.write("Hello World!")
|
|
21
|
+
#
|
|
22
|
+
# puts web_socket.gets
|
|
23
|
+
#
|
|
24
|
+
# web_socket.close
|
|
25
|
+
#
|
|
26
|
+
class WebSocket
|
|
27
|
+
include Protocol::WebSocket::Headers
|
|
28
|
+
extend Forwardable
|
|
29
|
+
|
|
30
|
+
def_delegators :@socket, :addr, :remote_address, :close, :to_io
|
|
31
|
+
|
|
32
|
+
def self.open(host, port)
|
|
33
|
+
socket = TCPSocket.new(host, port)
|
|
34
|
+
request = UpgradeRequest.new(host, port)
|
|
35
|
+
socket.write(request.to_s)
|
|
36
|
+
socket.flush
|
|
37
|
+
|
|
38
|
+
response = HTTPResponse.new
|
|
39
|
+
response.parse(socket)
|
|
40
|
+
raise ResponseException.new("Bad Status", response) unless response.status == "101"
|
|
41
|
+
|
|
42
|
+
request.verify response
|
|
43
|
+
|
|
44
|
+
new(socket)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def initialize(socket)
|
|
48
|
+
@socket = socket
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [String]
|
|
52
|
+
def gets
|
|
53
|
+
framer = Protocol::WebSocket::Framer.new(@socket)
|
|
54
|
+
frame = framer.read_frame
|
|
55
|
+
raise "frame is not a text" unless frame.is_a? Protocol::WebSocket::TextFrame
|
|
56
|
+
|
|
57
|
+
frame.unpack
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def write(message)
|
|
61
|
+
frame = Protocol::WebSocket::TextFrame.new(true, message)
|
|
62
|
+
frame.write(@socket)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "socket"
|
|
4
|
+
require "protocol/websocket/headers"
|
|
5
|
+
require "webrick/httprequest"
|
|
6
|
+
require "webrick/httpresponse"
|
|
7
|
+
require "webrick/config"
|
|
8
|
+
require_relative "web_socket"
|
|
9
|
+
|
|
10
|
+
module Wands
|
|
11
|
+
# The WebSocketServer class is responsible for accepting WebSocket connections.
|
|
12
|
+
# This class has the same interface as TCPServer.
|
|
13
|
+
#
|
|
14
|
+
# Example usage:
|
|
15
|
+
#
|
|
16
|
+
# server = WebSocketServer.new('localhost', 2345)
|
|
17
|
+
# loop do
|
|
18
|
+
# begin
|
|
19
|
+
# socket = server.accept
|
|
20
|
+
# next unless socket
|
|
21
|
+
# puts "Accepted connection from #{socket.remote_address.ip_address} #{socket.remote_address.ip_port}"
|
|
22
|
+
#
|
|
23
|
+
# received_message = socket.gets
|
|
24
|
+
# puts "Received: #{received_message}"
|
|
25
|
+
#
|
|
26
|
+
# socket.write received_message
|
|
27
|
+
# socket.close
|
|
28
|
+
# rescue WEBrick::HTTPStatus::EOFError => e
|
|
29
|
+
# STDERR.puts e.message
|
|
30
|
+
# rescue Errno::ECONNRESET => e
|
|
31
|
+
# STDERR.puts "#{e.message} #{socket.remote_address.ip_address} #{socket.remote_address.ip_port}"
|
|
32
|
+
# rescue EOFError => e
|
|
33
|
+
# STDERR.puts "#{e.message} #{socket.remote_address.ip_address} #{socket.remote_address.ip_port}"
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
class WebSocketServer
|
|
38
|
+
include Protocol::WebSocket::Headers
|
|
39
|
+
|
|
40
|
+
def self.open(hostname, port)
|
|
41
|
+
new(hostname, port)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(hostname, port)
|
|
45
|
+
@tcp_server = TCPServer.new hostname, port
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def accept
|
|
49
|
+
socket = @tcp_server.accept
|
|
50
|
+
|
|
51
|
+
request = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
|
|
52
|
+
headers = read_headers_from request, socket
|
|
53
|
+
unless headers["upgrade"].include? PROTOCOL
|
|
54
|
+
socket.close
|
|
55
|
+
raise "Not a websocket request"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
response = response_to headers
|
|
59
|
+
response.send_response socket
|
|
60
|
+
|
|
61
|
+
WebSocket.new socket
|
|
62
|
+
rescue WEBrick::HTTPStatus::BadRequest => e
|
|
63
|
+
warn "WEBRick error message: #{e.full_message}"
|
|
64
|
+
warn "HTTP request string: #{request}" if request
|
|
65
|
+
if socket
|
|
66
|
+
socket.write "HTTP/1.1 400 Bad Request\r\n\r\n"
|
|
67
|
+
socket.close
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def read_headers_from(request, socket)
|
|
74
|
+
request.parse(socket)
|
|
75
|
+
request.header
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def response_to(headers)
|
|
79
|
+
response_key = calculate_accept_nonce_from headers
|
|
80
|
+
response = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
|
|
81
|
+
response.status = 101
|
|
82
|
+
response.upgrade! PROTOCOL
|
|
83
|
+
response[SEC_WEBSOCKET_ACCEPT] = response_key
|
|
84
|
+
|
|
85
|
+
response
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def calculate_accept_nonce_from(headers)
|
|
89
|
+
key = headers[SEC_WEBSOCKET_KEY].first
|
|
90
|
+
Nounce.accept_digest(key)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/wands.rb
ADDED
data/sig/wands.rbs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Wands
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
class WebSocket
|
|
5
|
+
@socket: TCPSocket
|
|
6
|
+
|
|
7
|
+
def initialize: (TCPSocket) -> void
|
|
8
|
+
def gets: () -> String
|
|
9
|
+
def write: (String) -> void
|
|
10
|
+
def self.open: (String, Integer) -> WebSocket
|
|
11
|
+
def close: () -> void
|
|
12
|
+
def addr: () -> Addrinfo
|
|
13
|
+
def remote_address: () -> Addrinfo
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class WebSocketServer
|
|
17
|
+
@tcp_server: TCPServer
|
|
18
|
+
|
|
19
|
+
def initialize: (String, Integer) -> void
|
|
20
|
+
def self.open: (String, Integer) -> WebSocketServer
|
|
21
|
+
def accept: () -> WebSocket
|
|
22
|
+
def close: () -> void
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def calculate_accept_nonce_from: (Hash[String, Array[String]]?) -> String
|
|
27
|
+
def read_headers_from: (WEBrick::HTTPRequest, TCPSocket) -> Hash[String, Array[String]]?
|
|
28
|
+
def response_to: (Hash[String, Array[String]]?) -> WEBrick::HTTPResponse
|
|
29
|
+
end
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: wands
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- shigeru.nakajima
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: protocol-websocket
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.20'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.20'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: webrick
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.9'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.9'
|
|
40
|
+
description: A WebSocket library with the same layer as Ruby's TCPSocket, which does
|
|
41
|
+
not have the function of an HTTP server, in order to use WebSocket as a new protocol
|
|
42
|
+
for dRuby.
|
|
43
|
+
email:
|
|
44
|
+
- shigeru.nakajima@gmail.com
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- ".idea/.gitignore"
|
|
50
|
+
- ".idea/misc.xml"
|
|
51
|
+
- ".idea/modules.xml"
|
|
52
|
+
- ".idea/vcs.xml"
|
|
53
|
+
- ".idea/wands.iml"
|
|
54
|
+
- ".rubocop.yml"
|
|
55
|
+
- LICENSE
|
|
56
|
+
- README.md
|
|
57
|
+
- Rakefile
|
|
58
|
+
- lib/wands.rb
|
|
59
|
+
- lib/wands/http_response.rb
|
|
60
|
+
- lib/wands/response_exception.rb
|
|
61
|
+
- lib/wands/upgrade_request.rb
|
|
62
|
+
- lib/wands/version.rb
|
|
63
|
+
- lib/wands/web_socket.rb
|
|
64
|
+
- lib/wands/web_socket_server.rb
|
|
65
|
+
- sig/wands.rbs
|
|
66
|
+
homepage: https://github.com/ledsun/wands
|
|
67
|
+
licenses:
|
|
68
|
+
- MIT
|
|
69
|
+
metadata:
|
|
70
|
+
allowed_push_host: https://rubygems.org
|
|
71
|
+
homepage_uri: https://github.com/ledsun/wands
|
|
72
|
+
rubygems_mfa_required: 'true'
|
|
73
|
+
rdoc_options: []
|
|
74
|
+
require_paths:
|
|
75
|
+
- lib
|
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: 3.1.0
|
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '0'
|
|
86
|
+
requirements: []
|
|
87
|
+
rubygems_version: 3.6.2
|
|
88
|
+
specification_version: 4
|
|
89
|
+
summary: A low-level WebSocket library compatible with Ruby's TCPSocket.
|
|
90
|
+
test_files: []
|