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.
- checksums.yaml +4 -4
- data/.rubocop.yml +70 -7
- data/.yard/templates/default/layout/html/layout.erb +34 -0
- data/AGENTS.md +16 -0
- data/CHANGELOG.md +158 -1
- data/CODE_OF_CONDUCT.md +1 -1
- data/README.md +590 -23
- data/ROADMAP.md +55 -0
- data/Rakefile +4 -4
- data/Steepfile +39 -0
- data/bin/takagi-dev +159 -0
- data/docs/FIRST_PLUGIN_GUIDE.md +224 -0
- data/docs/HOOKS.md +31 -0
- data/examples/client_lifecycle_example.rb +118 -0
- data/examples/cloud_gateway_app.rb +217 -0
- data/examples/nested_api_app.rb +258 -0
- data/examples/simple_device_app.rb +71 -0
- data/examples/takagi.yml +138 -0
- data/lib/takagi/application.rb +256 -0
- data/lib/takagi/base/middleware_management.rb +39 -0
- data/lib/takagi/base/plugin_management.rb +75 -0
- data/lib/takagi/base/reactor_management.rb +104 -0
- data/lib/takagi/base/server_lifecycle.rb +156 -0
- data/lib/takagi/base.rb +103 -11
- data/lib/takagi/branding.rb +88 -0
- data/lib/takagi/cbor/decoder.rb +385 -0
- data/lib/takagi/cbor/encoder.rb +260 -0
- data/lib/takagi/cbor/error.rb +17 -0
- data/lib/takagi/cbor/version.rb +9 -0
- data/lib/takagi/client/response.rb +236 -0
- data/lib/takagi/client.rb +265 -0
- data/lib/takagi/client_base.rb +204 -0
- data/lib/takagi/coap/code_helpers.rb +190 -0
- data/lib/takagi/coap/registries/base.rb +165 -0
- data/lib/takagi/coap/registries/content_format.rb +71 -0
- data/lib/takagi/coap/registries/message_type.rb +69 -0
- data/lib/takagi/coap/registries/method.rb +38 -0
- data/lib/takagi/coap/registries/option.rb +71 -0
- data/lib/takagi/coap/registries/response.rb +93 -0
- data/lib/takagi/coap/registries/signaling.rb +34 -0
- data/lib/takagi/coap/signaling.rb +10 -0
- data/lib/takagi/coap.rb +37 -0
- data/lib/takagi/composite_router.rb +186 -0
- data/lib/takagi/config.rb +337 -0
- data/lib/takagi/controller/resource_allocator.rb +164 -0
- data/lib/takagi/controller/thread_pool.rb +144 -0
- data/lib/takagi/controller.rb +319 -0
- data/lib/takagi/core/attribute_set.rb +128 -0
- data/lib/takagi/discovery/core_link_format.rb +137 -0
- data/lib/takagi/errors.rb +536 -0
- data/lib/takagi/event_bus/address_prefix.rb +142 -0
- data/lib/takagi/event_bus/async_executor.rb +235 -0
- data/lib/takagi/event_bus/coap_bridge.rb +208 -0
- data/lib/takagi/event_bus/future.rb +153 -0
- data/lib/takagi/event_bus/lru_cache.rb +157 -0
- data/lib/takagi/event_bus/message_buffer.rb +237 -0
- data/lib/takagi/event_bus/observer_cleanup.rb +110 -0
- data/lib/takagi/event_bus/scope.rb +74 -0
- data/lib/takagi/event_bus.rb +594 -0
- data/lib/takagi/helpers.rb +88 -0
- data/lib/takagi/hooks.rb +82 -0
- data/lib/takagi/initializer.rb +18 -0
- data/lib/takagi/logger.rb +15 -6
- data/lib/takagi/message/base.rb +155 -0
- data/lib/takagi/message/deduplication_cache.rb +84 -0
- data/lib/takagi/message/inbound.rb +147 -0
- data/lib/takagi/message/outbound.rb +223 -0
- data/lib/takagi/message/request.rb +158 -0
- data/lib/takagi/message/retransmission_manager.rb +193 -0
- data/lib/takagi/middleware/authentication.rb +19 -0
- data/lib/takagi/middleware/caching.rb +23 -0
- data/lib/takagi/middleware/debugging.rb +16 -0
- data/lib/takagi/middleware/logging.rb +14 -0
- data/lib/takagi/middleware/metrics.rb +440 -0
- data/lib/takagi/middleware/rate_limiting.rb +24 -0
- data/lib/takagi/middleware_stack.rb +166 -0
- data/lib/takagi/network/base.rb +76 -0
- data/lib/takagi/network/framing/tcp.rb +222 -0
- data/lib/takagi/network/framing/udp.rb +110 -0
- data/lib/takagi/network/registry.rb +72 -0
- data/lib/takagi/network/tcp.rb +60 -0
- data/lib/takagi/network/tcp_sender.rb +21 -0
- data/lib/takagi/network/udp.rb +61 -0
- data/lib/takagi/network/udp_sender.rb +20 -0
- data/lib/takagi/observable/emitter.rb +62 -0
- data/lib/takagi/observable/reactor.rb +488 -0
- data/lib/takagi/observable/registry.rb +122 -0
- data/lib/takagi/observe_registry.rb +10 -0
- data/lib/takagi/observer/client.rb +68 -0
- data/lib/takagi/observer/registry.rb +137 -0
- data/lib/takagi/observer/sender.rb +39 -0
- data/lib/takagi/observer/watcher.rb +43 -0
- data/lib/takagi/plugin.rb +313 -0
- data/lib/takagi/profiles.rb +176 -0
- data/lib/takagi/reactor.rb +23 -0
- data/lib/takagi/reactor_registry.rb +64 -0
- data/lib/takagi/registry/base.rb +268 -0
- data/lib/takagi/response_builder.rb +141 -0
- data/lib/takagi/router/metadata_extractor.rb +133 -0
- data/lib/takagi/router/route_matcher.rb +83 -0
- data/lib/takagi/router.rb +284 -25
- data/lib/takagi/serialization/base.rb +102 -0
- data/lib/takagi/serialization/cbor_serializer.rb +92 -0
- data/lib/takagi/serialization/json_serializer.rb +96 -0
- data/lib/takagi/serialization/octet_stream_serializer.rb +82 -0
- data/lib/takagi/serialization/registry.rb +187 -0
- data/lib/takagi/serialization/text_serializer.rb +87 -0
- data/lib/takagi/serialization.rb +117 -0
- data/lib/takagi/server/multi.rb +41 -0
- data/lib/takagi/server/registry.rb +71 -0
- data/lib/takagi/server/tcp.rb +249 -0
- data/lib/takagi/server/udp.rb +139 -0
- data/lib/takagi/server/udp_worker.rb +174 -0
- data/lib/takagi/server.rb +1 -31
- data/lib/takagi/server_registry.rb +10 -0
- data/lib/takagi/tcp_client.rb +142 -0
- data/lib/takagi/version.rb +2 -1
- data/lib/takagi.rb +24 -3
- data/sig/takagi/application.rbs +48 -0
- data/sig/takagi/base/middleware_management.rbs +33 -0
- data/sig/takagi/base/reactor_management.rbs +52 -0
- data/sig/takagi/base/server_lifecycle.rbs +54 -0
- data/sig/takagi/base.rbs +48 -0
- data/sig/takagi/cbor/decoder.rbs +171 -0
- data/sig/takagi/cbor/encoder.rbs +146 -0
- data/sig/takagi/cbor/error.rbs +19 -0
- data/sig/takagi/cbor/version.rbs +7 -0
- data/sig/takagi/client/response.rbs +148 -0
- data/sig/takagi/client.rbs +119 -0
- data/sig/takagi/client_base.rbs +135 -0
- data/sig/takagi/coap/code_helpers.rbs +91 -0
- data/sig/takagi/coap/registries/base.rbs +95 -0
- data/sig/takagi/coap/registries/content_format.rbs +47 -0
- data/sig/takagi/coap/registries/message_type.rbs +53 -0
- data/sig/takagi/coap/registries/method.rbs +27 -0
- data/sig/takagi/coap/registries/option.rbs +43 -0
- data/sig/takagi/coap/registries/response.rbs +52 -0
- data/sig/takagi/coap.rbs +24 -0
- data/sig/takagi/composite_router.rbs +46 -0
- data/sig/takagi/config.rbs +134 -0
- data/sig/takagi/controller.rbs +73 -0
- data/sig/takagi/core/attribute_set.rbs +57 -0
- data/sig/takagi/discovery/core_link_format.rbs +50 -0
- data/sig/takagi/event_bus/address_prefix.rbs +78 -0
- data/sig/takagi/event_bus/async_executor.rbs +88 -0
- data/sig/takagi/event_bus/coap_bridge.rbs +93 -0
- data/sig/takagi/event_bus/future.rbs +78 -0
- data/sig/takagi/event_bus/lru_cache.rbs +86 -0
- data/sig/takagi/event_bus/message_buffer.rbs +133 -0
- data/sig/takagi/event_bus/observer_cleanup.rbs +62 -0
- data/sig/takagi/event_bus.rbs +320 -0
- data/sig/takagi/helpers.rbs +34 -0
- data/sig/takagi/initializer.rbs +9 -0
- data/sig/takagi/logger.rbs +17 -0
- data/sig/takagi/message/base.rbs +64 -0
- data/sig/takagi/message/deduplication_cache.rbs +49 -0
- data/sig/takagi/message/inbound.rbs +76 -0
- data/sig/takagi/message/outbound.rbs +48 -0
- data/sig/takagi/message/request.rbs +32 -0
- data/sig/takagi/message/retransmission_manager.rbs +76 -0
- data/sig/takagi/middleware/authentication.rbs +11 -0
- data/sig/takagi/middleware/caching.rbs +13 -0
- data/sig/takagi/middleware/debugging.rbs +9 -0
- data/sig/takagi/middleware/logging.rbs +7 -0
- data/sig/takagi/middleware/metrics.rbs +15 -0
- data/sig/takagi/middleware/rate_limiting.rbs +13 -0
- data/sig/takagi/middleware_stack.rbs +69 -0
- data/sig/takagi/network/tcp_sender.rbs +10 -0
- data/sig/takagi/network/udp_sender.rbs +14 -0
- data/sig/takagi/observe_registry.rbs +36 -0
- data/sig/takagi/observer/client.rbs +36 -0
- data/sig/takagi/observer/sender.rbs +12 -0
- data/sig/takagi/observer/watcher.rbs +18 -0
- data/sig/takagi/profiles.rbs +33 -0
- data/sig/takagi/reactor.rbs +20 -0
- data/sig/takagi/reactor_registry.rbs +14 -0
- data/sig/takagi/response_builder.rbs +12 -0
- data/sig/takagi/router/metadata_extractor.rbs +71 -0
- data/sig/takagi/router/route_matcher.rbs +43 -0
- data/sig/takagi/router.rbs +166 -0
- data/sig/takagi/serialization.rbs +32 -0
- data/sig/takagi/server/multi.rbs +16 -0
- data/sig/takagi/server/tcp.rbs +42 -0
- data/sig/takagi/server/udp.rbs +52 -0
- data/sig/takagi/server/udp_worker.rbs +42 -0
- data/sig/takagi/server.rbs +4 -0
- data/sig/takagi/server_registry.rbs +71 -0
- data/sig/takagi/tcp_client.rbs +23 -0
- data/sig/takagi/version.rbs +5 -0
- data/takagi.gemspec +37 -35
- metadata +204 -31
- data/.idea/.gitignore +0 -8
- data/.idea/misc.xml +0 -4
- data/.idea/modules.xml +0 -8
- data/.idea/takagi.iml +0 -81
- data/.idea/vcs.xml +0 -6
- data/lib/takagi/message.rb +0 -75
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 26c002dd5bfe9314b9519828621f17c9ee0acaf0e71e2fba44bcf546dfd6cfa0
|
|
4
|
+
data.tar.gz: db6fe50046b1e6b9633b6614a6bba79da335184c9fda9b7c7951b45ce3991427
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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/
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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:
|
|
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
|
-
## [
|
|
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
|
|
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
|
|