opal-up 0.0.6 → 0.0.8
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/README.md +0 -1
- data/ext/up_ext/up_ext.c +80 -44
- data/lib/up/bun/server.rb +10 -3
- data/lib/up/ruby/cluster.rb +15 -3
- data/lib/up/u_web_socket/server.rb +28 -11
- data/lib/up/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: cb3a4f16540780758e686bbd53c9ab5467b85988bd83a990b05ab54b124c2d2d
|
|
4
|
+
data.tar.gz: 292c74cb7b0771cf807af2b1ebc221707f2b92bd28ca2e1271038b242aa94fc5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4fbbd939aa7c268d503953c9d7b36d92071c23ae498df1c948acb6886007a66eb60218766528fbb6f5fe1016cdd77890a039533c40fbe3baad8594cca77f8e2d
|
|
7
|
+
data.tar.gz: da01a9584cd43ec5d5c2b97cad04c2bf6895ec029e5e34f4614a9381010788009c97f09c5b8e832913befbb6fb2b3b9157f1baeeff280cbd3e527bb61b4450e6
|
data/README.md
CHANGED
|
@@ -99,7 +99,6 @@ When using secure sockets, the -a, -c and -k options must be provided
|
|
|
99
99
|
|
|
100
100
|
Up! implements the [Rack Spec as of Rack 3.0](https://github.com/rack/rack/blob/main/SPEC.rdoc) with the following differences:
|
|
101
101
|
- `rack.hijack` is not implemented, but `rack.upgrade` instead is, see "Websockets" below
|
|
102
|
-
- `rack.input` is currently still missing
|
|
103
102
|
- Tempfile support is currently incomplete, affecting a few keys in the Rack Env ('tempfile' missing in Opal).
|
|
104
103
|
- Some Rack modules/classes still have issues when run in Opal and may not work as expected
|
|
105
104
|
|
data/ext/up_ext/up_ext.c
CHANGED
|
@@ -26,6 +26,7 @@ static ID at_instance;
|
|
|
26
26
|
static ID at_member_id;
|
|
27
27
|
static ID at_members;
|
|
28
28
|
static ID at_open;
|
|
29
|
+
static ID at_port;
|
|
29
30
|
static ID at_protocol;
|
|
30
31
|
static ID at_secret;
|
|
31
32
|
static ID at_server;
|
|
@@ -37,6 +38,7 @@ static ID id_close;
|
|
|
37
38
|
static ID id_each;
|
|
38
39
|
static ID id_host;
|
|
39
40
|
static ID id_logger;
|
|
41
|
+
static ID id_new;
|
|
40
42
|
static ID id_on_close;
|
|
41
43
|
static ID id_on_drained;
|
|
42
44
|
static ID id_on_message;
|
|
@@ -122,6 +124,8 @@ typedef struct server_s {
|
|
|
122
124
|
VALUE port;
|
|
123
125
|
VALUE logger;
|
|
124
126
|
VALUE env_template;
|
|
127
|
+
VALUE body;
|
|
128
|
+
VALUE env;
|
|
125
129
|
int workers;
|
|
126
130
|
int member_id;
|
|
127
131
|
char secret[37];
|
|
@@ -283,6 +287,43 @@ typedef struct publish_data_s {
|
|
|
283
287
|
server_s *s;
|
|
284
288
|
} publish_data_s;
|
|
285
289
|
|
|
290
|
+
static void up_internal_call_app(server_s *s, uws_res_t *res, VALUE env) {
|
|
291
|
+
// call app
|
|
292
|
+
VALUE rres = rb_funcall(s->rapp, id_call, 1, env);
|
|
293
|
+
|
|
294
|
+
if (TYPE(rres) != T_ARRAY)
|
|
295
|
+
goto response_error;
|
|
296
|
+
|
|
297
|
+
// response status
|
|
298
|
+
VALUE rstatus = rb_ary_entry(rres, 0);
|
|
299
|
+
if (!up_internal_set_response_status(res, rstatus))
|
|
300
|
+
goto response_error;
|
|
301
|
+
|
|
302
|
+
// collect headers
|
|
303
|
+
VALUE rheaders = rb_ary_entry(rres, 1);
|
|
304
|
+
if (TYPE(rheaders) != T_HASH)
|
|
305
|
+
goto response_error;
|
|
306
|
+
rb_hash_foreach(rheaders, up_internal_res_header_handler, (VALUE)res);
|
|
307
|
+
|
|
308
|
+
// collect response body
|
|
309
|
+
VALUE rparts = rb_ary_entry(rres, 2);
|
|
310
|
+
up_internal_collect_response_body(res, rparts);
|
|
311
|
+
|
|
312
|
+
// end response
|
|
313
|
+
uws_res_end_without_body(USE_SSL, res, false);
|
|
314
|
+
|
|
315
|
+
// close resources if necessary
|
|
316
|
+
if (rb_respond_to(rparts, id_close))
|
|
317
|
+
rb_funcall(rparts, id_close, 0);
|
|
318
|
+
|
|
319
|
+
return;
|
|
320
|
+
response_error:
|
|
321
|
+
fprintf(stderr, "response error\n");
|
|
322
|
+
uws_res_end_without_body(USE_SSL, res, false);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
static void up_internal_abort_data(uws_res_t *res, void *arg) {}
|
|
326
|
+
|
|
286
327
|
static void up_internal_process_publish_post_data(uws_res_t *res,
|
|
287
328
|
const char *chunk,
|
|
288
329
|
size_t chunk_length,
|
|
@@ -299,9 +340,22 @@ static void up_internal_process_publish_post_data(uws_res_t *res,
|
|
|
299
340
|
break;
|
|
300
341
|
}
|
|
301
342
|
}
|
|
302
|
-
if (channel_length > 0 && message_length > 0)
|
|
343
|
+
if (channel_length > 0 && message_length > 0)
|
|
303
344
|
uws_publish(USE_SSL, s->app, channel_start, channel_length, message_start,
|
|
304
345
|
message_length, TEXT, false);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
static void up_internal_process_post_data(uws_res_t *res, const char *chunk,
|
|
349
|
+
size_t chunk_length, bool is_end,
|
|
350
|
+
void *arg) {
|
|
351
|
+
server_s *s = (server_s *)arg;
|
|
352
|
+
rb_str_cat(s->body, chunk, chunk_length);
|
|
353
|
+
if (is_end) {
|
|
354
|
+
// set rack.input
|
|
355
|
+
rb_hash_aset(s->env, rack_input, rb_funcall(cStringIO, id_new, 1, s->body));
|
|
356
|
+
up_internal_call_app(s, res, s->env);
|
|
357
|
+
s->body = Qnil;
|
|
358
|
+
s->env = Qnil;
|
|
305
359
|
}
|
|
306
360
|
}
|
|
307
361
|
|
|
@@ -322,48 +376,25 @@ static void up_internal_publish_handler(uws_res_t *res, uws_req_t *req,
|
|
|
322
376
|
}
|
|
323
377
|
}
|
|
324
378
|
|
|
325
|
-
static void
|
|
326
|
-
void *arg) {
|
|
379
|
+
static void up_server_any_handler(uws_res_t *res, uws_req_t *req, void *arg) {
|
|
327
380
|
// prepare rack env
|
|
328
381
|
server_s *s = (server_s *)arg;
|
|
329
|
-
VALUE
|
|
330
|
-
up_server_prepare_env(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (TYPE(rres) != T_ARRAY)
|
|
335
|
-
goto response_error;
|
|
336
|
-
|
|
337
|
-
// response status
|
|
338
|
-
VALUE rstatus = rb_ary_entry(rres, 0);
|
|
339
|
-
if (!up_internal_set_response_status(res, rstatus))
|
|
340
|
-
goto response_error;
|
|
341
|
-
|
|
342
|
-
// collect headers
|
|
343
|
-
VALUE rheaders = rb_ary_entry(rres, 1);
|
|
344
|
-
if (TYPE(rheaders) != T_HASH)
|
|
345
|
-
goto response_error;
|
|
346
|
-
rb_hash_foreach(rheaders, up_internal_res_header_handler, (VALUE)res);
|
|
347
|
-
|
|
348
|
-
// collect response body
|
|
349
|
-
VALUE rparts = rb_ary_entry(rres, 2);
|
|
350
|
-
up_internal_collect_response_body(res, rparts);
|
|
351
|
-
|
|
352
|
-
// end response
|
|
353
|
-
uws_res_end_without_body(USE_SSL, res, false);
|
|
382
|
+
VALUE env = rb_hash_dup(s->env_template);
|
|
383
|
+
up_server_prepare_env(env, req);
|
|
384
|
+
up_internal_call_app(s, res, env);
|
|
385
|
+
RB_GC_GUARD(env);
|
|
386
|
+
}
|
|
354
387
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
388
|
+
static void up_server_post_handler(uws_res_t *res, uws_req_t *req, void *arg) {
|
|
389
|
+
// prepare rack env
|
|
390
|
+
server_s *s = (server_s *)arg;
|
|
391
|
+
s->env = rb_hash_dup(s->env_template);
|
|
392
|
+
up_server_prepare_env(s->env, req);
|
|
358
393
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
RB_GC_GUARD(renv);
|
|
364
|
-
response_error:
|
|
365
|
-
fprintf(stderr, "response error\n");
|
|
366
|
-
uws_res_end_without_body(USE_SSL, res, false);
|
|
394
|
+
// receive POST data
|
|
395
|
+
s->body = rb_enc_str_new("", 0, utf8_encoding);
|
|
396
|
+
uws_res_on_data(USE_SSL, res, up_internal_process_post_data, (void *)s);
|
|
397
|
+
uws_res_on_aborted(USE_SSL, res, up_internal_abort_data, NULL);
|
|
367
398
|
}
|
|
368
399
|
|
|
369
400
|
static void
|
|
@@ -599,6 +630,8 @@ static VALUE up_server_init(int argc, VALUE *argv, VALUE self) {
|
|
|
599
630
|
s->port = rport;
|
|
600
631
|
s->logger = rargs[3];
|
|
601
632
|
|
|
633
|
+
rb_ivar_set(self, at_port, s->port);
|
|
634
|
+
|
|
602
635
|
return self;
|
|
603
636
|
}
|
|
604
637
|
|
|
@@ -613,8 +646,8 @@ void up_ws_drain_handler(uws_websocket_t *ws, void *user_data) {
|
|
|
613
646
|
|
|
614
647
|
void up_ws_ping_handler(uws_websocket_t *ws, const char *message, size_t length,
|
|
615
648
|
void *user_data) {
|
|
616
|
-
/* You don't need to handle this one, we automatically respond to pings as
|
|
617
|
-
* standard */
|
|
649
|
+
/* You don't need to handle this one, we automatically respond to pings as
|
|
650
|
+
* per standard */
|
|
618
651
|
}
|
|
619
652
|
|
|
620
653
|
void up_ws_pong_handler(uws_websocket_t *ws, const char *message, size_t length,
|
|
@@ -807,7 +840,8 @@ static VALUE up_server_listen(VALUE self) {
|
|
|
807
840
|
sigemptyset(&upclcl.sa_mask);
|
|
808
841
|
sigaction(SIGINT, &upclcl, NULL);
|
|
809
842
|
}
|
|
810
|
-
|
|
843
|
+
uws_app_post(USE_SSL, s->app, "/*", up_server_post_handler, (void *)s);
|
|
844
|
+
uws_app_any(USE_SSL, s->app, "/*", up_server_any_handler, (void *)s);
|
|
811
845
|
uws_ws(USE_SSL, s->app, "/*",
|
|
812
846
|
(uws_socket_behavior_t){.compression = DISABLED,
|
|
813
847
|
.maxPayloadLength = 5 * 1024 * 1024,
|
|
@@ -938,6 +972,7 @@ void Init_up_ext(void) {
|
|
|
938
972
|
at_member_id = rb_intern("@member_id");
|
|
939
973
|
at_members = rb_intern("@members");
|
|
940
974
|
at_open = rb_intern("@open");
|
|
975
|
+
at_port = rb_intern("@port");
|
|
941
976
|
at_protocol = rb_intern("@protocol");
|
|
942
977
|
at_secret = rb_intern("@secret");
|
|
943
978
|
at_server = rb_intern("@server");
|
|
@@ -949,6 +984,7 @@ void Init_up_ext(void) {
|
|
|
949
984
|
id_each = rb_intern("each");
|
|
950
985
|
id_host = rb_intern("host");
|
|
951
986
|
id_logger = rb_intern("logger");
|
|
987
|
+
id_new = rb_intern("new");
|
|
952
988
|
id_on_close = rb_intern("on_close");
|
|
953
989
|
id_on_drained = rb_intern("on_drained");
|
|
954
990
|
id_on_message = rb_intern("on_message");
|
|
@@ -980,14 +1016,14 @@ void Init_up_ext(void) {
|
|
|
980
1016
|
rb_gc_register_address(&cLogger);
|
|
981
1017
|
cLogger = rb_const_get(rb_cObject, rb_intern("Logger"));
|
|
982
1018
|
rb_gc_register_address(&default_logger);
|
|
983
|
-
default_logger = rb_funcall(cLogger,
|
|
1019
|
+
default_logger = rb_funcall(cLogger, id_new, 1, rb_stderr);
|
|
984
1020
|
|
|
985
1021
|
rb_require("stringio");
|
|
986
1022
|
|
|
987
1023
|
rb_gc_register_address(&cStringIO);
|
|
988
1024
|
cStringIO = rb_const_get(rb_cObject, rb_intern("StringIO"));
|
|
989
1025
|
rb_gc_register_address(&default_input);
|
|
990
|
-
default_input = rb_funcall(cStringIO,
|
|
1026
|
+
default_input = rb_funcall(cStringIO, id_new, 1, empty_string);
|
|
991
1027
|
|
|
992
1028
|
up_setup_rack_env_template();
|
|
993
1029
|
|
data/lib/up/bun/server.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# backtick_javascript: true
|
|
2
2
|
require 'logger'
|
|
3
|
+
require 'stringio'
|
|
3
4
|
require 'up/cli'
|
|
4
5
|
require 'up/client'
|
|
5
6
|
|
|
@@ -23,7 +24,7 @@ module Up
|
|
|
23
24
|
@ca_file = ca_file
|
|
24
25
|
@cert_file = cert_file
|
|
25
26
|
@key_file = key_file
|
|
26
|
-
@default_input =
|
|
27
|
+
@default_input = StringIO.new('', 'r')
|
|
27
28
|
@server = nil
|
|
28
29
|
@logger = logger
|
|
29
30
|
@t_factory = proc { |filename, _content_type| File.new(filename, 'a+') }
|
|
@@ -65,11 +66,17 @@ module Up
|
|
|
65
66
|
port: #@port,
|
|
66
67
|
hostname: #@host,
|
|
67
68
|
development: false,
|
|
68
|
-
fetch(req, server) {
|
|
69
|
+
async fetch(req, server) {
|
|
69
70
|
const upgrade = req.headers.get('Upgrade');
|
|
70
71
|
const env = new Map();
|
|
71
72
|
env.set('rack.errors',#{STDERR});
|
|
72
|
-
|
|
73
|
+
if (req.method === 'POST') {
|
|
74
|
+
let body = await req.text();
|
|
75
|
+
console.log('received: ', body);
|
|
76
|
+
env.set('rack.input', #{StringIO.new(`body`)});
|
|
77
|
+
} else {
|
|
78
|
+
env.set('rack.input', #@default_input);
|
|
79
|
+
}
|
|
73
80
|
env.set('rack.logger', #@logger);
|
|
74
81
|
env.set('rack.multipart.buffer_size', 4096);
|
|
75
82
|
env.set('rack.multipart.tempfile_factory', #@t_factory);
|
data/lib/up/ruby/cluster.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# backtick_javascript: true
|
|
2
2
|
require 'etc'
|
|
3
3
|
require 'random/formatter'
|
|
4
|
+
require 'socket'
|
|
4
5
|
require 'up_ext'
|
|
5
6
|
|
|
6
7
|
module Up
|
|
@@ -38,8 +39,10 @@ module Up
|
|
|
38
39
|
|
|
39
40
|
def install_signal_handlers
|
|
40
41
|
Signal.trap('CHLD') do
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
unless members_alive?
|
|
43
|
+
warn "\nError: a cluster worker died!"
|
|
44
|
+
kill_members
|
|
45
|
+
end
|
|
43
46
|
end
|
|
44
47
|
Signal.trap('INT') do
|
|
45
48
|
warn "\nReceived CTRL-C!"
|
|
@@ -49,7 +52,7 @@ module Up
|
|
|
49
52
|
|
|
50
53
|
def kill_members
|
|
51
54
|
Signal.trap('CHLD', 'IGNORE')
|
|
52
|
-
STDERR.print "Stopping workers: "
|
|
55
|
+
STDERR.print "Stopping all workers: "
|
|
53
56
|
@members.each do |mid|
|
|
54
57
|
Process.kill('INT', mid) rescue nil
|
|
55
58
|
STDERR.print '.'
|
|
@@ -58,6 +61,15 @@ module Up
|
|
|
58
61
|
warn "\nCluster stopped."
|
|
59
62
|
Signal.trap('CHLD', 'DEFAULT')
|
|
60
63
|
end
|
|
64
|
+
|
|
65
|
+
def members_alive?
|
|
66
|
+
@workers.times do |i|
|
|
67
|
+
TCPSocket.new('localhost', @port + i + 1).close
|
|
68
|
+
end
|
|
69
|
+
true
|
|
70
|
+
rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL
|
|
71
|
+
false
|
|
72
|
+
end
|
|
61
73
|
end
|
|
62
74
|
end
|
|
63
75
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# backtick_javascript: true
|
|
2
2
|
require 'logger'
|
|
3
|
+
require 'stringio'
|
|
3
4
|
require 'up/cli'
|
|
4
5
|
require 'up/client'
|
|
5
6
|
|
|
@@ -29,7 +30,7 @@ module Up
|
|
|
29
30
|
@ca_file = ca_file
|
|
30
31
|
@cert_file = cert_file
|
|
31
32
|
@key_file = key_file
|
|
32
|
-
@default_input =
|
|
33
|
+
@default_input = StringIO.new('', 'r')
|
|
33
34
|
@server = nil
|
|
34
35
|
@logger = logger
|
|
35
36
|
@t_factory = proc { |filename, _content_type| File.new(filename, 'a+') }
|
|
@@ -58,20 +59,20 @@ module Up
|
|
|
58
59
|
#{`parts`.close if `parts`.respond_to?(:close)}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
self.prepare_env = function(req) {
|
|
62
|
+
self.prepare_env = function(req, ins) {
|
|
62
63
|
const env = new Map();
|
|
63
64
|
env.set('rack.errors',#{STDERR});
|
|
64
|
-
env.set('rack.input',
|
|
65
|
-
env.set('rack.logger',
|
|
65
|
+
env.set('rack.input', ins.default_input);
|
|
66
|
+
env.set('rack.logger', ins.logger);
|
|
66
67
|
env.set('rack.multipart.buffer_size', 4096);
|
|
67
|
-
env.set('rack.multipart.tempfile_factory',
|
|
68
|
-
env.set('rack.url_scheme',
|
|
68
|
+
env.set('rack.multipart.tempfile_factory', ins.t_factory);
|
|
69
|
+
env.set('rack.url_scheme', ins.scheme);
|
|
69
70
|
env.set('SCRIPT_NAME', "");
|
|
70
71
|
env.set('SERVER_PROTOCOL', 'HTTP/1.1');
|
|
71
72
|
env.set('HTTP_VERSION', 'HTTP/1.1');
|
|
72
|
-
env.set('SERVER_NAME',
|
|
73
|
-
env.set('SERVER_PORT',
|
|
74
|
-
env.set('QUERY_STRING', req.getQuery());
|
|
73
|
+
env.set('SERVER_NAME', ins.host);
|
|
74
|
+
env.set('SERVER_PORT', ins.port);
|
|
75
|
+
env.set('QUERY_STRING', req.getQuery() || '');
|
|
75
76
|
env.set('REQUEST_METHOD', req.getMethod().toUpperCase());
|
|
76
77
|
env.set('PATH_INFO', req.getUrl());
|
|
77
78
|
req.forEach((k, v) => { env.set('HTTP_' + k.toUpperCase().replaceAll('-', '_'), v) });
|
|
@@ -91,8 +92,24 @@ module Up
|
|
|
91
92
|
} else {
|
|
92
93
|
#@server = uws.App();
|
|
93
94
|
}
|
|
95
|
+
#@server.post('/*', (res, req) => {
|
|
96
|
+
const env = ouws.prepare_env(req, self);
|
|
97
|
+
let buffer = Buffer.from('');
|
|
98
|
+
res.onData((chunk, is_last) => {
|
|
99
|
+
buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
|
|
100
|
+
if (is_last === true) {
|
|
101
|
+
env.set('rack.input', #{StringIO.new(`buffer.toString()`)});
|
|
102
|
+
const rack_res = #@app.$call(env);
|
|
103
|
+
res.writeStatus(rack_res[0].toString() + ' OK');
|
|
104
|
+
ouws.handle_headers(rack_res[1], res);
|
|
105
|
+
ouws.handle_response(rack_res[2], res);
|
|
106
|
+
res.end();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
res.onAborted(() => {});
|
|
110
|
+
});
|
|
94
111
|
#@server.any('/*', (res, req) => {
|
|
95
|
-
const rack_res = #@app.$call(ouws.prepare_env(req));
|
|
112
|
+
const rack_res = #@app.$call(ouws.prepare_env(req, self));
|
|
96
113
|
res.writeStatus(rack_res[0].toString() + ' OK');
|
|
97
114
|
ouws.handle_headers(rack_res[1], res);
|
|
98
115
|
ouws.handle_response(rack_res[2], res);
|
|
@@ -136,7 +153,7 @@ module Up
|
|
|
136
153
|
},
|
|
137
154
|
sendPingsAutomatically: true,
|
|
138
155
|
upgrade: (res, req, context) => {
|
|
139
|
-
const env = ouws.prepare_env(req);
|
|
156
|
+
const env = ouws.prepare_env(req, self);
|
|
140
157
|
env.set('rack.upgrade?', #{:websocket});
|
|
141
158
|
const rack_res = #@app.$call(env);
|
|
142
159
|
const handler = env.get('rack.upgrade');
|
data/lib/up/version.rb
CHANGED