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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# Base class for extensible constant registries.
|
|
5
|
+
#
|
|
6
|
+
# Provides a pattern for registering CoAP protocol constants with:
|
|
7
|
+
# - Numeric value
|
|
8
|
+
# - Human-readable name
|
|
9
|
+
# - Symbol accessor (optional)
|
|
10
|
+
#
|
|
11
|
+
# This allows plugins to extend the protocol without modifying core code.
|
|
12
|
+
#
|
|
13
|
+
# @example Creating a custom registry
|
|
14
|
+
# class MyRegistry < Registries::Base
|
|
15
|
+
# register(1, 'First Value', :first)
|
|
16
|
+
# register(2, 'Second Value', :second)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# MyRegistry::FIRST # => 1
|
|
20
|
+
# MyRegistry.name_for(1) # => "First Value"
|
|
21
|
+
# MyRegistry.all # => {1 => "First Value", 2 => "Second Value"}
|
|
22
|
+
class Base
|
|
23
|
+
self.@registry: untyped
|
|
24
|
+
|
|
25
|
+
self.@reverse_registry: untyped
|
|
26
|
+
|
|
27
|
+
# Register a new constant in the registry
|
|
28
|
+
#
|
|
29
|
+
# @param value [Integer] Numeric value of the constant
|
|
30
|
+
# @param name [String] Human-readable name
|
|
31
|
+
# @param symbol [Symbol, nil] Optional symbol for constant access
|
|
32
|
+
# @param rfc [String, nil] Optional RFC reference
|
|
33
|
+
#
|
|
34
|
+
# @example
|
|
35
|
+
# register(69, '2.05 Content', :content, rfc: 'RFC 7252 §5.9.1.4')
|
|
36
|
+
def self.register: (untyped value, untyped name, ?untyped? symbol, ?rfc: untyped?) -> untyped
|
|
37
|
+
|
|
38
|
+
# Get human-readable name for a value
|
|
39
|
+
#
|
|
40
|
+
# @param value [Integer] The numeric value
|
|
41
|
+
# @return [String, nil] The name, or nil if not found
|
|
42
|
+
def self.name_for: (untyped value) -> untyped
|
|
43
|
+
|
|
44
|
+
# Get numeric value for a name or symbol
|
|
45
|
+
#
|
|
46
|
+
# @param key [String, Symbol] The name or symbol
|
|
47
|
+
# @return [Integer, nil] The value, or nil if not found
|
|
48
|
+
def self.value_for: (untyped key) -> untyped
|
|
49
|
+
|
|
50
|
+
# Get RFC reference for a value
|
|
51
|
+
#
|
|
52
|
+
# @param value [Integer] The numeric value
|
|
53
|
+
# @return [String, nil] The RFC reference, or nil if not found
|
|
54
|
+
def self.rfc_for: (untyped value) -> untyped
|
|
55
|
+
|
|
56
|
+
# Check if a value is registered
|
|
57
|
+
#
|
|
58
|
+
# @param value [Integer] The value to check
|
|
59
|
+
# @return [Boolean] true if registered
|
|
60
|
+
def self.registered?: (untyped value) -> untyped
|
|
61
|
+
|
|
62
|
+
# Get all registered constants
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash] Map of value => name
|
|
65
|
+
def self.all: () -> untyped
|
|
66
|
+
|
|
67
|
+
# Iterate over registered values
|
|
68
|
+
#
|
|
69
|
+
# @yield [Integer] each registered numeric value
|
|
70
|
+
# @return [Enumerator] if no block given
|
|
71
|
+
def self.each_value: () ?{ (?) -> untyped } -> untyped
|
|
72
|
+
|
|
73
|
+
# Get all registered values
|
|
74
|
+
#
|
|
75
|
+
# @return [Array<Integer>] Array of all values
|
|
76
|
+
def self.values: () -> untyped
|
|
77
|
+
|
|
78
|
+
# Get registry metadata for a value
|
|
79
|
+
#
|
|
80
|
+
# @param value [Integer] The numeric value
|
|
81
|
+
# @return [Hash, nil] Full metadata hash
|
|
82
|
+
def self.metadata_for: (untyped value) -> untyped
|
|
83
|
+
|
|
84
|
+
# Clear all registrations (useful for testing)
|
|
85
|
+
def self.clear!: () -> untyped
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def self.registry: () -> untyped
|
|
90
|
+
|
|
91
|
+
def self.reverse_registry: () -> untyped
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# CoAP Content-Format Registry (RFC 7252 §12.3)
|
|
5
|
+
#
|
|
6
|
+
# Extensible registry for CoAP content-format codes.
|
|
7
|
+
# Plugins can register custom content formats without modifying core code.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined formats
|
|
10
|
+
# Takagi::CoAP::Registries::ContentFormat::JSON # => 50
|
|
11
|
+
# Takagi::CoAP::Registries::ContentFormat::TEXT_PLAIN # => 0
|
|
12
|
+
#
|
|
13
|
+
# @example Registering a custom format
|
|
14
|
+
# Takagi::CoAP::Registries::ContentFormat.register(65000, 'application/custom', :custom)
|
|
15
|
+
# Takagi::CoAP::Registries::ContentFormat::CUSTOM # => 65000
|
|
16
|
+
#
|
|
17
|
+
# @example Looking up format names
|
|
18
|
+
# Takagi::CoAP::Registries::ContentFormat.name_for(50) # => "application/json"
|
|
19
|
+
class ContentFormat < Base
|
|
20
|
+
# Get MIME type for a content-format code
|
|
21
|
+
# @param code [Integer] Content-format code
|
|
22
|
+
# @return [String, nil] MIME type
|
|
23
|
+
def self.mime_type_for: (untyped code) -> untyped
|
|
24
|
+
|
|
25
|
+
# Get content-format code for a MIME type
|
|
26
|
+
# @param mime_type [String] MIME type
|
|
27
|
+
# @return [Integer, nil] Content-format code
|
|
28
|
+
def self.code_for_mime: (untyped mime_type) -> untyped
|
|
29
|
+
|
|
30
|
+
# Check if format is JSON-based
|
|
31
|
+
# @param code [Integer] Content-format code
|
|
32
|
+
# @return [Boolean] true if JSON format
|
|
33
|
+
def self.json?: (untyped code) -> untyped
|
|
34
|
+
|
|
35
|
+
# Check if format is CBOR-based
|
|
36
|
+
# @param code [Integer] Content-format code
|
|
37
|
+
# @return [Boolean] true if CBOR format
|
|
38
|
+
def self.cbor?: (untyped code) -> untyped
|
|
39
|
+
|
|
40
|
+
# Check if format is text-based
|
|
41
|
+
# @param code [Integer] Content-format code
|
|
42
|
+
# @return [Boolean] true if text format
|
|
43
|
+
def self.text?: (untyped code) -> untyped
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# CoAP Message Type Registry (RFC 7252 §3)
|
|
5
|
+
#
|
|
6
|
+
# Extensible registry for CoAP message types.
|
|
7
|
+
#
|
|
8
|
+
# @example Using predefined types
|
|
9
|
+
# Takagi::CoAP::Registries::MessageType::CONFIRMABLE # => 0
|
|
10
|
+
# Takagi::CoAP::Registries::MessageType::ACK # => 2
|
|
11
|
+
#
|
|
12
|
+
# @example Looking up type names
|
|
13
|
+
# Takagi::CoAP::Registries::MessageType.name_for(0) # => "Confirmable"
|
|
14
|
+
class MessageType < Base
|
|
15
|
+
# Aliases for convenience
|
|
16
|
+
CON: untyped
|
|
17
|
+
|
|
18
|
+
NON: untyped
|
|
19
|
+
|
|
20
|
+
ACK: untyped
|
|
21
|
+
|
|
22
|
+
RST: untyped
|
|
23
|
+
|
|
24
|
+
# Check if type is confirmable
|
|
25
|
+
# @param type [Integer] Message type
|
|
26
|
+
# @return [Boolean] true if confirmable
|
|
27
|
+
def self.confirmable?: (untyped type) -> untyped
|
|
28
|
+
|
|
29
|
+
# Check if type is non-confirmable
|
|
30
|
+
# @param type [Integer] Message type
|
|
31
|
+
# @return [Boolean] true if non-confirmable
|
|
32
|
+
def self.non_confirmable?: (untyped type) -> untyped
|
|
33
|
+
|
|
34
|
+
# Check if type is acknowledgement
|
|
35
|
+
# @param type [Integer] Message type
|
|
36
|
+
# @return [Boolean] true if acknowledgement
|
|
37
|
+
def self.acknowledgement?: (untyped type) -> untyped
|
|
38
|
+
|
|
39
|
+
alias self.ack? self.acknowledgement?
|
|
40
|
+
|
|
41
|
+
# Check if type is reset
|
|
42
|
+
# @param type [Integer] Message type
|
|
43
|
+
# @return [Boolean] true if reset
|
|
44
|
+
def self.reset?: (untyped type) -> untyped
|
|
45
|
+
|
|
46
|
+
# Check if type is valid
|
|
47
|
+
# @param type [Integer] Message type
|
|
48
|
+
# @return [Boolean] true if valid
|
|
49
|
+
def self.valid?: (untyped type) -> untyped
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# CoAP Method Code Registry (RFC 7252 §12.1.1)
|
|
5
|
+
#
|
|
6
|
+
# Extensible registry for CoAP request method codes.
|
|
7
|
+
# Plugins can register custom methods without modifying core code.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined methods
|
|
10
|
+
# Takagi::CoAP::Registries::Method::GET # => 1
|
|
11
|
+
# Takagi::CoAP::Registries::Method::POST # => 2
|
|
12
|
+
#
|
|
13
|
+
# @example Registering a custom method
|
|
14
|
+
# Takagi::CoAP::Registries::Method.register(5, 'FETCH', :fetch, rfc: 'RFC 8132')
|
|
15
|
+
# Takagi::CoAP::Registries::Method::FETCH # => 5
|
|
16
|
+
#
|
|
17
|
+
# @example Looking up method names
|
|
18
|
+
# Takagi::CoAP::Registries::Method.name_for(1) # => "GET"
|
|
19
|
+
class Method < Base
|
|
20
|
+
# Check if code is a valid method code
|
|
21
|
+
# @param code [Integer] Code to check
|
|
22
|
+
# @return [Boolean] true if valid method
|
|
23
|
+
def self.valid?: (untyped code) -> untyped
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# CoAP Option Number Registry (RFC 7252 §5.10)
|
|
5
|
+
#
|
|
6
|
+
# Extensible registry for CoAP option numbers.
|
|
7
|
+
# Plugins can register custom options without modifying core code.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined options
|
|
10
|
+
# Takagi::CoAP::Registries::Option::URI_PATH # => 11
|
|
11
|
+
# Takagi::CoAP::Registries::Option::CONTENT_FORMAT # => 12
|
|
12
|
+
#
|
|
13
|
+
# @example Registering a custom option
|
|
14
|
+
# Takagi::CoAP::Registries::Option.register(65000, 'Custom-Option', :custom_option)
|
|
15
|
+
# Takagi::CoAP::Registries::Option::CUSTOM_OPTION # => 65000
|
|
16
|
+
#
|
|
17
|
+
# @example Looking up option names
|
|
18
|
+
# Takagi::CoAP::Registries::Option.name_for(11) # => "Uri-Path"
|
|
19
|
+
class Option < Base
|
|
20
|
+
# Check if an option is critical
|
|
21
|
+
# Critical options must be understood by the recipient
|
|
22
|
+
# @param number [Integer] Option number
|
|
23
|
+
# @return [Boolean] true if critical
|
|
24
|
+
def self.critical?: (untyped number) -> untyped
|
|
25
|
+
|
|
26
|
+
# Check if an option is unsafe to forward
|
|
27
|
+
# @param number [Integer] Option number
|
|
28
|
+
# @return [Boolean] true if unsafe
|
|
29
|
+
def self.unsafe?: (untyped number) -> untyped
|
|
30
|
+
|
|
31
|
+
# Check if an option has NoCacheKey property
|
|
32
|
+
# @param number [Integer] Option number
|
|
33
|
+
# @return [Boolean] true if NoCacheKey
|
|
34
|
+
def self.no_cache_key?: (untyped number) -> untyped
|
|
35
|
+
|
|
36
|
+
# Check if option number is valid
|
|
37
|
+
# @param number [Integer] Option number
|
|
38
|
+
# @return [Boolean] true if valid
|
|
39
|
+
def self.valid?: (untyped number) -> untyped
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module CoAP
|
|
3
|
+
module Registries
|
|
4
|
+
# CoAP Response Code Registry (RFC 7252 §12.1.2)
|
|
5
|
+
#
|
|
6
|
+
# Extensible registry for CoAP response codes.
|
|
7
|
+
# Plugins can register custom response codes without modifying core code.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined codes
|
|
10
|
+
# Takagi::CoAP::Registries::Response::CONTENT # => 69 (2.05)
|
|
11
|
+
# Takagi::CoAP::Registries::Response::NOT_FOUND # => 132 (4.04)
|
|
12
|
+
#
|
|
13
|
+
# @example Registering a custom code
|
|
14
|
+
# Takagi::CoAP::Registries::Response.register(231, '7.07 Custom', :custom)
|
|
15
|
+
# Takagi::CoAP::Registries::Response::CUSTOM # => 231
|
|
16
|
+
#
|
|
17
|
+
# @example Looking up code names
|
|
18
|
+
# Takagi::CoAP::Registries::Response.name_for(69) # => "2.05 Content"
|
|
19
|
+
class Response < Base
|
|
20
|
+
# Get the response class (2, 4, 5, etc.)
|
|
21
|
+
# @param code [Integer] Response code
|
|
22
|
+
# @return [Integer] Class number
|
|
23
|
+
def self.class_for: (untyped code) -> untyped
|
|
24
|
+
|
|
25
|
+
# Check if code is a success (2.xx)
|
|
26
|
+
# @param code [Integer] Response code
|
|
27
|
+
# @return [Boolean] true if success
|
|
28
|
+
def self.success?: (untyped code) -> untyped
|
|
29
|
+
|
|
30
|
+
# Check if code is a client error (4.xx)
|
|
31
|
+
# @param code [Integer] Response code
|
|
32
|
+
# @return [Boolean] true if client error
|
|
33
|
+
def self.client_error?: (untyped code) -> untyped
|
|
34
|
+
|
|
35
|
+
# Check if code is a server error (5.xx)
|
|
36
|
+
# @param code [Integer] Response code
|
|
37
|
+
# @return [Boolean] true if server error
|
|
38
|
+
def self.server_error?: (untyped code) -> untyped
|
|
39
|
+
|
|
40
|
+
# Check if code is any error (4.xx or 5.xx)
|
|
41
|
+
# @param code [Integer] Response code
|
|
42
|
+
# @return [Boolean] true if error
|
|
43
|
+
def self.error?: (untyped code) -> untyped
|
|
44
|
+
|
|
45
|
+
# Check if code is a valid response code
|
|
46
|
+
# @param code [Integer] Code to check
|
|
47
|
+
# @return [Boolean] true if valid response code
|
|
48
|
+
def self.valid?: (untyped code) -> untyped
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/sig/takagi/coap.rbs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
# CoAP Protocol implementation following RFC 7252 and related RFCs.
|
|
3
|
+
#
|
|
4
|
+
# This module provides a registry-based system for CoAP protocol constants,
|
|
5
|
+
# allowing plugins and extensions to register additional constants without
|
|
6
|
+
# modifying core code.
|
|
7
|
+
#
|
|
8
|
+
# @example Registering a custom response code
|
|
9
|
+
# Takagi::CoAP::Registries::Response.register(231, '7.01 Custom Code', :custom_code)
|
|
10
|
+
#
|
|
11
|
+
# @example Using registered constants
|
|
12
|
+
# code = Takagi::CoAP::Registries::Response::CONTENT # => 69
|
|
13
|
+
# Takagi::CoAP::Registries::Response.name_for(69) # => "2.05 Content"
|
|
14
|
+
module CoAP
|
|
15
|
+
# Default CoAP port (RFC 7252 §6.1)
|
|
16
|
+
DEFAULT_PORT: 5683
|
|
17
|
+
|
|
18
|
+
# Default CoAPS (secure) port (RFC 7252 §6.2)
|
|
19
|
+
DEFAULT_SECURE_PORT: 5684
|
|
20
|
+
|
|
21
|
+
# CoAP version (RFC 7252 §3)
|
|
22
|
+
VERSION: 1
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Takagi::CompositeRouter - Routes requests to mounted controllers
|
|
2
|
+
module Takagi
|
|
3
|
+
class CompositeRouter
|
|
4
|
+
# Represents a mounted controller
|
|
5
|
+
class MountedController < Struct[untyped]
|
|
6
|
+
attr_accessor controller_class: singleton(Controller)
|
|
7
|
+
attr_accessor mount_path: String
|
|
8
|
+
attr_accessor router: Router
|
|
9
|
+
attr_accessor nested_controllers: Array[singleton(Controller)]
|
|
10
|
+
|
|
11
|
+
# Check if this mount handles the given path
|
|
12
|
+
def handles?: (String path) -> bool
|
|
13
|
+
|
|
14
|
+
# Strip mount prefix from path
|
|
15
|
+
def relative_path: (String path) -> String
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize: () -> void
|
|
19
|
+
|
|
20
|
+
# Mount a controller at a path
|
|
21
|
+
def mount: (singleton(Controller) controller_class, ?at: String?) -> void
|
|
22
|
+
|
|
23
|
+
# Find a route handler
|
|
24
|
+
def find_route: (String method, String path) -> [Proc?, Hash[Symbol, String]]
|
|
25
|
+
|
|
26
|
+
# Get all routes from all controllers
|
|
27
|
+
def all_routes: () -> Array[String]
|
|
28
|
+
|
|
29
|
+
# Get link format entries from all controllers
|
|
30
|
+
def link_format_entries: () -> Array[Router::RouteEntry]
|
|
31
|
+
|
|
32
|
+
# Get all mounted controllers
|
|
33
|
+
def mounted_controllers: () -> Array[MountedController]
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Find the mounted controller for a path
|
|
38
|
+
def find_mounted_controller: (String path) -> MountedController?
|
|
39
|
+
|
|
40
|
+
# Recursively mount nested controllers
|
|
41
|
+
def mount_nested_controllers: (MountedController parent) -> void
|
|
42
|
+
|
|
43
|
+
attr_reader mounted: Array[MountedController]
|
|
44
|
+
attr_reader logger: Logger
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
# Stores runtime configuration loaded from YAML or manual overrides.
|
|
3
|
+
class Config
|
|
4
|
+
@custom: untyped
|
|
5
|
+
|
|
6
|
+
@server_name: untyped
|
|
7
|
+
|
|
8
|
+
@logger: untyped
|
|
9
|
+
|
|
10
|
+
@port: untyped
|
|
11
|
+
|
|
12
|
+
@bind_address: untyped
|
|
13
|
+
|
|
14
|
+
@auto_migrate: untyped
|
|
15
|
+
|
|
16
|
+
@threads: untyped
|
|
17
|
+
|
|
18
|
+
@processes: untyped
|
|
19
|
+
|
|
20
|
+
@protocols: untyped
|
|
21
|
+
|
|
22
|
+
@observability: untyped
|
|
23
|
+
|
|
24
|
+
@event_bus: untyped
|
|
25
|
+
|
|
26
|
+
@router: untyped
|
|
27
|
+
|
|
28
|
+
@middleware: untyped
|
|
29
|
+
|
|
30
|
+
Observability: untyped
|
|
31
|
+
|
|
32
|
+
EventBusConfig: untyped
|
|
33
|
+
|
|
34
|
+
RouterConfig: untyped
|
|
35
|
+
|
|
36
|
+
MiddlewareConfig: untyped
|
|
37
|
+
|
|
38
|
+
attr_accessor port: untyped
|
|
39
|
+
|
|
40
|
+
attr_accessor bind_address: untyped
|
|
41
|
+
|
|
42
|
+
attr_accessor logger: untyped
|
|
43
|
+
|
|
44
|
+
attr_accessor observability: untyped
|
|
45
|
+
|
|
46
|
+
attr_accessor auto_migrate: untyped
|
|
47
|
+
|
|
48
|
+
attr_accessor custom: untyped
|
|
49
|
+
|
|
50
|
+
attr_accessor processes: untyped
|
|
51
|
+
|
|
52
|
+
attr_accessor threads: untyped
|
|
53
|
+
|
|
54
|
+
attr_accessor protocols: untyped
|
|
55
|
+
|
|
56
|
+
attr_accessor server_name: untyped
|
|
57
|
+
|
|
58
|
+
attr_accessor event_bus: untyped
|
|
59
|
+
|
|
60
|
+
attr_accessor router: untyped
|
|
61
|
+
|
|
62
|
+
attr_accessor middleware: untyped
|
|
63
|
+
|
|
64
|
+
def initialize: () -> void
|
|
65
|
+
|
|
66
|
+
def []: (untyped key) -> untyped
|
|
67
|
+
|
|
68
|
+
def []=: (untyped key, untyped value) -> untyped
|
|
69
|
+
|
|
70
|
+
def method_missing: (untyped name, *untyped args) { (?) -> untyped } -> untyped
|
|
71
|
+
|
|
72
|
+
def respond_to_missing?: (untyped name, ?bool include_private) -> untyped
|
|
73
|
+
|
|
74
|
+
def load_file: (untyped path) -> untyped
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def apply_basic_settings: (untyped data) -> untyped
|
|
79
|
+
|
|
80
|
+
def apply_logger: (untyped data) -> (nil | untyped)
|
|
81
|
+
|
|
82
|
+
def apply_observability: (untyped data) -> (nil | untyped)
|
|
83
|
+
|
|
84
|
+
def apply_event_bus: (untyped data) -> (nil | untyped)
|
|
85
|
+
|
|
86
|
+
def apply_router: (untyped data) -> (nil | untyped)
|
|
87
|
+
|
|
88
|
+
def apply_middleware: (untyped data) -> (nil | untyped)
|
|
89
|
+
|
|
90
|
+
def apply_custom_settings: (untyped data) -> untyped
|
|
91
|
+
|
|
92
|
+
def load_yaml: (untyped path) -> untyped
|
|
93
|
+
|
|
94
|
+
def resolve_logger_output: (untyped target) -> untyped
|
|
95
|
+
|
|
96
|
+
def resolve_logger_level: (untyped level) -> untyped
|
|
97
|
+
|
|
98
|
+
def set_server_defaults: () -> untyped
|
|
99
|
+
|
|
100
|
+
def set_observability_defaults: () -> untyped
|
|
101
|
+
|
|
102
|
+
def set_event_bus_defaults: () -> untyped
|
|
103
|
+
|
|
104
|
+
def set_router_defaults: () -> untyped
|
|
105
|
+
|
|
106
|
+
def set_middleware_defaults: () -> untyped
|
|
107
|
+
|
|
108
|
+
def assign_setting: (untyped data, untyped key) { (untyped) -> untyped } -> (nil | untyped)
|
|
109
|
+
|
|
110
|
+
def assign_processes: (untyped data) -> (nil | untyped)
|
|
111
|
+
|
|
112
|
+
def assign_protocols: (untyped protocols) -> (nil | untyped)
|
|
113
|
+
|
|
114
|
+
def assign_event_bus_core: (untyped event_bus_data) -> untyped
|
|
115
|
+
|
|
116
|
+
def assign_message_buffer_settings: (untyped event_bus_data) -> untyped
|
|
117
|
+
|
|
118
|
+
def assign_event_bus_setting: (untyped event_bus_data, untyped key) -> (nil | untyped)
|
|
119
|
+
|
|
120
|
+
# Parse middleware entry from YAML config
|
|
121
|
+
# Supports both simple strings and hash with options
|
|
122
|
+
#
|
|
123
|
+
# @example Simple string
|
|
124
|
+
# "Logging"
|
|
125
|
+
#
|
|
126
|
+
# @example Hash with options
|
|
127
|
+
# { name: "Caching", options: { ttl: 300 } }
|
|
128
|
+
def parse_middleware_entry: (untyped entry) -> untyped
|
|
129
|
+
|
|
130
|
+
# Default middleware stack
|
|
131
|
+
# Returns an array of middleware configurations
|
|
132
|
+
def default_middleware_stack: () -> ::Array[{ name: "Debugging", options: ::Hash[untyped, untyped] }]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Takagi::Controller - Base class for modular controllers
|
|
2
|
+
module Takagi
|
|
3
|
+
class Controller
|
|
4
|
+
# Controller configuration hash
|
|
5
|
+
type config_hash = {
|
|
6
|
+
mount_path: String?,
|
|
7
|
+
nested_from: singleton(Controller)?,
|
|
8
|
+
nested_controllers: Array[singleton(Controller)],
|
|
9
|
+
profile: Symbol?,
|
|
10
|
+
processes: Integer?,
|
|
11
|
+
threads: Integer?
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# Get the controller's isolated router
|
|
15
|
+
def self.router: () -> Router
|
|
16
|
+
|
|
17
|
+
# Get the controller's configuration
|
|
18
|
+
def self.config: () -> config_hash
|
|
19
|
+
|
|
20
|
+
# Configure the controller
|
|
21
|
+
def self.configure: () { (ConfigContext) -> void } -> void
|
|
22
|
+
|
|
23
|
+
# Register a route
|
|
24
|
+
def self.add_route: (String method, String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
25
|
+
|
|
26
|
+
# HTTP/CoAP method shortcuts (get, post, put, delete, etc.)
|
|
27
|
+
def self.get: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
28
|
+
def self.post: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
29
|
+
def self.put: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
30
|
+
def self.delete: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
31
|
+
def self.patch: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
32
|
+
def self.fetch: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
33
|
+
def self.ipatch: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
34
|
+
|
|
35
|
+
# Observable route registration
|
|
36
|
+
def self.observable: (String path, ?metadata: Hash[Symbol, untyped]) { (Message::Inbound, Hash[Symbol, String]) -> untyped } -> void
|
|
37
|
+
|
|
38
|
+
# Get the full mount path
|
|
39
|
+
def self.mount_path: () -> String?
|
|
40
|
+
|
|
41
|
+
# Check if mounted
|
|
42
|
+
def self.mounted?: () -> bool
|
|
43
|
+
|
|
44
|
+
# Get nested controllers
|
|
45
|
+
def self.nested_controllers: () -> Array[singleton(Controller)]
|
|
46
|
+
|
|
47
|
+
# Get profile name
|
|
48
|
+
def self.profile_name: () -> Symbol?
|
|
49
|
+
|
|
50
|
+
# Get effective process count
|
|
51
|
+
def self.process_count: () -> Integer?
|
|
52
|
+
|
|
53
|
+
# Get effective thread count
|
|
54
|
+
def self.thread_count: () -> Integer?
|
|
55
|
+
|
|
56
|
+
# Configuration DSL context
|
|
57
|
+
class ConfigContext
|
|
58
|
+
def initialize: (singleton(Controller) controller_class) -> void
|
|
59
|
+
|
|
60
|
+
# Set mount path
|
|
61
|
+
def mount: (String path, ?nested_from: singleton(Controller)?) -> void
|
|
62
|
+
|
|
63
|
+
# Nest child controllers
|
|
64
|
+
def nest: (*singleton(Controller) controllers) -> void
|
|
65
|
+
|
|
66
|
+
# Set load profile
|
|
67
|
+
def profile: (Symbol name) -> void
|
|
68
|
+
|
|
69
|
+
# Set configuration value
|
|
70
|
+
def set: (Symbol key, untyped value) -> void
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Takagi
|
|
2
|
+
module Core
|
|
3
|
+
# Encapsulates CoRE Link Format attribute handling for a single route.
|
|
4
|
+
# The DSL is shared between request-time handlers and boot-time helpers,
|
|
5
|
+
# so changes applied here are idempotent and safe to call repeatedly.
|
|
6
|
+
class AttributeSet
|
|
7
|
+
@metadata: untyped
|
|
8
|
+
|
|
9
|
+
@overrides: untyped
|
|
10
|
+
|
|
11
|
+
CONTENT_FORMATS: { "text/plain" => 0, "application/link-format" => 40, "application/xml" => 41, "application/octet-stream" => 42, "application/exi" => 47, "application/json" => 50, "application/cbor" => 60 }
|
|
12
|
+
|
|
13
|
+
REMOVE: untyped
|
|
14
|
+
|
|
15
|
+
attr_reader metadata: untyped
|
|
16
|
+
|
|
17
|
+
def initialize: (untyped metadata) -> void
|
|
18
|
+
|
|
19
|
+
# Evaluates a block that configures any mix of CoRE attributes.
|
|
20
|
+
# Accepts the same DSL as the runtime helpers exposed in RouteContext.
|
|
21
|
+
def core: () ?{ (?) -> untyped } -> (untyped | nil)
|
|
22
|
+
|
|
23
|
+
def ct: (untyped value) -> untyped
|
|
24
|
+
|
|
25
|
+
alias content_format ct
|
|
26
|
+
|
|
27
|
+
def sz: (untyped value) -> untyped
|
|
28
|
+
|
|
29
|
+
def title: (untyped value) -> untyped
|
|
30
|
+
|
|
31
|
+
def obs: (?bool value) -> untyped
|
|
32
|
+
|
|
33
|
+
alias observable obs
|
|
34
|
+
|
|
35
|
+
def rt: (*untyped values) -> untyped
|
|
36
|
+
|
|
37
|
+
def interface: (*untyped values) -> untyped
|
|
38
|
+
|
|
39
|
+
alias if_ interface
|
|
40
|
+
|
|
41
|
+
def attribute: (untyped name, untyped value) -> untyped
|
|
42
|
+
|
|
43
|
+
# Persists staged attribute overrides back onto the route metadata.
|
|
44
|
+
# Invoked automatically after request handling, but also exposed so
|
|
45
|
+
# callers (e.g. Takagi::Router#configure_core) can persist updates.
|
|
46
|
+
def apply!: () -> (nil | untyped)
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def assign_list: (untyped key, untyped values) -> (nil | untyped)
|
|
51
|
+
|
|
52
|
+
def metadata_override: (untyped key, untyped value) -> untyped
|
|
53
|
+
|
|
54
|
+
def normalize_content_format: (untyped value) -> untyped
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|