mqtt-sub_handler 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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