iodine 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c633ef1f40df47f2edefcd78b2bd3fc2a896ab7a704b298f42765d605b375947
4
- data.tar.gz: e810cccda11b73c2c4881fd90e4e0132efbf62c11857edee457381cb700c6302
3
+ metadata.gz: 3223346c9846721cd2c6c5ef4c49e6abd9e43b28921ba1413d0b8c09c7372375
4
+ data.tar.gz: 20fde29985c40d22743f77eae4ad5a981e8f3e033798539436e54995ee9fade5
5
5
  SHA512:
6
- metadata.gz: 1e376b5ca69fb98da82062508687cd2bdaf7bb55b2071559d23c2f5eb330cd7fc9f7856865a86cb382357106835027e5296a8f0c67113a0522dd1a6ac9323bbf
7
- data.tar.gz: ecd04e8c645961e8df5e4bfa7e2666a71a81dfda1647fe7e43c27894abb9431010663821d36a99bca23727cb0077f6f00144e0cd563a2a34ba9426ab80bb24cb
6
+ metadata.gz: b76b9b6abbf1df98c1bcb02df5efb5e138f8f529391f9d566a42f270ea99c7915d44c12096b663b008f8f62892ef6b58f2d4a138c67b39cf12b71e2c65047c6f
7
+ data.tar.gz: a1ab694050056c0bc848c17b121d0b239a0845137ed70b918a2ca4bc067d6f8c956a5430466205299e6122520fce677380c662eb7f72de5b5cf626bcb78584d4
@@ -6,6 +6,12 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.6.1
10
+
11
+ **Fix**: (`Iodine::PubSub`) fixed typo, `Iodine::PubSub.detach` is now correctly spelled.
12
+
13
+ **Fix**: (`Iodine::PubSub`) fix issue #37 where iodine would crash after the server's shutdown process due to Ruby Pub/Sub engines still being attached (or set as default) even after the Ruby interpreter freed all the Ruby objects. Credit to @sj26 (Samuel Cochran) for reporting the issue.
14
+
9
15
  #### Change log v.0.6.0
10
16
 
11
17
  I apologize to all my amazing early adopters for the rapid changes in the API for connection objects (SSE / WebSockets) and Pub/Sub. This was a result of an attempt to create a de-facto standard with other server authors. Hopefully the API in the 0.6.0 release will see the last of the changes.
@@ -33,33 +33,30 @@ WebSocket and EventSource connection upgrade and handling is performed using a C
33
33
 
34
34
  The Callback Object should be a class (or an instance of such class) where **instances** implement any of the following callbacks:
35
35
 
36
- * `on_open()` WILL be called once the connection had been established.
36
+ * `on_open(client)` WILL be called once the connection had been established.
37
37
 
38
- * `on_message(data)` WILL be called when incoming WebSocket data is received.
38
+ * `on_message(client, data)` WILL be called when incoming WebSocket data is received.
39
39
 
40
40
  This callback is ignored for EventSource connections.
41
41
 
42
42
  `data` will be a String with an encoding of UTF-8 for text messages and `binary` encoding for non-text messages (as specified by the WebSocket Protocol).
43
43
 
44
- The *client* **MUST** assume that the `data` String will be a **recyclable buffer** and that it's content will be corrupted the moment the `on_message` callback returns.
44
+ The *callback object* **MUST** assume that the `data` String will be a **recyclable buffer** and that it's content will be corrupted the moment the `on_message` callback returns.
45
45
 
46
46
  Servers **MAY**, optionally, implement a **recyclable buffer** for the `on_message` callback. However, this is optional and it is *not* required.
47
47
 
48
- * `on_drained()` **MAY** be called when the the `write` buffer becomes empty. **If** `pending` returns a non-zero value, the `on_drained` callback **MUST** be called once the write buffer becomes empty.
48
+ * `on_drained(client)` **MAY** be called when the the `write` buffer becomes empty. **If** `pending` returns a non-zero value, the `on_drained` callback **MUST** be called once the write buffer becomes empty.
49
49
 
50
- * `on_shutdown()` **MAY** be called during the server's graceful shutdown process, _before_ the connection is closed and in addition to the `on_close` function (which is called _after_ the connection is closed.
50
+ * `on_shutdown(client)` **MAY** be called during the server's graceful shutdown process, _before_ the connection is closed and in addition to the `on_close` function (which is called _after_ the connection is closed.
51
51
 
