apiotics-test 0.1.49

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +260 -0
  4. data/Rakefile +33 -0
  5. data/lib/apiotics.rb +58 -0
  6. data/lib/apiotics/client.rb +20 -0
  7. data/lib/apiotics/configuration.rb +23 -0
  8. data/lib/apiotics/extract.rb +107 -0
  9. data/lib/apiotics/hardware.rb +109 -0
  10. data/lib/apiotics/insert.rb +115 -0
  11. data/lib/apiotics/parse.rb +20 -0
  12. data/lib/apiotics/portal.rb +217 -0
  13. data/lib/apiotics/railtie.rb +14 -0
  14. data/lib/apiotics/server.rb +238 -0
  15. data/lib/apiotics/version.rb +3 -0
  16. data/lib/generators/apiotics/channel/USAGE +10 -0
  17. data/lib/generators/apiotics/channel/channel_generator.rb +35 -0
  18. data/lib/generators/apiotics/channel/templates/apiotics_channel.rb.erb +9 -0
  19. data/lib/generators/apiotics/channel/templates/apiotics_channel_client.coffee.erb +16 -0
  20. data/lib/generators/apiotics/channel/templates/apiotics_channel_initializer.rb.erb +3 -0
  21. data/lib/generators/apiotics/controller/USAGE +8 -0
  22. data/lib/generators/apiotics/controller/controller_generator.rb +25 -0
  23. data/lib/generators/apiotics/controller/templates/apiotics_scaffold.rb.erb +60 -0
  24. data/lib/generators/apiotics/create_model/USAGE +10 -0
  25. data/lib/generators/apiotics/create_model/create_model_generator.rb +76 -0
  26. data/lib/generators/apiotics/create_model/templates/apiotics_logs_model.rb.erb +7 -0
  27. data/lib/generators/apiotics/create_model/templates/apiotics_model.rb.erb +49 -0
  28. data/lib/generators/apiotics/create_model/templates/apiotics_module.rb.erb +14 -0
  29. data/lib/generators/apiotics/create_model/templates/apiotics_module_model.rb.erb +8 -0
  30. data/lib/generators/apiotics/create_model/templates/create_module_model_table.rb.erb +9 -0
  31. data/lib/generators/apiotics/create_table/USAGE +9 -0
  32. data/lib/generators/apiotics/create_table/create_table_generator.rb +62 -0
  33. data/lib/generators/apiotics/create_table/templates/create_logs_table.rb.erb +14 -0
  34. data/lib/generators/apiotics/create_table/templates/create_table.rb.erb +16 -0
  35. data/lib/generators/apiotics/initializer/USAGE +8 -0
  36. data/lib/generators/apiotics/initializer/initializer_generator.rb +29 -0
  37. data/lib/generators/apiotics/initializer/templates/apiotics.rb.erb +10 -0
  38. data/lib/generators/apiotics/initializer/templates/apiotics_module.rb.erb +6 -0
  39. data/lib/generators/apiotics/initializer/templates/apiotics_parents.rb.erb +3 -0
  40. data/lib/generators/apiotics/initializer/templates/apiotics_settings.rb.erb +9 -0
  41. data/lib/generators/apiotics/initializer/templates/apiotics_targets.rb.erb +4 -0
  42. data/lib/generators/apiotics/initializer/templates/setting.rb.erb +3 -0
  43. data/lib/generators/apiotics/install/USAGE +11 -0
  44. data/lib/generators/apiotics/install/install_generator.rb +11 -0
  45. data/lib/generators/apiotics/migration/USAGE +10 -0
  46. data/lib/generators/apiotics/migration/migration_generator.rb +54 -0
  47. data/lib/generators/apiotics/migration/templates/create_logs_table.rb.erb +14 -0
  48. data/lib/generators/apiotics/migration/templates/migrate_table.rb.erb +12 -0
  49. data/lib/generators/apiotics/model/USAGE +11 -0
  50. data/lib/generators/apiotics/model/model_generator.rb +58 -0
  51. data/lib/generators/apiotics/scaffold/scaffold_generator.rb +23 -0
  52. data/lib/generators/apiotics/scaffold/templates/USAGE +0 -0
  53. data/lib/generators/apiotics/script/USAGE +8 -0
  54. data/lib/generators/apiotics/script/script_generator.rb +45 -0
  55. data/lib/generators/apiotics/script/templates/comm_server.rake +19 -0
  56. data/lib/generators/apiotics/script/templates/dev_comm_server.rake +19 -0
  57. data/lib/generators/apiotics/script/templates/dev_server.rb +8 -0
  58. data/lib/generators/apiotics/script/templates/dev_server_control.rb +7 -0
  59. data/lib/generators/apiotics/script/templates/install_firmware.rake +10 -0
  60. data/lib/generators/apiotics/script/templates/publish_script.rake +6 -0
  61. data/lib/generators/apiotics/script/templates/script.rb.erb +12 -0
  62. data/lib/generators/apiotics/script/templates/server.rb +8 -0
  63. data/lib/generators/apiotics/script/templates/server_control.rb +7 -0
  64. data/lib/generators/apiotics/script/templates/test_comm_server.rake +19 -0
  65. data/lib/generators/apiotics/script/templates/test_server.rb +8 -0
  66. data/lib/generators/apiotics/script/templates/test_server_control.rb +7 -0
  67. data/lib/generators/apiotics/view/USAGE +12 -0
  68. data/lib/generators/apiotics/view/templates/default.css.erb +18 -0
  69. data/lib/generators/apiotics/view/templates/edit.html.erb +6 -0
  70. data/lib/generators/apiotics/view/templates/form.html.erb +52 -0
  71. data/lib/generators/apiotics/view/templates/index.html.erb +66 -0
  72. data/lib/generators/apiotics/view/templates/show.html.erb +56 -0
  73. data/lib/generators/apiotics/view/view_generator.rb +26 -0
  74. data/lib/tasks/simbiotes_tasks.rake +4 -0
  75. metadata +256 -0
