apiotics-test 0.1.49

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