52
- * `on_close()` **MUST** be called _after_ the connection was closed for whatever reason (socket errors, parsing errors, timeouts, client disconnection, `close` being called, etc').
52
+ * `on_close(client)` **MUST** be called _after_ the connection was closed for whatever reason (socket errors, parsing errors, timeouts, client disconnection, `close` being called, etc').
53
53
 
54
- * `on_open`, `on_drained`, `on_shutdown` and `on_close` shouldn't expect any arguments (`arity == 0`).
55
54
 
56
- The following method names are reserved for the network implementation: `write`, `close`, `open?` and `pending`.
55
+ The server **MUST** provide the Callback Object with a `client` object, that supports the following methods (this approach promises applications could be server agnostic):
57
56
 
58
- The server **MUST** extend the Callback Object's *class* using `extend`, so the Callback Object **inherits** the following methods (this approach promises applications could be server agnostic\*):
57
+ * `write(data)` will schedule the data to be sent. `data` **MUST** be a String.
59
58
 
60
- * `write(data)` will attempt to send the data through the connection. `data` **MUST** be a String.
61
-
62
- `write` has the same delivery promise as `Socket#write` (a successful `write` does **not** mean any of the data will reach the other side).
59
+ A call to `write` only promises that the data is scheduled to be sent. Servers are encouraged to avoid blocking and return immediately, deferring the actual `write` operation for later.
63
60
 
64
61
  `write` shall return `true` on success and `false` if the connection is closed.
65
62
 
@@ -69,15 +66,15 @@ The server **MUST** extend the Callback Object's *class* using `extend`, so the
69
66
 
70
67
  * If `data` is binary encoded it will be sent as non-text (as specified by the WebSocket Protocol).
71
68
 
72
- A server **SHOULD** document whether `write` will block or return immediately. It is **RECOMMENDED** that servers implement buffered IO, allowing `write` to return immediately when resources allow and block (or, possibly, disconnect) when the IO buffer is full.
69
+ A server **SHOULD** document whether `write` will block. It is **RECOMMENDED** that servers implement buffered IO, allowing `write` to return immediately when resources allow and block (or, possibly, disconnect) when the IO buffer is full.
73
70
 
74
71
  * `close` closes the connection once all the data in the outgoing queue was sent. If `close` is called while there is still data to be sent, `close` will only take effect once the data was sent.
75
72
 
76
73
  `close` shall always return `nil`.
77
74
 
78
- * `open?` returns the state of the connection. Servers **MUST** set the method to return `true` if the connection is open and `false` if the connection is closed or marked to be closed.
75
+ * `open?` returns `true` if the connection isn't known to have been closed and `false` if the connection is known to be closed or marked to be closed.
79
76
 
80
- * `pending` **MUST** return -1 if the connection is closed or the number of pending writes (calls to `write`) that need to be processed before the next time the `on_drained` callback is called\*.
77
+ * `pending` **MUST** return -1 if the connection is closed. Otherwise, `pending` **SHOULD** return the number of pending writes (messages in the `write` queue\*) that need to be processed before the next time the `on_drained` callback is called.
81
78
 
82
79
  Servers **MAY** choose to always return the value `0` if they never call the `on_drained` callback and the connection is open.
83
80
 
@@ -85,7 +82,6 @@ The server **MUST** extend the Callback Object's *class* using `extend`, so the
85
82
 
86
83
  \*Servers that divide large messages into a number of smaller messages (implement message fragmentation) MAY count each fragment separately, as if the fragmentation was performed by the user and `write` was called more than once per message.
87
84
 
88
- The following keyword(s) (both as method names and instance variable names) is reserved for the internal server implementations: `_sock`, `_cid`.
89
85
 
90
86
  WebSocket `ping` / `pong`, timeouts and network considerations should be implemented by the server. It is **RECOMMENDED** (but not required) that the server send `ping`s to prevent connection timeouts and detect network failure.
91
87
 
@@ -139,20 +135,20 @@ The following is an example WebSocket echo server implemented using this specifi
139
135
 
140
136
  ```ruby
141
137
  class WSConnection
142
- def on_open
138
+ def on_open(client)
143
139
  puts "WebSocket connection established."
144
140
  end
145
- def on_message(data)
146
- write data
141
+ def on_message(client, data)
142
+ client.write data
147
143
  puts "on_drained MUST be implemented if #{ pending } != 0."
148
144
  end
149
- def on_drained
145
+ def on_drained(client)
150
146
  puts "Yap,on_drained is implemented."
151
147
  end
152
- def on_shutdown
153
- write "The server is going away. Goodbye."
148
+ def on_shutdown(client)
149
+ client.write "The server is going away. Goodbye."
154
150
  end
155
- def on_close
151
+ def on_close(client)
156
152
  puts "WebSocket connection closed."
157
153
  end
158
154
  end
@@ -170,22 +166,22 @@ end
170
166
  run App
171
167
  ```
172
168
 
173
- The following is uses Push notifications for both WebSocket and SSE connections. The Pub/Sub API isn't part of this specification:
169
+ The following example uses Push notifications for both WebSocket and SSE connections. The Pub/Sub API isn't part of this specification but it is supported by iodine:
174
170
 
175
171
  ```ruby
176
172
  class Chat
177
173
  def initialize(nickname)
178
174
  @nickname = nickname
179
175
  end
180
- def on_open
181
- subscribe "chat"
182
- publish "chat", "#{@nickname} joined the chat."
176
+ def on_open(client)
177
+ client.subscribe "chat"
178
+ client.publish "chat", "#{@nickname} joined the chat."
183
179
  end
184
- def on_message(data)
185
- publish "chat", "#{@nickname}: #{data}"
180
+ def on_message(client, data)
181
+ client.publish "chat", "#{@nickname}: #{data}"
186
182
  end
187
- def on_close
188
- publish "chat", "#{@nickname}: left the chat."
183
+ def on_close(client)
184
+ client.publish "chat", "#{@nickname}: left the chat."
189
185
  end
190
186
  end
191
187
 
@@ -583,6 +583,7 @@ static VALUE iodine_pubsub_unsubscribe(VALUE self, VALUE name) {
583
583
  return ret;
584
584
  }
585
585
 
586
+ // clang-format off
586
587
  /**
587
588
  Publishes a message to a channel.
588
589
 
@@ -601,11 +602,11 @@ Alternatively, accepts the following named arguments:
601
602
 
602
603
  :message :: The message to be published (required).
603
604
 
604
- :engine :: If provided, the engine to use for pub/sub. Otherwise the default
605
- engine is used.
605
+ :engine :: If provided, the engine to use for pub/sub. Otherwise the default engine is used.
606
606
 
607
607
  */
608
608
  static VALUE iodine_pubsub_publish(int argc, VALUE *argv, VALUE self) {
609
+ // clang-format on
609
610
  VALUE rb_ch, rb_msg, rb_engine = Qnil;
610
611
  const pubsub_engine_s *engine = NULL;
611
612
  switch (argc) {
@@ -220,6 +220,8 @@ static void iodine_pubsub_data_mark(void *c_) {
220
220
  /* a callback for the GC (marking active objects) */
221
221
  static void iodine_pubsub_data_free(void *c_) {
222
222
  iodine_pubsub_s *data = c_;
223
+ pubsub_engine_deregister(data->engine);
224
+ IodineStore.remove(data->handler); /* redundant except during exit */
223
225
  if (data->dealloc) {
224
226
  data->dealloc(data->engine);
225
227
  }
@@ -335,7 +337,7 @@ static VALUE iodine_pubsub_attach(VALUE self, VALUE engine) {
335
337
  * the {Iodine::PubSub::Engine}'s callbacks ({Iodine::PubSub::Engine#subscribe}
336
338
  * and {Iodine::PubSub::Engine#unsubscribe})
337
339
  */
338
- static VALUE iodine_pubsub_dettach(VALUE self, VALUE engine) {
340
+ static VALUE iodine_pubsub_detach(VALUE self, VALUE engine) {
339
341
  iodine_pubsub_s *e = iodine_pubsub_CData(engine);
340
342
  if (!e) {
341
343
  rb_raise(rb_eTypeError, "not a valid engine");
@@ -657,7 +659,8 @@ void iodine_pubsub_init(void) {
657
659
  rb_define_module_function(PubSubModule, "default", iodine_pubsub_default_get,
658
660
  0);
659
661
  rb_define_module_function(PubSubModule, "attach", iodine_pubsub_attach, 1);
660
- rb_define_module_function(PubSubModule, "dettach", iodine_pubsub_dettach, 1);
662
+ rb_define_module_function(PubSubModule, "dettach", iodine_pubsub_detach, 1);
663
+ rb_define_module_function(PubSubModule, "detach", iodine_pubsub_detach, 1);
661
664
  rb_define_module_function(PubSubModule, "reset", iodine_pubsub_reset, 1);
662
665
 
663
666
  /* Define the Engine class and it's methods */
@@ -446,8 +446,10 @@ void pubsub_engine_deregister(pubsub_engine_s *engine) {
446
446
  (fio_hash_key_s){.hash = (uintptr_t)engine, .obj = FIOBJ_INVALID}, NULL);
447
447
  fio_hash_compact(&engines);
448
448
  spn_unlock(&engn_lock);
449
- if (!old)
450
- fprintf(stderr, "Deregister error, not registered?\n");
449
+ // if (!old) {
450
+ // fprintf(stderr, "WARNING: (pub/sub) Deregister error,"
451
+ // " not registered?\n");
452
+ // }
451
453
  }
452
454
 
453
455
  /**
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.6.0'.freeze
2
+ VERSION = '0.6.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-12 00:00:00.000000000 Z
11
+ date: 2018-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack