opal-up 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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