def main(): loop = asyncio.get_event_loop() face = ThreadsafeFace(loop, "aleph.ndn.ucla.edu") counter = Counter() face.stopWhen(lambda: counter._callbackCount >= 1) name1 = Name("/") dump("Express name ", name1.toUri()) # This call to exressIinterest is thread safe because face is a ThreadsafeFace. face.expressInterest(name1, counter.onData, counter.onTimeout) # Run until stopWhen stops the loop. loop.run_forever() face.shutdown()
class BaseNode(object): """ This class contains methods/attributes common to both node and controller. """ def __init__(self): """ Initialize the network and security classes for the node """ super(BaseNode, self).__init__() self._identityStorage = IotIdentityStorage() self._identityManager = IotIdentityManager(self._identityStorage) self._policyManager = IotPolicyManager(self._identityStorage) # hopefully there is some private/public key pair available self._keyChain = KeyChain(self._identityManager, self._policyManager) self._registrationFailures = 0 self._prepareLogging() self._setupComplete = False self._instanceSerial = None # waiting devices register this prefix and respond to discovery # or configuration interest self._hubPrefix = Name('/localhop/configure') def getSerial(self): """ Since you may wish to run two nodes on a Raspberry Pi, each node will generate a unique serial number each time it starts up. """ if self._instanceSerial is None: prefixLen = 4 prefix = '' for i in range(prefixLen): prefix += (chr(random.randint(0,0xff))) suffix = self.getDeviceSerial().lstrip('0') self._instanceSerial = '-'.join([prefix.encode('hex'), suffix]) return self._instanceSerial ## # Logging ## def _prepareLogging(self): self.log = logging.getLogger(str(self.__class__)) self.log.setLevel(logging.DEBUG) logFormat = "%(asctime)-15s %(name)-20s %(funcName)-20s (%(levelname)-8s):\n\t%(message)s" self._console = logging.StreamHandler() self._console.setFormatter(logging.Formatter(logFormat)) self._console.setLevel(logging.INFO) # without this, a lot of ThreadsafeFace errors get swallowed up logging.getLogger("trollius").addHandler(self._console) self.log.addHandler(self._console) def setLogLevel(self, level): """ Set the log level that will be output to standard error :param level: A log level constant defined in the logging module (e.g. logging.INFO) """ self._console.setLevel(level) def getLogger(self): """ :return: The logger associated with this node :rtype: logging.Logger """ return self.log ### # Startup and shutdown ### def beforeLoopStart(self): """ Called before the event loop starts. """ pass def getDefaultCertificateName(self): try: certName = self._identityStorage.getDefaultCertificateNameForIdentity( self._policyManager.getDeviceIdentity()) except SecurityException: certName = self._keyChain.getDefaultCertificateName() return certName def start(self): """ Begins the event loop. After this, the node's Face is set up and it can send/receive interests+data """ self.log.info("Starting up") self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, '') self.face.setCommandSigningInfo(self._keyChain, self.getDefaultCertificateName()) self._keyChain.setFace(self.face) self._isStopped = False self.face.stopWhen(lambda:self._isStopped) self.beforeLoopStart() try: self.loop.run_forever() except KeyboardInterrupt: pass except Exception as e: self.log.exception(e, exc_info=True) finally: self._isStopped = True def stop(self): """ Stops the node, taking it off the network """ self.log.info("Shutting down") self._isStopped = True ### # Data handling ### def signData(self, data): """ Sign the data with our network certificate :param pyndn.Data data: The data to sign """ self._keyChain.sign(data, self.getDefaultCertificateName()) def sendData(self, data, transport, sign=True): """ Reply to an interest with a data packet, optionally signing it. :param pyndn.Data data: The response data packet :param pyndn.Transport transport: The transport to send the data through. This is obtained from an incoming interest handler :param boolean sign: (optional, default=True) Whether the response must be signed. """ if sign: self.signData(data) transport.send(data.wireEncode().buf()) ### # # ## def onRegisterFailed(self, prefix): """ Called when the node cannot register its name with the forwarder :param pyndn.Name prefix: The network name that failed registration """ if self._registrationFailures < 5: self._registrationFailures += 1 self.log.warn("Could not register {}, retry: {}/{}".format(prefix.toUri(), self._registrationFailures, 5)) self.face.registerPrefix(self.prefix, self._onCommandReceived, self.onRegisterFailed) else: self.log.critical("Could not register device prefix, ABORTING") self._isStopped = True def verificationFailed(self, dataOrInterest): """ Called when verification of a data packet or command interest fails. :param pyndn.Data or pyndn.Interest: The packet that could not be verified """ self.log.info("Received invalid" + dataOrInterest.getName().toUri()) @staticmethod def getDeviceSerial(): """ Find and return the serial number of the Raspberry Pi. Provided in case you wish to distinguish data from nodes with the same name by serial. :return: The serial number extracted from device information in /proc/cpuinfo :rtype: str """ with open('/proc/cpuinfo') as f: for line in f: if line.startswith('Serial'): return line.split(':')[1].strip()
class RegisterSongList(object): def __init__(self, prefix="/ndn/edu/ucla/remap/music/list"): logging.basicConfig() '''#这些log是干嘛的myIP="192.168.1.1",lightIP="192.168.1.50", self.log = logging.getLogger("RegisterSongList") self.log.setLevel(logging.DEBUG) sh = logging.StreamHandler() sh.setLevel(logging.DEBUG) self.log.addHandler(sh) fh = logging.FileHandler("RegisterSongList.log") fh.setLevel(logging.INFO) self.log.addHandler(fh)''' self.device = "PC3" self.deviceComponent = Name.Component(self.device) self.excludeDevice = None #self.songList = originalList #security? self.prefix = Name(prefix) self.changePrefix = Name("/ndn/edu/ucla/remap/music/storage") self.keychain = KeyChain() self.certificateName = self.keychain.getDefaultCertificateName() self.address = "" self._isStopped = True #self.payloadBuffer = [] #self.kinetsender = KinetSender(myIP, playerIP,self.STRAND_SIZE*self.COLORS_PER_LIGHT) def start(self): print "reg start" self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop,self.address) self.face.setCommandSigningInfo(self.keychain,self.certificateName) self.face.registerPrefix(self.prefix,self.onInterest,self.onRegisterFailed) self._isStopped = False self.face.stopWhen(lambda:self._isStopped) try: self.loop.run_forever() except KeyboardInterrupt: sys.exit() finally: self.stop() def stop(self): self.loop.close() #self.kinetsender.stop = True #self.kinetsender.complete.wait() self.face.shutdown() self.face = None sys.exit(1) def signData(self,data): data.setSignature(Sha256WithRsaSignature()) #self.keychain.sign(data,self.certificateName) def onInterest(self, prefix, interest, transport, registeredPrefixId): print "received interest" initInterest = Name(interest.getName()) print "interest name:",initInterest.toUri() #d = Data(interest.getName().getPrefix(prefix.size()+1)) #self.excludeDevice = interest.getName().get(prefix.size()) #initInterest = interest.getName() d = Data(interest.getName().append(self.deviceComponent)) try: print "start to set data's content" currentString = ','.join(currentList) d.setContent("songList of " +self.device+":"+currentString+ "\n") self.face.registerPrefix(self.changePrefix,self.onInterest,self.onRegisterFailed) except KeyboardInterrupt: print "key interrupt" sys.exit(1) except Exception as e: print e d.setContent("Bad command\n") finally: self.keychain.sign(d,self.certificateName) encodedData = d.wireEncode() transport.send(encodedData.toBuffer()) print d.getName().toUri() print d.getContent() self.stop() '''print"remove register" self.face.removeRegisteredPrefix(registeredPrefixId) time.sleep(30) #sleep 30s which means user cannot update the song list twice within 1 minutes print"register again" self.face.registerPrefix(self.prefix, self.onInterest, self.onRegisterFailed)''' def onRegisterFailed(self, prefix): self.log.error("Could not register " + prefix.toUri()) self.stop()
class RegisterSongList(object): def __init__(self, prefix="/ndn/edu/ucla/remap/music/list"): logging.basicConfig() '''#这些log是干嘛的myIP="192.168.1.1",lightIP="192.168.1.50", self.log = logging.getLogger("RegisterSongList") self.log.setLevel(logging.DEBUG) sh = logging.StreamHandler() sh.setLevel(logging.DEBUG) self.log.addHandler(sh) fh = logging.FileHandler("RegisterSongList.log") fh.setLevel(logging.INFO) self.log.addHandler(fh)''' self.device = "PC3" self.deviceComponent = Name.Component(self.device) self.excludeDevice = None #self.songList = originalList #security? self.prefix = Name(prefix) self.changePrefix = Name("/ndn/edu/ucla/remap/music/storage") self.keychain = KeyChain() self.certificateName = self.keychain.getDefaultCertificateName() self.address = "" self._isStopped = True #self.payloadBuffer = [] #self.kinetsender = KinetSender(myIP, playerIP,self.STRAND_SIZE*self.COLORS_PER_LIGHT) def start(self): print "reg start" self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, self.address) self.face.setCommandSigningInfo(self.keychain, self.certificateName) self.face.registerPrefix(self.prefix, self.onInterest, self.onRegisterFailed) self._isStopped = False self.face.stopWhen(lambda: self._isStopped) try: self.loop.run_forever() except KeyboardInterrupt: sys.exit() finally: self.stop() def stop(self): self.loop.close() #self.kinetsender.stop = True #self.kinetsender.complete.wait() self.face.shutdown() self.face = None sys.exit(1) def signData(self, data): data.setSignature(Sha256WithRsaSignature()) #self.keychain.sign(data,self.certificateName) def onInterest(self, prefix, interest, transport, registeredPrefixId): print "received interest" initInterest = Name(interest.getName()) print "interest name:", initInterest.toUri() #d = Data(interest.getName().getPrefix(prefix.size()+1)) #self.excludeDevice = interest.getName().get(prefix.size()) #initInterest = interest.getName() d = Data(interest.getName().append(self.deviceComponent)) try: print "start to set data's content" currentString = ','.join(currentList) d.setContent("songList of " + self.device + ":" + currentString + "\n") self.face.registerPrefix(self.changePrefix, self.onInterest, self.onRegisterFailed) except KeyboardInterrupt: print "key interrupt" sys.exit(1) except Exception as e: print e d.setContent("Bad command\n") finally: self.keychain.sign(d, self.certificateName) encodedData = d.wireEncode() transport.send(encodedData.toBuffer()) print d.getName().toUri() print d.getContent() self.stop() '''print"remove register" self.face.removeRegisteredPrefix(registeredPrefixId) time.sleep(30) #sleep 30s which means user cannot update the song list twice within 1 minutes print"register again" self.face.registerPrefix(self.prefix, self.onInterest, self.onRegisterFailed)''' def onRegisterFailed(self, prefix): self.log.error("Could not register " + prefix.toUri()) self.stop()
class IotConsole(object): """ This uses the controller's credentials to provide a management interface to the user. It does not go through the security handshake (as it should be run on the same device as the controller) and so does not inherit from the BaseNode. """ def __init__(self, networkName, nodeName): super(IotConsole, self).__init__() self.deviceSuffix = Name(nodeName) self.networkPrefix = Name(networkName) self.prefix = Name(self.networkPrefix).append(self.deviceSuffix) self._identityStorage = IotIdentityStorage() self._policyManager = IotPolicyManager(self._identityStorage) self._identityManager = IotIdentityManager(self._identityStorage) self._keyChain = KeyChain(self._identityManager, self._policyManager) self._policyManager.setEnvironmentPrefix(self.networkPrefix) self._policyManager.setTrustRootIdentity(self.prefix) self._policyManager.setDeviceIdentity(self.prefix) self._policyManager.updateTrustRules() self.foundCommands = {} self.unconfiguredDevices = [] # TODO: use xDialog in XWindows self.ui = Dialog(backtitle="NDN IoT User Console", height=18, width=78) trolliusLogger = logging.getLogger("trollius") trolliusLogger.addHandler(logging.StreamHandler()) def start(self): """ Start up the UI """ self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, "") controllerCertificateName = self._identityStorage.getDefaultCertificateNameForIdentity(self.prefix) self.face.setCommandSigningInfo(self._keyChain, controllerCertificateName) self._keyChain.setFace(self.face) # shouldn't be necessarym but doesn't hurt self._isStopped = False self.face.stopWhen(lambda: self._isStopped) self.loop.call_soon(self.displayMenu) try: self.loop.run_forever() except KeyboardInterrupt: pass except Exception as e: print(e) # self.log('Exception', e) finally: self._isStopped = True def stop(self): self._isStopped = True ####### # GUI ####### def displayMenu(self): menuOptions = OrderedDict( [ ("List network services", self.listCommands), ("Pair a device", self.pairDevice), ("Express interest", self.expressInterest), ("Quit", self.stop), ] ) (retCode, retStr) = self.ui.mainMenu("Main Menu", menuOptions.keys()) if retCode == Dialog.DIALOG_ESC or retCode == Dialog.DIALOG_CANCEL: # TODO: ask if you're sure you want to quit self.stop() if retCode == Dialog.DIALOG_OK: menuOptions[retStr]() ####### # List all commands ###### def listCommands(self): self._requestDeviceList(self._showCommandList, self.displayMenu) def _requestDeviceList(self, successCallback, timeoutCallback): self.ui.alert("Requesting services list...", False) interestName = Name(self.prefix).append("listCommands") interest = Interest(interestName) interest.setInterestLifetimeMilliseconds(3000) # self.face.makeCommandInterest(interest) self.face.expressInterest( interest, self._makeOnCommandListCallback(successCallback), self._makeOnCommandListTimeoutCallback(timeoutCallback), ) def _makeOnCommandListTimeoutCallback(self, callback): def onCommandListTimeout(interest): self.ui.alert("Timed out waiting for services list") self.loop.call_soon(callback) return onCommandListTimeout def _makeOnCommandListCallback(self, callback): def onCommandListReceived(interest, data): try: commandInfo = json.loads(str(data.getContent())) except: self.ui.alert("An error occured while reading the services list") self.loop.call_soon(self.displayMenu) else: self.foundCommands = commandInfo self.loop.call_soon(callback) return onCommandListReceived def _showCommandList(self): try: commandList = [] for capability, commands in self.foundCommands.items(): commandList.append("\Z1{}:".format(capability)) for info in commands: signingStr = "signed" if info["signed"] else "unsigned" commandList.append("\Z0\t{} ({})".format(info["name"], signingStr)) commandList.append("") if len(commandList) == 0: # should not happen commandList = ["----NONE----"] allCommands = "\n".join(commandList) oldTitle = self.ui.title self.ui.title = "Available services" self.ui.alert(allCommands, preExtra=["--colors"]) self.ui.title = oldTitle # self.ui.menu('Available services', commandList, prefix='', extras=['--no-cancel']) finally: self.loop.call_soon(self.displayMenu) ####### # New device ###### def pairDevice(self): self._scanForUnconfiguredDevices() def _enterPairingInfo(self, serial, pin="", newName=""): fields = [Dialog.FormField("PIN", pin), Dialog.FormField("Device name", newName)] (retCode, retList) = self.ui.form("Pairing device {}".format(serial), fields) if retCode == Dialog.DIALOG_OK: pin, newName = retList if len(pin) == 0 or len(newName) == 0: self.ui.alert("All fields are required") self.loop.call_soon(self._enterPairingInfo, serial, pin, newName) else: try: pinBytes = pin.decode("hex") except TypeError: self.ui.alert("Pin is invalid") self.loop.call_soon(self._enterPairingInfo, serial, pin, newName) else: self._addDeviceToNetwork(serial, newName, pin.decode("hex")) elif retCode == Dialog.DIALOG_CANCEL or retCode == Dialog.DIALOG_ESC: self.loop.call_soon(self._showConfigurationList) def _showConfigurationList(self): foundDevices = self.unconfiguredDevices[:] emptyStr = "----NONE----" if len(foundDevices) == 0: foundDevices.append(emptyStr) retCode, retStr = self.ui.menu( "Select a device to configure", foundDevices, preExtras=["--ok-label", "Configure", "--extra-button", "--extra-label", "Refresh"], ) if retCode == Dialog.DIALOG_CANCEL or retCode == Dialog.DIALOG_ESC: self.loop.call_soon(self.displayMenu) elif retCode == Dialog.DIALOG_EXTRA: self.loop.call_soon(self._scanForUnconfiguredDevices) elif retCode == Dialog.DIALOG_OK and retStr != emptyStr: self.loop.call_soon(self._enterPairingInfo, retStr) else: self.loop.call_soon(self._showConfigurationList) def _scanForUnconfiguredDevices(self): # unconfigured devices should register '/localhop/configure' # we keep asking for unconfigured devices until we stop getting replies foundDevices = [] self.ui.alert("Scanning for unconfigured devices...", False) def onDeviceTimeout(interest): # assume we're done - everyone is excluded self.unconfiguredDevices = foundDevices self.loop.call_soon(self._showConfigurationList) def onDeviceResponse(interest, data): updatedInterest = Interest(interest) deviceSerial = str(data.getContent()) if len(deviceSerial) > 0: foundDevices.append(deviceSerial) updatedInterest.getExclude().appendComponent(Name.Component(deviceSerial)) # else ignore the malformed response self.face.expressInterest(updatedInterest, onDeviceResponse, onDeviceTimeout) interest = Interest(Name("/localhop/configure")) interest.setInterestLifetimeMilliseconds(2000) self.face.expressInterest(interest, onDeviceResponse, onDeviceTimeout) def _addDeviceToNetwork(self, serial, suffix, pin): self.ui.alert("Sending pairing info to gateway...", False) # we must encrypt this so no one can see the pin! message = DevicePairingInfoMessage() message.info.deviceSuffix = suffix message.info.deviceSerial = serial message.info.devicePin = pin rawBytes = ProtobufTlv.encode(message) encryptedBytes = self._identityManager.encryptForIdentity(rawBytes, self.prefix) encodedBytes = base64.urlsafe_b64encode(str(encryptedBytes)) interestName = Name(self.prefix).append("addDevice").append(encodedBytes) interest = Interest(interestName) # todo: have the controller register this console as a listener # and update it with pairing status interest.setInterestLifetimeMilliseconds(5000) self.face.makeCommandInterest(interest) self.face.expressInterest(interest, self._onAddDeviceResponse, self._onAddDeviceTimeout) def _onAddDeviceResponse(self, interest, data): try: responseCode = int(str(data.getContent())) if responseCode == 202: self.ui.alert("Gateway received pairing info") else: self.ui.alert("Error encountered while sending pairing info") except: self.ui.alert("Exception encountered while decoding gateway reply") finally: self.loop.call_soon(self.displayMenu) def _onAddDeviceTimeout(self, interest): self.ui.alert("Timed out sending pairing info to gateway") self.loop.call_soon(self.displayMenu) ###### # Express interest ##### def expressInterest(self): if len(self.foundCommands) == 0: self._requestDeviceList(self._showInterestMenu, self._showInterestMenu) else: self.loop.call_soon(self._showInterestMenu) def _showInterestMenu(self): # display a menu of all available interests, on selection allow user to # (1) extend it # (2) send it signed/unsigned # NOTE: should it add custom ones to the list? commandSet = set() wildcard = "<Enter Interest Name>" try: for commands in self.foundCommands.values(): commandSet.update([c["name"] for c in commands]) commandList = list(commandSet) commandList.append(wildcard) (returnCode, returnStr) = self.ui.menu("Choose a command", commandList, prefix=" ") if returnCode == Dialog.DIALOG_OK: if returnStr == wildcard: returnStr = self.networkPrefix.toUri() self.loop.call_soon(self._expressCustomInterest, returnStr) else: self.loop.call_soon(self.displayMenu) except: self.loop.call_soon(self.displayMenu) def _expressCustomInterest(self, interestName): # TODO: make this a form, add timeout field try: handled = False (returnCode, returnStr) = self.ui.prompt( "Send interest", interestName, preExtra=["--extra-button", "--extra-label", "Signed", "--ok-label", "Unsigned"], ) if returnCode == Dialog.DIALOG_ESC or returnCode == Dialog.DIALOG_CANCEL: self.loop.call_soon(self.expressInterest) else: interestName = Name(returnStr) doSigned = returnCode == Dialog.DIALOG_EXTRA interest = Interest(interestName) interest.setInterestLifetimeMilliseconds(5000) interest.setChildSelector(1) interest.setMustBeFresh(True) if doSigned: self.face.makeCommandInterest(interest) self.ui.alert("Waiting for response to {}".format(interestName.toUri()), False) self.face.expressInterest(interest, self.onDataReceived, self.onInterestTimeout) except: self.loop.call_soon(self.expressInterest) def onInterestTimeout(self, interest): try: self.ui.alert("Interest timed out:\n{}".format(interest.getName().toUri())) except: self.ui.alert("Interest timed out") finally: self.loop.call_soon(self.expressInterest) def onDataReceived(self, interest, data): try: dataString = "{}\n\n".format(data.getName().toUri()) dataString += "Contents:\n{}".format(repr(data.getContent().toRawStr())) self.ui.alert(dataString) except: self.ui.alert("Exception occured displaying data contents") finally: self.loop.call_soon(self.expressInterest)
class BaseNode(object): """ This class contains methods/attributes common to both node and controller. """ def __init__(self): """ Initialize the network and security classes for the node """ super(BaseNode, self).__init__() self._identityStorage = IotIdentityStorage() self._identityManager = IotIdentityManager(self._identityStorage) self._policyManager = IotPolicyManager(self._identityStorage) # hopefully there is some private/public key pair available self._keyChain = KeyChain(self._identityManager, self._policyManager) self._registrationFailures = 0 self._prepareLogging() self._setupComplete = False self._instanceSerial = None # waiting devices register this prefix and respond to discovery # or configuration interest self._hubPrefix = Name('/localhop/configure') def getSerial(self): """ Since you may wish to run two nodes on a Raspberry Pi, each node will generate a unique serial number each time it starts up. """ if self._instanceSerial is None: prefixLen = 4 prefix = '' for i in range(prefixLen): prefix += (chr(random.randint(0, 0xff))) suffix = self.getDeviceSerial().lstrip('0') self._instanceSerial = '-'.join([prefix.encode('hex'), suffix]) return self._instanceSerial ## # Logging ## def _prepareLogging(self): self.log = logging.getLogger(str(self.__class__)) self.log.setLevel(logging.DEBUG) logFormat = "%(asctime)-15s %(name)-20s %(funcName)-20s (%(levelname)-8s):\n\t%(message)s" self._console = logging.StreamHandler() self._console.setFormatter(logging.Formatter(logFormat)) self._console.setLevel(logging.INFO) # without this, a lot of ThreadsafeFace errors get swallowed up logging.getLogger("trollius").addHandler(self._console) self.log.addHandler(self._console) def setLogLevel(self, level): """ Set the log level that will be output to standard error :param level: A log level constant defined in the logging module (e.g. logging.INFO) """ self._console.setLevel(level) def getLogger(self): """ :return: The logger associated with this node :rtype: logging.Logger """ return self.log ### # Startup and shutdown ### def beforeLoopStart(self): """ Called before the event loop starts. """ pass def getDefaultCertificateName(self): try: certName = self._identityStorage.getDefaultCertificateNameForIdentity( self._policyManager.getDeviceIdentity()) except SecurityException: certName = self._keyChain.getDefaultCertificateName() return certName def start(self): """ Begins the event loop. After this, the node's Face is set up and it can send/receive interests+data """ self.log.info("Starting up") self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, '') self.face.setCommandSigningInfo(self._keyChain, self.getDefaultCertificateName()) self._keyChain.setFace(self.face) self._isStopped = False self.face.stopWhen(lambda: self._isStopped) self.beforeLoopStart() try: self.loop.run_forever() except KeyboardInterrupt: pass except Exception as e: self.log.exception(e, exc_info=True) finally: self._isStopped = True def stop(self): """ Stops the node, taking it off the network """ self.log.info("Shutting down") self._isStopped = True ### # Data handling ### def signData(self, data): """ Sign the data with our network certificate :param pyndn.Data data: The data to sign """ self._keyChain.sign(data, self.getDefaultCertificateName()) def sendData(self, data, transport, sign=True): """ Reply to an interest with a data packet, optionally signing it. :param pyndn.Data data: The response data packet :param pyndn.Transport transport: The transport to send the data through. This is obtained from an incoming interest handler :param boolean sign: (optional, default=True) Whether the response must be signed. """ if sign: self.signData(data) transport.send(data.wireEncode().buf()) ### # # ## def onRegisterFailed(self, prefix): """ Called when the node cannot register its name with the forwarder :param pyndn.Name prefix: The network name that failed registration """ if self._registrationFailures < 5: self._registrationFailures += 1 self.log.warn("Could not register {}, retry: {}/{}".format( prefix.toUri(), self._registrationFailures, 5)) self.face.registerPrefix(self.prefix, self._onCommandReceived, self.onRegisterFailed) else: self.log.critical("Could not register device prefix, ABORTING") self._isStopped = True def verificationFailed(self, dataOrInterest): """ Called when verification of a data packet or command interest fails. :param pyndn.Data or pyndn.Interest: The packet that could not be verified """ self.log.info("Received invalid" + dataOrInterest.getName().toUri()) @staticmethod def getDeviceSerial(): """ Find and return the serial number of the Raspberry Pi. Provided in case you wish to distinguish data from nodes with the same name by serial. :return: The serial number extracted from device information in /proc/cpuinfo :rtype: str """ with open('/proc/cpuinfo') as f: for line in f: if line.startswith('Serial'): return line.split(':')[1].strip()
class LightController(): shouldSign = False COLORS_PER_LIGHT = 3 STRAND_SIZE = 50 #mengchen: let's make the lighting lits only a half every time #HALF_STRAND_SIZE = 25 def __init__(self, nStrands=1, myIP="192.168.1.1", lightIP="192.168.1.50", prefix="/testlight"): self.log = logging.getLogger("LightController") self.log.setLevel(logging.DEBUG) sh = logging.StreamHandler() sh.setLevel(logging.DEBUG) self.log.addHandler(sh) fh = logging.FileHandler("LightController.log") fh.setLevel(logging.INFO) self.log.addHandler(fh) self.payloadBuffer = [[0]*self.STRAND_SIZE*self.COLORS_PER_LIGHT for n in range(nStrands)] self.kinetsender = KinetSender(myIP, lightIP, nStrands, self.STRAND_SIZE*self.COLORS_PER_LIGHT) self.prefix = Name(prefix) self.keychain = KeyChain() self.address = "" self._isStopped = True self.lightState = False #mengchen: let's make the lighting lits only a half every time #self.uphalf = True self.HALF_STRAND_SIZE = 25 self.certificateName = self.keychain.getDefaultCertificateName() self.receiveFile = open('interestReceiveFile', 'w') def unix_time_now(self): epoch = datetime.datetime.utcfromtimestamp(0) delta = datetime.datetime.utcnow() - epoch return delta.total_seconds() * 1000.0 # XXX: we should get a thread for this or something! def start(self): self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, self.address) self.face.setCommandSigningInfo(self.keychain, self.certificateName) self.face.registerPrefix(self.prefix, self.onLightingCommand, self.onRegisterFailed) self._isStopped = False self.face.stopWhen(lambda:self._isStopped) try: self.loop.run_forever() except KeyboardInterrupt: #self.stop() #print "key interrupt in run_forever" sys.exit() finally: #print "executing finally" self.stop() def stop(self): self.loop.close() self.kinetsender.stop = True #print "before wait" #self.kinetsender.complete.set #self.kinetsender.complete.wait() self.face.shutdown() self.face = None #print "sys exit" self.receiveFile.close() sys.exit(1) def signData(self, data): if LightController.shouldSign: self.keychain.sign(data, self.certificateName) else: data.setSignature(Sha256WithRsaSignature()) def setPayloadColor(self, strand, color): # will expand this to allow the repeats, etc # if self.uphalf and not self.lightState: # self.uphalf = False # self.payloadBuffer[strand] = [int(color.r)&0xff, int(color.g)&0xff, int(color.b)&0xff]*self.HALF_STRAND_SIZE+[int(0)&0xff, int(0)&0xff, int(0)&0xff]*self.HALF_STRAND_SIZE #if not self.uphalf and self.lightState : # self.uphalf = True self.payloadBuffer[strand] = [int(color.r)&0xff, int(color.g)&0xff, int(color.b)&0xff]*self.STRAND_SIZE def onLightingCommand(self, prefix, interest, transport, prefixId): #print datetime.datetime.now() self.receiveFile.write('{0:f}'.format(self.unix_time_now()) + '\n') interestName = Name(interest.getName()) #interstname: /ndn/ucla.edu/sculptures/ai_bus/lights/setRGB/%83%0D%84%0B%87%09%89%01%04%8A%01%01%8B%01%01 #d: <pyndn.data.Data object at 0xb64825d0> print "interstname", interestName.toUri() d = Data(interest.getName()) # get the command parameters from the name try: commandComponent = interest.getName().get(prefix.size()) #print commandComponent.toEscapedString():setRGB #print "prefix ",prefix.toUri():/ndn/ucla.edu/sculpture/ai_bus/lights #print "get name",interest.getName().toUri() commandParams = interest.getName().get(prefix.size()+1) #print "commandParams ",commandParams:%83%0D%84%0B%87%09%89%01%04%8A%01%01%8B%01%01 lightingCommand = LightCommandMessage() ProtobufTlv.decode(lightingCommand, commandParams.getValue()) #self.log.info("Command: " + commandComponent.toEscapedString()) requestedColor = lightingCommand.command.pattern.colors[0] colorStr = str((requestedColor.r, requestedColor.g, requestedColor.b)) #self.log.info("Requested color: " + colorStr) self.setPayloadColor(0, requestedColor) self.lightState = not self.lightState if self.lightState: print "Off" else: print "On" #print requestedColor self.sendLightPayload(1) d.setContent("Gotcha: " + colorStr+ "\n") except KeyboardInterrupt: print "key interrupt" sys.exit(1) except Exception as e: print e d.setContent("Bad command\n") finally: d.getMetaInfo().setFinalBlockID(0) self.signData(d) encodedData = d.wireEncode() transport.send(encodedData.toBuffer()) def onRegisterFailed(self, prefix): self.log.error("Could not register " + prefix.toUri()) self.stop() def sendLightPayload(self, port): # print port # print self.payloadBuffer[port-1] self.kinetsender.setPayload(port, self.payloadBuffer[port-1])
class RegisterSongList(object): def __init__(self, prefix="/ndn/edu/ucla/remap/music/list"): logging.basicConfig() self.device = "PC1" self.deviceComponent = Name.Component(self.device) self.excludeDevice = None self.prefix = Name(prefix) self.changePrefix = Name("/ndn/edu/ucla/remap/music/storage") self.keychain = KeyChain() self.certificateName = self.keychain.getDefaultCertificateName() self.address = "" self._isStopped = True def start(self): print "reg start" self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, self.address) self.face.setCommandSigningInfo(self.keychain, self.certificateName) self.face.registerPrefix(self.prefix, self.onInterest, self.onRegisterFailed) self._isStopped = False self.face.stopWhen(lambda: self._isStopped) try: self.loop.run_forever() except KeyboardInterrupt: sys.exit() finally: self.stop() def stop(self): self.loop.close() self.face.shutdown() self.face = None sys.exit(1) def signData(self, data): data.setSignature(Sha256WithRsaSignature()) def onInterest(self, prefix, interest, transport, registeredPrefixId): print "received interest" initInterest = Name(interest.getName()) print "interest name:", initInterest.toUri() d = Data(interest.getName().append(self.deviceComponent)) try: print "start to set data's content" currentString = ','.join(currentList) d.setContent("songList of " + self.device + ":" + currentString + "\n") self.face.registerPrefix(self.changePrefix, self.onInterest, self.onRegisterFailed) except KeyboardInterrupt: print "key interrupt" sys.exit(1) except Exception as e: print e d.setContent("Bad command\n") finally: self.keychain.sign(d, self.certificateName) encodedData = d.wireEncode() transport.send(encodedData.toBuffer()) print d.getName().toUri() print d.getContent() self.loop.close() self.face.shutdown() self.face = None def onRegisterFailed(self, prefix): self.log.error("Could not register " + prefix.toUri()) self.stop()
class RepoConsumer: TIMEOUT = 100 def __init__(self, dataPrefix, interestLifetime=100, lastVersion=None, start=True): self.prefix = Name(dataPrefix) #used in the exclude to make sure we get new data only self.lastVersion = lastVersion self.face = None self.dataFormat = re.compile("\((\d+\.?\d*)\)") # data should start with a timestamp in logFormat = '%(asctime)-10s %(message)s' self.logger = logging.getLogger('RepoConsumer') self.logger.setLevel(logging.DEBUG) self.logger.addHandler(logging.StreamHandler()) fh = logging.FileHandler('repo_consumer.log', mode='w') fh.setLevel(logging.DEBUG) fh.setFormatter(logging.Formatter(logFormat)) self.logger.addHandler(fh) self.createTiming = [] self.receiveTiming = [] self.timeouts = 0 self.notReady = 0 self.lastReceivedTime = 0 self.lastCreatedTime = 0 self.backoffCounter = 0 self.interestLifetime = interestLifetime self.nextIssue = None self.loop = None self.isCancelled = False def start(self): self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, "") self.face.stopWhen(lambda:self.isCancelled) self.reissueInterest() self.loop.run_forever() def stop(self): self.loop.close() self.face.shutdown() self.loop = None self.face = None def onData(self, interest, data): now = time.time() # for now, assume there is a version appended to the interest nameLength = interest.getName().size() dataStr = data.getContent().toRawStr() try: lastComponent = data.getName().get(-1).toEscapedString() if str(lastComponent) == 'MISSING': self.notReady += 1 #self.backoffCounter += 1 logger.info('repo not ready') self.reissueInterest() return self.lastVersion = data.getName().get(nameLength) self.logger.debug(interest.getName().toUri() + ": version " + self.lastVersion.toEscapedString()) match = self.dataFormat.match(data.getContent().toRawStr()) ts = float(match.group(1)) if self.lastReceivedTime != 0 and self.lastCreatedTime != 0: self.createTiming.append(now-self.lastReceivedTime) self.receiveTiming.append(now-self.lastCreatedTime) self.lastReceivedTime = now self.lastCreatedTime = ts self.logger.debug("Created: " + str(ts) + ", received: " + str(now)) except Exception as e: self.logger.exception(str(e)) #self.backoffCounter -= 1 self.reissueInterest() def onTimeout(self, interest): self.logger.debug("timeout") self.timeouts += 1 #self.backoffCounter += 1 self.reissueInterest() def reissueInterest(self): BACKOFF_THRESHOLD = 10 if self.backoffCounter > BACKOFF_THRESHOLD: self.TIMEOUT += 50 self.backoffCounter = 0 self.logger.debug('Backing off interval to ' + str(self.TIMEOUT)) if self.backoffCounter < -BACKOFF_THRESHOLD: self.TIMEOUT -= 50 self.backoffCounter = 0 self.logger.debug('Reducing backoff interval to ' + str(self.TIMEOUT)) if self.nextIssue is not None: now = time.clock() if self.nextIssue > now: pass # time.sleep(self.nextIssue-now) interest = Interest(Name(self.prefix)) interest.setInterestLifetimeMilliseconds(self.interestLifetime) interest.setMustBeFresh(False) if self.lastVersion is not None: e = Exclude() e.appendAny() e.appendComponent(self.lastVersion) interest.setExclude(e) interest.setChildSelector(1) #rightmost == freshest self.face.expressInterest(interest, self.onData, self.onTimeout) self.nextIssue = time.clock()+self.TIMEOUT/2000 def printStats(self): # the first value may have been sitting in the repo forever, so ignore the first time timing = self.createTiming self.logger.info('***** Statistics ***** ') if len(timing) > 1: self.logger.info('{1:3.2f}/{2:3.2f}/{3:3.2f} min/mean/max delay(creation)'.format(len(timing), min(timing), mean(timing), max(timing))) timing = self.receiveTiming if len(timing) > 1: self.logger.info('{1:3.2f}/{2:3.2f}/{3:3.2f} min/mean/max delay(receipt)'.format(len(timing), min(timing), mean(timing), max(timing))) self.logger.info('{} data requests satisfied'.format(len(timing))) self.logger.info('{} timeouts'.format(self.timeouts)) self.logger.info('{} not ready responses'.format(self.notReady)) self.logger.info('*'*22)
class NdnRepoClient(object): def __init__(self, repoPrefix=None): super(NdnRepoClient, self).__init__() if repoPrefix is not None: self.repoPrefix = Name(repoPrefix) else: self.repoPrefix = Name('/test/repo') self.loadKey() self.isStopped = False self.dataReady = asyncio.Event() self.resultQueue = asyncio.Queue() self.log = logging.getLogger(str(self.__class__)) h = logging.FileHandler('repo_client.log') s = logging.StreamHandler() logFormatter = logging.Formatter( '%(asctime)-15s %(levelname)-8s %(funcName)s\n\t%(message)s') s.setFormatter(logFormatter) h.setFormatter(logFormatter) self.log.addHandler(h) self.log.addHandler(s) s.setLevel(logging.WARN) self.log.setLevel(logging.DEBUG) self.isStopped = True logging.getLogger('trollius').addHandler(h) self.knownKeys = {} self.pendingKeys = [] def loadKey(self, keyFile='bms_key.pri'): self.keyId = '\xa2\xeb9\xbcGo$\xad\xbf\xe9?k\xb2\xb8|\xa8 E\x96\x13\x1e\xb9\x97\x91Z\xf6\xda\xd1]\xa1lD' with open(keyFile, 'r') as keyFile: binDer = keyFile.read() self.privateKey = RSA.importKey(binDer) @asyncio.coroutine def _decryptAndPrintRecord(self, recordData, keyName, parentDoc): keyUri = keyName.toUri() def cleanString(dirty): return ''.join(filter(string.printable.__contains__, str(dirty))) def onKeyDataReceived(keyInterest, keyData): self.log.debug('Got key for {}'.format(keyInterest.getName())) cipherText = str(keyData.getContent()) symKeyRaw = self.privateKey.decrypt(cipherText) symKey = symKeyRaw[-64:].decode('hex') msg = recordData[8:] iv = msg[:16] cipherText = msg[16:] cipher = AES.new(key=symKey, IV=iv, mode=AES.MODE_CBC) decData = cleanString(cipher.decrypt(cipherText)) fromJson = json.loads(decData) fromJson.update(parentDoc) self.knownKeys[keyUri] = keyData try: self.pendingKeys.remove(keyUri) except ValueError: pass # already removed self.resultQueue.put_nowait(fromJson) def onKeyTimeout(keyInterest): self.log.error('Could not get decryption key for {}'.format(keyInterest.getName())) self.resultQueue.put_nowait({}) i = Interest(keyName) i.setMustBeFresh(False) i.setInterestLifetimeMilliseconds(2000) if keyUri in self.knownKeys: self.log.debug('Using known key') onKeyDataReceived(i, self.knownKeys[keyUri]) elif keyUri in self.pendingKeys: self.log.debug('Waiting on pending key') timeout = 0 while keyUri not in self.knownKeys: yield From(asyncio.sleep(0.5)) timeout += 1 if timeout > 5: self.log.warn('Timed out on key {}'.format(keyUri)) onKeyTimeout(i) break else: onKeyDataReceived(i, self.knownKeys[keyUri]) else: self.log.debug('Adding {} to pending keys'.format(keyUri)) self.pendingKeys.append(keyUri) self.keyFace.expressInterest(i, onKeyDataReceived, onKeyTimeout) def prettifyResults(self, resultsList): # dictionary comparison is by length (# of k:v pairs) allKeys = max(resultsList).keys() columnWidths = {} for k in allKeys: if k == 'ts': columnWidths[k] = len(max([(result[k]).isoformat() for result in resultsList if k in result])) else: columnWidths[k] = len(max([str(result[k]) for result in resultsList if k in result])) columnWidths[k] = max(columnWidths[k], len(k)+2) headerLen = sum(columnWidths.values())+len(k) print '-'*headerLen headers = [] for k in allKeys: headers.append('{0:^{1}}'.format(k, columnWidths[k])) print '|'+'|'.join(headers)+'|' print '-'*headerLen for result in resultsList: line = [] for k in allKeys: if k not in result: val = '' elif k == 'ts': val = result[k].isoformat() else: val = result[k] line.append('{0:^{1}}'.format(val, columnWidths[k])) print '|'+'|'.join(line)+'|' print '-'*headerLen @asyncio.coroutine def collectResults(self, allData): try: for record in allData: parentDoc = {k:v for (k,v) in record.items() if k not in [u'_id', u'value']} aDataVal = str(record[u'value']) keyTs = aDataVal[:8] keyDataName = Name('/ndn/ucla.edu/bms/melnitz/kds').append(keyTs).append(self.keyId) yield From(self._decryptAndPrintRecord(aDataVal, keyDataName, parentDoc)) receivedVals = [] try: for i in asyncio.as_completed([ self.resultQueue.get() for n in range(len(allData))], timeout=5): v = yield From(i) receivedVals.append(v) except asyncio.TimeoutError: pass self.prettifyResults(receivedVals) print finally: self.dataReady.set() def onDataReceived(self, interest, data): # now we have to retrieve the key dataContent = str(data.getContent()) dataContent = BSON(dataContent) dataDict = dataContent.decode() allData = dataDict['results'] totalCount = dataDict['count'] dataCount = len(allData) skipPos = dataDict['skip'] print '---------' print 'Got {}/{} result(s), starting at {}'.format(dataCount, totalCount, skipPos) asyncio.async(self.collectResults(allData)) def onDataTimeout(self, interest): self.log.warn("Timed out on {}".format(interest.toUri())) self.dataReady.set() def sendDataRequestCommand(self, dataName): interest = Interest(dataName) interest.setInterestLifetimeMilliseconds(4000) self.face.expressInterest(interest, self.onDataReceived, self.onDataTimeout) return interest def stop(self): self.isStopped = True def parseSqlSelect(self, statement): statement = statement.strip() queryDict = {} try: selection, parts = re.split(r'\s+WHERE\s+', statement, flags=re.I) except ValueError: print 'WHERE clause is missing' return None selectMatch = re.match(r'^SELECT\s+(?:(\*)|(\w+,(\s*\w+)*))', selection, flags=re.I) if selectMatch is None: print 'Malformed SELECT' return None expressions = re.split(r'\s+AND\s+', parts, flags=re.I) for ex in expressions: if len(ex) == 0: continue try: k,v = ex.split('=') except ValueError: print 'Malformed WHERE clause {}'.format(ex) else: queryDict[k.strip()] = v.strip() return queryDict # get = pairs def assembleDataName(self): schemaStr = ('/ndn/ucla.edu/bms/{building}/data/{room}/electrical/panel/{panel_name}/{quantity}/{data_type}') keyNames = ['building', 'room', 'panel_name', 'quantity', 'data_type'] sqlStatement = raw_input('Query> ').strip() valueDict = self.parseSqlSelect(sqlStatement) if valueDict is None: return None for k in keyNames: valueDict.setdefault(k, '_') dataName = schemaStr.format(**valueDict) return Name(dataName) @asyncio.coroutine def parseDataRequest(self): while True: self.dataReady.clear() dataName = self.assembleDataName() if dataName is not None: self.loop.call_soon(self.sendDataRequestCommand, dataName) yield From(self.dataReady.wait()) def start(self): self.isStopped = False self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, '') self.keyFace = ThreadsafeFace(self.loop, 'borges.metwi.ucla.edu') self.face.stopWhen(lambda:self.isStopped) self.keyFace.stopWhen(lambda:self.isStopped) k = KeyChain() self.face.setCommandSigningInfo(k, k.getDefaultCertificateName()) try: self.loop.run_until_complete(self.parseDataRequest()) except (EOFError, KeyboardInterrupt): pass finally: self.face.shutdown()
class IotConsole(object): """ This uses the controller's credentials to provide a management interface to the user. It does not go through the security handshake (as it should be run on the same device as the controller) and so does not inherit from the BaseNode. """ def __init__(self, networkName, nodeName): super(IotConsole, self).__init__() self.deviceSuffix = Name(nodeName) self.networkPrefix = Name(networkName) self.prefix = Name(self.networkPrefix).append(self.deviceSuffix) self._identityStorage = IotIdentityStorage() self._policyManager = IotPolicyManager(self._identityStorage) self._identityManager = IotIdentityManager(self._identityStorage) self._keyChain = KeyChain(self._identityManager, self._policyManager) self._policyManager.setEnvironmentPrefix(self.networkPrefix) self._policyManager.setTrustRootIdentity(self.prefix) self._policyManager.setDeviceIdentity(self.prefix) self._policyManager.updateTrustRules() self.foundCommands = {} self.unconfiguredDevices = [] # TODO: use xDialog in XWindows self.ui = Dialog(backtitle='NDN IoT User Console', height=18, width=78) trolliusLogger = logging.getLogger('trollius') trolliusLogger.addHandler(logging.StreamHandler()) def start(self): """ Start up the UI """ self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop, '') controllerCertificateName = self._identityStorage.getDefaultCertificateNameForIdentity( self.prefix) self.face.setCommandSigningInfo(self._keyChain, controllerCertificateName) self._keyChain.setFace( self.face) # shouldn't be necessarym but doesn't hurt self._isStopped = False self.face.stopWhen(lambda: self._isStopped) self.loop.call_soon(self.displayMenu) try: self.loop.run_forever() except KeyboardInterrupt: pass except Exception as e: print(e) #self.log('Exception', e) finally: self._isStopped = True def stop(self): self._isStopped = True ####### # GUI ####### def displayMenu(self): menuOptions = OrderedDict([('List network services', self.listCommands), ('Pair a device', self.pairDevice), ('Express interest', self.expressInterest), ('Quit', self.stop)]) (retCode, retStr) = self.ui.mainMenu('Main Menu', menuOptions.keys()) if retCode == Dialog.DIALOG_ESC or retCode == Dialog.DIALOG_CANCEL: # TODO: ask if you're sure you want to quit self.stop() if retCode == Dialog.DIALOG_OK: menuOptions[retStr]() ####### # List all commands ###### def listCommands(self): self._requestDeviceList(self._showCommandList, self.displayMenu) def _requestDeviceList(self, successCallback, timeoutCallback): self.ui.alert('Requesting services list...', False) interestName = Name(self.prefix).append('listCommands') interest = Interest(interestName) interest.setInterestLifetimeMilliseconds(3000) #self.face.makeCommandInterest(interest) self.face.expressInterest( interest, self._makeOnCommandListCallback(successCallback), self._makeOnCommandListTimeoutCallback(timeoutCallback)) def _makeOnCommandListTimeoutCallback(self, callback): def onCommandListTimeout(interest): self.ui.alert('Timed out waiting for services list') self.loop.call_soon(callback) return onCommandListTimeout def _makeOnCommandListCallback(self, callback): def onCommandListReceived(interest, data): try: commandInfo = json.loads(str(data.getContent())) except: self.ui.alert( 'An error occured while reading the services list') self.loop.call_soon(self.displayMenu) else: self.foundCommands = commandInfo self.loop.call_soon(callback) return onCommandListReceived def _showCommandList(self): try: commandList = [] for capability, commands in self.foundCommands.items(): commandList.append('\Z1{}:'.format(capability)) for info in commands: signingStr = 'signed' if info['signed'] else 'unsigned' commandList.append('\Z0\t{} ({})'.format( info['name'], signingStr)) commandList.append('') if len(commandList) == 0: # should not happen commandList = ['----NONE----'] allCommands = '\n'.join(commandList) oldTitle = self.ui.title self.ui.title = 'Available services' self.ui.alert(allCommands, preExtra=['--colors']) self.ui.title = oldTitle #self.ui.menu('Available services', commandList, prefix='', extras=['--no-cancel']) finally: self.loop.call_soon(self.displayMenu) ####### # New device ###### def pairDevice(self): self._scanForUnconfiguredDevices() def _enterPairingInfo(self, serial, pin='', newName=''): fields = [ Dialog.FormField('PIN', pin), Dialog.FormField('Device name', newName) ] (retCode, retList) = self.ui.form('Pairing device {}'.format(serial), fields) if retCode == Dialog.DIALOG_OK: pin, newName = retList if len(pin) == 0 or len(newName) == 0: self.ui.alert('All fields are required') self.loop.call_soon(self._enterPairingInfo, serial, pin, newName) else: try: pinBytes = pin.decode('hex') except TypeError: self.ui.alert('Pin is invalid') self.loop.call_soon(self._enterPairingInfo, serial, pin, newName) else: self._addDeviceToNetwork(serial, newName, pin.decode('hex')) elif retCode == Dialog.DIALOG_CANCEL or retCode == Dialog.DIALOG_ESC: self.loop.call_soon(self._showConfigurationList) def _showConfigurationList(self): foundDevices = self.unconfiguredDevices[:] emptyStr = '----NONE----' if len(foundDevices) == 0: foundDevices.append(emptyStr) retCode, retStr = self.ui.menu('Select a device to configure', foundDevices, preExtras=[ '--ok-label', 'Configure', '--extra-button', '--extra-label', 'Refresh' ]) if retCode == Dialog.DIALOG_CANCEL or retCode == Dialog.DIALOG_ESC: self.loop.call_soon(self.displayMenu) elif retCode == Dialog.DIALOG_EXTRA: self.loop.call_soon(self._scanForUnconfiguredDevices) elif retCode == Dialog.DIALOG_OK and retStr != emptyStr: self.loop.call_soon(self._enterPairingInfo, retStr) else: self.loop.call_soon(self._showConfigurationList) def _scanForUnconfiguredDevices(self): # unconfigured devices should register '/localhop/configure' # we keep asking for unconfigured devices until we stop getting replies foundDevices = [] self.ui.alert('Scanning for unconfigured devices...', False) def onDeviceTimeout(interest): # assume we're done - everyone is excluded self.unconfiguredDevices = foundDevices self.loop.call_soon(self._showConfigurationList) def onDeviceResponse(interest, data): updatedInterest = Interest(interest) deviceSerial = str(data.getContent()) if len(deviceSerial) > 0: foundDevices.append(deviceSerial) updatedInterest.getExclude().appendComponent( Name.Component(deviceSerial)) # else ignore the malformed response self.face.expressInterest(updatedInterest, onDeviceResponse, onDeviceTimeout) interest = Interest(Name('/localhop/configure')) interest.setInterestLifetimeMilliseconds(2000) self.face.expressInterest(interest, onDeviceResponse, onDeviceTimeout) def _addDeviceToNetwork(self, serial, suffix, pin): self.ui.alert('Sending pairing info to gateway...', False) # we must encrypt this so no one can see the pin! message = DevicePairingInfoMessage() message.info.deviceSuffix = suffix message.info.deviceSerial = serial message.info.devicePin = pin rawBytes = ProtobufTlv.encode(message) encryptedBytes = self._identityManager.encryptForIdentity( rawBytes, self.prefix) encodedBytes = base64.urlsafe_b64encode(str(encryptedBytes)) interestName = Name( self.prefix).append('addDevice').append(encodedBytes) interest = Interest(interestName) # todo: have the controller register this console as a listener # and update it with pairing status interest.setInterestLifetimeMilliseconds(5000) self.face.makeCommandInterest(interest) self.face.expressInterest(interest, self._onAddDeviceResponse, self._onAddDeviceTimeout) def _onAddDeviceResponse(self, interest, data): try: responseCode = int(str(data.getContent())) if responseCode == 202: self.ui.alert('Gateway received pairing info') else: self.ui.alert('Error encountered while sending pairing info') except: self.ui.alert('Exception encountered while decoding gateway reply') finally: self.loop.call_soon(self.displayMenu) def _onAddDeviceTimeout(self, interest): self.ui.alert('Timed out sending pairing info to gateway') self.loop.call_soon(self.displayMenu) ###### # Express interest ##### def expressInterest(self): if len(self.foundCommands) == 0: self._requestDeviceList(self._showInterestMenu, self._showInterestMenu) else: self.loop.call_soon(self._showInterestMenu) def _showInterestMenu(self): # display a menu of all available interests, on selection allow user to # (1) extend it # (2) send it signed/unsigned # NOTE: should it add custom ones to the list? commandSet = set() wildcard = '<Enter Interest Name>' try: for commands in self.foundCommands.values(): commandSet.update([c['name'] for c in commands]) commandList = list(commandSet) commandList.append(wildcard) (returnCode, returnStr) = self.ui.menu('Choose a command', commandList, prefix=' ') if returnCode == Dialog.DIALOG_OK: if returnStr == wildcard: returnStr = self.networkPrefix.toUri() self.loop.call_soon(self._expressCustomInterest, returnStr) else: self.loop.call_soon(self.displayMenu) except: self.loop.call_soon(self.displayMenu) def _expressCustomInterest(self, interestName): #TODO: make this a form, add timeout field try: handled = False (returnCode, returnStr) = self.ui.prompt('Send interest', interestName, preExtra=[ '--extra-button', '--extra-label', 'Signed', '--ok-label', 'Unsigned' ]) if returnCode == Dialog.DIALOG_ESC or returnCode == Dialog.DIALOG_CANCEL: self.loop.call_soon(self.expressInterest) else: interestName = Name(returnStr) doSigned = (returnCode == Dialog.DIALOG_EXTRA) interest = Interest(interestName) interest.setInterestLifetimeMilliseconds(5000) interest.setChildSelector(1) interest.setMustBeFresh(True) if (doSigned): self.face.makeCommandInterest(interest) self.ui.alert( 'Waiting for response to {}'.format(interestName.toUri()), False) self.face.expressInterest(interest, self.onDataReceived, self.onInterestTimeout) except: self.loop.call_soon(self.expressInterest) def onInterestTimeout(self, interest): try: self.ui.alert('Interest timed out:\n{}'.format( interest.getName().toUri())) except: self.ui.alert('Interest timed out') finally: self.loop.call_soon(self.expressInterest) def onDataReceived(self, interest, data): try: dataString = '{}\n\n'.format(data.getName().toUri()) dataString += 'Contents:\n{}'.format( repr(data.getContent().toRawStr())) self.ui.alert(dataString) except: self.ui.alert('Exception occured displaying data contents') finally: self.loop.call_soon(self.expressInterest)
class NdnRepoPing(object): """ A repo is supposed to be notified of new data by the publisher. Since the publisher doesn't know about this repo, I will 'manually' poke the repo to insert data points. """ def __init__(self, repoPrefix=None): super(NdnRepoPing, self).__init__() if repoPrefix is not None: self.repoPrefix = repoPrefix else: self.repoPrefix = Name('/test/repo') self.repoWatchNames = [] self.log = logging.getLogger(str(self.__class__)) h = logging.FileHandler('repo_ping.log') h.setFormatter(logging.Formatter( '%(asctime)-15s %(levelname)-8s %(funcName)s\n\t%(message)s')) self.log.addHandler(h) self.log.setLevel(logging.DEBUG) self.isStopped = True logging.getLogger('trollius').addHandler(h) def onDataReceived(self, interest, data): self.log.debug('Response to {}'.format(interest.getName())) responseMessage = RepoCommandResponseMessage() ProtobufTlv.decode(responseMessage, data.getContent()) self.log.debug('Status code: {}'.format( responseMessage.response.status_code)) def onTimeout(self, interest): self.log.info('Timed out on {}'.format(interest.getName())) def sendRepoInsertCommand(self, dataName): self.log.debug('Sending insert command for {}'.format(dataName)) commandMessage = RepoCommandParameterMessage() command = commandMessage.command for component in dataName: command.name.components.append(str(component.getValue())) command.start_block_id = command.end_block_id = 0 commandComponent = ProtobufTlv.encode(commandMessage) interestName = Name(self.repoPrefix).append('insert') interestName.append(commandComponent) interest = Interest(interestName) interest.setInterestLifetimeMilliseconds(4000) self.face.makeCommandInterest(interest) self.face.expressInterest(interest, self.onDataReceived, self.onTimeout) @asyncio.coroutine def sendNextInsertRequest(self): sleepTime = 60*15 while True: for name in self.repoWatchNames: self.sendRepoInsertCommand(name) yield From(asyncio.sleep(sleepTime)) def start(self): self.isStopped = False self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.face = ThreadsafeFace(self.loop, '') k = KeyChain() self.face.setCommandSigningInfo(k, k.getDefaultCertificateName()) self.face.stopWhen(lambda:self.isStopped) try: self.loop.run_until_complete(self.sendNextInsertRequest()) finally: self.face.shutdown() def stop(self): self.isStopped = True def addWatchName(self, newName): if newName not in self.repoWatchNames: self.repoWatchNames.append(Name(newName))
class RegisterSongList(object): def __init__(self, prefix="/ndn/edu/ucla/remap/music/list"): logging.basicConfig() self.device = "PC1" self.deviceComponent = Name.Component(self.device) self.excludeDevice = None self.prefix = Name(prefix) self.changePrefix = Name("/ndn/edu/ucla/remap/music/storage") self.keychain = KeyChain() self.certificateName = self.keychain.getDefaultCertificateName() self.address = "" self._isStopped = True def start(self): print "reg start" self.loop = asyncio.get_event_loop() self.face = ThreadsafeFace(self.loop,self.address) self.face.setCommandSigningInfo(self.keychain,self.certificateName) self.face.registerPrefix(self.prefix,self.onInterest,self.onRegisterFailed) self._isStopped = False self.face.stopWhen(lambda:self._isStopped) try: self.loop.run_forever() except KeyboardInterrupt: sys.exit() finally: self.stop() def stop(self): self.loop.close() self.face.shutdown() self.face = None sys.exit(1) def signData(self,data): data.setSignature(Sha256WithRsaSignature()) def onInterest(self, prefix, interest, transport, registeredPrefixId): print "received interest" initInterest = Name(interest.getName()) print "interest name:",initInterest.toUri() d = Data(interest.getName().append(self.deviceComponent)) try: print "start to set data's content" currentString = ','.join(currentList) d.setContent("songList of " +self.device+":"+currentString+ "\n") self.face.registerPrefix(self.changePrefix,self.onInterest,self.onRegisterFailed) except KeyboardInterrupt: print "key interrupt" sys.exit(1) except Exception as e: print e d.setContent("Bad command\n") finally: self.keychain.sign(d,self.certificateName) encodedData = d.wireEncode() transport.send(encodedData.toBuffer()) print d.getName().toUri() print d.getContent() self.loop.close() self.face.shutdown() self.face = None def onRegisterFailed(self, prefix): self.log.error("Could not register " + prefix.toUri()) self.stop()