takagi 0.1.0 → 1.1.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 (197) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +70 -7
  3. data/.yard/templates/default/layout/html/layout.erb +34 -0
  4. data/AGENTS.md +16 -0
  5. data/CHANGELOG.md +158 -1
  6. data/CODE_OF_CONDUCT.md +1 -1
  7. data/README.md +590 -23
  8. data/ROADMAP.md +55 -0
  9. data/Rakefile +4 -4
  10. data/Steepfile +39 -0
  11. data/bin/takagi-dev +159 -0
  12. data/docs/FIRST_PLUGIN_GUIDE.md +224 -0
  13. data/docs/HOOKS.md +31 -0
  14. data/examples/client_lifecycle_example.rb +118 -0
  15. data/examples/cloud_gateway_app.rb +217 -0
  16. data/examples/nested_api_app.rb +258 -0
  17. data/examples/simple_device_app.rb +71 -0
  18. data/examples/takagi.yml +138 -0
  19. data/lib/takagi/application.rb +256 -0
  20. data/lib/takagi/base/middleware_management.rb +39 -0
  21. data/lib/takagi/base/plugin_management.rb +75 -0
  22. data/lib/takagi/base/reactor_management.rb +104 -0
  23. data/lib/takagi/base/server_lifecycle.rb +156 -0
  24. data/lib/takagi/base.rb +103 -11
  25. data/lib/takagi/branding.rb +88 -0
  26. data/lib/takagi/cbor/decoder.rb +385 -0
  27. data/lib/takagi/cbor/encoder.rb +260 -0
  28. data/lib/takagi/cbor/error.rb +17 -0
  29. data/lib/takagi/cbor/version.rb +9 -0
  30. data/lib/takagi/client/response.rb +236 -0
  31. data/lib/takagi/client.rb +265 -0
  32. data/lib/takagi/client_base.rb +204 -0
  33. data/lib/takagi/coap/code_helpers.rb +190 -0
  34. data/lib/takagi/coap/registries/base.rb +165 -0
  35. data/lib/takagi/coap/registries/content_format.rb +71 -0
  36. data/lib/takagi/coap/registries/message_type.rb +69 -0
  37. data/lib/takagi/coap/registries/method.rb +38 -0
  38. data/lib/takagi/coap/registries/option.rb +71 -0
  39. data/lib/takagi/coap/registries/response.rb +93 -0
  40. data/lib/takagi/coap/registries/signaling.rb +34 -0
  41. data/lib/takagi/coap/signaling.rb +10 -0
  42. data/lib/takagi/coap.rb +37 -0
  43. data/lib/takagi/composite_router.rb +186 -0
  44. data/lib/takagi/config.rb +337 -0
  45. data/lib/takagi/controller/resource_allocator.rb +164 -0
  46. data/lib/takagi/controller/thread_pool.rb +144 -0
  47. data/lib/takagi/controller.rb +319 -0
  48. data/lib/takagi/core/attribute_set.rb +128 -0
  49. data/lib/takagi/discovery/core_link_format.rb +137 -0
  50. data/lib/takagi/errors.rb +536 -0
  51. data/lib/takagi/event_bus/address_prefix.rb +142 -0
  52. data/lib/takagi/event_bus/async_executor.rb +235 -0
  53. data/lib/takagi/event_bus/coap_bridge.rb +208 -0
  54. data/lib/takagi/event_bus/future.rb +153 -0
  55. data/lib/takagi/event_bus/lru_cache.rb +157 -0
  56. data/lib/takagi/event_bus/message_buffer.rb +237 -0
  57. data/lib/takagi/event_bus/observer_cleanup.rb +110 -0
  58. data/lib/takagi/event_bus/scope.rb +74 -0
  59. data/lib/takagi/event_bus.rb +594 -0
  60. data/lib/takagi/helpers.rb +88 -0
  61. data/lib/takagi/hooks.rb +82 -0
  62. data/lib/takagi/initializer.rb +18 -0
  63. data/lib/takagi/logger.rb +15 -6
  64. data/lib/takagi/message/base.rb +155 -0
  65. data/lib/takagi/message/deduplication_cache.rb +84 -0
  66. data/lib/takagi/message/inbound.rb +147 -0
  67. data/lib/takagi/message/outbound.rb +223 -0
  68. data/lib/takagi/message/request.rb +158 -0
  69. data/lib/takagi/message/retransmission_manager.rb +193 -0
  70. data/lib/takagi/middleware/authentication.rb +19 -0
  71. data/lib/takagi/middleware/caching.rb +23 -0
  72. data/lib/takagi/middleware/debugging.rb +16 -0
  73. data/lib/takagi/middleware/logging.rb +14 -0
  74. data/lib/takagi/middleware/metrics.rb +440 -0
  75. data/lib/takagi/middleware/rate_limiting.rb +24 -0
  76. data/lib/takagi/middleware_stack.rb +166 -0
  77. data/lib/takagi/network/base.rb +76 -0
  78. data/lib/takagi/network/framing/tcp.rb +222 -0
  79. data/lib/takagi/network/framing/udp.rb +110 -0
  80. data/lib/takagi/network/registry.rb +72 -0
  81. data/lib/takagi/network/tcp.rb +60 -0
  82. data/lib/takagi/network/tcp_sender.rb +21 -0
  83. data/lib/takagi/network/udp.rb +61 -0
  84. data/lib/takagi/network/udp_sender.rb +20 -0
  85. data/lib/takagi/observable/emitter.rb +62 -0
  86. data/lib/takagi/observable/reactor.rb +488 -0
  87. data/lib/takagi/observable/registry.rb +122 -0
  88. data/lib/takagi/observe_registry.rb +10 -0
  89. data/lib/takagi/observer/client.rb +68 -0
  90. data/lib/takagi/observer/registry.rb +137 -0
  91. data/lib/takagi/observer/sender.rb +39 -0
  92. data/lib/takagi/observer/watcher.rb +43 -0
  93. data/lib/takagi/plugin.rb +313 -0
  94. data/lib/takagi/profiles.rb +176 -0
  95. data/lib/takagi/reactor.rb +23 -0
  96. data/lib/takagi/reactor_registry.rb +64 -0
  97. data/lib/takagi/registry/base.rb +268 -0
  98. data/lib/takagi/response_builder.rb +141 -0
  99. data/lib/takagi/router/metadata_extractor.rb +133 -0
  100. data/lib/takagi/router/route_matcher.rb +83 -0
  101. data/lib/takagi/router.rb +284 -25
  102. data/lib/takagi/serialization/base.rb +102 -0
  103. data/lib/takagi/serialization/cbor_serializer.rb +92 -0
  104. data/lib/takagi/serialization/json_serializer.rb +96 -0
  105. data/lib/takagi/serialization/octet_stream_serializer.rb +82 -0
  106. data/lib/takagi/serialization/registry.rb +187 -0
  107. data/lib/takagi/serialization/text_serializer.rb +87 -0
  108. data/lib/takagi/serialization.rb +117 -0
  109. data/lib/takagi/server/multi.rb +41 -0
  110. data/lib/takagi/server/registry.rb +71 -0
  111. data/lib/takagi/server/tcp.rb +249 -0
  112. data/lib/takagi/server/udp.rb +139 -0
  113. data/lib/takagi/server/udp_worker.rb +174 -0
  114. data/lib/takagi/server.rb +1 -31
  115. data/lib/takagi/server_registry.rb +10 -0
  116. data/lib/takagi/tcp_client.rb +142 -0
  117. data/lib/takagi/version.rb +2 -1
  118. data/lib/takagi.rb +24 -3
  119. data/sig/takagi/application.rbs +48 -0
  120. data/sig/takagi/base/middleware_management.rbs +33 -0
  121. data/sig/takagi/base/reactor_management.rbs +52 -0
  122. data/sig/takagi/base/server_lifecycle.rbs +54 -0
  123. data/sig/takagi/base.rbs +48 -0
  124. data/sig/takagi/cbor/decoder.rbs +171 -0
  125. data/sig/takagi/cbor/encoder.rbs +146 -0
  126. data/sig/takagi/cbor/error.rbs +19 -0
  127. data/sig/takagi/cbor/version.rbs +7 -0
  128. data/sig/takagi/client/response.rbs +148 -0
  129. data/sig/takagi/client.rbs +119 -0
  130. data/sig/takagi/client_base.rbs +135 -0
  131. data/sig/takagi/coap/code_helpers.rbs +91 -0
  132. data/sig/takagi/coap/registries/base.rbs +95 -0
  133. data/sig/takagi/coap/registries/content_format.rbs +47 -0
  134. data/sig/takagi/coap/registries/message_type.rbs +53 -0
  135. data/sig/takagi/coap/registries/method.rbs +27 -0
  136. data/sig/takagi/coap/registries/option.rbs +43 -0
  137. data/sig/takagi/coap/registries/response.rbs +52 -0
  138. data/sig/takagi/coap.rbs +24 -0
  139. data/sig/takagi/composite_router.rbs +46 -0
  140. data/sig/takagi/config.rbs +134 -0
  141. data/sig/takagi/controller.rbs +73 -0
  142. data/sig/takagi/core/attribute_set.rbs +57 -0
  143. data/sig/takagi/discovery/core_link_format.rbs +50 -0
  144. data/sig/takagi/event_bus/address_prefix.rbs +78 -0
  145. data/sig/takagi/event_bus/async_executor.rbs +88 -0
  146. data/sig/takagi/event_bus/coap_bridge.rbs +93 -0
  147. data/sig/takagi/event_bus/future.rbs +78 -0
  148. data/sig/takagi/event_bus/lru_cache.rbs +86 -0
  149. data/sig/takagi/event_bus/message_buffer.rbs +133 -0
  150. data/sig/takagi/event_bus/observer_cleanup.rbs +62 -0
  151. data/sig/takagi/event_bus.rbs +320 -0
  152. data/sig/takagi/helpers.rbs +34 -0
  153. data/sig/takagi/initializer.rbs +9 -0
  154. data/sig/takagi/logger.rbs +17 -0
  155. data/sig/takagi/message/base.rbs +64 -0
  156. data/sig/takagi/message/deduplication_cache.rbs +49 -0
  157. data/sig/takagi/message/inbound.rbs +76 -0
  158. data/sig/takagi/message/outbound.rbs +48 -0
  159. data/sig/takagi/message/request.rbs +32 -0
  160. data/sig/takagi/message/retransmission_manager.rbs +76 -0
  161. data/sig/takagi/middleware/authentication.rbs +11 -0
  162. data/sig/takagi/middleware/caching.rbs +13 -0
  163. data/sig/takagi/middleware/debugging.rbs +9 -0
  164. data/sig/takagi/middleware/logging.rbs +7 -0
  165. data/sig/takagi/middleware/metrics.rbs +15 -0
  166. data/sig/takagi/middleware/rate_limiting.rbs +13 -0
  167. data/sig/takagi/middleware_stack.rbs +69 -0
  168. data/sig/takagi/network/tcp_sender.rbs +10 -0
  169. data/sig/takagi/network/udp_sender.rbs +14 -0
  170. data/sig/takagi/observe_registry.rbs +36 -0
  171. data/sig/takagi/observer/client.rbs +36 -0
  172. data/sig/takagi/observer/sender.rbs +12 -0
  173. data/sig/takagi/observer/watcher.rbs +18 -0
  174. data/sig/takagi/profiles.rbs +33 -0
  175. data/sig/takagi/reactor.rbs +20 -0
  176. data/sig/takagi/reactor_registry.rbs +14 -0
  177. data/sig/takagi/response_builder.rbs +12 -0
  178. data/sig/takagi/router/metadata_extractor.rbs +71 -0
  179. data/sig/takagi/router/route_matcher.rbs +43 -0
  180. data/sig/takagi/router.rbs +166 -0
  181. data/sig/takagi/serialization.rbs +32 -0
  182. data/sig/takagi/server/multi.rbs +16 -0
  183. data/sig/takagi/server/tcp.rbs +42 -0
  184. data/sig/takagi/server/udp.rbs +52 -0
  185. data/sig/takagi/server/udp_worker.rbs +42 -0
  186. data/sig/takagi/server.rbs +4 -0
  187. data/sig/takagi/server_registry.rbs +71 -0
  188. data/sig/takagi/tcp_client.rbs +23 -0
  189. data/sig/takagi/version.rbs +5 -0
  190. data/takagi.gemspec +37 -35
  191. metadata +204 -31
  192. data/.idea/.gitignore +0 -8
  193. data/.idea/misc.xml +0 -4
  194. data/.idea/modules.xml +0 -8
  195. data/.idea/takagi.iml +0 -81
  196. data/.idea/vcs.xml +0 -6
  197. data/lib/takagi/message.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3dbe9feeb83c1626cf6c518a2b42c80d8cc5d20c7b6c4cb88c53df425be6427
