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 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