xconn 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/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +22 -0
- data/Makefile +9 -0
- data/README.md +2 -0
- data/Rakefile +14 -0
- data/bin/xconn +79 -0
- data/docs/index.md +7 -0
- data/docs/installation.md +11 -0
- data/example/sample/example.rb +23 -0
- data/example/sample/included_app.rb +12 -0
- data/lib/tasks/tasks.rake +24 -0
- data/lib/wamp/app.rb +39 -0
- data/lib/wamp/connection/session.rb +35 -0
- data/lib/wamp/connection/stream.rb +68 -0
- data/lib/wamp/connection/websocket_client.rb +137 -0
- data/lib/wamp/connection/websocket_connection.rb +52 -0
- data/lib/wamp/manager/base.rb +41 -0
- data/lib/wamp/manager/connection.rb +32 -0
- data/lib/wamp/manager/event/abort.rb +21 -0
- data/lib/wamp/manager/event/authenticate.rb +14 -0
- data/lib/wamp/manager/event/base.rb +41 -0
- data/lib/wamp/manager/event/call.rb +40 -0
- data/lib/wamp/manager/event/challenge.rb +26 -0
- data/lib/wamp/manager/event/error.rb +30 -0
- data/lib/wamp/manager/event/event.rb +20 -0
- data/lib/wamp/manager/event/goodbye.rb +18 -0
- data/lib/wamp/manager/event/hello.rb +38 -0
- data/lib/wamp/manager/event/invocation.rb +24 -0
- data/lib/wamp/manager/event/publish.rb +22 -0
- data/lib/wamp/manager/event/published.rb +13 -0
- data/lib/wamp/manager/event/register.rb +30 -0
- data/lib/wamp/manager/event/registered.rb +37 -0
- data/lib/wamp/manager/event/result.rb +13 -0
- data/lib/wamp/manager/event/subscribe.rb +39 -0
- data/lib/wamp/manager/event/subscribed.rb +26 -0
- data/lib/wamp/manager/event/unregister.rb +19 -0
- data/lib/wamp/manager/event/unregistered.rb +13 -0
- data/lib/wamp/manager/event/unsubscribe.rb +29 -0
- data/lib/wamp/manager/event/unsubscribed.rb +13 -0
- data/lib/wamp/manager/event/welcome.rb +21 -0
- data/lib/wamp/manager/event/yield.rb +13 -0
- data/lib/wamp/manager/event.rb +60 -0
- data/lib/wamp/manager/hello_event.rb +263 -0
- data/lib/wamp/manager/session.rb +91 -0
- data/lib/wamp/manager/subscription.rb +38 -0
- data/lib/wamp/manager.rb +12 -0
- data/lib/wamp/message_handler/api.rb +67 -0
- data/lib/wamp/message_handler/base.rb +65 -0
- data/lib/wamp/message_handler/call.rb +14 -0
- data/lib/wamp/message_handler/challenge.rb +12 -0
- data/lib/wamp/message_handler/error.rb +18 -0
- data/lib/wamp/message_handler/event.rb +18 -0
- data/lib/wamp/message_handler/goodbye.rb +19 -0
- data/lib/wamp/message_handler/hello.rb +18 -0
- data/lib/wamp/message_handler/invocation.rb +35 -0
- data/lib/wamp/message_handler/publish.rb +14 -0
- data/lib/wamp/message_handler/published.rb +18 -0
- data/lib/wamp/message_handler/register.rb +14 -0
- data/lib/wamp/message_handler/registered.rb +30 -0
- data/lib/wamp/message_handler/result.rb +17 -0
- data/lib/wamp/message_handler/subscribe.rb +14 -0
- data/lib/wamp/message_handler/subscribed.rb +30 -0
- data/lib/wamp/message_handler/unregister.rb +14 -0
- data/lib/wamp/message_handler/unregistered.rb +32 -0
- data/lib/wamp/message_handler/unsubscribe.rb +14 -0
- data/lib/wamp/message_handler/unsubscribed.rb +33 -0
- data/lib/wamp/message_handler/welcome.rb +12 -0
- data/lib/wamp/message_handler.rb +75 -0
- data/lib/wamp/router/base.rb +45 -0
- data/lib/wamp/router/client.rb +55 -0
- data/lib/wamp/router/connection.rb +150 -0
- data/lib/wamp/router/realm.rb +92 -0
- data/lib/wamp/router/server.rb +83 -0
- data/lib/wamp/router.rb +12 -0
- data/lib/wamp/serializer/cbor.rb +18 -0
- data/lib/wamp/serializer/json.rb +18 -0
- data/lib/wamp/serializer/message_pack.rb +18 -0
- data/lib/wamp/serializer.rb +5 -0
- data/lib/wamp/type/error.rb +24 -0
- data/lib/wamp/type/event.rb +16 -0
- data/lib/wamp/type/invocation.rb +16 -0
- data/lib/wamp/type/publication.rb +14 -0
- data/lib/wamp/type/registration.rb +14 -0
- data/lib/wamp/type/result.rb +16 -0
- data/lib/wamp/type/subscription.rb +14 -0
- data/lib/wamp/type/success.rb +8 -0
- data/lib/wamp/type.rb +16 -0
- data/lib/wamp/version.rb +5 -0
- data/lib/wamp.rb +15 -0
- data/mkdocs.yml +67 -0
- data/sig/wamp/serializer/json.rbs +10 -0
- data/sig/wamp.rbs +11 -0
- data/wamp.gemspec +40 -0
- metadata +223 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f4a4f50da44bd4849d8e503de34fcdee9edf558c06244ec43746b81401c09e3a
|
|
4
|
+
data.tar.gz: 5624eedc589212e83ba1684ab67e06d27bbb14c35dc8cf91245aed67b92475ce
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2867240ea024fafcd2fbc93da161473a546989fe349bc9be61a3e12c209d2358187957f291b0ee9d58874e524139cbfbd567838a4305bde178bb5c7e2519f253
|
|
7
|
+
data.tar.gz: 477e4d9640d8da4e555ace59c5b29f76c7b2b799399c4ad76e17ef9402ca2284519299c4b1e931b18d8e788ba60af7c72300f87819969743e51819fcd9bfb403
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.6
|
|
3
|
+
NewCops: enable
|
|
4
|
+
|
|
5
|
+
Style/StringLiterals:
|
|
6
|
+
Enabled: true
|
|
7
|
+
EnforcedStyle: double_quotes
|
|
8
|
+
|
|
9
|
+
Style/StringLiteralsInInterpolation:
|
|
10
|
+
Enabled: true
|
|
11
|
+
EnforcedStyle: double_quotes
|
|
12
|
+
|
|
13
|
+
Layout/LineLength:
|
|
14
|
+
Max: 120
|
|
15
|
+
|
|
16
|
+
Metrics/BlockLength:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Layout/BeginEndAlignment:
|
|
20
|
+
EnforcedStyleAlignWith: start_of_line
|
|
21
|
+
|
|
22
|
+
Layout/EndAlignment:
|
|
23
|
+
EnforcedStyleAlignWith: start_of_line
|
|
24
|
+
|
|
25
|
+
Layout/MultilineMethodCallIndentation:
|
|
26
|
+
EnforcedStyle: indented
|
|
27
|
+
|
|
28
|
+
Layout/CaseIndentation:
|
|
29
|
+
EnforcedStyle: end
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Simple Things Inc.
|
|
4
|
+
Copyright (c) 2024 XConnIO Ltd.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
data/Makefile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
require "rubocop/rake_task"
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new
|
|
11
|
+
|
|
12
|
+
task default: %i[spec rubocop]
|
|
13
|
+
|
|
14
|
+
Dir.glob("lib/tasks/**/*.rake").each { |r| load r }
|
data/bin/xconn
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "wamp"
|
|
6
|
+
|
|
7
|
+
require "optparse"
|
|
8
|
+
|
|
9
|
+
options = { host: "127.0.0.1", port: 8080, realm: "realm1", directory: ".", app: "App" }
|
|
10
|
+
OptionParser.new do |opts|
|
|
11
|
+
opts.banner = "Usage: xconn [options]"
|
|
12
|
+
|
|
13
|
+
opts.on("-hHOST", "--host HOST", "WebSocket host (default: ws://127.0.0.1:8080/ws)") do |host|
|
|
14
|
+
options[:host] = host
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
opts.on("-rREALM", "--realm REALM", "Realm (default: reaml1)") do |realm|
|
|
18
|
+
options[:realm] = realm
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
opts.on("-pPORT", "--port PORT", "Port (default: 8080)") do |port|
|
|
22
|
+
options[:port] = port
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
opts.on("-dDIRECTORY", "--directory DIRECTORY", 'Directory (default: ".")') do |directory|
|
|
26
|
+
options[:directory] = directory
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
opts.on("-aAPP", "--app APP", 'App (default: "App")') do |app|
|
|
30
|
+
options[:app] = app
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
opts.on("-v", "--version", "Gem Version") do |version|
|
|
34
|
+
options[:version] = version
|
|
35
|
+
end
|
|
36
|
+
end.parse!
|
|
37
|
+
|
|
38
|
+
if options.include?(:version)
|
|
39
|
+
puts "Xconn v#{Wamp::VERSION}"
|
|
40
|
+
exit 0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_client_session(router)
|
|
44
|
+
session = Wamp::Connection::Session.new
|
|
45
|
+
|
|
46
|
+
server_session = Wamp::Router::Client.new
|
|
47
|
+
server_session.router = router
|
|
48
|
+
server_session.connection = session
|
|
49
|
+
|
|
50
|
+
session.stream = server_session
|
|
51
|
+
session
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
router = Wamp::Router::Base.new
|
|
55
|
+
router.add_realm(options.fetch(:realm))
|
|
56
|
+
|
|
57
|
+
client = create_client_session(router).tap(&:on_open)
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
Pathname.new(options[:directory]).glob("**/*.rb").each { |file| require file.to_s }
|
|
61
|
+
rescue LoadError => e
|
|
62
|
+
puts e.message
|
|
63
|
+
exit 1
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
app = Object.const_get(options[:app])
|
|
68
|
+
app.new.procedures.each do |procedure, func|
|
|
69
|
+
client.api.register(procedure, func) do
|
|
70
|
+
puts "Registered procedure: #{procedure}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
rescue StandardError => e
|
|
74
|
+
puts e.message
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
server = Wamp::Router::Server.new(router, options)
|
|
79
|
+
server.run
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "wamp"
|
|
4
|
+
require "date"
|
|
5
|
+
require_relative "included_app"
|
|
6
|
+
|
|
7
|
+
# SystemApp
|
|
8
|
+
class Example < Wamp::App
|
|
9
|
+
register echo: "io.xconn.echo", current_date: "io.xconn.date.get"
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super
|
|
13
|
+
include_app(IncludedApp.new, "test.")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def echo(invocation)
|
|
17
|
+
Wamp::Type::Result.new(args: invocation.args, kwargs: invocation.kwargs, details: invocation.details)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def current_date(_invocation)
|
|
21
|
+
Wamp::Type::Result.new(args: Date.today.iso8601)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "wamp"
|
|
4
|
+
|
|
5
|
+
# Class that can be included
|
|
6
|
+
class IncludedApp < Wamp::App
|
|
7
|
+
register echo: "foo.bar.echo"
|
|
8
|
+
|
|
9
|
+
def echo(invocation)
|
|
10
|
+
Wamp::Type::Result.new(args: invocation.args, kwargs: invocation.kwargs, details: invocation.details)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :xconn do
|
|
4
|
+
desc "Start SAMPLE app"
|
|
5
|
+
task :run, [:host, :port, :realm, :directory, :app] do |_t, args|
|
|
6
|
+
host = args[:host] || "127.0.0.1"
|
|
7
|
+
port = args[:port] || 8080
|
|
8
|
+
realm = args[:realm] || "realm1"
|
|
9
|
+
app = args[:app] || "Example"
|
|
10
|
+
directory = args[:directory] || "./example/sample"
|
|
11
|
+
|
|
12
|
+
command = "bin/xconn -h #{host} -p #{port} -r #{realm} -d #{directory} -a #{app}"
|
|
13
|
+
|
|
14
|
+
puts "Running: #{command}"
|
|
15
|
+
|
|
16
|
+
trap("SIGINT") do
|
|
17
|
+
puts "\nReceived SIGINT. Gracefully exiting..."
|
|
18
|
+
|
|
19
|
+
exit 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
`#{command}`
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/wamp/app.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wamp
|
|
4
|
+
# WAMPApp
|
|
5
|
+
class App
|
|
6
|
+
def initialize
|
|
7
|
+
@procedures = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def include_app(app, prefix = "")
|
|
11
|
+
if prefix&.length&.zero?
|
|
12
|
+
procedures.merge!(app.procedures)
|
|
13
|
+
else
|
|
14
|
+
app.procedures.each do |procedure, func|
|
|
15
|
+
procedures.merge!({ "#{prefix}#{procedure}" => func })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def procedures
|
|
21
|
+
return {} if self.class.procedures && self.class.procedures.empty?
|
|
22
|
+
return @procedures if @procedures.any?
|
|
23
|
+
|
|
24
|
+
self.class.procedures.map do |procedure, registration_name|
|
|
25
|
+
@procedures[registration_name.to_s] = method(procedure)
|
|
26
|
+
end
|
|
27
|
+
@procedures
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
attr_reader :procedures
|
|
32
|
+
|
|
33
|
+
def register(procedures = {})
|
|
34
|
+
@procedures ||= {}
|
|
35
|
+
@procedures.merge!(procedures)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wamp
|
|
4
|
+
module Connection
|
|
5
|
+
# Client Session
|
|
6
|
+
class Session
|
|
7
|
+
attr_reader :joiner, :session, :store, :api
|
|
8
|
+
attr_accessor :executor, :stream
|
|
9
|
+
|
|
10
|
+
def initialize(joiner = Wampproto::Joiner.new("realm1"))
|
|
11
|
+
@joiner = joiner
|
|
12
|
+
@session = Wampproto::Session.new(joiner.serializer)
|
|
13
|
+
@api = MessageHandler::Api.new(self)
|
|
14
|
+
@store = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def on_join(&block)
|
|
18
|
+
self.executor = block
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def on_open
|
|
22
|
+
stream.on_message joiner.send_hello
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def on_message(data)
|
|
26
|
+
handler = MessageHandler.resolve(data, self)
|
|
27
|
+
handler.handle
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def transmit(data)
|
|
31
|
+
stream.on_message data
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nio4r"
|
|
4
|
+
|
|
5
|
+
module Wamp
|
|
6
|
+
module Connection
|
|
7
|
+
# creates actual socket and provides a way to read and write to it
|
|
8
|
+
class Stream
|
|
9
|
+
def initialize(socket_object)
|
|
10
|
+
@socket_object = socket_object
|
|
11
|
+
uri = URI.parse(socket_object.url)
|
|
12
|
+
|
|
13
|
+
@selector = NIO::Selector.new
|
|
14
|
+
@socket = TCPSocket.new(uri.host, uri.port)
|
|
15
|
+
monitor = @selector.register(@socket, :r)
|
|
16
|
+
monitor.value = proc { read_nonblock(monitor.io) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def write(data)
|
|
20
|
+
written = @socket.write_nonblock(data, exception: false)
|
|
21
|
+
|
|
22
|
+
case written
|
|
23
|
+
when :wait_writable
|
|
24
|
+
# procceed
|
|
25
|
+
when data.bytesize
|
|
26
|
+
data.bytesize
|
|
27
|
+
else
|
|
28
|
+
puts [:incomplete_write]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def receive(data)
|
|
33
|
+
@socket_object.parse(data)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run
|
|
37
|
+
loop do
|
|
38
|
+
@selector.select { |monitor| monitor.value.call if monitor.readable? }
|
|
39
|
+
break if @closed
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def read_nonblock(io)
|
|
44
|
+
incoming = io.read_nonblock(4096, exception: false)
|
|
45
|
+
|
|
46
|
+
case incoming
|
|
47
|
+
when :wait_readable
|
|
48
|
+
nil
|
|
49
|
+
when nil
|
|
50
|
+
close
|
|
51
|
+
else
|
|
52
|
+
receive incoming
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def shutdown
|
|
57
|
+
@selector.deregister(@socket)
|
|
58
|
+
@socket.close
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def close
|
|
62
|
+
shutdown
|
|
63
|
+
@socket_object.connection_gone
|
|
64
|
+
@closed = true
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "websocket/driver"
|
|
4
|
+
require_relative "stream"
|
|
5
|
+
|
|
6
|
+
module Wamp
|
|
7
|
+
module Connection
|
|
8
|
+
# handles opening connection and providing callbacks when data is avaialble
|
|
9
|
+
class WebsocketClient
|
|
10
|
+
CONNECTING = 0
|
|
11
|
+
OPEN = 1
|
|
12
|
+
CLOSING = 2
|
|
13
|
+
CLOSED = 3
|
|
14
|
+
|
|
15
|
+
attr_reader :url
|
|
16
|
+
|
|
17
|
+
def initialize(event_target, protocols) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
18
|
+
@event_target = event_target
|
|
19
|
+
|
|
20
|
+
@driver = @driver_started = nil
|
|
21
|
+
@close_params = ["", 1006]
|
|
22
|
+
|
|
23
|
+
@url = event_target.url
|
|
24
|
+
@ready_state = CONNECTING
|
|
25
|
+
|
|
26
|
+
@driver = WebSocket::Driver.client(self, protocols: protocols)
|
|
27
|
+
|
|
28
|
+
@driver.on(:open) { |_e| open }
|
|
29
|
+
@driver.on(:message) { |e| receive_message(e.data) }
|
|
30
|
+
@driver.on(:close) { |e| begin_close(e.reason, e.code) }
|
|
31
|
+
@driver.on(:error) { |e| emit_error(e.message) }
|
|
32
|
+
|
|
33
|
+
@stream = Wamp::Connection::Stream.new(self)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run
|
|
37
|
+
start_driver
|
|
38
|
+
@stream.run
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def start_driver
|
|
42
|
+
return if @driver_started
|
|
43
|
+
|
|
44
|
+
@driver_started = true
|
|
45
|
+
@driver.start
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def write(data)
|
|
49
|
+
@stream.write(data)
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
emit_error(e.message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def transmit(message)
|
|
55
|
+
return false if @ready_state > OPEN
|
|
56
|
+
|
|
57
|
+
case message
|
|
58
|
+
when Numeric then @driver.text(message.to_s)
|
|
59
|
+
when String then @driver.text(message)
|
|
60
|
+
when Array then @driver.binary(message)
|
|
61
|
+
else false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def connection_gone
|
|
66
|
+
finalize_close
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def close(code = nil, reason = nil)
|
|
70
|
+
code ||= 1000
|
|
71
|
+
reason ||= ""
|
|
72
|
+
|
|
73
|
+
unless code == 1000 || (code >= 3000 && code <= 4999)
|
|
74
|
+
raise ArgumentError, "Failed to execute 'close' on WebSocket: " \
|
|
75
|
+
"The code must be either 1000, or between 3000 and 4999. " \
|
|
76
|
+
"#{code} is neither."
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
@ready_state = CLOSING unless @ready_state == CLOSED
|
|
80
|
+
@driver.close(reason, code)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parse(data)
|
|
84
|
+
@driver.parse(data)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def alive?
|
|
88
|
+
@ready_state == OPEN
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# This is populated after successful handeshake
|
|
92
|
+
def protocol
|
|
93
|
+
@driver.protocol
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def open
|
|
99
|
+
return unless @ready_state == CONNECTING
|
|
100
|
+
|
|
101
|
+
@ready_state = OPEN
|
|
102
|
+
|
|
103
|
+
@event_target.on_open
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def receive_message(data)
|
|
107
|
+
return unless @ready_state == OPEN
|
|
108
|
+
|
|
109
|
+
@event_target.on_message(data)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def emit_error(message)
|
|
113
|
+
return if @ready_state >= CLOSING
|
|
114
|
+
|
|
115
|
+
@event_target.on_error(message)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def begin_close(reason, code)
|
|
119
|
+
return if @ready_state == CLOSED
|
|
120
|
+
|
|
121
|
+
@ready_state = CLOSING
|
|
122
|
+
@close_params = [reason, code]
|
|
123
|
+
|
|
124
|
+
@stream.close
|
|
125
|
+
finalize_close
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def finalize_close
|
|
129
|
+
return if @ready_state == CLOSED
|
|
130
|
+
|
|
131
|
+
@ready_state = CLOSED
|
|
132
|
+
|
|
133
|
+
@event_target.on_close(*@close_params)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "wampproto"
|
|
4
|
+
require_relative "websocket_client"
|
|
5
|
+
|
|
6
|
+
module Wamp
|
|
7
|
+
module Connection
|
|
8
|
+
# Conn
|
|
9
|
+
class WebSocketConnection < Session
|
|
10
|
+
attr_reader :url, :websocket
|
|
11
|
+
|
|
12
|
+
def initialize(url = "ws://localhost:8080/ws", joiner = Wampproto::Joiner.new("realm1"))
|
|
13
|
+
super(joiner)
|
|
14
|
+
@url = url
|
|
15
|
+
@websocket = Wamp::Connection::WebsocketClient.new(self, protocols)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run
|
|
19
|
+
websocket.run
|
|
20
|
+
ensure
|
|
21
|
+
p %i[run close]
|
|
22
|
+
websocket.close
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def on_open
|
|
26
|
+
transmit joiner.send_hello
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def transmit(data)
|
|
30
|
+
websocket.transmit data
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def on_close(reason, code)
|
|
34
|
+
p [:on_close, reason, code]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def on_error; end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def protocols
|
|
42
|
+
case joiner.serializer.name
|
|
43
|
+
when Wampproto::Serializer::JSON.name then "wamp.2.json"
|
|
44
|
+
when Wampproto::Serializer::Msgpack.name then "wamp.2.msgpack"
|
|
45
|
+
when Wampproto::Serializer::Cbor.name then "wamp.2.cbor"
|
|
46
|
+
end.then do |protocol|
|
|
47
|
+
[protocol]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "event"
|
|
4
|
+
require_relative "subscription"
|
|
5
|
+
|
|
6
|
+
module Wamp
|
|
7
|
+
module Manager
|
|
8
|
+
# no:doc
|
|
9
|
+
class Base
|
|
10
|
+
include WebSocket::Driver::EventEmitter
|
|
11
|
+
attr_reader :session
|
|
12
|
+
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
super()
|
|
15
|
+
@options = options
|
|
16
|
+
@session = Session.new(self)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def transmit(data); end
|
|
20
|
+
|
|
21
|
+
def on_message(message)
|
|
22
|
+
manager = Manager::Event.resolve(message, session)
|
|
23
|
+
manager.emit_event(message)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def auth
|
|
27
|
+
@options.fetch(:auth, Auth::Anonymous.new)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def run
|
|
31
|
+
message = Message::Hello.new("realm1")
|
|
32
|
+
manager = Manager::Event::Hello.new(message, session)
|
|
33
|
+
manager.add_event_listener # adds on :join event listener
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def authenticate(challenge)
|
|
37
|
+
auth.authenticate(challenge)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wamp
|
|
4
|
+
module Manager
|
|
5
|
+
# connection
|
|
6
|
+
class Connection < Connection::Base
|
|
7
|
+
attr_reader :session
|
|
8
|
+
|
|
9
|
+
def initialize(*args)
|
|
10
|
+
super
|
|
11
|
+
@session = Session.new(self)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def on_message(data)
|
|
15
|
+
message = Message.resolve(coder.decode(data))
|
|
16
|
+
session.on_message(message)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def on_open
|
|
20
|
+
send_hello_message
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def send_hello_message
|
|
26
|
+
message = Message::Hello.new(@realm, auth.details)
|
|
27
|
+
manager = Manager::Event::Hello.new(message, self)
|
|
28
|
+
manager.add_event_listener # adds on :join event listener
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Wamp
|
|
6
|
+
module Manager
|
|
7
|
+
module Event
|
|
8
|
+
# Abort Message Event
|
|
9
|
+
class Abort < Base
|
|
10
|
+
def emit_event_name
|
|
11
|
+
:close
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def emit_event(message)
|
|
15
|
+
session.emit(emit_event_name, message)
|
|
16
|
+
session.close(1000, message.reason)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|