4
- data.tar.gz: ab8e5225fcaba27dbdc3a743eeff33b44a9f8f6b66f169212d62a9b01b5b9308
3
+ metadata.gz: 26c002dd5bfe9314b9519828621f17c9ee0acaf0e71e2fba44bcf546dfd6cfa0
4
+ data.tar.gz: db6fe50046b1e6b9633b6614a6bba79da335184c9fda9b7c7951b45ce3991427
5
5
  SHA512:
6
- metadata.gz: f63adf24e94b8b87a333742405ca77d450861ffaa028879f603f01e8731700dc1358fc0aa1a486e0715cec984c91b17ca970ae8354f8ac4a5f6ae757ec291be8
7
- data.tar.gz: 6e933738a7102e970480566238caf888444ee1016e564176241b3d7598cd5b404d5e979769c4ab234b1b53803fb14cf031e7b2b8fca135cb3442b504e5783b01
6
+ metadata.gz: e99977403a3866b4d6dcf99add786d4830e0db2ab372afc4f47948618a2afc2f7b5fcba8ddfc01f064d4ae93412c1ea0b3b32676321ab0c82640de5cc7298d84
7
+ data.tar.gz: 939e3b682f3a973b76c5482c2fb91815a898546db029ee697270f069ad4baf8b28e8ebdb75634a0546a749db1f9a66b45a52c951d5c0d741ed8173daf8625724
data/.rubocop.yml CHANGED
@@ -1,13 +1,76 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+ Exclude:
5
+ - 'bin/**/*'
6
+ - 'db/**/*'
7
+ - 'spec/**/*'
8
+ - 'node_modules/**/*'
9
+ - 'vendor/**/*'
3
10
 
