mqtt-sub_handler 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77c5c7ff31447b119bde650cc2bab092e930fb1e
4
- data.tar.gz: 73f5d04c7d2acb4da546ab3b9a16995e643a96ab
3
+ metadata.gz: eea6058ba5750daeebbf41696765e1702b60495a
4
+ data.tar.gz: 3dbea34eea6371096173df3cccf2468d682e0786
5
5
  SHA512:
6
- metadata.gz: ecb77d9ee3bdf6d121edf8c19808c973a3a1c9ca1736119793d7b2a6afa0abb2720b7ab4e4613a6165ac473db1ee36ca0d746af6c3add4ac3e5fa58d9ad89e55
7
- data.tar.gz: 1cb20f6c9c7a6e40a09b36d868e65698aaa953a5cd48e5a6f55ca18cb73d965d6f5c99ffdbda0f356f0407e175f3f432204bd3e9edbee966a49ae4579f5f2c86
6
+ metadata.gz: 9cda8aadc97990675ca7d3b443fa69f82dfb253a4c67eddad0f0bc7a769b24012d30947cd8e7d72df417eea919981590a17e3166e7aa31f9a7deb6bde58d9478
7
+ data.tar.gz: 1cf6cd63dde250ad6da0d09dbea8b0610cbd375db61305df229d31951961902d26d789fe476b77b9d9be932f9ffcf779474d70372b8a2c30bbbee84d8582534b
@@ -0,0 +1,175 @@
1
+
2
+ require 'json'
3
+ require_relative 'persistence_extensions.rb'
4
+
5
+ module MQTT
6
+ class Persistence
7
+ # Provide persistence for tasks that regularly restart, using MQTT retained messages.
8
+ # As a fun side effect, this also allows for live monitoring and modifying!
9
+ #
10
+ # @author Xasin
11
+
12
+
13
+ # Initialize the Persistence instance.
14
+ # This will immediately connect and subscribe to the wildcard of `dir + "/#"`
15
+ # @param mqtt [MQTT::SubHandler] The MQTT instance to use for storing/communication
16
+ # @param dir [String] A valid MQTT topic string under which to nest the persistence.
17
+ def initialize(mqtt, dir = "Persistence")
18
+ raise ArgumentError, "Not a mqtt class!" unless mqtt.is_a? MQTT::SubHandler
19
+
20
+ @mqtt = mqtt;
21
+ @dir = dir;
22
+
23
+ @rawData = Hash.new();
24
+ @paramList = Hash.new();
25
+
26
+ @mqtt.subscribe_to "#{@dir}/+" do |data, key|
27
+ _process_data(data, key[0].to_sym);
28
+ end
29
+ end
30
+
31
+
32
+ # Prepare a piece of data to be sent to the MQTT topic
33
+ # It must either respond to `to_mqtt_string` or to `to_json`
34
+ def _prepare_send(data, key)
35
+ if(data.respond_to? :to_mqtt_string)
36
+ return data.to_mqtt_string;
37
+ else
38
+ return data.to_json
39
+ end
40
+ end
41
+ private :_prepare_send
42
+
43
+ # Parse a raw String received from MQTT.
44
+ # If the given class type responds to `from_mqtt_string`, that
45
+ # function is used for processing.
46
+ # `JSON.parse` will be used otherwise.
47
+ # @return [key-type, nil] Returns the parsed data, nil if that fails.
48
+ def _parse_received(data, key)
49
+ begin
50
+ dType = @paramList[key][:type];
51
+ if(dType.respond_to? :from_mqtt_string)
52
+ return dType.from_mqtt_string(data);
53
+ else
54
+ return JSON.parse(data, symbolize_names: true);
55
+ end
56
+ rescue JSON::ParserError
57
+ return nil;
58
+ end
59
+ end
60
+ private :_parse_received
61
+
62
+ # This processes new data received from MQTT.
63
+ # It returns if the raw string hasn't changed, and will trigger the callbacks.
64
+ def _process_data(data, key)
65
+ return if @rawData[key] == data;
66
+ @rawData[key] = data;
67
+
68
+ return unless param = @paramList[key];
69
+
70
+ oldData = param[:current];
71
+ param[:current] = _parse_received(data, key);
72
+ param[:cbList].each do |cb|
73
+ cb.call(param[:current], oldData);
74
+ end
75
+
76
+ if(param[:first])
77
+ param.delete :first
78
+ param[:cbList] = [param[:cbList], param[:change_cb]].flatten;
79
+ end
80
+ end
81
+ private :_process_data
82
+
83
+ # Force setting up a key, overwriting what was already configured.
84
+ # You usually don't need this!
85
+ # @param key [Symbol] The key that should be set up.
86
+ # @param type_class [#from_mqtt_string] The class to use to parse the data. A JSON-conversion
87
+ # is used if the class doesn't respond to `from_mqtt_string`
88
+ def setup!(key, type_class = nil)
89
+ raise ArgumentError, "Key needs to be a symbol!" unless key.is_a? Symbol
90
+
91
+ @paramList[key] = {
92
+ type: type_class,
93
+ current: nil,
94
+ cbList: Array.new(),
95
+
96
+ first: true,
97
+ change_cb: Array.new(),
98
+ }
99
+
100
+ if(data = @rawData[key])
101
+ @rawData[key] = nil;
102
+ _process_data(data, key);
103
+ end
104
+ end
105
+ # Set up a key, unless it has already been configured.
106
+ # @param (See #setup!)
107
+ def setup(key, type_class = nil)
108
+ return if @paramList.key? key;
109
+ setup!(key, type_class);
110
+ end
111
+
112
+ # Read out a given, set-up key, returning `nil` if nothing has been read yet (or the value is nil right now),
113
+ # returning the data otherwise.
114
+ # If a block is given (using the on_set alias), this block will be added as a callback.
115
+ # @param key [Symbol] The key to fetch. Must have been set up first!
116
+ # @yieldparam newData The newly parsed data (depending on the key's type.)
117
+ # @yieldparam oldData The former data that was present.
118
+ def [](key, &callback)
119
+ raise ArgumentError, "Key needs to be a symbol!" unless key.is_a? Symbol
120
+ raise ArgumentError, "Key has not been set up!" unless @paramList.key? key;
121
+
122
+ if(callback)
123
+ @paramList[key][:cbList] << callback
124
+ yield(@paramList[key][:current], nil) if @paramList[key][:current]
125
+ end
126
+
127
+ return @paramList[key][:current];
128
+ end
129
+ alias on_set []
130
+
131
+ # Set a given key to a new value, provided the key has been set up.
132
+ # Will run the `on_change` and `on_set` callbacks immediately, then publish to MQTT.
133
+ # @param key [Symbol] The key to write. Must have been set up first!
134
+ # @param data [#to_json, #to_mqtt_string] The data to write.
135
+ def []=(key, data)
136
+ raise ArgumentError, "Key needs to be a symbol!" unless key.is_a? Symbol
137
+ raise ArgumentError, "Key has not been set up!" unless param = @paramList[key];
138
+
139
+ newString = _prepare_send(data, key);
140
+ return if @rawData[key] == newString;
141
+ @rawData[key] = newString;
142
+
143
+ if(param[:first])
144
+ param.delete :first
145
+ param[:cbList] = [param[:cbList], param[:change_cb]].flatten;
146
+ end
147
+
148
+ oldData = param[:current];
149
+ param[:current] = data;
150
+ param[:cbList].each do |cb|
151
+ cb.call(param[:current], oldData);
152
+ end
153
+
154
+ @mqtt.publish_to "#{@dir}/#{key}", newString, retain: true;
155
+ end
156
+
157
+ # Add a callback to be triggered whenever the key's value changes.
158
+ # The slight difference to `on_set` is that this callback is not executed on the very first
159
+ # value received from MQTT, making it easier to not trigger some code on restart, only on actual changes.
160
+ # @param (See #[])
161
+ # @yieldparam (See #[])
162
+ def on_change(key, &callback)
163
+ raise ArgumentError, "Key needs to be a symbol!" unless key.is_a? Symbol
164
+ raise ArgumentError, "Key has not been set up!" unless @paramList.key? key;
165
+
166
+ raise ArgumentError, "A callback needs to be given!" unless callback;
167
+
168
+ if(@paramList[key][:first])
169
+ @paramList[key][:change_cb] << callback;
170
+ else
171
+ @paramList[key][:cbList] << callback;
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,13 @@
1
+
2
+ class Time
3
+ def to_mqtt_string
4
+ to_f().to_json()
5
+ end
6
+
7
+ def self.from_mqtt_string(string)
8
+ data = JSON.parse(string);
9
+ return nil unless data.is_a? Numeric;
10
+
11
+ return self.at(data);
12
+ end
13
+ end
@@ -26,8 +26,10 @@ module MQTT
26
26
  private :call_interested
27
27
 
28
28
  def raw_subscribe_to(topic, qos: nil)
29
- if(@retained_topics[topic]) then
30
- publish_to(topic, @retained_topics[topic])
29
+ @retained_topics.each do |retTopic, retData|
30
+ if SubHandler.getTopicMatch(retTopic, SubHandler.get_topic_split(topic))
31
+ publish_to(retTopic, retData)
32
+ end
31
33
  end
32
34
  end
33
35
  private :raw_subscribe_to
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mqtt-sub_handler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xasin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-26 00:00:00.000000000 Z
11
+ date: 2018-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mqtt
@@ -89,10 +89,12 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - README.md
91
91
  - lib/mqtt/Waitpoint.rb
92
+ - lib/mqtt/persistence.rb
93
+ - lib/mqtt/persistence_extensions.rb
92
94
  - lib/mqtt/sub_handler.rb
93
95
  - lib/mqtt/sub_testing.rb
94
96
  - lib/mqtt/subscription_classes.rb
95
- homepage: https://github.com/XasWorks/XasCode/tree/MQTT_GEM/Ruby/MQTT
97
+ homepage: https://github.com/XasWorks/XasCode/tree/master/Ruby/MQTT
96
98
  licenses:
97
99
  - GPL-3.0
98
100
  metadata: {}
@@ -112,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
114
  version: '0'
113
115
  requirements: []
114
116
  rubyforge_project:
115
- rubygems_version: 2.6.14.1
117
+ rubygems_version: 2.5.2.1
116
118
  signing_key:
117
119
  specification_version: 4
118
120
  summary: Asynchronous, topic-based MQTT gem