iodine 0.7.59 → 0.8.0

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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -20
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -146
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -0,0 +1,263 @@
1
+ #ifndef H___IODINE_LISTENER___H
2
+ #define H___IODINE_LISTENER___H
3
+ #include "iodine.h"
4
+
5
+ /* *****************************************************************************
6
+ Iodine Listener - Server Socket Listener Management
7
+
8
+ This module provides the Iodine::Listener Ruby class which represents an
9
+ active server socket listener. Listeners are created via Iodine.listen()
10
+ and can be used to:
11
+
12
+ - Map URL routes to different handlers (for HTTP listeners)
13
+ - Get/set the handler for raw TCP/WebSocket connections
14
+ - Manage listener lifecycle
15
+
16
+ The Listener class wraps either:
17
+ - fio_http_listener_s for HTTP/WebSocket listeners
18
+ - fio_io_listener_s for raw TCP listeners
19
+
20
+ Ruby API (Iodine::Listener):
21
+ - listener.map(url: "/path", handler: obj) - Map URL to handler (HTTP only)
22
+ - listener.map - Get current handler
23
+
24
+ Note: Listeners can only be created via Iodine.listen(), not directly
25
+ instantiated.
26
+ ***************************************************************************** */
27
+
28
+ /* *****************************************************************************
29
+ Ruby Object
30
+ ***************************************************************************** */
31
+
32
+ /** The Iodine::Listener Ruby class */
33
+ static VALUE iodine_rb_IODINE_LISTENER;
34
+
35
+ /**
36
+ * Internal structure representing an Iodine listener.
37
+ *
38
+ * Wraps either an HTTP listener (fio_http_listener_s) or a raw IO listener
39
+ * (fio_io_listener_s) along with its Ruby handler object.
40
+ */
41
+ typedef struct {
42
+ void *listener; /**< Pointer to fio_http_listener_s or fio_io_listener_s */
43
+ VALUE handler; /**< Ruby handler object for callbacks */
44
+ bool is_http; /**< true if HTTP listener, false if raw TCP */
45
+ } iodine_listener_s;
46
+
47
+ static void iodine_listener_free(void *p) {
48
+ iodine_listener_s *m = (iodine_listener_s *)p;
49
+ ruby_xfree(m);
50
+ }
51
+
52
+ static size_t iodine_listener_size(const void *p) {
53
+ iodine_listener_s *m = (iodine_listener_s *)p;
54
+ return sizeof(*m);
55
+ }
56
+
57
+ FIO_IFUNC void iodine_listener_gc_mark(void *p) {
58
+ iodine_listener_s *m = (iodine_listener_s *)p;
59
+ if (!IODINE_STORE_IS_SKIP(m->handler))
60
+ rb_gc_mark(m->handler);
61
+ }
62
+
63
+ static const rb_data_type_t IODINE_LISTNER_DATA_TYPE = {
64
+ .wrap_struct_name = "IodineListner",
65
+ .function =
66
+ {
67
+ .dmark = iodine_listener_gc_mark,
68
+ .dfree = iodine_listener_free,
69
+ .dsize = iodine_listener_size,
70
+ },
71
+ .data = NULL,
72
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
73
+ };
74
+
75
+ static iodine_listener_s *iodine_listener_ptr(VALUE self) {
76
+ iodine_listener_s *m;
77
+ TypedData_Get_Struct(self, iodine_listener_s, &IODINE_LISTNER_DATA_TYPE, m);
78
+ return m;
79
+ }
80
+
81
+ static VALUE iodine_listener_alloc(VALUE klass) {
82
+ iodine_listener_s *m;
83
+ VALUE self = TypedData_Make_Struct(klass,
84
+ iodine_listener_s,
85
+ &IODINE_LISTNER_DATA_TYPE,
86
+ m);
87
+ *m = (iodine_listener_s){0};
88
+ return self;
89
+ }
90
+
91
+ /* *****************************************************************************
92
+ Helpers - Internal Handler Management
93
+ ***************************************************************************** */
94
+
95
+ /**
96
+ * Macro called when a listener's handler is set.
97
+ * Releases the old handler from the store and holds the new one.
98
+ * Also injects handler methods into the listener class.
99
+ */
100
+ #define IODINE_LISTNER_ONSET(o) \
101
+ do { \
102
+ STORE.release(old_value); \
103
+ STORE.hold(o->handler); \
104
+ iodine_handler_method_injection__inner(iodine_rb_IODINE_LISTENER, \
105
+ o->handler, \
106
+ 0); \
107
+ } while (0)
108
+
109
+ FIO_DEF_GETSET_FUNC(static,
110
+ iodine___listener,
111
+ iodine_listener_s,
112
+ VALUE,
113
+ handler,
114
+ IODINE_LISTNER_ONSET)
115
+
116
+ #undef IODINE_LISTNER_ONSET
117
+
118
+ /**
119
+ * Creates a new Iodine::Listener Ruby object wrapping a native listener.
120
+ *
121
+ * This is called internally by Iodine.listen() to create the Ruby wrapper.
122
+ *
123
+ * @param listener Pointer to the native listener (HTTP or raw)
124
+ * @param handler Ruby handler object for callbacks
125
+ * @param is_http true for HTTP listeners, false for raw TCP
126
+ * @return New Iodine::Listener VALUE
127
+ *
128
+ * @note Raises NoMemError if allocation fails.
129
+ */
130
+ static VALUE iodine_listener_new(void *listener, VALUE handler, bool is_http) {
131
+ VALUE r = iodine_listener_alloc(iodine_rb_IODINE_LISTENER);
132
+ if (IODINE_STORE_IS_SKIP(r))
133
+ rb_raise(rb_eNoMemError, "Listener loocation error!");
134
+ iodine_listener_s *l = iodine_listener_ptr(r);
135
+ *l = (iodine_listener_s){.listener = listener,
136
+ .handler = handler,
137
+ .is_http = is_http};
138
+ return r;
139
+ }
140
+
141
+ /* *****************************************************************************
142
+ API - Ruby Methods
143
+ ***************************************************************************** */
144
+
145
+ /**
146
+ * Maps a URL path to a handler or retrieves the current handler.
147
+ *
148
+ * For HTTP listeners:
149
+ * - With url and handler: Maps the URL path to the handler
150
+ * - With url only: Returns the handler for that URL path
151
+ * - With neither: Returns the default handler
152
+ *
153
+ * For raw TCP listeners:
154
+ * - URL parameter is not allowed (raises RuntimeError)
155
+ * - With handler: Sets the connection handler
156
+ * - Without handler: Returns the current handler
157
+ *
158
+ * @param argc Number of arguments
159
+ * @param argv Array of arguments (url:, handler:)
160
+ * @param o The Iodine::Listener instance
161
+ * @return The handler for the specified URL/listener
162
+ *
163
+ * @note Raises RuntimeError if called on an inactive listener.
164
+ * @note Raises RuntimeError if URL is provided for non-HTTP listener.
165
+ *
166
+ * Ruby: listener.map(url: "/api", handler: MyHandler)
167
+ * listener.map(url: "/api") # => returns handler
168
+ * listener.map # => returns default handler
169
+ */
170
+ static VALUE iodine_listener_map(int argc, VALUE *argv, VALUE o) {
171
+ iodine_listener_s *l = iodine_listener_ptr(o);
172
+ fio_http_settings_s settings;
173
+ VALUE url = Qnil;
174
+ VALUE handler = Qnil;
175
+
176
+ iodine_rb2c_arg(argc,
177
+ argv,
178
+ IODINE_ARG_RB(url, 0, "url", 0),
179
+ IODINE_ARG_RB(handler, 0, "handler", 0));
180
+ if (!l->listener)
181
+ rb_raise(rb_eRuntimeError,
182
+ "call to `map` can only be called on active listeners");
183
+ if (l->is_http) {
184
+ if (RB_TYPE_P(url, RUBY_T_SYMBOL))
185
+ url = rb_sym2str(rb_sym2id(url));
186
+ if (!IODINE_STORE_IS_SKIP(url))
187
+ rb_check_type(url, RUBY_T_STRING);
188
+ if (handler == Qnil) { /* read value */
189
+ handler = (VALUE)(fio_http_route_settings(
190
+ (fio_http_listener_s *)(l->listener),
191
+ IODINE_STORE_IS_SKIP(url) ? "/" : RSTRING_PTR(url))
192
+ ->udata);
193
+ } else { /* set value for HTTP router */
194
+ if (!IODINE_STORE_IS_SKIP(handler)) {
195
+ STORE.hold(handler);
196
+ iodine_handler_method_injection__inner(iodine_rb_IODINE_LISTENER,
197
+ handler,
198
+ 0);
199
+ }
200
+ settings =
201
+ *fio_http_listener_settings((fio_http_listener_s *)l->listener);
202
+ if (IODINE_STORE_IS_SKIP(handler))
203
+ handler = (VALUE)settings.udata;
204
+ settings.udata = (void *)handler;
205
+ settings.public_folder = FIO_STR_INFO0;
206
+ // TODO: test for a handler's public folder property?
207
+ fio_http_route FIO_NOOP((fio_http_listener_s *)l->listener,
208
+ RSTRING_PTR(url),
209
+ settings);
210
+ }
211
+ } else { /* not HTTP, URLs are invalid. */
212
+ if (!IODINE_STORE_IS_SKIP(url))
213
+ rb_raise(rb_eRuntimeError,
214
+ "URL values are only valid for HTTP listener objects.");
215
+ if (handler == Qnil) { /* read value */
216
+ handler = iodine___listener_handler(l);
217
+ } else { /* set value for raw router */
218
+ fio_io_listener_udata_set((fio_io_listener_s *)(l->listener),
219
+ (void *)handler);
220
+ iodine___listener_handler_set(l, handler);
221
+ }
222
+ }
223
+ return handler;
224
+ }
225
+
226
+ /**
227
+ * Raises an error - Listeners cannot be directly instantiated.
228
+ *
229
+ * Listeners must be created via Iodine.listen() which returns a
230
+ * properly configured Listener object.
231
+ *
232
+ * @param o The Listener instance (unused)
233
+ * @return Never returns (always raises)
234
+ *
235
+ * @note Always raises RuntimeError.
236
+ */
237
+ static VALUE iodine_listener_initialize(VALUE o) {
238
+ rb_raise(rb_eRuntimeError,
239
+ "Iodine Listeners can only be created using Iodine.listen");
240
+ return Qnil;
241
+ }
242
+
243
+ /* *****************************************************************************
244
+ Initialize - Ruby Class Registration
245
+ ***************************************************************************** */
246
+
247
+ /**
248
+ * Initializes the Iodine::Listener Ruby class.
249
+ *
250
+ * Defines the class under the Iodine module and registers:
251
+ * - Allocator function
252
+ * - initialize method (raises error - use Iodine.listen instead)
253
+ * - map method for URL routing (HTTP) or handler access (raw)
254
+ */
255
+ static void Init_Iodine_Listener(void) {
256
+ VALUE m = iodine_rb_IODINE_LISTENER =
257
+ rb_define_class_under(iodine_rb_IODINE, "Listener", rb_cObject);
258
+ STORE.hold(iodine_rb_IODINE_LISTENER);
259
+ rb_define_alloc_func(m, iodine_listener_alloc);
260
+ rb_define_method(m, "initialize", iodine_listener_initialize, 0);
261
+ rb_define_method(m, "map", iodine_listener_map, -1);
262
+ }
263
+ #endif /* H___IODINE_LISTENER___H */
@@ -0,0 +1,297 @@
1
+ #ifndef H___IODINE_LOG___H
2
+ #define H___IODINE_LOG___H
3
+ #include "iodine.h"
4
+
5
+ /* *****************************************************************************
6
+ Iodine::Logger - Ruby-facing leveled logging
7
+
8
+ Routes Ruby log messages through the facil.io C STL logging system
9
+ (FIO_LOG_*), so Ruby output shares the same stderr sink, level prefixes,
10
+ truncation limits, and the global log level (Iodine::Logger.level /
11
+ FIO_LOG_LEVEL) as the C core.
12
+
13
+ Log levels (from facil.io):
14
+ - 0: FIO_LOG_LEVEL_NONE - No logging
15
+ - 1: FIO_LOG_LEVEL_FATAL - Fatal errors only
16
+ - 2: FIO_LOG_LEVEL_ERROR - Errors and above
17
+ - 3: FIO_LOG_LEVEL_WARNING - Warnings and above
18
+ - 4: FIO_LOG_LEVEL_INFO - Info and above (default)
19
+ - 5: FIO_LOG_LEVEL_DEBUG - Debug and above
20
+
21
+ Ruby API:
22
+ - Iodine::Logger.fatal(*msg, &blk) / .error / .warn / .info / .debug
23
+ (each argument logged separately; callable arguments invoked; a block's
24
+ return value logged; nothing evaluated while the level is silenced)
25
+ - Iodine::Logger << msg (alias for info)
26
+ - Iodine::Logger.level / .level= (Integer 0-5 or Symbol)
27
+ - Iodine::Logger::NONE / FATAL / ERROR / WARN / INFO / DEBUG constants
28
+ ***************************************************************************** */
29
+
30
+ static VALUE iodine_rb_IODINE_LOGGER;
31
+
32
+ /* *****************************************************************************
33
+ Leveled logging methods
34
+ ***************************************************************************** */
35
+
36
+ /** Emits a single message at the given level through the C STL logging. */
37
+ static void iodine_log_emit_value(int level, VALUE msg) {
38
+ VALUE str = rb_obj_as_string(msg);
39
+ const char *cstr = StringValueCStr(str);
40
+ switch (level) {
41
+ case FIO_LOG_LEVEL_FATAL: FIO_LOG_FATAL("%s", cstr); break;
42
+ case FIO_LOG_LEVEL_ERROR: FIO_LOG_ERROR("%s", cstr); break;
43
+ case FIO_LOG_LEVEL_WARNING: FIO_LOG_WARNING("%s", cstr); break;
44
+ case FIO_LOG_LEVEL_INFO: FIO_LOG_INFO("%s", cstr); break;
45
+ default: FIO_LOG_DEBUG2("%s", cstr); break;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Shared implementation for all leveled methods.
51
+ *
52
+ * Each argument is logged as its own message. Arguments that answer `call`
53
+ * (e.g. Proc / lambda) are invoked and their return value is logged. If a
54
+ * block is given, it is called last and its return value is logged (Rack
55
+ * SPEC compatible logger behavior).
56
+ *
57
+ * Lazy evaluation: when the level exceeds the current verbosity, nothing is
58
+ * evaluated - arguments are not converted, callables are not invoked and the
59
+ * block is not called.
60
+ */
61
+ static VALUE iodine_log_write(int level, int argc, VALUE *argv) {
62
+ if (level > FIO_LOG_LEVEL_GET())
63
+ return Qnil;
64
+ for (int i = 0; i < argc; ++i) {
65
+ VALUE msg = argv[i];
66
+ if (rb_respond_to(msg, IODINE_CALL_ID))
67
+ msg = rb_funcall2(msg, IODINE_CALL_ID, 0, NULL);
68
+ iodine_log_emit_value(level, msg);
69
+ }
70
+ if (rb_block_given_p())
71
+ iodine_log_emit_value(
72
+ level,
73
+ rb_funcall2(rb_block_proc(), IODINE_CALL_ID, 0, NULL));
74
+ return Qnil;
75
+ }
76
+
77
+ /**
78
+ * @!method fatal(*messages, &block)
79
+ * Logs each message at fatal level (level 1).
80
+ *
81
+ * Callable arguments are invoked and a block's return value is logged
82
+ * (evaluated only when the level is active).
83
+ *
84
+ * @param messages [Array<Object>] the messages (converted with #to_s)
85
+ * @return [nil]
86
+ */
87
+ static VALUE iodine_log_fatal(int argc, VALUE *argv, VALUE self) {
88
+ return iodine_log_write(FIO_LOG_LEVEL_FATAL, argc, argv);
89
+ (void)self;
90
+ }
91
+
92
+ /**
93
+ * @!method error(*messages, &block)
94
+ * Logs each message at error level (level 2).
95
+ *
96
+ * Callable arguments are invoked and a block's return value is logged
97
+ * (evaluated only when the level is active).
98
+ *
99
+ * @param messages [Array<Object>] the messages (converted with #to_s)
100
+ * @return [nil]
101
+ */
102
+ static VALUE iodine_log_error(int argc, VALUE *argv, VALUE self) {
103
+ return iodine_log_write(FIO_LOG_LEVEL_ERROR, argc, argv);
104
+ (void)self;
105
+ }
106
+
107
+ /**
108
+ * @!method warn(*messages, &block)
109
+ * Logs each message at warning level (level 3).
110
+ *
111
+ * Callable arguments are invoked and a block's return value is logged
112
+ * (evaluated only when the level is active).
113
+ *
114
+ * @param messages [Array<Object>] the messages (converted with #to_s)
115
+ * @return [nil]
116
+ */
117
+ static VALUE iodine_log_warn(int argc, VALUE *argv, VALUE self) {
118
+ return iodine_log_write(FIO_LOG_LEVEL_WARNING, argc, argv);
119
+ (void)self;
120
+ }
121
+
122
+ /**
123
+ * @!method info(*messages, &block)
124
+ * Logs each message at info level (level 4).
125
+ *
126
+ * Callable arguments are invoked and a block's return value is logged
127
+ * (evaluated only when the level is active).
128
+ *
129
+ * @param messages [Array<Object>] the messages (converted with #to_s)
130
+ * @return [nil]
131
+ */
132
+ static VALUE iodine_log_info(int argc, VALUE *argv, VALUE self) {
133
+ return iodine_log_write(FIO_LOG_LEVEL_INFO, argc, argv);
134
+ (void)self;
135
+ }
136
+
137
+ /**
138
+ * @!method <<(message)
139
+ * Alias for {#info} - logs the message at info level (level 4).
140
+ *
141
+ * @param message [Object] the message (converted with #to_s)
142
+ * @return [nil]
143
+ */
144
+ static VALUE iodine_log_lshift(int argc, VALUE *argv, VALUE self) {
145
+ return iodine_log_write(FIO_LOG_LEVEL_INFO, argc, argv);
146
+ (void)self;
147
+ }
148
+
149
+ /**
150
+ * @!method debug(*messages, &block)
151
+ * Logs each message at debug level (level 5), routed through FIO_LOG_DEBUG2
152
+ * (the C file:line prefix is omitted, since it would point at the binding
153
+ * rather than the Ruby caller).
154
+ *
155
+ * Callable arguments are invoked and a block's return value is logged
156
+ * (evaluated only when the level is active).
157
+ *
158
+ * @param messages [Array<Object>] the messages (converted with #to_s)
159
+ * @return [nil]
160
+ */
161
+ static VALUE iodine_log_debug(int argc, VALUE *argv, VALUE self) {
162
+ return iodine_log_write(FIO_LOG_LEVEL_DEBUG, argc, argv);
163
+ (void)self;
164
+ }
165
+
166
+ /* *****************************************************************************
167
+ Level helpers
168
+ ***************************************************************************** */
169
+
170
+ /**
171
+ * @!method level
172
+ * Returns the current logging level (the process-wide C STL log level).
173
+ *
174
+ * @return [Integer] the current log level (0-5)
175
+ */
176
+ static VALUE iodine_log_level(VALUE self) {
177
+ return RB_INT2FIX(((long)FIO_LOG_LEVEL_GET()));
178
+ (void)self;
179
+ }
180
+
181
+ /**
182
+ * @!method level=(level)
183
+ * Sets the current logging level (the process-wide C STL log level).
184
+ *
185
+ * @param level [Integer, Symbol] the log level: 0-5, or one of
186
+ * :none, :fatal, :error, :warn, :info, :debug
187
+ * @return [Integer, Symbol] the given level
188
+ * @raise [TypeError] if level is not an Integer or Symbol
189
+ * @raise [ArgumentError] if the level value is unknown or out of range
190
+ */
191
+ static VALUE iodine_log_level_set(VALUE self, VALUE level) {
192
+ int n;
193
+ if (RB_TYPE_P(level, RUBY_T_SYMBOL)) {
194
+ ID id = rb_sym2id(level);
195
+ if (id == rb_intern("none")) {
196
+ n = FIO_LOG_LEVEL_NONE;
197
+ } else if (id == rb_intern("fatal")) {
198
+ n = FIO_LOG_LEVEL_FATAL;
199
+ } else if (id == rb_intern("error")) {
200
+ n = FIO_LOG_LEVEL_ERROR;
201
+ } else if (id == rb_intern("warn") || id == rb_intern("warning")) {
202
+ n = FIO_LOG_LEVEL_WARNING;
203
+ } else if (id == rb_intern("info")) {
204
+ n = FIO_LOG_LEVEL_INFO;
205
+ } else if (id == rb_intern("debug")) {
206
+ n = FIO_LOG_LEVEL_DEBUG;
207
+ } else {
208
+ rb_raise(rb_eArgError,
209
+ "unknown log level: :%s (expected :none, :fatal, :error, "
210
+ ":warn, :info or :debug)",
211
+ rb_id2name(id));
212
+ return Qnil;
213
+ }
214
+ } else {
215
+ rb_check_type(level, RUBY_T_FIXNUM);
216
+ long lng = RB_FIX2INT(level);
217
+ if (lng < FIO_LOG_LEVEL_NONE || lng > FIO_LOG_LEVEL_DEBUG) {
218
+ rb_raise(rb_eArgError, "log level must be between 0 and 5");
219
+ return Qnil;
220
+ }
221
+ n = (int)lng;
222
+ }
223
+ FIO_LOG_LEVEL_SET(n);
224
+ return level;
225
+ (void)self;
226
+ }
227
+
228
+ /* *****************************************************************************
229
+ Initialization
230
+ ***************************************************************************** */
231
+
232
+ /**
233
+ * Initializes the Iodine::Logger module.
234
+ */
235
+ static void Init_Iodine_Logger(void) {
236
+ iodine_rb_IODINE_LOGGER = rb_define_module_under(iodine_rb_IODINE, "Logger");
237
+ STORE.hold(iodine_rb_IODINE_LOGGER);
238
+
239
+ /* Log level constants (mirroring the facil.io FIO_LOG_LEVEL_* values) */
240
+ rb_define_const(iodine_rb_IODINE_LOGGER,
241
+ "NONE",
242
+ RB_INT2FIX(FIO_LOG_LEVEL_NONE));
243
+ rb_define_const(iodine_rb_IODINE_LOGGER,
244
+ "FATAL",
245
+ RB_INT2FIX(FIO_LOG_LEVEL_FATAL));
246
+ rb_define_const(iodine_rb_IODINE_LOGGER,
247
+ "ERROR",
248
+ RB_INT2FIX(FIO_LOG_LEVEL_ERROR));
249
+ rb_define_const(iodine_rb_IODINE_LOGGER,
250
+ "WARN",
251
+ RB_INT2FIX(FIO_LOG_LEVEL_WARNING));
252
+ rb_define_const(iodine_rb_IODINE_LOGGER,
253
+ "INFO",
254
+ RB_INT2FIX(FIO_LOG_LEVEL_INFO));
255
+ rb_define_const(iodine_rb_IODINE_LOGGER,
256
+ "DEBUG",
257
+ RB_INT2FIX(FIO_LOG_LEVEL_DEBUG));
258
+
259
+ /* Leveled logging methods (module functions: callable on the module and
260
+ * available as private instance methods when included) */
261
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
262
+ "fatal",
263
+ iodine_log_fatal,
264
+ -1);
265
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
266
+ "error",
267
+ iodine_log_error,
268
+ -1);
269
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
270
+ "warn",
271
+ iodine_log_warn,
272
+ -1);
273
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
274
+ "info",
275
+ iodine_log_info,
276
+ -1);
277
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
278
+ "debug",
279
+ iodine_log_debug,
280
+ -1);
281
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
282
+ "<<",
283
+ iodine_log_lshift,
284
+ -1);
285
+
286
+ /* Level helpers */
287
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
288
+ "level",
289
+ iodine_log_level,
290
+ 0);
291
+ rb_define_module_function(iodine_rb_IODINE_LOGGER,
292
+ "level=",
293
+ iodine_log_level_set,
294
+ 1);
295
+ }
296
+
297
+ #endif /* H___IODINE_LOG___H */