blob: 3de7c543348605670bd3aa58bafa247a118c6842 [file] [log] [blame]
Weiweie5640c62015-07-31 01:43:01 -07001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
3# Copyright (C) 2014 Regents of the University of California.
4# Author: Teng Liang <philoliang2011@gmail.com>
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17# A copy of the GNU General Public License is in the file COPYING.
18"""
Weiweif3132ed2015-08-05 11:20:49 -070019DeviceStorage implements a basic storage of devices and corresponding commands
Weiweie5640c62015-07-31 01:43:01 -070020"""
21
22import os
23import sqlite3
24from pyndn import Name
25from device_profile import DeviceProfile
26from hmac_key import HMACKey
Weiweif3132ed2015-08-05 11:20:49 -070027
Weiweie5640c62015-07-31 01:43:01 -070028INIT_DEVICE_TABLE = ["""
29CREATE TABLE IF NOT EXISTS
30 Device(
31 id INTEGER,
32 prefix BLOB NOT NULL UNIQUE,
33 location BLOB,
34 category BLOB,
35 type BLOB,
36 model BLOB,
37 serial_number BLOB,
38 manufacturer BLOB,
39 seed_name BLOB NOT NULL,
Weiweif3132ed2015-08-05 11:20:49 -070040 seed_sequence INTEGER NOT NULL,
41 seed_counter INTEGER NOT NULL,
Weiweie5640c62015-07-31 01:43:01 -070042 seed BLOB NOT NULL,
43 configuration_token BLOB NOT NULL,
Weiweif3132ed2015-08-05 11:20:49 -070044 configuration_token_sequence INTEGER NOT NULL,
45 configuration_token_counter INTEGER NOT NULL,
Weiweie5640c62015-07-31 01:43:01 -070046
47 PRIMARY KEY (id)
48 );
49"""]
50
51INIT_COMMAND_TABLE = ["""
52CREATE TABLE IF NOT EXISTS
53 Command(
54 id INTEGER,
55 device_id INTEGER NOT NULL,
56 name BLOB NOT NULL,
57 command_token_name BLOB NOT NULL,
Weiweif3132ed2015-08-05 11:20:49 -070058 command_token_sequence INTEGER NOT NULL,
59 command_token_counter INTEGER NOT NULL,
Weiweie5640c62015-07-31 01:43:01 -070060 command_token BLOB NOT NULL,
61
62 PRIMARY KEY(id)
63 FOREIGN KEY(device_id) REFERENCES Device(id)
64 );
65"""]
66
67INIT_SERVICE_PROFILE_TABLE = ["""
68CREATE TABLE IF NOT EXISTS
69 ServiceProfile(
70 id INTEGER,
71 device_id INTEGER NOT NULL,
72 name BLOB NOT NULL,
73
74 PRIMARY KEY(id)
75 FOREIGN KEY(device_id) REFERENCES Device(id)
76 );
77"""]
78
Weiweif3132ed2015-08-05 11:20:49 -070079class DeviceStorage(object):
Weiweie5640c62015-07-31 01:43:01 -070080 """
81 Create a new DeviceUserStorage to work with an SQLite file.
82 :param str databaseFilePath: (optional) The path of the SQLite file. If ommitted, use the default path.
83 """
84 def __init__(self, databaseFilePath = None):
85 if databaseFilePath == None or databaseFilePath == "":
86 if not "HOME" in os.environ:
87 home = '.'
88 else:
89 home = os.environ["HOME"]
90
91 dbDirectory = os.path.join(home, '.ndn')
92 if not os.path.exists(dbDirectory):
93 os.makedirs(dbDirectory)
94
95 databaseFilePath = os.path.join(dbDirectory, 'ndnhome-controller.db')
96
97 self._database = sqlite3.connect(databaseFilePath)
98
99 #Check if the Device table exists
100 cursor = self._database.cursor()
101 cursor.execute("SELECT name FROM sqlite_master WHERE TYPE ='table' and NAME = 'Device'")
102 if cursor.fetchone() == None:
103 #no device table exists, create one
104 for command in INIT_DEVICE_TABLE:
105 self._database.execute(command)
106 cursor.close()
107
108 #Check if the Command table exists
109 cursor = self._database.cursor()
110 cursor.execute("SELECT name FROM sqlite_master WHERE TYPE ='table' and NAME = 'Command'")
111 if cursor.fetchone() == None:
112 #no command table exists, create one
113 for command in INIT_COMMAND_TABLE:
114 self._database.execute(command)
115 cursor.close()
116
117 #Check if the ServiceProfile table exists
118 cursor = self._database.cursor()
119 cursor.execute("SELECT name FROM sqlite_master WHERE TYPE ='table' and NAME = 'ServiceProfile'")
120 if cursor.fetchone() == None:
121 #no ServiceProfile table exists, create one
122 for command in INIT_SERVICE_PROFILE_TABLE:
123 self._database.execute(command)
124 cursor.close()
125
126 self._database.commit()
127
128 def doesTableExist(self, tableName):
129 """
130 check if table exists
131 :param str tableName
132 :return True if exists, otherwise False
133 """
134 selectOperation = "SELECT name FROM sqlite_master WHERE TYPE='table' and NAME='" + tableName +"'"
135 #print selectOperation
136 cursor = self._database.cursor()
137 cursor.execute(selectOperation)
138 if cursor.fetchone() == None:
139 result = False
140 else:
141 result = True
142 cursor.close()
143 return result
144
145 def doesDeviceExist(self, prefix):
146 """
147 Check if the specified device already exists.
148
149 :param Name prefix: the prefix of device
150 :return True if the device exists, otherwise False
151 :rtype: bool
152 """
153 result = False
154 #print prefix
155 cursor = self._database.cursor()
156 cursor.execute("SELECT count(*) FROM Device WHERE prefix =?", (prefix.toUri(),))
157 (count,) = cursor.fetchone()
158 if count > 0:
159 result = True
160 #print 'device with %s is founnd, count %d' %(prefix, count)
161
162 cursor.close()
163 return result
164
165 def addDevice(self, deviceProfile, seed, configurationToken):
166 """
167 Add a new device to the Device table, do nothing if the device already exists
168
169 :param DeviceProfile devicePorfile: the deviceProfile of the device
170 :param Key seed: the seed of the device
171 :param Key configurationToken: the configurationToken of the device
172 :return the device id if it's added successfully, 0 if the device already exists, otherwise -1
173 :rtype: INTEGER
174 """
175 result = -1
176 data = (deviceProfile.getPrefix().toUri(),
177 deviceProfile.getLocation(),
178 deviceProfile.getCategory(),
179 deviceProfile.getType(),
180 deviceProfile.getModel(),
181 deviceProfile.getManufacturer(),
182 deviceProfile.getSerialNumber(),
183 seed.getName(),
184 seed.getSequence(),
185 seed.getCounter(),
186 seed.getKey(),
187 configurationToken.getKey(),
188 configurationToken.getSequence(),
189 configurationToken.getCounter()
190 )
191
192 #check if the device already exists, if yes return 0
193 prefixName = deviceProfile.getPrefix()
194 if self.doesDeviceExist(prefixName):
195 return 0
196
197 insertDevice = (
198 "INSERT INTO Device(prefix, location, category, type, model, manufacturer, serial_number, seed_name, seed_sequence, seed_counter,seed, configuration_token, configuration_token_sequence, configuration_token_counter)"
199 "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
200 )
201 cursor = self._database.cursor()
202 cursor.execute(insertDevice, data)
203 self._database.commit()
204 result = cursor.lastrowid
205 cursor.close()
206 return result
207
208 def getDeviceProfileFromDevice(self, prefix):
209 """
210 get the specified device profile
211 :param Name prefix: the device prefix
212 :return device profile of the device if exists, otherwise return None
213 :rtype: DeviceProfile
214 """
215 operation = (
216 "Select location, category, type, model, manufacturer, serial_number FROM Device "
217 "WHERE prefix = ?"
218 )
219
220 cursor = self._database.cursor()
221 cursor.execute(operation, (prefix.toUri(),))
222 result = cursor.fetchone()
223 cursor.close()
224 # print result
225 if result == None:
226 return None
227 else:
228 deviceProfile = DeviceProfile(prefix)
229 deviceProfile.setLocation(result[0])
230 deviceProfile.setCategory(result[1])
231 deviceProfile.setType(result[2])
232 deviceProfile.setModel(result[3])
233 deviceProfile.setManufacturer(result[4])
234 deviceProfile.setSerialNumber(result[5])
235
236 return deviceProfile
237
238 def getSeed(self, prefix):
239 """
240 get the seed of the specified device
241 :param Name prefix: the device prefix
242 :return seed of the device if exists, otherwise return None
243 :rtype: HMACKey
244
245 """
246 operation = (
247 "Select seed_name, seed_sequence, seed_counter, seed FROM Device "
248 "WHERE prefix = ?"
249 )
250
251 cursor = self._database.cursor()
252 cursor.execute(operation, (prefix.toUri(),))
253 result = cursor.fetchone()
254 cursor.close()
Weiweif3132ed2015-08-05 11:20:49 -0700255 #print result
Weiweie5640c62015-07-31 01:43:01 -0700256 if result == None:
257 return None
258 else:
259 seed = HMACKey(result[1], result[2], result[3], result[0])
260 return seed
261
262 # raise RuntimeError("getSeed is not implemented")
263
264 def getConfigurationToken(self, prefix):
265 """
266 get the seed of the specified device
267 :param Name prefix: the device prefix
268 :return seed of the device if exists, otherwise return None
269 :rtype: HMACKey
270
271 """
272 operation = (
273 "Select configuration_token_sequence, configuration_token_counter, configuration_token FROM Device "
274 "WHERE prefix = ?"
275 )
276
277 cursor = self._database.cursor()
278 cursor.execute(operation, (prefix.toUri(),))
279 result = cursor.fetchone()
280 cursor.close()
Weiweif3132ed2015-08-05 11:20:49 -0700281 #print result
Weiweie5640c62015-07-31 01:43:01 -0700282 if result == None:
283 return None
284 else:
285 configurationToken = HMACKey(result[0], result[1], result[2])
286 return configurationToken
287 # raise RuntimeError("getConfigurationToken is not implemented")
288
289 def getDeviceEntry(self, prefix):
290 """
291 get the specified device entry
292 :param Name prefix: the device prefix
293 :return '' return the corresponding row of the device
294 :rtype: str
295 """
296 cursor = self._database.cursor()
297 cursor.execute("SELECT * FROM Device WHERE prefix =?", (prefix.toUri(),))
298 row = cursor.fetchone()
299 cursor.close()
300 return row
301
302 def deleteDevice(self, prefix):
303 """
304 delete specified device.
305 :param Name prefix: The device prefix
306 :return: 1 if successful, 0 if no device to delete, otherwise -1.
307 :rtype: INTEGER
308 """
309 result = -1
310 if not self.doesDeviceExist(prefix):
311 return 0
312 cursor = self._database.cursor()
313 deleteDevice = "DELETE FROM Device WHERE prefix=?"
314 cursor.execute(deleteDevice, (prefix.toUri(),))
315 self._database.commit()
316 cursor.close()
317 return 1
318
319 def getDeviceId(self, prefix):
320 """
321 get the device id of some specified device
322 :param Name prefix: the device prefix
323 :return id of the device, 0 if the device doesn't exist
324 :rtype: INTEGER
325 """
326 if not self.doesDeviceExist(prefix):
327 return 0
328 cursor = self._database.cursor()
329 operation = "SELECT id FROM Device WHERE prefix=?"
330 cursor.execute(operation, (prefix.toUri(),))
331 result = cursor.fetchone()
332 deviceId = result[0]
333 self._database.commit()
334 cursor.close()
335 return deviceId
336
337 def updateDevice(self, prefix, newDeviceProfile = None , newSeed = None , newcConfigurationToken = None ):
338 """
339 update specifided device
340 :param Name prefix
341 :param DeviceProfile newDeviceProfile
342 :param HMACKey newSeed
343 :param newConfigurationToken
344 :return id of the device if successful, 0 if device not found, otherwise -1
345 :rtype int
346 """
347 raise RuntimeError("getConfigurationToken is not implemented")
348
349 def updateOneColumnOfDevice(self, prefix, columnName, newColumnValue):
350 """
351 update the value of a specified column of a specified device
352 :param Name prefix: the device prefix
353 :param str columnName: column to be updated
354 :param newColumnValue: new column value
355 :return id of the device if successful. 0 if device not found, otherwise -1
356 :rtype int
357 """
358 result = -1
359 if not self.doesDeviceExist(prefix):
360 return 0
361
362 updateDevice = "UPDATE Device Set " + columnName + "=? WHERE prefix=?"
363 #print updateDevice
364 cursor = self._database.cursor()
365 #print newColumnValue
366 cursor.execute(updateDevice, (newColumnValue,prefix.toUri()))
367 self._database.commit()
368 result = cursor.lastrowid
369 cursor.close()
370 return result
371
372 def doesCommandExist(self, deviceId, commandName):
373 """
374 check if the specified command already exists.
375
376 :param Integer device_id: the device id
377 :return True if the command exists, otherwise False
378 :rtype: bool
379 """
380 result = False
381
382 cursor = self._database.cursor()
383 cursor.execute("SELECT count(*) FROM Command WHERE device_id =? AND name = ?", (deviceId, commandName))
384 (count,) = cursor.fetchone()
385 if count > 0:
386 result = True
387
388 cursor.close()
389 return result
390
391 def addCommand(self, deviceId, name, commandToken):
392 """
393 Add a new command to the Command table, do nothing if the device already exists
394
395 :param int deviceId: the device id to which the command belongs to
396 :param str name: the command name
397 :param HMACKey commandToken: the command token
398 :return the command id if it's added successfully, 0 if the command already exists, otherwise -1
399 :rtype: int
400 """
401 result = -1
402 data = (deviceId,
403 name,
404 commandToken.getName(),
405 commandToken.getSequence(),
406 commandToken.getCounter(),
407 commandToken.getKey()
408 )
409
410 #check if the command already exists, if yes return 0
411 if self.doesCommandExist(deviceId, name):
412 return 0
413
414 insertCommand = (
415 "INSERT INTO Command(device_id, name, command_token_name, command_token_sequence, command_token_counter, command_token)"
416 "VALUES(?,?,?,?,?,?)"
417 )
418 cursor = self._database.cursor()
419 cursor.execute(insertCommand, data)
420 self._database.commit()
421 result = cursor.lastrowid
422 cursor.close()
423 return result
424
425 def deleteCommand(self, deviceId, name = None):
426 """
427 delete specified commands.
428 :param str name: The command name, if None, delete all commands of the device
429 :param int deviceId: device id of the command
430 :return: 1 if successful, 0 if no command to delete, otherwise -1.
431 :rtype: int
432 """
433 result = -1
434 if not name == None:
435 if not self.doesCommandExist(deviceId, name):
436 return 0
437 cursor = self._database.cursor()
438 deleteCommand = "DELETE FROM Command WHERE device_id=? AND name=?"
439 cursor.execute(deleteCommand, (deviceId, name))
440 self._database.commit()
441 cursor.close()
442 return 1
443 else:
444 selectOperation = "SELECT count(*) FROM Command WHERE deviceId=?"
445 cursor = self._database.cursor()
446 cursor.execute(selectOperation, (deviceId,))
447 (count,) = cursor.fetchone()
448 if not count > 0:
449 return 0
450 deleteCommand = "DELETE FROM Command WHERE deviceId=?"
451 cursor.execute(deleteCommand, (deviceId))
452 self._database.commit()
453 cursor.close()
454 return 1
455
456 return result
457
458 def getCommandsOfDevice(self, deviceId):
459 """
460 get all the commands of a specified device
461 :param int deviceId: device id of the command
462 :return command name list if any commands exist, otherwise None
463
464 """
465 operation = "SELECT name FROM Command WHERE device_id = ?"
466 #operation2 = "SELECT count(*) FROM Command WHERE device_id = ? "
467 cursor = self._database.cursor()
468 #cursor.execute(operation2,(deviceId,))
469 #(count,) = cursor.fetchone
470
471 #if not count > 0:
472 #return None
473 cursor.execute(operation, (deviceId,))
474 result = cursor.fetchall()
Weiweif3132ed2015-08-05 11:20:49 -0700475 #print result
Weiweie5640c62015-07-31 01:43:01 -0700476 commandList = []
477 if result == None:
478 return commandList
479 else:
480 for row in result:
481 commandList.append(row[0])
482
483 return commandList
484
485 def getCommandToken(self, deviceId, commandName):
486 """
487 get command token of a specified command
488 :param int deviceId: device id of the command
489 :param str commandName: device name of the command
490 :return command token if command existsm, otherwise None
491 :rtype HMACKey
492 """
493 operation = "SELECT command_token_sequence, command_token_counter,command_token, command_token_name FROM Command WHERE device_id = ? AND name = ?"
494 cursor = self._database.cursor()
495 cursor.execute(operation, (deviceId, commandName))
496 result = cursor.fetchone()
497 if result == None:
498 return None
499 else:
500 commandToken = HMACKey(result[0], result[1], result[2], result[3])
501 return commandToken
502
503 def doesServiceProfileExist(self, deviceId, serviceProfileName):
504 """
505 check if the specified service profile already exists.
506
507 :param Integer device_id: the device id
508 :param str serviceProfileName: name of the service profile
509 :return True if the service profile exists, otherwise False
510 :rtype: bool
511 """
512 result = False
513
514 cursor = self._database.cursor()
515 cursor.execute("SELECT count(*) FROM ServiceProfile WHERE device_id =? AND name = ?", (deviceId, serviceProfileName))
516 (count,) = cursor.fetchone()
517 if count > 0:
518 result = True
519
520 cursor.close()
521 return result
522
523 def addServiceProfile(self, deviceId, name):
524 """
525 Add a new command to the ServiceProfile table, do nothing if the device already exists
526
527 :param int deviceId: the device id to which the command belongs to
528 :param str name: the service profile name
529 :return the service profile id if it's added successfully, 0 if the service profile already exists, otherwise -1
530 :rtype: int
531 """
532 result = -1
533 data = (deviceId,
534 name,
535 )
536
537 #check if the service profile already exists, if yes return 0
538 if self.doesServiceProfileExist(deviceId, name):
539 return 0
540
541 insertCommand = (
542 "INSERT INTO ServiceProfile(device_id, name)"
543 "VALUES(?,?)"
544 )
545 cursor = self._database.cursor()
546 cursor.execute(insertCommand, data)
547 self._database.commit()
548 result = cursor.lastrowid
549 cursor.close()
550 return result
551
552 def deleteServiceProfile(self, deviceId, name = None):
553 """
554 delete specified service profile.
555 :param str name: The command name, if None, delete all profiless of the device
556 :param int deviceId: device id
557 :return: 1 if successful, 0 if no service profile to delete, otherwise -1.
558 :rtype: int
559 """
560 result = -1
561 if not name == None:
562 if not self.doesServiceProfileExist(deviceId, name):
563 return 0
564 cursor = self._database.cursor()
565 deleteProfile = "DELETE FROM ServiceProfile WHERE device_id=? AND name=?"
566 cursor.execute(deleteProfile, (deviceId, name))
567 self._database.commit()
568 cursor.close()
569 return 1
570 else:
571 selectOperation = "SELECT count(*) FROM ServiceProfile WHERE deviceId=?"
572 cursor = self._database.cursor()
573 cursor.execute(selectOperation, (deviceId,))
574 (count,) = cursor.fetchone()
575 if not count > 0:
576 return 0
577 deleteProfile = "DELETE FROM ServiceProfile WHERE deviceId=?"
578 cursor.execute(deleteProfile, (deviceId))
579 self._database.commit()
580 cursor.close()
581 return 1
582
583 return result
584
585 def getServiceProfilesOfDevice(self, deviceId):
586 """
587 get all the service profiles of a specified device
588 :param int deviceId: device id of the command
589 :return service profiles name list if any service profiles exist, otherwise None
590 """
591 operation = "SELECT name FROM ServiceProfile WHERE device_id = ?"
592 cursor = self._database.cursor()
593 cursor.execute(operation, (deviceId,))
594 result = cursor.fetchall()
595 #print result
596 serviceProfileList = []
597 if not result == None:
598 for row in result:
599 serviceProfileList.append(row[0])
600 return serviceProfileList
601
602