forest_admin_rpc_agent 1.7.1 → 1.8.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 +4 -4
- data/lib/forest_admin_rpc_agent/routes/sse.rb +80 -14
- data/lib/forest_admin_rpc_agent/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d79eae397fb216be01160a0bf1807af637c000c736087983e5388d9f4b69b316
|
4
|
+
data.tar.gz: 74eb1e5a8e70cc62dc9443e5771a0e5f9abc9381383e176fbd61202454b9faec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04ea3178afb1f079e1aa0c1b66a34765b1dc5575650c2519a7719e7f2d6a941f7385008c22383d2d30f8a02a98e9ae5361864d26fb3577bda09c656fd4d3d50b
|
7
|
+
data.tar.gz: 8e7697a78a44fb891040f184c1d8d769449a60e537f1ffff071eca38383c11ff507eef1eb573ffa50a489b30ea32edc4da4ae9764b680f05d67d18c47553f0c8
|
@@ -3,10 +3,13 @@ require 'jsonapi-serializers'
|
|
3
3
|
module ForestAdminRpcAgent
|
4
4
|
module Routes
|
5
5
|
class Sse
|
6
|
-
|
6
|
+
DEFAULT_HEARTBEAT_INTERVAL = 1
|
7
|
+
|
8
|
+
def initialize(url = 'rpc/sse', method = 'get', name = 'rpc_sse', heartbeat_interval: DEFAULT_HEARTBEAT_INTERVAL)
|
7
9
|
@url = url
|
8
10
|
@method = method
|
9
11
|
@name = name
|
12
|
+
@heartbeat_interval = heartbeat_interval
|
10
13
|
end
|
11
14
|
|
12
15
|
def registered(app)
|
@@ -20,11 +23,58 @@ module ForestAdminRpcAgent
|
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
|
-
def register_sinatra(
|
24
|
-
|
26
|
+
def register_sinatra(app)
|
27
|
+
route_instance = self
|
28
|
+
app.send(@method.to_sym, "/#{@url}") do
|
29
|
+
auth_middleware = ForestAdminRpcAgent::Middleware::Authentication.new(->(_env) { [200, {}, ['OK']] })
|
30
|
+
status, headers, response = auth_middleware.call(env)
|
31
|
+
|
32
|
+
halt status, headers, response if status != 200
|
33
|
+
|
34
|
+
content_type 'text/event-stream'
|
35
|
+
headers 'Cache-Control' => 'no-cache',
|
36
|
+
'Connection' => 'keep-alive',
|
37
|
+
'X-Accel-Buffering' => 'no'
|
38
|
+
|
39
|
+
stream(:keep_open) do |out|
|
40
|
+
should_continue = true
|
41
|
+
server_stopped = false
|
42
|
+
stop_proc = proc do
|
43
|
+
should_continue = false
|
44
|
+
server_stopped = true
|
45
|
+
end
|
46
|
+
original_handler = trap('INT', stop_proc)
|
47
|
+
|
48
|
+
begin
|
49
|
+
streamer = SseStreamer.new(out)
|
50
|
+
|
51
|
+
while should_continue
|
52
|
+
streamer.write('', event: 'heartbeat')
|
53
|
+
sleep route_instance.instance_variable_get(:@heartbeat_interval)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Send RpcServerStop only if server is stopping (not client disconnect)
|
57
|
+
if server_stopped
|
58
|
+
begin
|
59
|
+
streamer.write({ event: 'RpcServerStop' }, event: 'RpcServerStop')
|
60
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] RpcServerStop event sent')
|
61
|
+
rescue StandardError => e
|
62
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', "[SSE] Error sending stop event: #{e.message}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
rescue IOError, Errno::EPIPE => e
|
66
|
+
# Client disconnected normally
|
67
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', "[SSE] Client disconnected: #{e.message}")
|
68
|
+
ensure
|
69
|
+
trap('INT', original_handler)
|
70
|
+
out.close if out.respond_to?(:close)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
25
74
|
end
|
26
75
|
|
27
76
|
def register_rails(router)
|
77
|
+
route_instance = self
|
28
78
|
handler = proc do |hash|
|
29
79
|
request = ActionDispatch::Request.new(hash)
|
30
80
|
auth_middleware = ForestAdminRpcAgent::Middleware::Authentication.new(->(_env) { [200, {}, ['OK']] })
|
@@ -34,31 +84,47 @@ module ForestAdminRpcAgent
|
|
34
84
|
headers = {
|
35
85
|
'Content-Type' => 'text/event-stream',
|
36
86
|
'Cache-Control' => 'no-cache',
|
37
|
-
'Connection' => 'keep-alive'
|
87
|
+
'Connection' => 'keep-alive',
|
88
|
+
'X-Accel-Buffering' => 'no'
|
38
89
|
}
|
39
90
|
|
40
91
|
should_continue = true
|
41
|
-
|
42
|
-
stop_proc = proc
|
92
|
+
server_stopped = false
|
93
|
+
stop_proc = proc do
|
94
|
+
should_continue = false
|
95
|
+
server_stopped = true
|
96
|
+
end
|
43
97
|
original_handler = trap('INT', stop_proc)
|
44
98
|
|
45
99
|
body = Enumerator.new do |yielder|
|
46
100
|
stream = SseStreamer.new(yielder)
|
47
101
|
|
48
102
|
begin
|
103
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] Starting stream')
|
104
|
+
|
49
105
|
while should_continue
|
50
|
-
# ForestAdminRpcAgent::Facades::Container.logger.log('Debug', '[SSE] heartbeat')
|
51
106
|
stream.write('', event: 'heartbeat')
|
52
|
-
sleep
|
107
|
+
sleep route_instance.instance_variable_get(:@heartbeat_interval)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Send RpcServerStop only if server is stopping (not client disconnect)
|
111
|
+
if server_stopped
|
112
|
+
begin
|
113
|
+
stream.write({ event: 'RpcServerStop' }, event: 'RpcServerStop')
|
114
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] RpcServerStop event sent')
|
115
|
+
rescue StandardError => e
|
116
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', "[SSE] Error sending stop event: #{e.message}")
|
117
|
+
end
|
53
118
|
end
|
54
|
-
rescue IOError
|
55
|
-
# Client disconnected
|
56
|
-
|
119
|
+
rescue IOError, Errno::EPIPE => e
|
120
|
+
# Client disconnected normally
|
121
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', "[SSE] Client disconnected: #{e.message}")
|
122
|
+
rescue StandardError => e
|
123
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Error', "[SSE] Unexpected error: #{e.message}")
|
124
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Error', e.backtrace.join("\n"))
|
57
125
|
ensure
|
58
126
|
trap('INT', original_handler)
|
59
|
-
|
60
|
-
# ForestAdminRpcAgent::Facades::Container.logger.log('Debug', '[SSE] stopped streaming')
|
61
|
-
yielder.close if yielder.respond_to?(:close)
|
127
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] Stream stopped')
|
62
128
|
end
|
63
129
|
end
|
64
130
|
|