litecable 0.4.2 → 0.7.2
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 +5 -5
- data/CHANGELOG.md +38 -1
- data/LICENSE.txt +1 -1
- data/README.md +27 -28
- data/lib/lite_cable.rb +23 -2
- data/lib/lite_cable/anycable.rb +22 -13
- data/lib/lite_cable/broadcast_adapters.rb +35 -0
- data/lib/lite_cable/broadcast_adapters/any_cable.rb +11 -0
- data/lib/lite_cable/broadcast_adapters/base.rb +17 -0
- data/lib/lite_cable/broadcast_adapters/memory.rb +11 -0
- data/lib/lite_cable/channel.rb +1 -0
- data/lib/lite_cable/channel/base.rb +4 -2
- data/lib/lite_cable/channel/registry.rb +5 -0
- data/lib/lite_cable/channel/streams.rb +1 -2
- data/lib/lite_cable/coders.rb +1 -0
- data/lib/lite_cable/coders/json.rb +1 -0
- data/lib/lite_cable/coders/raw.rb +2 -1
- data/lib/lite_cable/config.rb +8 -6
- data/lib/lite_cable/connection.rb +1 -0
- data/lib/lite_cable/connection/authorization.rb +1 -0
- data/lib/lite_cable/connection/base.rb +2 -2
- data/lib/lite_cable/connection/identification.rb +3 -0
- data/lib/lite_cable/connection/streams.rb +1 -0
- data/lib/lite_cable/connection/subscriptions.rb +10 -5
- data/lib/lite_cable/internal.rb +1 -0
- data/lib/lite_cable/logging.rb +4 -2
- data/lib/lite_cable/server.rb +1 -6
- data/lib/lite_cable/server/client_socket.rb +1 -0
- data/lib/lite_cable/server/client_socket/base.rb +17 -21
- data/lib/lite_cable/server/client_socket/subscriptions.rb +3 -2
- data/lib/lite_cable/server/heart_beat.rb +4 -1
- data/lib/lite_cable/server/middleware.rb +7 -6
- data/lib/lite_cable/server/subscribers_map.rb +3 -0
- data/lib/lite_cable/version.rb +2 -1
- data/lib/litecable.rb +1 -0
- metadata +28 -75
- data/.gem_release.yml +0 -3
- data/.gitignore +0 -40
- data/.rubocop.yml +0 -63
- data/.travis.yml +0 -7
- data/Gemfile +0 -4
- data/Rakefile +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/circle.yml +0 -8
- data/examples/sinatra/Gemfile +0 -16
- data/examples/sinatra/Procfile +0 -3
- data/examples/sinatra/README.md +0 -33
- data/examples/sinatra/anycable +0 -18
- data/examples/sinatra/app.rb +0 -52
- data/examples/sinatra/assets/app.css +0 -169
- data/examples/sinatra/assets/cable.js +0 -584
- data/examples/sinatra/assets/reset.css +0 -223
- data/examples/sinatra/bin/anycable-go +0 -0
- data/examples/sinatra/chat.rb +0 -39
- data/examples/sinatra/config.ru +0 -28
- data/examples/sinatra/views/index.slim +0 -8
- data/examples/sinatra/views/layout.slim +0 -15
- data/examples/sinatra/views/login.slim +0 -8
- data/examples/sinatra/views/resetcss.slim +0 -224
- data/examples/sinatra/views/room.slim +0 -68
- data/litecable.gemspec +0 -33
data/lib/lite_cable/coders.rb
CHANGED
data/lib/lite_cable/config.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
2
|
+
|
3
|
+
require "anyway_config"
|
4
|
+
require "logger"
|
4
5
|
|
5
6
|
module LiteCable
|
6
|
-
#
|
7
|
+
# AnyCable configuration
|
7
8
|
class Config < Anyway::Config
|
8
9
|
require "lite_cable/coders/json"
|
9
10
|
require "lite_cable/coders/raw"
|
@@ -11,8 +12,9 @@ module LiteCable
|
|
11
12
|
config_name :litecable
|
12
13
|
|
13
14
|
attr_config :logger,
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
coder: Coders::JSON,
|
16
|
+
broadcast_adapter: :memory,
|
17
|
+
identifier_coder: Coders::Raw,
|
18
|
+
log_level: Logger::INFO
|
17
19
|
end
|
18
20
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
|
-
# rubocop:disable Metrics/LineLength
|
4
4
|
module Connection
|
5
5
|
# A Connection object represents a client "connected" to the application.
|
6
6
|
# It contains all of the channel subscriptions. Incoming messages are then routed to these channel subscriptions
|
@@ -37,7 +37,6 @@ module LiteCable
|
|
37
37
|
# it easy to use cookies that were set when logging in via a web interface to authorize the connection.
|
38
38
|
#
|
39
39
|
class Base
|
40
|
-
# rubocop:enable Metrics/LineLength
|
41
40
|
include Authorization
|
42
41
|
prepend Identification
|
43
42
|
include Logging
|
@@ -79,6 +78,7 @@ module LiteCable
|
|
79
78
|
|
80
79
|
def transmit(cable_message)
|
81
80
|
return if disconnected?
|
81
|
+
|
82
82
|
socket.transmit encode(cable_message)
|
83
83
|
end
|
84
84
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "set"
|
3
4
|
|
4
5
|
module LiteCable
|
@@ -13,6 +14,7 @@ module LiteCable
|
|
13
14
|
define_method(identifier) do
|
14
15
|
return instance_variable_get(:"@#{identifier}") if
|
15
16
|
instance_variable_defined?(:"@#{identifier}")
|
17
|
+
|
16
18
|
fetch_identifier(identifier.to_s)
|
17
19
|
end
|
18
20
|
end
|
@@ -66,6 +68,7 @@ module LiteCable
|
|
66
68
|
identifiers.each_with_object({}) do |id, acc|
|
67
69
|
obj = instance_variable_get("@#{id}")
|
68
70
|
next unless obj
|
71
|
+
|
69
72
|
acc[id.to_s] = LiteCable.config.identifier_coder.encode(obj)
|
70
73
|
end
|
71
74
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Connection
|
4
5
|
# Manage the connection channels and route messages
|
5
6
|
class Subscriptions
|
6
7
|
class Error < StandardError; end
|
8
|
+
|
7
9
|
class AlreadySubscribedError < Error; end
|
10
|
+
|
8
11
|
class UnknownCommandError < Error; end
|
12
|
+
|
9
13
|
class ChannelNotFoundError < Error; end
|
10
14
|
|
11
15
|
include Logging
|
@@ -52,9 +56,9 @@ module LiteCable
|
|
52
56
|
def execute_command(data)
|
53
57
|
command = data.delete("command")
|
54
58
|
case command
|
55
|
-
when "subscribe"
|
59
|
+
when "subscribe" then add(data["identifier"])
|
56
60
|
when "unsubscribe" then remove(data["identifier"])
|
57
|
-
when "message"
|
61
|
+
when "message" then perform_action(data["identifier"], data["data"])
|
58
62
|
else
|
59
63
|
raise UnknownCommandError, "Command not found #{command}"
|
60
64
|
end
|
@@ -67,6 +71,7 @@ module LiteCable
|
|
67
71
|
def find!(identifier)
|
68
72
|
channel = find(identifier)
|
69
73
|
raise ChannelNotFoundError unless channel
|
74
|
+
|
70
75
|
channel
|
71
76
|
end
|
72
77
|
|
@@ -87,17 +92,17 @@ module LiteCable
|
|
87
92
|
|
88
93
|
def transmit_subscription_confirmation(identifier)
|
89
94
|
connection.transmit identifier: identifier,
|
90
|
-
|
95
|
+
type: LiteCable::INTERNAL[:message_types][:confirmation]
|
91
96
|
end
|
92
97
|
|
93
98
|
def transmit_subscription_rejection(identifier)
|
94
99
|
connection.transmit identifier: identifier,
|
95
|
-
|
100
|
+
type: LiteCable::INTERNAL[:message_types][:rejection]
|
96
101
|
end
|
97
102
|
|
98
103
|
def transmit_subscription_cancel(identifier)
|
99
104
|
connection.transmit identifier: identifier,
|
100
|
-
|
105
|
+
type: LiteCable::INTERNAL[:message_types][:cancel]
|
101
106
|
end
|
102
107
|
|
103
108
|
def log_fmt(msg)
|
data/lib/lite_cable/internal.rb
CHANGED
data/lib/lite_cable/logging.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "logger"
|
3
4
|
|
4
5
|
module LiteCable
|
5
6
|
module Logging # :nodoc:
|
@@ -12,7 +13,7 @@ module LiteCable
|
|
12
13
|
@logger = LiteCable.config.logger
|
13
14
|
return if @logger == false
|
14
15
|
|
15
|
-
@logger ||= ::Logger.new(
|
16
|
+
@logger ||= ::Logger.new($stderr).tap do |logger|
|
16
17
|
logger.level = LiteCable.config.log_level
|
17
18
|
end
|
18
19
|
end
|
@@ -22,6 +23,7 @@ module LiteCable
|
|
22
23
|
|
23
24
|
def log(level, message = nil)
|
24
25
|
return unless LiteCable::Logging.logger
|
26
|
+
|
25
27
|
LiteCable::Logging.logger.send(level, PREFIX) { message || yield }
|
26
28
|
end
|
27
29
|
end
|
data/lib/lite_cable/server.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
# Rack middleware to hijack sockets.
|
4
5
|
#
|
@@ -14,12 +15,6 @@ module LiteCable
|
|
14
15
|
|
15
16
|
class << self
|
16
17
|
attr_accessor :subscribers_map
|
17
|
-
|
18
|
-
# Broadcast encoded message to the stream
|
19
|
-
def broadcast(stream, message, coder: nil)
|
20
|
-
coder ||= LiteCable.config.coder
|
21
|
-
subscribers_map.broadcast stream, message, coder
|
22
|
-
end
|
23
18
|
end
|
24
19
|
|
25
20
|
self.subscribers_map = SubscribersMap.new
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Server
|
4
5
|
module ClientSocket
|
5
6
|
# Wrapper over web socket
|
6
|
-
# rubocop:disable Metrics/ClassLength
|
7
7
|
class Base
|
8
8
|
include Logging
|
9
9
|
include Subscriptions
|
@@ -17,10 +17,10 @@ module LiteCable
|
|
17
17
|
@version = version
|
18
18
|
@active = true
|
19
19
|
|
20
|
-
@open_handlers
|
20
|
+
@open_handlers = []
|
21
21
|
@message_handlers = []
|
22
|
-
@close_handlers
|
23
|
-
@error_handlers
|
22
|
+
@close_handlers = []
|
23
|
+
@error_handlers = []
|
24
24
|
|
25
25
|
@close_on_error = true
|
26
26
|
end
|
@@ -36,6 +36,9 @@ module LiteCable
|
|
36
36
|
type: type
|
37
37
|
)
|
38
38
|
socket.write frame.to_s
|
39
|
+
rescue EOFError, Errno::ECONNRESET => e
|
40
|
+
log(:debug, "Socket gone: #{e}")
|
41
|
+
close
|
39
42
|
rescue IOError, Errno::EPIPE, Errno::ETIMEDOUT => e
|
40
43
|
log(:error, "Socket send failed: #{e}")
|
41
44
|
close
|
@@ -61,6 +64,7 @@ module LiteCable
|
|
61
64
|
@error_handlers << block
|
62
65
|
end
|
63
66
|
|
67
|
+
# rubocop: disable Metrics/MethodLength
|
64
68
|
def listen
|
65
69
|
keepalive
|
66
70
|
Thread.new do
|
@@ -69,13 +73,11 @@ module LiteCable
|
|
69
73
|
@open_handlers.each(&:call)
|
70
74
|
each_frame do |data|
|
71
75
|
@message_handlers.each do |h|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
close if close_on_error
|
78
|
-
end
|
76
|
+
h.call(data)
|
77
|
+
rescue => e # rubocop: disable Style/RescueStandardError
|
78
|
+
log(:error, "Socket receive failed: #{e}")
|
79
|
+
@error_handlers.each { |eh| eh.call(e, data) }
|
80
|
+
close if close_on_error
|
79
81
|
end
|
80
82
|
end
|
81
83
|
ensure
|
@@ -83,6 +85,7 @@ module LiteCable
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
end
|
88
|
+
# rubocop: enable Metrics/MethodLength
|
86
89
|
|
87
90
|
def close
|
88
91
|
return unless @active
|
@@ -131,22 +134,15 @@ module LiteCable
|
|
131
134
|
end
|
132
135
|
end
|
133
136
|
|
134
|
-
# rubocop:disable Metrics/AbcSize
|
135
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
136
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
137
|
-
# rubocop:disable Metrics/MethodLength
|
138
137
|
def each_frame
|
139
138
|
framebuffer = WebSocket::Frame::Incoming::Server.new(version: version)
|
140
139
|
|
141
140
|
while IO.select([socket])
|
142
|
-
|
143
|
-
data, _addrinfo = socket.recvfrom(2000)
|
144
|
-
else
|
145
|
-
data, _addrinfo = socket.readpartial(2000), socket.peeraddr
|
146
|
-
end
|
141
|
+
data = socket.respond_to?(:recv) ? socket.recv(2000) : socket.readpartial(2000)
|
147
142
|
break if data.empty?
|
143
|
+
|
148
144
|
framebuffer << data
|
149
|
-
while frame = framebuffer.next
|
145
|
+
while frame = framebuffer.next # rubocop:disable Lint/AssignmentInCondition
|
150
146
|
case frame.type
|
151
147
|
when :close
|
152
148
|
return
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Server
|
4
5
|
module ClientSocket
|
@@ -6,12 +7,12 @@ module LiteCable
|
|
6
7
|
module Subscriptions
|
7
8
|
def subscribe(channel, broadcasting)
|
8
9
|
LiteCable::Server.subscribers_map
|
9
|
-
|
10
|
+
.add_subscriber(broadcasting, self, channel)
|
10
11
|
end
|
11
12
|
|
12
13
|
def unsubscribe(channel, broadcasting)
|
13
14
|
LiteCable::Server.subscribers_map
|
14
|
-
|
15
|
+
.remove_subscriber(broadcasting, self, channel)
|
15
16
|
end
|
16
17
|
|
17
18
|
def unsubscribe_from_all(channel)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Server
|
4
5
|
# Sends pings to sockets
|
@@ -22,6 +23,7 @@ module LiteCable
|
|
22
23
|
@stopped = true
|
23
24
|
end
|
24
25
|
|
26
|
+
# rubocop: disable Metrics/MethodLength
|
25
27
|
def run
|
26
28
|
Thread.new do
|
27
29
|
Thread.current.abort_on_exception = true
|
@@ -39,11 +41,12 @@ module LiteCable
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
44
|
+
# rubocop: enable Metrics/MethodLength
|
42
45
|
|
43
46
|
private
|
44
47
|
|
45
48
|
def ping_message(time)
|
46
|
-
{
|
49
|
+
{type: LiteCable::INTERNAL[:message_types][:ping], message: time}.to_json
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Server
|
4
5
|
# Rack middleware to hijack the socket
|
@@ -11,15 +12,15 @@ module LiteCable
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def call(env)
|
14
|
-
return [404, {
|
15
|
-
env["HTTP_UPGRADE"] ==
|
15
|
+
return [404, {"Content-Type" => "text/plain"}, ["Not Found"]] unless
|
16
|
+
env["HTTP_UPGRADE"] == "websocket"
|
16
17
|
|
17
|
-
raise HijackNotAvailable unless env[
|
18
|
+
raise HijackNotAvailable unless env["rack.hijack"]
|
18
19
|
|
19
|
-
env[
|
20
|
+
env["rack.hijack"].call
|
20
21
|
handshake = send_handshake(env)
|
21
22
|
|
22
|
-
socket = ClientSocket::Base.new env, env[
|
23
|
+
socket = ClientSocket::Base.new env, env["rack.hijack_io"], handshake.version
|
23
24
|
init_connection socket
|
24
25
|
init_heartbeat socket
|
25
26
|
socket.listen
|
@@ -34,7 +35,7 @@ module LiteCable
|
|
34
35
|
)
|
35
36
|
|
36
37
|
handshake.from_rack env
|
37
|
-
env[
|
38
|
+
env["rack.hijack_io"].write handshake.to_s
|
38
39
|
handshake
|
39
40
|
end
|
40
41
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module LiteCable
|
3
4
|
module Server
|
4
5
|
# From https://github.com/rails/rails/blob/v5.0.1/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb
|
@@ -31,6 +32,7 @@ module LiteCable
|
|
31
32
|
def remove_socket(socket, channel)
|
32
33
|
list = @sync.synchronize do
|
33
34
|
return unless @sockets.key?(socket)
|
35
|
+
|
34
36
|
@sockets[socket].dup
|
35
37
|
end
|
36
38
|
|
@@ -42,6 +44,7 @@ module LiteCable
|
|
42
44
|
def broadcast(stream, message, coder)
|
43
45
|
list = @sync.synchronize do
|
44
46
|
return unless @streams.key?(stream)
|
47
|
+
|
45
48
|
@streams[stream].to_a
|
46
49
|
end
|
47
50
|
|
data/lib/lite_cable/version.rb
CHANGED