@@ -0,0 +1,109 @@
1
+ require 'os'
2
+
3
+ module Apiotics
4
+ class Hardware
5
+ def self.bits
6
+ OS.bits
7
+ end
8
+
9
+ def self.linux
10
+ OS.linux?
11
+ end
12
+
13
+ def self.mac
14
+ OS.mac?
15
+ end
16
+
17
+ def self.save_openocd
18
+ os = nil
19
+ if self.linux == true
20
+ if self.bits == 64
21
+ os = "debian64"
22
+ elsif self.bits == 32
23
+ os = "debian32"
24
+ end
25
+ elsif self.mac == true
26
+ os = "mac"
27
+ end
28
+ unless os == nil
29
+ data = Apiotics::Portal.openocd(os)
30
+ directory = Rails.root.join('lib', 'openocd')
31
+ Dir.mkdir directory unless Dir.exist?(directory)
32
+ path = Rails.root.join('lib', 'openocd', 'openocd.tgz')
33
+ file = File.new(path, 'w')
34
+ file.write data.force_encoding(Encoding::UTF_8)
35
+ file.close
36
+ end
37
+ end
38
+
39
+ def self.unpack_openocd
40
+ directory = Rails.root.join('lib', 'openocd')
41
+ Dir.chdir directory
42
+ path = Rails.root.join('lib', 'openocd', 'openocd.tgz')
43
+ msg = system("tar -xvzf #{path}")
44
+ if msg == true
45
+ File.delete(path) if File.exist?(path)
46
+ end
47
+ end
48
+
49
+ def self.install_firmware(config_script, firmware_path, starting_address)
50
+ directory = Rails.root.join('lib', 'openocd', 'gnuarmeclipse')
51
+ unless Dir.exist?(directory)
52
+ self.save_openocd
53
+ self.unpack_openocd
54
+ end
55
+ directory = Rails.root.join('lib', 'openocd', 'gnuarmeclipse', 'openocd')
56
+ Dir.chdir directory
57
+ version_folder = Dir['*/'].first[0..-2]
58
+ directory = Rails.root.join('lib', 'openocd', 'gnuarmeclipse', 'openocd', version_folder)
59
+ Dir.chdir directory
60
+ string = "bin/openocd -f \"scripts/board/" + config_script + "\"" + " -c \"program " + firmware_path.to_s + " exit " + starting_address.to_s + "\""
61
+ msg = system(string)
62
+ end
63
+
64
+ def self.openocd(worker_name, name)
65
+ download_directory = Rails.root.join('lib', 'openocd')
66
+ Dir.mkdir download_directory unless Dir.exist?(download_directory)
67
+ download_directory = Rails.root.join('lib', 'openocd', 'downloads')
68
+ Dir.mkdir download_directory unless Dir.exist?(download_directory)
69
+ Dir.chdir download_directory
70
+ config = Apiotics::Portal.openocd_worker_config(worker_name)
71
+ config = JSON.parse(config)
72
+ unless config["openocd_config_file_name"] == nil || config["openocd_config_file_name"] == ""
73
+ path = Rails.root.join('lib', 'openocd', 'downloads', config["firmware_file_name"])
74
+ if File.exist?(path)
75
+ else
76
+ firmware_data = Apiotics::Portal.download_firmware(worker_name)
77
+ file = File.new(path, 'w')
78
+ file.write firmware_data.force_encoding(Encoding::UTF_8)
79
+ file.close
80
+ end
81
+ clean_string = "1" * 68 * 8
82
+ clean = Array.new
83
+ clean[0] = clean_string
84
+ clean_bits = clean.pack("B*")
85
+ if name != nil
86
+ if name.length > 64
87
+ name = name[0..63]
88
+ end
89
+ data = File.open(path, 'r+')
90
+ version_offset = 2048
91
+ offset = version_offset + 4 + 68 + 68 + 68
92
+ IO.write(data, clean_bits.force_encoding(Encoding::UTF_8), offset)
93
+ name = name + "\0"
94
+ IO.write(data, name, offset)
95
+ data.close
96
+ else
97
+ data = File.open(path, 'r+')
98
+ version_offset = 2048
99
+ offset = version_offset + 4 + 68 + 68 + 68
100
+ IO.write(data, clean_bits.force_encoding(Encoding::UTF_8), offset)
101
+ data.close
102
+ end
103
+ msg = self.install_firmware(config["openocd_config_file_name"], path, config["openocd_start_address"])
104
+ end
105
+ return msg
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,115 @@
1
+ # This class takes ruby hashes and saves them to the appropriate database table.
2
+ # All model methods that have corresponding IoT interfaces have six database fields associated with them.
3
+ # The first is a field named the same as the method. The second is name_ack, and third is name_complete, the fourth is name_timestamp, the fifth is name_status, the sixth is name_action.
4
+ # In the hash, instance is the record id (not necessarily the id column), driver is the model, interface is the method.
5
+ # Data should be saved both to the model's database table and to the corresponding log table (name_method_logs).
6
+
7
+ module Apiotics
8
+ class Insert
9
+ def initialize(hash = {"action" => "set-complete", "instance" => 1, "driver" => "test_driver", "interface" => "control", "value" => 72, "timestamp" => "1000000000000", "status" => "ok"})
10
+ @action = hash["action"]
11
+ @id = hash["instance"]
12
+ @class = hash["driver"]
13
+ @methods = hash["interface"]
14
+ @value = hash["value"]
15
+ @timestamp = hash["timestamp"]
16
+ @status = hash["status"]
17
+ @valid = true
18
+ begin
19
+ find_record
20
+ @methods.each do |k,v|
21
+ @record.send(("#{k}_action=").to_sym, @action)
22
+ @type = @record.class.columns_hash[k].type
23
+ #change_value
24
+ @record.send("#{k}=".to_sym, v)
25
+ @record.send("#{k}_timestamp=".to_sym, @timestamp)
26
+ @record.send("#{k}_status=".to_sym, @status)
27
+ end
28
+ if @action == "set-complete"
29
+ set_complete
30
+ elsif @action == "set-request-ack"
31
+ set_ack
32
+ elsif @action == "get-ack"
33
+ get_ack
34
+ end
35
+ rescue
36
+ @valid = false
37
+ end
38
+ end
39
+
40
+ def find_record
41
+ begin
42
+ klass = @class.classify.constantize
43
+ master_klass = (klass.parent.to_s + "::" + klass.parent.to_s).classify.constantize
44
+ master_record = master_klass.find_by(apiotics_instance: @id)
45
+ @record = master_record.send(@class.demodulize.underscore.downcase)
46
+ rescue Exception => e
47
+ puts e.to_s
48
+ end
49
+ end
50
+
51
+ def set_ack
52
+ @methods.each do |k,v|
53
+ @record.send("#{k}_ack=".to_sym, true)
54
+ @record.send("#{k}_complete=".to_sym, false)
55
+ end
56
+ end
57
+
58
+ def set_complete
59
+ @methods.each do |k,v|
60
+ @record.send("#{k}_ack=".to_sym, true)
61
+ @record.send("#{k}_complete=".to_sym, true)
62
+ end
63
+ end
64
+
65
+ def get_ack
66
+ @methods.each do |k,v|
67
+ @record.send("#{k}_ack=".to_sym, true)
68
+ @record.send("#{k}_complete=".to_sym, false)
69
+ end
70
+ end
71
+
72
+ def save
73
+ @record.skip_extract = true
74
+ @record.save
75
+ @record.skip_extract = false
76
+ end
77
+
78
+ def action
79
+ @action.to_s
80
+ end
81
+
82
+ def save_log
83
+ @methods.each do |k,v|
84
+ klass = "#{@class}_#{k}_log".classify.constantize
85
+ r = klass.new
86
+ r.send(("#{k}_action=").to_sym, @action)
87
+ r.send("#{k}=".to_sym, v)
88
+ r.send("#{k}_timestamp=".to_sym, @timestamp)
89
+ r.send("#{k}_status=".to_sym, @status)
90
+ r.send("#{k}_ack=".to_sym, @record.send("#{k}_ack"))
91
+ r.send("#{k}_complete=".to_sym, @record.send("#{k}_complete"))
92
+ r.send("#{@class.classify.demodulize.underscore.gsub("/","_")}_id=".to_sym, @record.id)
93
+ r.save
94
+ end
95
+ end
96
+
97
+ def valid
98
+ return @valid
99
+ end
100
+
101
+ def change_value
102
+ if @type == :boolean
103
+ if @value == "true"
104
+ @value = true
105
+ elsif @value == "false"
106
+ @value = false
107
+ end
108
+ elsif @type == :integer
109
+ @value = @value.to_i
110
+ elsif @type == :string
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,20 @@
1
+ # This class is responsible for parsing JSON messages and configuration files into ruby hashes.
2
+
3
+ require 'json'
4
+
5
+ module Apiotics
6
+ class Parse
7
+
8
+ def self.message(string)
9
+ JSON.parse(string)
10
+ end
11
+
12
+ def self.config(string)
13
+ JSON.parse(string)
14
+ end
15
+
16
+ def self.portal(string)
17
+ JSON.parse(string)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,217 @@
1
+
2
+ require 'httparty'
3
+ require 'rest-client'
4
+
5
+ module Apiotics
6
+ class Portal
7
+
8
+ def self.get_attributes(parent_name, model_name)
9
+ configuration = Portal.retrieve_configuration
10
+ attributes = Portal.parse_drivers_and_scripts(configuration, parent_name, model_name)
11
+ end
12
+
13
+ def self.parse_drivers_and_scripts(hash, parent_name, model_name)
14
+ attributes_hash = nil
15
+ hash["workers"][parent_name]["drivers"].each do |k,v|
16
+ name = v["metadata"]["common name"].classify
17
+ if name == model_name.classify
18
+ attributes_hash = Hash.new
19
+ attributes_hash[:kind] = "driver"
20
+ attributes_hash[:attributes] = Hash.new
21
+ v["interfaces"].each do |k,v|
22
+ attributes_hash[:attributes][k] = {
23
+ type: v["type"],
24
+ accessor: v["accessor type"],
25
+ units: v["units"],
26
+ noise: v["noise threshold"],
27
+ values: v["values"],
28
+ range: v["range"]
29
+ }
30
+ end
31
+ end
32
+ end
33
+ hash["workers"][parent_name]["scripts"].each do |k,v|
34
+ name = v["metadata"]["common name"].classify
35
+ if name == model_name.classify
36
+ attributes_hash = Hash.new
37
+ attributes_hash[:kind] = "script"
38
+ attributes_hash[:attributes] = Hash.new
39
+ v["interfaces"].each do |key,value|
40
+ attributes_hash[:attributes][key] = {
41
+ type: value["type"],
42
+ accessor: value["accessor type"],
43
+ units: value["units"],
44
+ noise: value["noise threshold"],
45
+ values: value["values"],
46
+ range: value["range"]
47
+ }
48
+ end
49
+ attributes_hash[:inputs] = Hash.new
50
+ v["inputs"].each do |key,value|
51
+ attributes_hash[:inputs][key] = value
52
+ end
53
+ end
54
+ end
55
+ return attributes_hash
56
+ end
57
+
58
+ def self.retrieve_configuration
59
+ json = HTTParty.post("#{Apiotics.configuration.portal}api/hive", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key}).body
60
+ hash = Apiotics::Parse.portal(json)
61
+ end
62
+
63
+ def self.parse_all_interfaces
64
+ configuration = Portal.retrieve_configuration
65
+ hash = Hash.new
66
+ configuration["workers"].each do |key, value|
67
+ hash[key] = Hash.new
68
+ configuration["workers"][key]["drivers"].each do |k,v|
69
+ a = Array.new
70
+ if v["interfaces"] != nil
71
+ v["interfaces"].each do |key, value|
72
+ a << key
73
+ end
74
+ end
75
+ hash[key][v["metadata"]["common name"]] = a
76
+ end
77
+ configuration["workers"][key]["scripts"].each do |k,v|
78
+ a = Array.new
79
+ if v["interfaces"] != nil
80
+ v["interfaces"].each do |key, value|
81
+ a << key
82
+ end
83
+ end
84
+ hash[key][v["metadata"]["common name"]] = a
85
+ end
86
+ end
87
+ hash
88
+ end
89
+
90
+ def self.parse_parents
91
+ configuration = Portal.retrieve_configuration
92
+ hash = Hash.new
93
+ configuration["workers"].each do |key, value|
94
+ if hash[key] == nil
95
+ hash[key] = Hash.new
96
+ end
97
+ value["drivers"].each do |k, v|
98
+ if hash[key][k] == nil
99
+ hash[key][k] = Hash.new
100
+ end
101
+ if v["parents"] != {}
102
+ v["parents"].each do |parent_driver, parent_hash|
103
+ parent_hash.each do |parent_interface, parent_value|
104
+ if parent_value.is_a? Hash
105
+ hash[key][k][parent_value["interface"]] = Hash.new
106
+ hash[key][k][parent_value["interface"]]["interface"] = parent_interface
107
+ hash[key][k][parent_value["interface"]]["driver"] = parent_driver
108
+ if hash[key][parent_driver] == nil
109
+ hash[key][parent_driver] = Hash.new
110
+ hash[key][parent_driver][parent_interface] = Hash.new
111
+ end
112
+ hash[key][parent_driver][parent_interface]["interface"] = parent_value["interface"]
113
+ hash[key][parent_driver][parent_interface]["driver"] = k
114
+ if parent_value.keys.count > 2
115
+ parent_value.each do |pv_key, pv_value|
116
+ unless pv_key == "interface"
117
+ hash[key][parent_driver][parent_interface][pv_key] = pv_value
118
+ hash[key][k][parent_value["interface"]][pv_value] = pv_key
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ hash
129
+ end
130
+
131
+ def self.sync_device_instances(worker_name, sync_data)
132
+ instance_hash = JSON.parse(HTTParty.post("#{Apiotics.configuration.portal}api/workers", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key}).body)
133
+ klass = (worker_name.to_s + "::" + worker_name.to_s).constantize rescue nil
134
+ unless klass == nil
135
+ instance_ids = Hash.new
136
+ instance_id_array = Array.new
137
+ instance_hash[worker_name].each do |instance_id,status_hash|
138
+ if status_hash["status"] == "Active"
139
+ instance_ids[instance_id] = status_hash
140
+ instance_id_array << instance_id
141
+ end
142
+ end
143
+ stale_instances = klass.where.not(apiotics_instance: instance_id_array)
144
+ stale_instances.destroy_all
145
+ instance_ids.each do |instance_id, status_hash|
146
+ i = klass.find_by(apiotics_instance: instance_id)
147
+ if i == nil
148
+ i = klass.new
149
+ i.apiotics_instance = instance_id
150
+ i.name = status_hash["name"]
151
+ i.save(:validate => false)
152
+ Apiotics.configuration.targets[worker_name].keys.each do |key|
153
+ subklass = (worker_name + "::" + key).constantize rescue nil
154
+ unless subklass == nil
155
+ s = subklass.new
156
+ k = worker_name.underscore.gsub(" ","_").to_s + "_id="
157
+ s.send((k).to_sym, i.id)
158
+ s.skip_extract = true
159
+ if sync_data == true
160
+ s.sync
161
+ end
162
+ s.save(:validate => false)
163
+ s.skip_extract = false
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ def self.upload_script(worker, script)
172
+ payload = {
173
+ :multipart => true,
174
+ :script_file => File.open("#{Rails.root}/lib/scripts/apiotics/#{worker.underscore.downcase}/#{script.underscore.downcase}.rb", 'rb'),
175
+ :public_key => Apiotics.configuration.public_key,
176
+ :private_key => Apiotics.configuration.private_key,
177
+ :worker_name => worker,
178
+ :script_name => script
179
+ }
180
+ r = RestClient.post("#{Apiotics.configuration.portal}api/upload_script", payload)
181
+ end
182
+
183
+ def self.generate_certificate(csr)
184
+ csr_file = Tempfile.new
185
+ csr_file.write(csr)
186
+ csr_file.rewind
187
+ payload = {
188
+ :multipart => true,
189
+ :csr => csr_file,
190
+ :public_key => Apiotics.configuration.public_key,
191
+ :private_key => Apiotics.configuration.private_key
192
+ }
193
+ r = RestClient.post("#{Apiotics.configuration.portal}api/generate_certificate", payload)
194
+ instance_hash = JSON.parse(r.body)
195
+ return instance_hash["certificate"]
196
+ end
197
+
198
+ def self.ca_certificate
199
+ response = HTTParty.post("#{Apiotics.configuration.portal}api/ca_certificate", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key}).body
200
+ hash = JSON.parse(response)
201
+ return hash["ca_certificate"]
202
+ end
203
+
204
+ def self.openocd(system)
205
+ response = HTTParty.post("#{Apiotics.configuration.portal}api/openocd", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key, :system => system}).body
206
+ end
207
+
208
+ def self.openocd_worker_config(worker_name)
209
+ response = HTTParty.post("#{Apiotics.configuration.portal}api/openocd_details", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key, :worker => worker_name}).body
210
+ end
211
+
212
+ def self.download_firmware(worker_name)
213
+ response = HTTParty.post("#{Apiotics.configuration.portal}api/download", :query => {:public_key => Apiotics.configuration.public_key, :private_key => Apiotics.configuration.private_key, :worker => worker_name}).body
214
+ end
215
+
216
+ end
217
+ end