4
- Style/StringLiterals:
5
- Enabled: true
6
- EnforcedStyle: double_quotes
11
+ Style/Documentation:
12
+ Exclude:
13
+ - 'lib/takagi/middleware/**/*'
14
+ - 'lib/takagi/router.rb'
15
+ - 'lib/takagi/server.rb'
16
+ - 'lib/takagi/server/**/*'
17
+ - 'lib/takagi/logger.rb'
18
+ - 'spec/**/*'
7
19
 
8
- Style/StringLiteralsInInterpolation:
9
- Enabled: true
10
- EnforcedStyle: double_quotes
20
+ Metrics/MethodLength:
21
+ Max: 20
22
+ Exclude:
23
+ - 'lib/takagi/server/udp_worker.rb'
24
+ - 'lib/takagi/coap/code_helpers.rb'
25
+
26
+ Metrics/AbcSize:
27
+ Max: 30
28
+
29
+ Metrics/CyclomaticComplexity:
30
+ Max: 9
31
+ Exclude:
32
+ - 'lib/takagi/coap/code_helpers.rb'
33
+
34
+ Metrics/BlockLength:
35
+ Exclude:
36
+ - 'spec/**/*'
11
37
 
12
38
  Layout/LineLength:
13
- Max: 120
39
+ Max: 140
40
+
41
+ Naming/AccessorMethodName:
42
+ Enabled: false
43
+
44
+ Style/ClassVars:
45
+ Enabled: false
46
+
47
+ Gemspec/DevelopmentDependencies:
48
+ Enabled: false
49
+
50
+ # Class length is acceptable for core infrastructure classes
51
+ Metrics/ClassLength:
52
+ Max: 160
53
+
54
+ # Allow boolean parameters for DSL methods where the boolean is semantically meaningful
55
+ Style/OptionalBooleanParameter:
56
+ Enabled: false
57
+
58
+ # Allow longer parameter lists for server initialization with many config options
59
+ Metrics/ParameterLists:
60
+ Max: 7
61
+
62
+ # MetadataExtractionContext intentionally doesn't call super - it overrides parent initialization
63
+ # Client class doesn't need super - it's a custom wrapper class
64
+ Lint/MissingSuper:
65
+ Exclude:
66
+ - 'lib/takagi/router.rb'
67
+ - 'lib/takagi/client.rb'
68
+
69
+ # Allow multiline block chains for complex transformations
70
+ Style/MultilineBlockChain:
71
+ Enabled: false
72
+
73
+ # CodeHelpers module has complex conversion logic that benefits from clarity over brevity
74
+ Metrics/PerceivedComplexity:
75
+ Exclude:
76
+ - 'lib/takagi/coap/code_helpers.rb'
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <base href="/docs/takagi/">
5
+ <%= erb(:headers) %>
6
+ <!-- Google tag (gtag.js) -->
7
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-M7YHJSNC1F"></script>
8
+ <script>
9
+ window.dataLayer = window.dataLayer || [];
10
+ function gtag(){dataLayer.push(arguments);}
11
+ gtag('js', new Date());
12
+
13
+ gtag('config', 'G-M7YHJSNC1F');
14
+ </script>
15
+ </head>
16
+ <body>
17
+ <div class="nav_wrap">
18
+ <iframe id="nav" src="<%= @nav_url %>?1"></iframe>
19
+ <div id="resizer"></div>
20
+ </div>
21
+
22
+ <div id="main" tabindex="-1">
23
+ <div id="header">
24
+ <%= erb(:breadcrumb) %>
25
+ <%= erb(:search) %>
26
+ <div class="clear"></div>
27
+ </div>
28
+
29
+ <div id="content"><%= yieldall %></div>
30
+
31
+ <%= erb(:footer) %>
32
+ </div>
33
+ </body>
34
+ </html>
data/AGENTS.md ADDED
@@ -0,0 +1,16 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ Takagi ships as a Ruby gem. Core runtime lives in `lib/`, with `lib/takagi/` grouping features by concern: networking (`network/`), server loops (`server/`, `reactor.rb`), message codecs (`message/`), and middleware helpers. Entry points such as `lib/takagi.rb` and `lib/takagi/client.rb` wire the API. CLI utilities reside in `bin/` (`bin/takagi-client`, `bin/takagi-test`, `bin/setup`). Specs live under `spec/`, with fast unit coverage in `spec/unit/` and interoperability notes in `spec/rfc/`. Shared type signatures are captured in `sig/` and governed by `Steepfile`. Configuration metadata lives in `takagi.gemspec`.
5
+
6
+ ## Build, Test, and Development Commands
7
+ Run `bin/setup` once to install Bundler and project gems. Use `bundle exec rake spec` (Rake default) for the full RSpec suite. `bundle exec rubocop` enforces style, and `bundle exec rubocop -A` may auto-correct trivial issues. Type-check before publishing with `bundle exec steep check`. The sample clients in `bin/takagi-client` and `bin/takagi-test` illustrate running the networking stack against fixtures.
8
+
9
+ ## Coding Style & Naming Conventions
10
+ Follow Ruby community defaults: two-space indentation, trailing commas only when RuboCop suggests, and snake_case for filenames plus CamelCase for classes/modules. Organize new files under the closest matching namespace in `lib/takagi/`. Prefer keyword arguments for clarity in public APIs, and keep log messages routed through `Takagi::Logger`. Always run RuboCop prior to opening a PR.
11
+
12
+ ## Testing Guidelines
13
+ Author specs alongside code in the matching `spec/unit/` subtree; mirror the module path (`lib/takagi/network/socket.rb` → `spec/unit/network/socket_spec.rb`). Write behavior-focused `describe` blocks and ensure new observers or protocols also receive an integration example in `spec/rfc/`. Use `bundle exec rspec spec/unit/<path>` for quick feedback. Keep existing shared contexts up to date and add fixtures under `spec/support` when needed.
14
+
15
+ ## Commit & Pull Request Guidelines
16
+ Commits use short, present-tense subjects (`Fix specs`, `Allow running TCP and UDP servers together`). Group related changes and include rationale in the body if behavior shifts. PRs should link the relevant roadmap or issue entry, summarize observable effects, note new commands or config toggles, and attach logs or screenshots when altering network flows. Confirm RuboCop, Steep, and the spec suite all pass before requesting review.
data/CHANGELOG.md CHANGED
@@ -1,4 +1,161 @@
1
- ## [Unreleased]
1
+ ## [1.1.0] - 2026-06-12
2
+
3
+ ### Version 1.1 - "Radius"
4
+
5
+ > *"When the workers rise, give them a backwards-compatible plugin system."*
6
+
7
+ 15 commits and 24 000+ lines later, the framework is no longer a PoC.
8
+ `Base` and `Client` got cleanly extracted into mixin modules, the
9
+ plugin system, reactor, CBOR codec, CoAP Registries, TCP transport
10
+ (RFC 8323) and EventBus all landed, and the worker pool finally
11
+ coordinates metrics across processes (the `Takagi::Middleware::Metrics`
12
+ middleware with per-PID snapshot files + `forward_to:` HTTP forward).
13
+ The release is named after R.U.R.'s Radius, who led the revolution
14
+ but did not die: the public API surface is **the same** as 1.0
15
+ (every 1.x call site works unchanged), with a few surgical additions
16
+ and exactly two minor packaging tweaks listed under "Breaking
17
+ changes" below.
18
+
19
+ ### Breaking changes
20
+
21
+ Honestly? Almost none. We were too conservative in the original
22
+ release notes. The actual breaking changes are tiny:
23
+
24
+ - **`Takagi::Client.new` keyword args changed.** `initialize(uri,
25
+ timeout: 5)` is now `initialize(uri, timeout: 5, protocol: nil,
26
+ use_retransmission: true)`. New optional `protocol:` lets the
27
+ caller force UDP or TCP; `use_retransmission:` toggles RFC 7252
28
+ CON retransmit logic (default on). If you only passed `uri` and
29
+ maybe `timeout:`, your code is unchanged.
30
+ - **gemspec `bindir` moved `exe/` → `bin/`.** The shipped executable
31
+ is `bin/takagi-dev` (the server runner CLI). The `takagi` executable
32
+ name is reserved for a future `takagi-cli` gem (the dispatcher for
33
+ `takagi server / new / generate` subcommands). If you ran
34
+ `exe/takagi*` or `bin/takagi` before, switch to `bin/takagi-dev`
35
+ (or `bundle exec takagi-dev`).
36
+
37
+ That's it. Everything else in 1.x either still works verbatim, was
38
+ moved into a mixin module (call sites identical), or was added as a
39
+ new optional API on top.
40
+
41
+ In particular — and this is the part the original draft got wrong:
42
+
43
+ - `App.get / post / put / delete / fetch { ... }` **still works**.
44
+ The DSL methods are dynamically defined from
45
+ `Takagi::CoAP::Registries::Method` (a new abstraction; see
46
+ Registries below) and delegate to the global router. The framework
47
+ is intentionally Sinatra-like here.
48
+ - `client.get / post / put / delete(path, options:, type:, &block)`
49
+ still work on `Takagi::Client` (and on `ClientBase`).
50
+ - `client.on(event, &cb)` **still works** — it's now defined on
51
+ `ClientBase#on` instead of `Client#on`, but `Client < ClientBase`
52
+ and `Forwardable` re-delegates it, so the call site is unchanged.
53
+ - `App.observable(path, metadata:, &block)` and
54
+ `App.core(path, method:, &block)` are **new additive** methods;
55
+ they coexist with the route DSL, not replace it.
56
+ - `App.boot!`, `App.run!`, `App.plugin`, `App.enable_plugins!`,
57
+ `App.use`, `App.middleware_stack`, `App.reactor`,
58
+ `App.use_reactor` all still exist — they're now in
59
+ `Takagi::Base::ServerLifecycle`, `MiddlewareManagement`,
60
+ `ReactorManagement`, `PluginManagement` mixin modules instead of
61
+ inline in `Base`, but the call sites are identical.
62
+ - `client.get_json / post_json / put_json` are **new** convenience
63
+ helpers on `ClientBase`.
64
+
65
+ ### New features
66
+
67
+ - **Plugin system** (`Takagi::Plugin`, `App.plugin :name, opts`).
68
+ Plugins declare metadata, dependencies, configuration schema, and
69
+ an `apply` hook. `Takagi::Application` composes them in order.
70
+ See `docs/FIRST_PLUGIN_GUIDE.md` and `examples/nested_api_app.rb`.
71
+ - **TCP transport (RFC 8323).** `Takagi::Server::Tcp` + a TCP-aware
72
+ `UdpClient` / `TcpClient` split. `Takagi::Client` picks the right
73
+ transport from the URI scheme (`coap://` vs `coap+tcp://`).
74
+ - **Reactor management.** Long-running background handlers (sensor
75
+ pollers, queue consumers) are first-class citizens via
76
+ `App.reactor(threads:, name:, interval:, &block)` and
77
+ `App.use_reactor(name, klass)`. The server starts and stops them
78
+ on `:server_starting` / `:server_stopped` hooks.
79
+ - **CBOR encoder/decoder (RFC 8949).** `Takagi::CBOR::Encoder` /
80
+ `Decoder` for compact payload transport alongside JSON.
81
+ - **Registries.** `Takagi::CoAP::Registries::{Method, Response,
82
+ ContentFormat, MessageType, Option}` expose the RFC 7252 / 8323
83
+ code points so middleware, codecs, and the new `Metrics` middleware
84
+ don't hard-code magic numbers. The dynamic `get / post / put /
85
+ delete` DSL on `Base` and `Router` is now driven by this registry.
86
+ - **EventBus.** `Takagi::EventBus.publish / consumer / send /
87
+ send_sync` with `LOCAL` / `CLUSTER` / `GLOBAL` scopes. `Takagi::Hooks`
88
+ is now a thin wrapper that picks the right transport.
89
+ - **`Takagi::Middleware::Metrics` for live request metrics.** New
90
+ middleware: per-PID snapshot files (`Dir.tmpdir/takagi-metrics`)
91
+ for cross-process aggregation, `Metrics.aggregate` class method
92
+ reads them, `forward_to:` option fires a fire-and-forget HTTP POST
93
+ to a parent/aggregator endpoint, `record` and
94
+ `increment_request_count` are public for external aggregators. Per-
95
+ route counters, response-code histogram, latency window.
96
+ - **`Takagi::Application` class.** A thin composition layer on top
97
+ of `Base`: subclass it and call `App.run!`. Recommended for new
98
+ projects; `Base` still works for backwards compatibility.
99
+ - **CLI.** `bin/takagi-dev` runs the app, `bin/takagi-client` and
100
+ `bin/takagi-test` were updated to match the new client API.
101
+ ### Documentation & examples
102
+
103
+ - `docs/FIRST_PLUGIN_GUIDE.md` — write your first plugin in 10
104
+ minutes
105
+ - `docs/HOOKS.md` — event reference
106
+ - `examples/cloud_gateway_app.rb` — full plugin composition
107
+ - `examples/nested_api_app.rb` — plugins depending on other plugins
108
+ - `examples/simple_device_app.rb` — observable + core endpoints
109
+ - `examples/client_lifecycle_example.rb` — new client API
110
+ end-to-end
111
+ - `examples/takagi.yml` — config schema example
112
+
113
+ ### Internals
114
+
115
+ - `Base` is now `< Router` and `extends` four mixin modules
116
+ (`ServerLifecycle`, `MiddlewareManagement`, `ReactorManagement`,
117
+ `PluginManagement`) instead of carrying everything inline. The
118
+ call sites are identical; the mixin split is purely for SRP.
119
+ - Server lifecycle is a clean state machine: `build_servers →
120
+ instantiate_server → start_all / stop_all`. Hooks are emitted at
121
+ every transition.
122
+ - `Takagi::Network::UdpSender` is a singleton; the UDP socket is
123
+ shared safely across worker threads (read) and the response path
124
+ (write) without contention.
125
+ - `Takagi::Observer::Watcher` drives `Takagi::ObserveRegistry`
126
+ re-notification and is started/stopped by the lifecycle hooks.
127
+
128
+ ### Migration cheatsheet (1.x → 2.0)
129
+
130
+ Almost certainly **no changes** for your app. Only if you used:
131
+
132
+ | 1.x | 2.0 |
133
+ |---|---|
134
+ | `Client.new(uri, timeout: 5)` | `Client.new(uri, timeout: 5)` (still works) — only if you want `protocol:` / `use_retransmission:` do you need to update |
135
+ | `exe/takagi` | `bin/takagi-dev` / `bundle exec takagi-dev` |
136
+
137
+ Optional upgrades worth making (additive, not required):
138
+
139
+ | 1.x style | 2.0 style |
140
+ |---|---|
141
+ | `App.get('/foo') { ... }` (still works) | leave as-is, or use `App.core('/foo', method: :get) { ... }` for explicit CoRE metadata |
142
+ | `App.observable('/foo') { ... }` (didn't exist) | same call, now supported for Observe resources |
143
+ | (no plugin system) | `App.plugin :sinatra` / `App.plugin :devtools` |
144
+ | (no reactor) | `App.reactor(:sensor_poller, interval: 30) { ... }` |
145
+ | `App.use(SomeMiddleware)` (still works) | prefer a Plugin (extracted lifecycle) when possible |
146
+
147
+
148
+
149
+ ## [1.0.0] - 2025-04-04
150
+
151
+ ### Version 1 - "It works on my machine"
152
+
153
+ - Observer should be working
154
+ - Other things probably too
155
+
156
+ ## [0.2.0] - 2025-03-24
157
+
158
+ - So far so good, development continues
2
159
 
3
160
  ## [0.1.0] - 2025-02-26
4
161
 
data/CODE_OF_CONDUCT.md CHANGED
@@ -39,7 +39,7 @@ This Code of Conduct applies within all community spaces, and also applies when
39
39
 
40
40
  ## Enforcement
41
41
 
42
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at domitea@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly.
43
43
 
44
44
  All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
45