mqtt-v5 0.0.1.ci.release

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 (36) hide show
  1. checksums.yaml +7 -0
  2. data/lib/mqtt/v5/async/client.rb +27 -0
  3. data/lib/mqtt/v5/client/authenticator.rb +83 -0
  4. data/lib/mqtt/v5/client/connection.rb +192 -0
  5. data/lib/mqtt/v5/client/session.rb +45 -0
  6. data/lib/mqtt/v5/client.rb +61 -0
  7. data/lib/mqtt/v5/errors.rb +19 -0
  8. data/lib/mqtt/v5/packet/auth.rb +57 -0
  9. data/lib/mqtt/v5/packet/connack.rb +110 -0
  10. data/lib/mqtt/v5/packet/connect.rb +130 -0
  11. data/lib/mqtt/v5/packet/disconnect.rb +78 -0
  12. data/lib/mqtt/v5/packet/ping_req.rb +20 -0
  13. data/lib/mqtt/v5/packet/ping_resp.rb +20 -0
  14. data/lib/mqtt/v5/packet/pub_ack.rb +60 -0
  15. data/lib/mqtt/v5/packet/pub_comp.rb +53 -0
  16. data/lib/mqtt/v5/packet/pub_rec.rb +60 -0
  17. data/lib/mqtt/v5/packet/pub_rel.rb +53 -0
  18. data/lib/mqtt/v5/packet/publish.rb +122 -0
  19. data/lib/mqtt/v5/packet/reason_code.rb +112 -0
  20. data/lib/mqtt/v5/packet/sub_ack.rb +66 -0
  21. data/lib/mqtt/v5/packet/subscribe.rb +87 -0
  22. data/lib/mqtt/v5/packet/unsub_ack.rb +59 -0
  23. data/lib/mqtt/v5/packet/unsubscribe.rb +112 -0
  24. data/lib/mqtt/v5/packet.rb +147 -0
  25. data/lib/mqtt/v5/packets.rb +25 -0
  26. data/lib/mqtt/v5/topic_alias/cache.rb +87 -0
  27. data/lib/mqtt/v5/topic_alias/frequency_weighted_policy.rb +50 -0
  28. data/lib/mqtt/v5/topic_alias/length_weighted_policy.rb +20 -0
  29. data/lib/mqtt/v5/topic_alias/lru_policy.rb +36 -0
  30. data/lib/mqtt/v5/topic_alias/manager.rb +143 -0
  31. data/lib/mqtt/v5/topic_alias/policy.rb +34 -0
  32. data/lib/mqtt/v5/topic_alias/weighted_policy.rb +48 -0
  33. data/lib/mqtt/v5/topic_alias.rb +27 -0
  34. data/lib/mqtt/v5/version.rb +11 -0
  35. data/lib/mqtt/v5.rb +4 -0
  36. metadata +88 -0
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+ require_relative '../version'
5
+ require 'mqtt/core/packet/connect'
6
+
7
+ module MQTT
8
+ module V5
9
+ module Packet
10
+ # MQTT 5.0 CONNECT packet
11
+ #
12
+ # Sent by client to establish connection with the broker.
13
+ #
14
+ # @see Core::Client#connect
15
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901033 MQTT 5.0 Spec §3.1
16
+ class Connect
17
+ include Packet
18
+ include Core::Packet::Connect
19
+
20
+ # Avoid name clashes between sub-properties
21
+ def self.sub_property_method(name, property_name)
22
+ case name
23
+ when :will_properties
24
+ return :will_user_properties if property_name == :user_properties
25
+ end
26
+ property_name
27
+ end
28
+
29
+ fixed(1)
30
+
31
+ # @!attribute [r] protocol_name
32
+ # @return [String<UTF8>] protocol name (managed automatically)
33
+ # @!attribute [r] protocol_version
34
+ # @return [Integer] protocol version (managed automatically)
35
+ # @!attribute [r] clean_start
36
+ # @return [Boolean] if true server will abandon any stored session (managed automatically from session store)
37
+ # @!attribute [r] will_qos
38
+ # @return [Integer] QoS level for the Will message: 0, 1, or 2 (default 0)
39
+ # @!attribute [r] will_retain
40
+ # @return [Boolean] should the Will message be retained (default false)
41
+ # @!attribute [r] keep_alive
42
+ # @return [Integer] maximum duration in seconds between packets sent by the client (default 60)
43
+
44
+ # @!group Properties
45
+
46
+ # @!attribute [r] session_expiry_interval
47
+ # @return [Integer] session expiry interval in seconds (managed automatically from session store)
48
+ # @!attribute [r] receive_maximum
49
+ # @return [Integer] maximum number of QoS 1 and 2 messages the client will process concurrently
50
+ # @!attribute [r] maximum_packet_size
51
+ # @return [Integer] maximum packet size the client is willing to accept
52
+ # @!attribute [r] topic_alias_maximum
53
+ # @return [Integer] maximum topic alias value the client accepts
54
+ # @!attribute [r] request_response_information
55
+ # @return [Boolean] whether the client requests response information
56
+ # @!attribute [r] request_problem_information
57
+ # @return [Boolean] whether the client requests problem information
58
+ # @!attribute [r] user_properties
59
+ # @return [Array<String, String>] user-defined properties as key-value pairs
60
+ # @!attribute [r] authentication_method
61
+ # @return [String<UTF8>] authentication method name
62
+ # @!attribute [r] authentication_data
63
+ # @return [String<Binary>] authentication data
64
+
65
+ # @!endgroup
66
+
67
+ # @!attribute [r] client_id
68
+ # @return [String<UTF8>] client identifier string (managed from session store, default '')
69
+ # @!attribute [r] will_topic
70
+ # @return [String<UTF8>] topic name to send the Will message to
71
+ # @!attribute [r] will_payload
72
+ # @return [String<Binary>] payload of the Will message
73
+ # @!attribute [r] will_properties
74
+ # @return [Hash<Symbol>] properties for the Will message
75
+ # @!attribute [r] username
76
+ # @return [String<UTF8>] username for authenticating with the server
77
+ # @!attribute [r] password
78
+ # @return [String<Binary>] password for authenticating with the server
79
+
80
+ variable(
81
+ protocol_name: :utf8string,
82
+ protocol_version: :int8,
83
+ connect_flags: flags(
84
+ :username_flag, :password_flag,
85
+ :will_retain,
86
+ [:will_qos, 2],
87
+ :will_flag,
88
+ :clean_start,
89
+ :reserved
90
+ ),
91
+ keep_alive: :int16,
92
+ properties: properties(:connect)
93
+ )
94
+
95
+ payload(
96
+ client_id: :utf8string,
97
+ will_properties: { type: properties(:will), if: :will_flag },
98
+ will_topic: { type: :utf8string, if: :will_flag },
99
+ will_payload: { type: :binary, if: :will_flag },
100
+ username: { type: :utf8string, if: :username },
101
+ password: { type: :binary, if: :password }
102
+ )
103
+
104
+ alias clean_requested? clean_start
105
+ alias username? :username_flag
106
+ alias password? :password_flag
107
+ alias will_flag? :will_flag
108
+
109
+ # @!visibility private
110
+ def defaults
111
+ super.merge!(client_id: '', keep_alive: 60, will_retain: false, will_qos: 0, clean_start: false)
112
+ end
113
+
114
+ # @!visibility private
115
+ def apply_overrides(data)
116
+ super
117
+ data.merge!(
118
+ protocol_name: 'MQTT',
119
+ protocol_version: PROTOCOL_VERSION
120
+ )
121
+ end
122
+
123
+ # @!visibility private
124
+ def success!(connack)
125
+ connack.success!
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MQTT
4
+ module V5
5
+ module Packet
6
+ # MQTT 5.0 DISCONNECT packet
7
+ #
8
+ # Sent by client to gracefully disconnect, or received from broker to indicate disconnection.
9
+ #
10
+ # @see Core::Client#disconnect
11
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205 MQTT 5.0 Spec §3.14
12
+ class Disconnect
13
+ include Packet
14
+
15
+ fixed(14)
16
+
17
+ # @!parse include ReasonCodeAck
18
+ # @!attribute [r] reason_code
19
+ # disconnection reason
20
+ #
21
+ # ✅ Success:
22
+ #
23
+ # - `0x00` Normal disconnection
24
+ # - `0x04` Disconnect with Will Message
25
+ #
26
+ # ❌ Error:
27
+ #
28
+ # - `0x80` Unspecified error
29
+ # - `0x81` Malformed Packet
30
+ # - `0x82` Protocol Error
31
+ # - `0x83` Implementation specific error
32
+ # - `0x87` Not authorized
33
+ # - `0x89` Server busy
34
+ # - `0x8B` Server shutting down
35
+ # - `0x8C` Bad authentication method
36
+ # - `0x8D` Keep alive timeout
37
+ # - `0x8E` Session taken over
38
+ # - `0x8F` Topic Filter invalid
39
+ # - `0x90` Topic Name invalid
40
+ # - `0x93` Receive Maximum exceeded
41
+ # - `0x94` Topic Alias invalid
42
+ # - `0x95` Packet too large
43
+ # - `0x96` Message rate too high
44
+ # - `0x97` Quota exceeded
45
+ # - `0x98` Administrative action
46
+ # - `0x99` Payload format invalid
47
+ # - `0x9A` Retain not supported
48
+ # - `0x9B` QoS not supported
49
+ # - `0x9C` Use another server
50
+ # - `0x9E` Shared Subscriptions not supported
51
+ # - `0x9F` Connection rate exceeded
52
+ # - `0xA0` Maximum connect time
53
+ # - `0xA1` Subscription Identifiers not supported
54
+ # - `0xA2` Wildcard Subscriptions not supported
55
+ #
56
+ # @return [ReasonCode]
57
+
58
+ # @!group Properties
59
+
60
+ # @!attribute [r] session_expiry_interval
61
+ # @return [Integer] session expiry interval in seconds
62
+ # @!attribute [r] reason_string
63
+ # @return [String<UTF8>] human-readable reason for disconnection
64
+ # @!attribute [r] user_properties
65
+ # @return [Array<String, String>] user-defined properties as key-value pairs
66
+ # @!attribute [r] server_reference
67
+ # @return [String<UTF8>] server reference for redirection
68
+
69
+ # @!endgroup
70
+
71
+ variable(
72
+ reason_code:, # automatically includes ReasonCodeAck
73
+ properties:
74
+ )
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PINGREQ packet
9
+ #
10
+ # Sent by client to keep the connection alive.
11
+ #
12
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901195 MQTT 5.0 Spec §3.12
13
+ class PingReq
14
+ include Packet
15
+
16
+ fixed(12)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PINGRESP packet
9
+ #
10
+ # Sent by broker in response to a PINGREQ packet.
11
+ #
12
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200 MQTT 5.0 Spec §3.13
13
+ class PingResp
14
+ include Packet
15
+
16
+ fixed(13)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PUBACK packet
9
+ #
10
+ # QoS 1 acknowledgement sent by broker in response to a PUBLISH packet.
11
+ #
12
+ # @see Core::Client#publish
13
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901121 MQTT 5.0 Spec §3.4
14
+ class PubAck
15
+ include Packet
16
+
17
+ fixed(4)
18
+
19
+ # @!attribute [r] packet_identifier
20
+ # @return [Integer] packet identifier matching the PUBLISH packet (receive only)
21
+
22
+ # @!parse include ReasonCodeAck
23
+ # @!attribute [r] reason_code
24
+ # acknowledgement status
25
+ #
26
+ # ✅ Success:
27
+ #
28
+ # - `0x00` Success
29
+ # - `0x10` No matching subscribers
30
+ #
31
+ # ❌ Error:
32
+ #
33
+ # - `0x80` Unspecified error
34
+ # - `0x83` Implementation specific error
35
+ # - `0x87` Not authorized
36
+ # - `0x90` Topic Name invalid
37
+ # - `0x91` Packet Identifier in use
38
+ # - `0x97` Quota exceeded
39
+ # - `0x99` Payload format invalid
40
+ #
41
+ # @return [ReasonCode]
42
+
43
+ # @!group Properties
44
+
45
+ # @!attribute [r] reason_string
46
+ # @return [String<UTF8>] human-readable reason for the response
47
+ # @!attribute [r] user_properties
48
+ # @return [Array<String, String>] user-defined properties as key-value pairs
49
+
50
+ # @!endgroup
51
+
52
+ variable(
53
+ packet_identifier: :int16,
54
+ reason_code:, # automatically includes ReasonCodeAck
55
+ properties:
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PUBCOMP packet
9
+ #
10
+ # QoS 2 publish complete (part 3) sent by broker in response to a PUBREL packet.
11
+ #
12
+ # @see Core::Client#publish
13
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901151 MQTT 5.0 Spec §3.7
14
+ class PubComp
15
+ include Packet
16
+
17
+ fixed(7)
18
+
19
+ # @!attribute [r] packet_identifier
20
+ # @return [Integer] packet identifier matching the PUBREL packet (receive only)
21
+
22
+ # @!parse include ReasonCodeAck
23
+ # @!attribute [r] reason_code
24
+ # acknowledgement status
25
+ #
26
+ # ✅ Success:
27
+ #
28
+ # - `0x00` Success
29
+ #
30
+ # ❌ Error:
31
+ #
32
+ # - `0x92` Packet Identifier not found
33
+ #
34
+ # @return [ReasonCode]
35
+
36
+ # @!group Properties
37
+
38
+ # @!attribute [r] reason_string
39
+ # @return [String<UTF8>] human-readable reason for the response
40
+ # @!attribute [r] user_properties
41
+ # @return [Array<String, String>] user-defined properties as key-value pairs
42
+
43
+ # @!endgroup
44
+
45
+ variable(
46
+ packet_identifier: :int16,
47
+ reason_code:, # automatically includes ReasonCodeAck
48
+ properties:
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PUBREC packet
9
+ #
10
+ # QoS 2 acknowledgement (part 1) sent by broker in response to a PUBLISH packet.
11
+ #
12
+ # @see Core::Client#publish
13
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901131 MQTT 5.0 Spec §3.5
14
+ class PubRec
15
+ include Packet
16
+
17
+ fixed(5)
18
+
19
+ # @!attribute [r] packet_identifier
20
+ # @return [Integer] packet identifier matching the PUBLISH packet (receive only)
21
+
22
+ # @!parse include ReasonCodeAck
23
+ # @!attribute [r] reason_code
24
+ # acknowledgement status
25
+ #
26
+ # ✅ Success:
27
+ #
28
+ # - `0x00` Success
29
+ # - `0x10` No matching subscribers
30
+ #
31
+ # ❌ Error:
32
+ #
33
+ # - `0x80` Unspecified error
34
+ # - `0x83` Implementation specific error
35
+ # - `0x87` Not authorized
36
+ # - `0x90` Topic Name invalid
37
+ # - `0x91` Packet Identifier in use
38
+ # - `0x97` Quota exceeded
39
+ # - `0x99` Payload format invalid
40
+ #
41
+ # @return [ReasonCode]
42
+
43
+ # @!group Properties
44
+
45
+ # @!attribute [r] reason_string
46
+ # @return [String<UTF8>] human-readable reason for the response
47
+ # @!attribute [r] user_properties
48
+ # @return [Array<String, String>] user-defined properties as key-value pairs
49
+
50
+ # @!endgroup
51
+
52
+ variable(
53
+ packet_identifier: :int16,
54
+ reason_code:, # automatically includes ReasonCodeAck
55
+ properties:
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+
5
+ module MQTT
6
+ module V5
7
+ module Packet
8
+ # MQTT 5.0 PUBREL packet
9
+ #
10
+ # QoS 2 publish release (part 2) sent by client in response to a PUBREC packet.
11
+ #
12
+ # @see Core::Client#publish
13
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901141 MQTT 5.0 Spec §3.6
14
+ class PubRel
15
+ include Packet
16
+
17
+ fixed(6, [:reserved, 4, 0b0010])
18
+
19
+ # @!attribute [r] packet_identifier
20
+ # @return [Integer] packet identifier matching the PUBREC packet (receive only)
21
+
22
+ # @!parse include ReasonCodeAck
23
+ # @!attribute [r] reason_code
24
+ # acknowledgement status
25
+ #
26
+ # ✅ Success:
27
+ #
28
+ # - `0x00` Success
29
+ #
30
+ # ❌ Error:
31
+ #
32
+ # - `0x92` Packet Identifier not found
33
+ #
34
+ # @return [ReasonCode]
35
+
36
+ # @!group Properties
37
+
38
+ # @!attribute [r] reason_string
39
+ # @return [String<UTF8>] human-readable reason for the response
40
+ # @!attribute [r] user_properties
41
+ # @return [Array<String, String>] user-defined properties as key-value pairs
42
+
43
+ # @!endgroup
44
+
45
+ variable(
46
+ packet_identifier: :int16,
47
+ reason_code:, # automatically includes ReasonCodeAck
48
+ properties:
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../packet'
4
+ require 'mqtt/core/packet/publish'
5
+
6
+ module MQTT
7
+ module V5
8
+ module Packet
9
+ # MQTT 5.0 PUBLISH packet
10
+ #
11
+ # Sent by client to publish a message to the broker, or received from broker when subscribed to a topic.
12
+ #
13
+ # @see Client#publish
14
+ # @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901100 MQTT 5.0 Spec §3.3
15
+ class Publish
16
+ include Packet
17
+ include Core::Packet::Publish
18
+
19
+ # @!attribute [r] dup
20
+ # @return [Boolean] duplicate delivery flag (managed automatically by session)
21
+ # @!attribute [r] qos
22
+ # @return [Integer] QoS level: 0, 1, or 2 (default 0)
23
+ # @!attribute [r] retain
24
+ # @return [Boolean] should this message be retained by the broker (default false)
25
+ fixed(3, :dup, [:qos, 2], :retain)
26
+
27
+ # @!attribute [r] packet_identifier
28
+ # @return [Integer] packet identifier for QoS 1/2 exchanges (managed automatically by session)
29
+
30
+ # @!group Properties
31
+
32
+ # @!attribute [r] payload_format_indicator
33
+ # @return [Integer] 0 = unspecified, 1 = UTF-8 encoded payload (auto-detected from payload encoding)
34
+ # @!attribute [r] message_expiry_interval
35
+ # @return [Integer] message expiry interval in seconds
36
+ # @!attribute [r] response_topic
37
+ # @return [String<UTF8>] topic name for response messages
38
+ # @!attribute [r] correlation_data
39
+ # @return [String<Binary>] correlation data for request/response
40
+ # @!attribute [r] user_properties
41
+ # @return [Array<String, String>] user-defined properties as key-value pairs
42
+ # @!attribute [r] subscription_identifiers
43
+ # @return [Array<Integer>] subscription identifiers (receive only, set by broker)
44
+ # @!attribute [r] content_type
45
+ # @return [String<UTF8>] content type description
46
+
47
+ variable(
48
+ topic_name: :utf8string,
49
+ packet_identifier: { type: :int16, if: -> { qos.positive? } },
50
+ properties:
51
+ )
52
+
53
+ # @!visibility private
54
+ alias orig_topic_alias topic_alias
55
+
56
+ # @!attribute [r] topic_alias
57
+ # Managed automatically by {TopicAlias::Manager}. See {Client#publish}.
58
+ # @return [Integer|nil] the assigned topic alias id
59
+ def topic_alias
60
+ (@alias_info && @alias_info[:alias]) || orig_topic_alias
61
+ end
62
+
63
+ # @!endgroup
64
+
65
+ # @return [Boolean] whether {TopicAlias::Manager} will try to assign an outgoing {#topic_alias}
66
+ # @see Client#publish
67
+ def assign_alias?
68
+ @assign_alias
69
+ end
70
+
71
+ # @!visibility private
72
+ attr_reader :alias_info
73
+
74
+ # @!visibility private
75
+ alias orig_topic_name topic_name
76
+
77
+ # @!attribute [r] topic_name
78
+ # @return [String<UTF8>] topic name to publish to
79
+ def topic_name
80
+ (@alias_info && @alias_info[:name]) || orig_topic_name
81
+ end
82
+
83
+ alias topic topic_name
84
+
85
+ # @!attribute [r] payload
86
+ # @return [String<Binary>] message payload
87
+ payload(payload: :remaining)
88
+
89
+ # @!visibility private
90
+ def apply_alias(alias: nil, name: nil)
91
+ @alias_info = { alias:, name: }
92
+ end
93
+
94
+ # @!visibility private
95
+ # Check if this packet matches a subscription identifier
96
+ # @param [Integer] sub_id subscription identifier to check
97
+ # @return [Boolean]
98
+ def match_subscription_identifier?(sub_id)
99
+ (subscription_identifiers || []).include?(sub_id)
100
+ end
101
+
102
+ # @!visibility private
103
+ def apply_data(data)
104
+ @assign_alias = data.delete(:assign_alias) if data.key?(:assign_alias)
105
+ super
106
+ end
107
+
108
+ # @!visibility private
109
+ def apply_overrides(data)
110
+ super
111
+ data[:payload_format_indicator] = 1 if payload&.encoding == Encoding::UTF_8
112
+ end
113
+
114
+ # @!visibility private
115
+ def validate
116
+ super
117
+ raise ArgumentError, 'Response topic cannot contain wildcards' if response_topic&.match?(/[#+]/)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end