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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e47b86e6f54cbdb8ecf23cf5b6c759127ac30a8f4f00764e39eeca57ca94e52d
4
- data.tar.gz: 6d93f3b96474fb1c18fadeb5a46083241947691470a0c3f7d36dc7025e1116de
3
+ metadata.gz: cb3a4f16540780758e686bbd53c9ab5467b85988bd83a990b05ab54b124c2d2d
4
+ data.tar.gz: 292c74cb7b0771cf807af2b1ebc221707f2b92bd28ca2e1271038b242aa94fc5
5
5
  SHA512:
6
- metadata.gz: 25d3c86c354d50656b266995a0d235460e6d9c45b1853d33d363636e1bead3b4539b8a068fee0cbfd58b27d2160759b2f1823ae039c2ce0c15793f6a95fd0541
7
- data.tar.gz: d3a6dd3a8e854a1ba75cfc297ecb5b4153c04b3814185add67424bcfd7574538d4365aebbd1006967e798d7af155ad0b98582955eb4f8c2e1f5633448d474433
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 up_server_request_handler(uws_res_t *res, uws_req_t *req,
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 renv = rb_hash_dup(s->env_template);
330
- up_server_prepare_env(renv, req);
331
-
332
- // call app
333
- VALUE rres = rb_funcall(s->rapp, id_call, 1, renv);
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
- // close resources if necessary
356
- if (rb_respond_to(rparts, id_close))
357
- rb_funcall(rparts, id_close, 0);
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
- return;
360
- RB_GC_GUARD(rstatus);
361
- RB_GC_GUARD(rheaders);
362
- RB_GC_GUARD(rres);
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 per
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
- uws_app_any(USE_SSL, s->app, "/*", up_server_request_handler, (void *)s);
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, rb_intern("new"), 1, rb_stderr);
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, rb_intern("new"), 1, empty_string);
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 = IO.new
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
- env.set('rack.input', #@default_input);
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);
@@ -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
- warn "\nError: a cluster member died!"
42
- kill_members
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 = IO.new
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', #@default_input);
65
- env.set('rack.logger', #@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', #@t_factory);
68
- env.set('rack.url_scheme', #@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', #@host);
73
- env.set('SERVER_PORT', #@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
@@ -1,3 +1,3 @@
1
1
  module Up
2
- VERSION = '0.0.6'.freeze
2
+ VERSION = '0.0.8'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-up
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann