def __init__(self, arg1 = None, arg2 = None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. tryFilePath = "/var/run/nfd.sock" # Use listdir because isfile doesn't see socket file types. if (os.path.basename(tryFilePath) in os.listdir(os.path.dirname(tryFilePath))): filePath = tryFilePath else: tryFilePath = "/tmp/.ndnd.sock" if (os.path.basename(tryFilePath) in os.listdir(os.path.dirname(tryFilePath))): filePath = tryFilePath if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name()
def __init__(self, arg1, arg2 = None): if type(arg1) is str: transport = TcpTransport() connectionInfo = TcpTransport.ConnectionInfo( arg1, arg2 if type(arg2) is int else 6363) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo)
def __init__(self, arg1=None, arg2=None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. filePath = self._getUnixSocketFilePathForLocalhost() if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name()
def putNack(self, interest, networkNack): """ Override to use the event loop given to the constructor to schedule putData to be called in a thread-safe manner. See Face.putData for calling details. """ # Check the encoding size here so that the error message happens before # dispatch. encoding = Node._encodeLpNack(interest, networkNack) if encoding.size() > self.getMaxNdnPacketSize(): raise RuntimeError( "The encoded Nack packet size exceeds the maximum limit getMaxNdnPacketSize()" ) self._loop.call_soon_threadsafe( super(ThreadsafeFace, self).putNack, interest, networkNack)
def nfdRegisterPrefix(self, registeredPrefixId, prefix, onInterest, onRegisterFailed, onRegisterSuccess, flags, commandKeyChain, commandCertificateName, face): """ Do the work of registerPrefix to register with NFD. :param int registeredPrefixId: The getNextEntryId() which registerPrefix got so it could return it to the caller. If this is 0, then don't add to _registeredPrefixTable (assuming it has already been done). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo." ) if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo." ) controlParameters = ControlParameters() controlParameters.setName(prefix) controlParameters.setForwardingFlags(flags) controlParameters.setOrigin(65) commandInterest = Interest() if self.isLocal(): commandInterest.setName(Name("/localhost/nfd/rib/register")) # The interest is answered by the local host, so set a short timeout. commandInterest.setInterestLifetimeMilliseconds(2000.0) else: commandInterest.setName(Name("/localhop/nfd/rib/register")) # The host is remote, so set a longer timeout. commandInterest.setInterestLifetimeMilliseconds(4000.0) # NFD only accepts TlvWireFormat packets. commandInterest.getName().append( controlParameters.wireEncode(TlvWireFormat.get())) self.makeCommandInterest(commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) # Send the registration interest. response = Node._RegisterResponse(prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId, self, onInterest, face) self.expressInterest(self.getNextEntryId(), commandInterest, response.onData, response.onTimeout, None, TlvWireFormat.get(), face)
def __init__(self, arg1 = None, arg2 = None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. filePath = self._getUnixSocketFilePathForLocalhost() if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name()
class Face(object): """ Create a new Face for communication with an NDN hub. This constructor has the forms Face(), Face(transport, connectionInfo) or Face(host, port). If the default Face() constructor is used, if the forwarder's Unix socket file exists then connect using UnixTransport, otherwise connect to "localhost" on port 6363 using TcpTransport. :param Transport transport: An object of a subclass of Transport used for communication. :param Transport.ConnectionInfo connectionInfo: An object of a subclass of Transport.ConnectionInfo to be used to connect to the transport. :param str host: In the Face(host, port) form of the constructor, host is the host of the NDN hub to connect using TcpTransport. :param int port: (optional) In the Face(host, port) form of the constructor, port is the port of the NDN hub. If omitted. use 6363. """ def __init__(self, arg1=None, arg2=None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. filePath = self._getUnixSocketFilePathForLocalhost() if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name() def expressInterest(self, interestOrName, arg2, arg3=None, arg4=None, arg5=None, arg6=None): """ Send the Interest through the transport, read the entire response and call onData, onTimeout or onNetworkNack as described below. There are two forms of expressInterest. The first form takes the exact interest (including lifetime): expressInterest(interest, onData [, onTimeout] [, onNetworkNack] [, wireFormat]). The second form creates the interest from a name and optional interest template: expressInterest(name [, interestTemplate], onData [, onTimeout] [, onNetworkNack] [, wireFormat]). :param Interest interest: The Interest (if the first form is used). This copies the Interest. :param Name name: A name for the Interest (if the second form is used). :param Interest interestTemplate: (optional) if not None, copy interest selectors from the template (if the second form is used). If omitted, use a default interest lifetime. :param onData: When a matching data packet is received, this calls onData(interest, data) where interest is the interest given to expressInterest and data is the received Data object. NOTE: You must not change the interest object - if you need to change it then make a copy. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onData: function object :param onTimeout: (optional) If the interest times out according to the interest lifetime, this calls onTimeout(interest) where interest is the interest given to expressInterest. However, if onTimeout is None or omitted, this does not use it. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onTimeout: function object :param onNetworkNack: (optional) When a network Nack packet for the interest is received and onNetworkNack is not None, this calls onNetworkNack(interest, networkNack) and does not call onTimeout. interest is the sent Interest and networkNack is the received NetworkNack. If onNetworkNack is supplied, then onTimeout must be supplied too. However, if a network Nack is received and onNetworkNack is null, do nothing and wait for the interest to time out. (Therefore, an application which does not yet process a network Nack reason treats a Nack the same as a timeout.) NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onNetworkNack: function object :param wireFormat: (optional) A WireFormat object used to encode the message. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :return: The pending interest ID which can be used with removePendingInterest. :rtype: int :throws: RuntimeError If the encoded interest size exceeds Face.getMaxNdnPacketSize(). """ args = self._getExpressInterestArgs(interestOrName, arg2, arg3, arg4, arg5, arg6) self._node.expressInterest(args['pendingInterestId'], args['interestCopy'], args['onData'], args['onTimeout'], args['onNetworkNack'], args['wireFormat'], self) return args['pendingInterestId'] def _getExpressInterestArgs(self, interestOrName, arg2, arg3, arg4, arg5, arg6): """ This is a protected helper method to resolve the different overloaded forms of Face.expressInterest and return the arguments to pass to Node.expressInterest. This is necessary to prepare arguments such as interestCopy before dispatching to Node.expressInterest. :return: A dictionary with the following keys: 'pendingInterestId', 'interestCopy', 'onData', 'onTimeout', 'onNetworkNack' and 'wireFormat'. :rtype: dict """ if type(interestOrName) is Interest: # Node.expressInterest requires a copy of the interest. interestCopy = Interest(interestOrName) else: # The first argument is a name. Make the interest from the name and # possible template. if type(arg2) is Interest: template = arg2 # Copy the template. interestCopy = Interest(template) interestCopy.setName(interestOrName) # Shift the remaining args to be processed below. arg2 = arg3 arg3 = arg4 arg4 = arg5 arg5 = arg6 else: # No template. interestCopy = Interest(interestOrName) # Set a default interest lifetime. interestCopy.setInterestLifetimeMilliseconds(4000.0) onData = arg2 # arg3, arg4, arg5 may be: # OnTimeout, OnNetworkNack, WireFormat # OnTimeout, OnNetworkNack, None # OnTimeout, WireFormat, None # OnTimeout, None, None # WireFormat, None, None # None, None, None if isinstance(arg3, collections.Callable): onTimeout = arg3 else: onTimeout = None if isinstance(arg4, collections.Callable): onNetworkNack = arg4 else: onNetworkNack = None if isinstance(arg3, WireFormat): wireFormat = arg3 elif isinstance(arg4, WireFormat): wireFormat = arg4 elif isinstance(arg5, WireFormat): wireFormat = arg5 else: wireFormat = WireFormat.getDefaultWireFormat() return { 'pendingInterestId': self._node.getNextEntryId(), 'interestCopy': interestCopy, 'onData': onData, 'onTimeout': onTimeout, 'onNetworkNack': onNetworkNack, 'wireFormat': wireFormat } def removePendingInterest(self, pendingInterestId): """ Remove the pending interest entry with the pendingInterestId from the pending interest table. This does not affect another pending interest with a different pendingInterestId, even if it has the same interest name. If there is no entry with the pendingInterestId, do nothing. :param int pendingInterestId: The ID returned from expressInterest. """ self._node.removePendingInterest(pendingInterestId) def setCommandSigningInfo(self, keyChain, certificateName): """ Set the KeyChain and certificate name used to sign command interests (e.g. for registerPrefix). :param KeyChain keyChain: The KeyChain object for signing interests, which must remain valid for the life of this Face. You must create the KeyChain object and pass it in. You can create a default KeyChain for your system with the default KeyChain constructor. :param Name certificateName: The certificate name for signing interests. This makes a copy of the Name. You can get the default certificate name with keyChain.getDefaultCertificateName() . """ self._commandKeyChain = keyChain self._commandCertificateName = Name(certificateName) def setCommandCertificateName(self, certificateName): """ Set the certificate name used to sign command interest (e.g. for registerPrefix), using the KeyChain that was set with setCommandSigningInfo. :param Name certificateName: The certificate name for signing interest. This makes a copy of the Name. """ self._commandCertificateName = Name(certificateName) def makeCommandInterest(self, interest, wireFormat=None): """ Append a timestamp component and a random value component to interest's name. Then use the keyChain and certificateName from setCommandSigningInfo to sign the interest. If the interest lifetime is not set, this sets it. :note: This method is an experimental feature. See the API docs for more detail at http://named-data.net/doc/ndn-ccl-api/face.html#face-makecommandinterest-method . :param Interest interest: The interest whose name is appended with components. :param wireFormat: (optional) A WireFormat object used to encode the SignatureInfo and to encode the interest name for signing. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._node.makeCommandInterest(interest, self._commandKeyChain, self._commandCertificateName, wireFormat) def registerPrefix(self, prefix, onInterest, onRegisterFailed, onRegisterSuccess=None, flags=None, wireFormat=None): """ Register prefix with the connected NDN hub and call onInterest when a matching interest is received. To register a prefix with NFD, you must first call setCommandSigningInfo. :param Name prefix: The Name for the prefix to register. This copies the Name. :param onInterest: If not None, this creates an interest filter from prefix so that when an Interest is received which matches the filter, this calls onInterest(prefix, interest, face, interestFilterId, filter). NOTE: You must not change the prefix or filter objects - if you need to change them then make a copy. If onInterest is None, it is ignored and you must call setInterestFilter. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onInterest: function object :param onRegisterFailed: If register prefix fails for any reason, this calls onRegisterFailed(prefix). NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onRegisterFailed: function object :param onRegisterSuccess: (optional) This calls onRegisterSuccess(prefix, registeredPrefixId) when this receives a success message from the forwarder. If onRegisterSuccess is None or omitted, this does not use it. (The onRegisterSuccess parameter comes after onRegisterFailed because it can be None or omitted, unlike onRegisterFailed.) NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onRegisterSuccess: function object :param ForwardingFlags flags: (optional) The flags for finer control of which interests are forwardedto the application. :param wireFormat: (optional) A WireFormat object used to encode this ControlParameters. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :raises: This raises an exception if setCommandSigningInfo has not been called to set the KeyChain, etc. for signing the command interest. """ registeredPrefixId = self._node.getNextEntryId() # Node.registerPrefix requires a copy of the prefix. self._registerPrefixHelper(registeredPrefixId, Name(prefix), onInterest, onRegisterFailed, onRegisterSuccess, flags, wireFormat) return registeredPrefixId def _registerPrefixHelper(self, registeredPrefixId, prefixCopy, onInterest, onRegisterFailed, arg5=None, arg6=None, arg7=None): """ This is a protected helper method to do the work of registerPrefix to resolve the different overloaded forms. The registeredPrefixId is from getNextEntryId(). This has no return value and can be used in a callback. """ # arg5, arg6, arg7 may be: # OnRegisterSuccess, ForwardingFlags, WireFormat # OnRegisterSuccess, ForwardingFlags, None # OnRegisterSuccess, WireFormat, None # OnRegisterSuccess, None, None # ForwardingFlags, WireFormat, None # ForwardingFlags, None, None # WireFormat, None, None # None, None, None if isinstance(arg5, collections.Callable): onRegisterSuccess = arg5 else: onRegisterSuccess = None if isinstance(arg5, ForwardingFlags): flags = arg5 elif isinstance(arg6, ForwardingFlags): flags = arg6 else: flags = ForwardingFlags() if isinstance(arg5, WireFormat): wireFormat = arg5 elif isinstance(arg6, WireFormat): wireFormat = arg6 elif isinstance(arg7, WireFormat): wireFormat = arg7 else: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() return self._node.registerPrefix(registeredPrefixId, prefixCopy, onInterest, onRegisterFailed, onRegisterSuccess, flags, wireFormat, self._commandKeyChain, self._commandCertificateName, self) def removeRegisteredPrefix(self, registeredPrefixId): """ Remove the registered prefix entry with the registeredPrefixId from the registered prefix table. This does not affect another registered prefix with a different registeredPrefixId, even if it has the same prefix name. If there is no entry with the registeredPrefixId, do nothing. :param int registeredPrefixId: The ID returned from registerPrefix. """ self._node.removeRegisteredPrefix(registeredPrefixId) def setInterestFilter(self, filterOrPrefix, onInterest): """ Add an entry to the local interest filter table to call the onInterest callback for a matching incoming Interest. This method only modifies the library's local callback table and does not register the prefix with the forwarder. It will always succeed. To register a prefix with the forwarder, use registerPrefix. There are two forms of setInterestFilter. The first form uses the exact given InterestFilter: setInterestFilter(filter, onInterest). The second form creates an InterestFilter from the given prefix Name: setInterestFilter(prefix, onInterest). :param InterestFilter filter: The InterestFilter with a prefix and optional regex filter used to match the name of an incoming Interest. This makes a copy of filter. :param Name prefix: The Name prefix used to match the name of an incoming Interest. This makes a copy of the Name. :param onInterest: When an Interest is received which matches the filter, this calls onInterest(prefix, interest, face, interestFilterId, filter). NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onInterest: function object :return: The interest filter ID which can be used with unsetInterestFilter. :rtype: int """ interestFilterId = self._node.getNextEntryId() # If filterOrPrefix is already an InterestFilter, the InterestFilter # constructor will make a copy as required by Node.setInterestFilter. filterCopy = InterestFilter(filterOrPrefix) self._node.setInterestFilter(interestFilterId, filterCopy, onInterest, self) return interestFilterId def unsetInterestFilter(self, interestFilterId): """ Remove the interest filter entry which has the interestFilterId from the interest filter table. This does not affect another interest filter with a different interestFilterId, even if it has the same prefix name. If there is no entry with the interestFilterId, do nothing. :param int interestFilterId: The ID returned from setInterestFilter. """ self._node.unsetInterestFilter(interestFilterId) def putData(self, data, wireFormat=None): """ The OnInterest callback calls this to put a Data packet which satisfies an Interest. :param Data data: The Data packet which satisfies the interest. :param WireFormat wireFormat: (optional) A WireFormat object used to encode the Data packet. If omitted, use WireFormat.getDefaultWireFormat(). :throws: RuntimeError If the encoded Data packet size exceeds getMaxNdnPacketSize(). """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() # We get the encoding now before calling send because it may dispatch to # asyncio to be called later, and the caller may modify data before then. encoding = data.wireEncode(wireFormat) if encoding.size() > self.getMaxNdnPacketSize(): raise RuntimeError( "The encoded Data packet size exceeds the maximum limit getMaxNdnPacketSize()" ) self.send(encoding) def send(self, encoding): """ Send the encoded packet out through the face. :param encoding: The blob or array with the the encoded packet to send. :type encoding: Blob or an array type with int elements :throws: RuntimeError If the packet size exceeds getMaxNdnPacketSize(). """ # If encoding is a Blob, get its buf(). encodingBuffer = encoding.buf() if isinstance(encoding, Blob) else encoding self._node.send(encodingBuffer) def processEvents(self): """ Process any packets to receive and call callbacks such as onData, onInterest or onTimeout. This returns immediately if there is no data to receive. This blocks while calling the callbacks. You should repeatedly call this from an event loop, with calls to sleep as needed so that the loop doesn't use 100% of the CPU. Since processEvents modifies the pending interest table, your application should make sure that it calls processEvents in the same thread as expressInterest (which also modifies the pending interest table). :raises: This may raise an exception for reading data or in the callback for processing the data. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ # Just call Node's processEvents. self._node.processEvents() def isLocal(self): """ Check if the face is local based on the current connection through the Transport; some Transport may cause network I/O (e.g. an IP host name lookup). :return: True if the face is local, false if not. :rtype bool: """ return self._node.isLocal() def shutdown(self): """ Shut down and disconnect this Face. """ self._node.shutdown() @staticmethod def getMaxNdnPacketSize(): """ Get the practical limit of the size of a network-layer packet. If a packet is larger than this, the library or application MAY drop it. :return: The maximum NDN packet size. :rtype: int """ return Common.MAX_NDN_PACKET_SIZE def callLater(self, delayMilliseconds, callback): """ Call callback() after the given delay. Even though this is public, it is not part of the public API of Face.This default implementation just calls Node.callLater, but a subclass can override. :param float delayMilliseconds: The delay in milliseconds. :param callback: This calls callback() after the delay. :type callback: function object """ self._node.callLater(delayMilliseconds, callback) @staticmethod def _getUnixSocketFilePathForLocalhost(): """ If the forwarder's Unix socket file path exists, then return the file path. Otherwise return an empty string. :return: The Unix socket file path to use, or an empty string. :rtype: str """ filePath = "/var/run/nfd.sock" # Use listdir because isfile doesn't see socket file types. if (os.path.basename(filePath) in os.listdir(os.path.dirname(filePath))): return filePath else: filePath = "/tmp/.ndnd.sock" if (os.path.basename(filePath) in os.listdir(os.path.dirname(filePath))): return filePath else: return ""
class Face(object): """ Create a new Face for communication with an NDN hub. This constructor has the forms Face(), Face(transport, connectionInfo) or Face(host, port). If the default Face() constructor is used, if the forwarder's Unix socket file exists then connect using UnixTransport, otherwise connect to "localhost" on port 6363 using TcpTransport. :param Transport transport: An object of a subclass of Transport used for communication. :param Transport.ConnectionInfo connectionInfo: An object of a subclass of Transport.ConnectionInfo to be used to connect to the transport. :param str host: In the Face(host, port) form of the constructor, host is the host of the NDN hub to connect using TcpTransport. :param int port: (optional) In the Face(host, port) form of the constructor, port is the port of the NDN hub. If omitted. use 6363. """ def __init__(self, arg1 = None, arg2 = None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. filePath = self._getUnixSocketFilePathForLocalhost() if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name() def setInterestLoopbackEnabled(self, interestLoopbackEnabled): """ Enable or disable Interest loopback. If Interest loopback is enabled, then an Interest to expressInterest is also sent to each of the matching OnInterest callbacks that the application gave to registerPrefix or setInterestFilter, and a Data that the application gives to putData can satisfy pending Interests. This way one part of an application can do Interest/Data exchange with another part through the same Face. Interest loopback is disabled by default. :param bool interestLoopbackEnabled: If True, enable Interest loopback, otherwise disable it. """ self._node.setInterestLoopbackEnabled(interestLoopbackEnabled) def expressInterest( self, interestOrName, arg2, arg3 = None, arg4 = None, arg5 = None, arg6 = None): """ Send the Interest through the transport, read the entire response and call onData, onTimeout or onNetworkNack as described below. There are two forms of expressInterest. The first form takes the exact interest (including lifetime): expressInterest(interest, onData [, onTimeout] [, onNetworkNack] [, wireFormat]). The second form creates the interest from a name and optional interest template: expressInterest(name [, interestTemplate], onData [, onTimeout] [, onNetworkNack] [, wireFormat]). :param Interest interest: The Interest (if the first form is used). This copies the Interest. :param Name name: A name for the Interest (if the second form is used). :param Interest interestTemplate: (optional) if not None, copy interest selectors from the template (if the second form is used). If omitted, use a default interest lifetime. :param onData: When a matching data packet is received, this calls onData(interest, data) where interest is the interest given to expressInterest and data is the received Data object. NOTE: You must not change the interest object - if you need to change it then make a copy. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onData: function object :param onTimeout: (optional) If the interest times out according to the interest lifetime, this calls onTimeout(interest) where interest is the interest given to expressInterest. However, if onTimeout is None or omitted, this does not use it. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onTimeout: function object :param onNetworkNack: (optional) When a network Nack packet for the interest is received and onNetworkNack is not None, this calls onNetworkNack(interest, networkNack) and does not call onTimeout. interest is the sent Interest and networkNack is the received NetworkNack. If onNetworkNack is supplied, then onTimeout must be supplied too. However, if a network Nack is received and onNetworkNack is None, do nothing and wait for the interest to time out. (Therefore, an application which does not yet process a network Nack reason treats a Nack the same as a timeout.) NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onNetworkNack: function object :param wireFormat: (optional) A WireFormat object used to encode the message. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :return: The pending interest ID which can be used with removePendingInterest. :rtype: int :throws: RuntimeError If the encoded interest size exceeds Face.getMaxNdnPacketSize(). """ args = self._getExpressInterestArgs( interestOrName, arg2, arg3, arg4, arg5, arg6) self._node.expressInterest( args['pendingInterestId'], args['interestCopy'], args['onData'], args['onTimeout'], args['onNetworkNack'], args['wireFormat'], self) return args['pendingInterestId'] def _getExpressInterestArgs(self, interestOrName, arg2, arg3, arg4, arg5, arg6): """ This is a protected helper method to resolve the different overloaded forms of Face.expressInterest and return the arguments to pass to Node.expressInterest. This is necessary to prepare arguments such as interestCopy before dispatching to Node.expressInterest. :return: A dictionary with the following keys: 'pendingInterestId', 'interestCopy', 'onData', 'onTimeout', 'onNetworkNack' and 'wireFormat'. :rtype: dict """ if isinstance(interestOrName, Interest): # Node.expressInterest requires a copy of the interest. interestCopy = Interest(interestOrName) else: # The first argument is a name. Make the interest from the name and # possible template. if isinstance(arg2, Interest): template = arg2 # Copy the template. interestCopy = Interest(template) interestCopy.setName(interestOrName) # Shift the remaining args to be processed below. arg2 = arg3 arg3 = arg4 arg4 = arg5 arg5 = arg6 else: # No template. interestCopy = Interest(interestOrName) # Set a default interest lifetime. interestCopy.setInterestLifetimeMilliseconds(4000.0) onData = arg2 # arg3, arg4, arg5 may be: # OnTimeout, OnNetworkNack, WireFormat # OnTimeout, OnNetworkNack, None # OnTimeout, WireFormat, None # OnTimeout, None, None # WireFormat, None, None # None, None, None if isinstance(arg3, collections.Callable): onTimeout = arg3 else: onTimeout = None if isinstance(arg4, collections.Callable): onNetworkNack = arg4 else: onNetworkNack = None if isinstance(arg3, WireFormat): wireFormat = arg3 elif isinstance(arg4, WireFormat): wireFormat = arg4 elif isinstance(arg5, WireFormat): wireFormat = arg5 else: wireFormat = WireFormat.getDefaultWireFormat() return { 'pendingInterestId': self._node.getNextEntryId(), 'interestCopy': interestCopy, 'onData': onData, 'onTimeout': onTimeout, 'onNetworkNack': onNetworkNack, 'wireFormat': wireFormat } def removePendingInterest(self, pendingInterestId): """ Remove the pending interest entry with the pendingInterestId from the pending interest table. This does not affect another pending interest with a different pendingInterestId, even if it has the same interest name. If there is no entry with the pendingInterestId, do nothing. :param int pendingInterestId: The ID returned from expressInterest. """ self._node.removePendingInterest(pendingInterestId) def setCommandSigningInfo(self, keyChain, certificateName): """ Set the KeyChain and certificate name used to sign command interests (e.g. for registerPrefix). :param KeyChain keyChain: The KeyChain object for signing interests, which must remain valid for the life of this Face. You must create the KeyChain object and pass it in. You can create a default KeyChain for your system with the default KeyChain constructor. :param Name certificateName: The certificate name for signing interests. This makes a copy of the Name. You can get the default certificate name with keyChain.getDefaultCertificateName() . """ self._commandKeyChain = keyChain self._commandCertificateName = Name(certificateName) def setCommandCertificateName(self, certificateName): """ Set the certificate name used to sign command interest (e.g. for registerPrefix), using the KeyChain that was set with setCommandSigningInfo. :param Name certificateName: The certificate name for signing interest. This makes a copy of the Name. """ self._commandCertificateName = Name(certificateName) def makeCommandInterest(self, interest, wireFormat = None): """ Append a timestamp component and a random value component to interest's name. Then use the keyChain and certificateName from setCommandSigningInfo to sign the interest. If the interest lifetime is not set, this sets it. :note: This method is an experimental feature. See the API docs for more detail at http://named-data.net/doc/ndn-ccl-api/face.html#face-makecommandinterest-method . :param Interest interest: The interest whose name is appended with components. :param wireFormat: (optional) A WireFormat object used to encode the SignatureInfo and to encode the interest name for signing. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._node.makeCommandInterest( interest, self._commandKeyChain, self._commandCertificateName, wireFormat) def registerPrefix( self, prefix, onInterest, onRegisterFailed, onRegisterSuccess = None, registrationOptions = None, wireFormat = None): """ Register prefix with the connected NDN hub and call onInterest when a matching interest is received. To register a prefix with NFD, you must first call setCommandSigningInfo. :param Name prefix: The Name for the prefix to register. This copies the Name. :param onInterest: If not None, this creates an interest filter from prefix so that when an Interest is received which matches the filter, this calls onInterest(prefix, interest, face, interestFilterId, filter). NOTE: You must not change the prefix or filter objects - if you need to change them then make a copy. If onInterest is None, it is ignored and you must call setInterestFilter. NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onInterest: function object :param onRegisterFailed: If register prefix fails for any reason, this calls onRegisterFailed(prefix). NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onRegisterFailed: function object :param onRegisterSuccess: (optional) This calls onRegisterSuccess(prefix, registeredPrefixId) when this receives a success message from the forwarder. If onRegisterSuccess is None or omitted, this does not use it. (The onRegisterSuccess parameter comes after onRegisterFailed because it can be None or omitted, unlike onRegisterFailed.) NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onRegisterSuccess: function object :param RegistrationOptions registrationOptions: (optional) The registration options for finer control of how to forward an interest and other options. :param wireFormat: (optional) A WireFormat object used to encode this ControlParameters. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :raises: This raises an exception if setCommandSigningInfo has not been called to set the KeyChain, etc. for signing the command interest. """ registeredPrefixId = self._node.getNextEntryId() # Node.registerPrefix requires a copy of the prefix. self._registerPrefixHelper( registeredPrefixId, Name(prefix), onInterest, onRegisterFailed, onRegisterSuccess, registrationOptions, wireFormat) return registeredPrefixId def _registerPrefixHelper( self, registeredPrefixId, prefixCopy, onInterest, onRegisterFailed, arg5 = None, arg6 = None, arg7 = None): """ This is a protected helper method to do the work of registerPrefix to resolve the different overloaded forms. The registeredPrefixId is from getNextEntryId(). This has no return value and can be used in a callback. """ # arg5, arg6, arg7 may be: # OnRegisterSuccess, RegistrationOptions, WireFormat # OnRegisterSuccess, RegistrationOptions, None # OnRegisterSuccess, WireFormat, None # OnRegisterSuccess, None, None # RegistrationOptions, WireFormat, None # RegistrationOptions, None, None # WireFormat, None, None # None, None, None if isinstance(arg5, collections.Callable): onRegisterSuccess = arg5 else: onRegisterSuccess = None if isinstance(arg5, RegistrationOptions): registrationOptions = arg5 elif isinstance(arg6, RegistrationOptions): registrationOptions = arg6 else: registrationOptions = RegistrationOptions() if isinstance(arg5, WireFormat): wireFormat = arg5 elif isinstance(arg6, WireFormat): wireFormat = arg6 elif isinstance(arg7, WireFormat): wireFormat = arg7 else: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() return self._node.registerPrefix( registeredPrefixId, prefixCopy, onInterest, onRegisterFailed, onRegisterSuccess, registrationOptions, wireFormat, self._commandKeyChain, self._commandCertificateName, self) def removeRegisteredPrefix(self, registeredPrefixId): """ Remove the registered prefix entry with the registeredPrefixId from the registered prefix table. This does not affect another registered prefix with a different registeredPrefixId, even if it has the same prefix name. If there is no entry with the registeredPrefixId, do nothing. :param int registeredPrefixId: The ID returned from registerPrefix. """ self._node.removeRegisteredPrefix(registeredPrefixId) def setInterestFilter(self, filterOrPrefix, onInterest): """ Add an entry to the local interest filter table to call the onInterest callback for a matching incoming Interest. This method only modifies the library's local callback table and does not register the prefix with the forwarder. It will always succeed. To register a prefix with the forwarder, use registerPrefix. There are two forms of setInterestFilter. The first form uses the exact given InterestFilter: setInterestFilter(filter, onInterest). The second form creates an InterestFilter from the given prefix Name: setInterestFilter(prefix, onInterest). :param InterestFilter filter: The InterestFilter with a prefix and optional regex filter used to match the name of an incoming Interest. This makes a copy of filter. :param Name prefix: The Name prefix used to match the name of an incoming Interest. This makes a copy of the Name. :param onInterest: When an Interest is received which matches the filter, this calls onInterest(prefix, interest, face, interestFilterId, filter). NOTE: The library will log any exceptions raised by this callback, but for better error handling the callback should catch and properly handle any exceptions. :type onInterest: function object :return: The interest filter ID which can be used with unsetInterestFilter. :rtype: int """ interestFilterId = self._node.getNextEntryId() # If filterOrPrefix is already an InterestFilter, the InterestFilter # constructor will make a copy as required by Node.setInterestFilter. filterCopy = InterestFilter(filterOrPrefix) self._node.setInterestFilter( interestFilterId, filterCopy, onInterest, self) return interestFilterId def unsetInterestFilter(self, interestFilterId): """ Remove the interest filter entry which has the interestFilterId from the interest filter table. This does not affect another interest filter with a different interestFilterId, even if it has the same prefix name. If there is no entry with the interestFilterId, do nothing. :param int interestFilterId: The ID returned from setInterestFilter. """ self._node.unsetInterestFilter(interestFilterId) def putData(self, data, wireFormat = None): """ The OnInterest callback calls this to put a Data packet which satisfies an Interest. :param Data data: The Data packet which satisfies the interest. :param WireFormat wireFormat: (optional) A WireFormat object used to encode the Data packet. If omitted, use WireFormat.getDefaultWireFormat(). :throws: RuntimeError If the encoded Data packet size exceeds getMaxNdnPacketSize(). """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._node.putData(data, wireFormat) def putNack(self, interest, networkNack): """ The OnInterest callback can call this to put a Nack for the received Interest. :note: This method is an experimental feature, and the API may change. :param Interest interest: The Interest to put in the Nack packet. :param NetworkNack networkNack: The NetworkNack with the reason code. For example, NetworkNack().setReason(NetworkNack.Reason.NO_ROUTE). :raises RuntimeError: If the encoded Nack packet size exceeds getMaxNdnPacketSize(). """ self._node.putNack(interest, networkNack) def send(self, encoding): """ Send the encoded packet out through the face. :param encoding: The blob or array with the the encoded packet to send. :type encoding: Blob or an array type with int elements :throws: RuntimeError If the packet size exceeds getMaxNdnPacketSize(). """ # If encoding is a Blob, get its buf(). encodingBuffer = encoding.buf() if isinstance(encoding, Blob) else encoding self._node.send(encodingBuffer) def processEvents(self): """ Process any packets to receive and call callbacks such as onData, onInterest or onTimeout. This returns immediately if there is no data to receive. This blocks while calling the callbacks. You should repeatedly call this from an event loop, with calls to sleep as needed so that the loop doesn't use 100% of the CPU. Since processEvents modifies the pending interest table, your application should make sure that it calls processEvents in the same thread as expressInterest (which also modifies the pending interest table). :raises: This may raise an exception for reading data or in the callback for processing the data. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ # Just call Node's processEvents. self._node.processEvents() def isLocal(self): """ Check if the face is local based on the current connection through the Transport; some Transport may cause network I/O (e.g. an IP host name lookup). :return: True if the face is local, false if not. :rtype bool: """ return self._node.isLocal() def shutdown(self): """ Shut down and disconnect this Face. """ self._node.shutdown() @staticmethod def getMaxNdnPacketSize(): """ Get the practical limit of the size of a network-layer packet. If a packet is larger than this, the library or application MAY drop it. :return: The maximum NDN packet size. :rtype: int """ return Common.MAX_NDN_PACKET_SIZE def callLater(self, delayMilliseconds, callback): """ Call callback() after the given delay. Even though this is public, it is not part of the public API of Face.This default implementation just calls Node.callLater, but a subclass can override. :param float delayMilliseconds: The delay in milliseconds. :param callback: This calls callback() after the delay. :type callback: function object """ self._node.callLater(delayMilliseconds, callback) @staticmethod def _getUnixSocketFilePathForLocalhost(): """ If the forwarder's Unix socket file path exists, then return the file path. Otherwise return an empty string. :return: The Unix socket file path to use, or an empty string. :rtype: str """ filePath = "/var/run/nfd.sock" # Use listdir because isfile doesn't see socket file types. if (os.path.basename(filePath) in os.listdir(os.path.dirname(filePath))): return filePath else: filePath = "/tmp/.ndnd.sock" if (os.path.basename(filePath) in os.listdir(os.path.dirname(filePath))): return filePath else: return ""
class Face(object): """ Create a new Face for communication with an NDN hub. This constructor has the forms Face(), Face(transport, connectionInfo) or Face(host, port). If the default Face() constructor is used, if the forwarder's Unix socket file exists then connect using UnixTransport, otherwise connect to "localhost" on port 6363 using TcpTransport. :param Transport transport: An object of a subclass of Transport used for communication. :param Transport.ConnectionInfo connectionInfo: An object of a subclass of Transport.ConnectionInfo to be used to connect to the transport. :param str host: In the Face(host, port) form of the constructor, host is the host of the NDN hub to connect using TcpTransport. :param int port: (optional) In the Face(host, port) form of the constructor, port is the port of the NDN hub. If omitted. use 6363. """ def __init__(self, arg1 = None, arg2 = None): if arg1 == None or Common.typeIsString(arg1): filePath = "" if arg1 == None and arg2 == None: # Check if we can connect using UnixSocket. tryFilePath = "/var/run/nfd.sock" # Use listdir because isfile doesn't see socket file types. if (os.path.basename(tryFilePath) in os.listdir(os.path.dirname(tryFilePath))): filePath = tryFilePath else: tryFilePath = "/tmp/.ndnd.sock" if (os.path.basename(tryFilePath) in os.listdir(os.path.dirname(tryFilePath))): filePath = tryFilePath if filePath == "": transport = TcpTransport() host = arg1 if arg1 != None else "localhost" connectionInfo = TcpTransport.ConnectionInfo( host, arg2 if type(arg2) is int else 6363) else: transport = UnixTransport() connectionInfo = UnixTransport.ConnectionInfo(filePath) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) self._commandKeyChain = None self._commandCertificateName = Name() def expressInterest( self, interestOrName, arg2, arg3 = None, arg4 = None, arg5 = None): """ Send the Interest through the transport, read the entire response and call onData(interest, data). There are two forms of expressInterest. The first form takes the exact interest (including lifetime): expressInterest(interest, onData [, onTimeout] [, wireFormat]). The second form creates the interest from a name and optional interest template: expressInterest(name [, interestTemplate], onData [, onTimeout] [, wireFormat]). :param Interest interest: The Interest (if the first form is used). This copies the Interest. :param Name name: A name for the Interest (if the second form is used). :param Interest interestTemplate: (optional) if not None, copy interest selectors from the template (if the second form is used). If omitted, use a default interest lifetime. :param onData: When a matching data packet is received, this calls onData(interest, data) where interest is the interest given to expressInterest and data is the received Data object. NOTE: You must not change the interest object - if you need to change it then make a copy. :type onData: function object :param onTimeout: (optional) If the interest times out according to the interest lifetime, this calls onTimeout(interest) where interest is the interest given to expressInterest. However, if onTimeout is None or omitted, this does not use it. :type onTimeout: function object :param wireFormat: (optional) A WireFormat object used to encode the message. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :return: The pending interest ID which can be used with removePendingInterest. :rtype: int """ # expressInterest(interest, onData) # expressInterest(interest, onData, wireFormat) # expressInterest(interest, onData, onTimeout) # expressInterest(interest, onData, onTimeout, wireFormat) if type(interestOrName) is Interest: # Node.expressInterest requires a copy of the interest. interest = Interest(interestOrName) onData = arg2 if isinstance(arg3, WireFormat): onTimeout = None wireFormat = arg3 else: onTimeout = arg3 wireFormat = arg4 else: # The first argument is a name. Make the interest from the name and # possible template. interest = Interest(interestOrName) # expressInterest(name, interestTemplate, onData) # expressInterest(name, interestTemplate, onData, wireFormat) # expressInterest(name, interestTemplate, onData, onTimeout) # expressInterest(name, interestTemplate, onData, onTimeout, wireFormat) if type(arg2) is Interest: template = arg2 interest.setMinSuffixComponents(template.getMinSuffixComponents()) interest.setMaxSuffixComponents(template.getMaxSuffixComponents()) interest.setKeyLocator(template.getKeyLocator()) interest.setExclude(template.getExclude()) interest.setChildSelector(template.getChildSelector()) interest.setMustBeFresh(template.getMustBeFresh()) interest.setScope(template.getScope()) interest.setInterestLifetimeMilliseconds( template.getInterestLifetimeMilliseconds()) # Don't copy the nonce. onData = arg3 if isinstance(arg4, WireFormat): onTimeout = None wireFormat = arg4 else: onTimeout = arg4 wireFormat = arg5 # expressInterest(name, onData) # expressInterest(name, onData, wireFormat) # expressInterest(name, onData, onTimeout) # expressInterest(name, onData, onTimeout, wireFormat) else: # Set a default interest lifetime. interest.setInterestLifetimeMilliseconds(4000.0) onData = arg2 if isinstance(arg3, WireFormat): onTimeout = None wireFormat = arg3 else: onTimeout = arg3 wireFormat = arg4 if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() return self._node.expressInterest( interest, onData, onTimeout, wireFormat) def removePendingInterest(self, pendingInterestId): """ Remove the pending interest entry with the pendingInterestId from the pending interest table. This does not affect another pending interest with a different pendingInterestId, even if it has the same interest name. If there is no entry with the pendingInterestId, do nothing. :param int pendingInterestId: The ID returned from expressInterest. """ self._node.removePendingInterest(pendingInterestId) def setCommandSigningInfo(self, keyChain, certificateName): """ Set the KeyChain and certificate name used to sign command interests (e.g. for registerPrefix). :param KeyChain keyChain: The KeyChain object for signing interests, which must remain valid for the life of this Face. You must create the KeyChain object and pass it in. You can create a default KeyChain for your system with the default KeyChain constructor. :param Name certificateName: The certificate name for signing interests. This makes a copy of the Name. You can get the default certificate name with keyChain.getDefaultCertificateName() . """ self._commandKeyChain = keyChain self._commandCertificateName = certificateName def setCommandCertificateName(self, certificateName): """ Set the certificate name used to sign command interest (e.g. for registerPrefix), using the KeyChain that was set with setCommandSigningInfo. :param Name certificateName: The certificate name for signing interest. This makes a copy of the Name. """ self._commandCertificateName = certificateName def makeCommandInterest(self, interest, wireFormat = None): """ Append a timestamp component and a random value component to interest's name. Then use the keyChain and certificateName from setCommandSigningInfo to sign the interest. If the interest lifetime is not set, this sets it. :param Interest interest: The interest whose name is append with components. :param wireFormat: (optional) A WireFormat object used to encode the SignatureInfo and to encode interest name for signing. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat """ if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._node.makeCommandInterest( interest, self._commandKeyChain, self._commandCertificateName, wireFormat) def registerPrefix( self, prefix, onInterest, onRegisterFailed, flags = None, wireFormat = None): """ Register prefix with the connected NDN hub and call onInterest when a matching interest is received. If you have not called setCommandSigningInfo, this assumes you are connecting to NDNx. If you have called setCommandSigningInfo, this first sends an NFD registration request, and if that times out then this sends an NDNx registration request. If need to register a prefix with NFD, you must first call setCommandSigningInfo. :param Name prefix: The Name for the prefix to register which is NOT copied for this internal Node method. The Face registerPrefix is reponsible for making a copy for Node to use.. :param onInterest: When an interest is received which matches the name prefix, this calls onInterest(prefix, interest, transport, registeredPrefixId). NOTE: You must not change the prefix object - if you need to change it then make a copy. :type onInterest: function object :param onRegisterFailed: If register prefix fails for any reason, this calls onRegisterFailed(prefix). :type onRegisterFailed: function object :param ForwardingFlags flags: The flags for finer control of which interests are forwardedto the application. :param wireFormat: (optional) A WireFormat object used to encode this ControlParameters. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :raises: This raises an exception if setCommandSigningInfo has not been called to set the KeyChain, etc. for signing the command interest. """ if flags == None: flags = ForwardingFlags() if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() # Node.expressInterest requires a copy of the prefix. self._node.registerPrefix( prefix, onInterest, onRegisterFailed, flags, wireFormat, self._commandKeyChain, self._commandCertificateName) def removeRegisteredPrefix(self, registeredPrefixId): """ Remove the registered prefix entry with the registeredPrefixId from the registered prefix table. This does not affect another registered prefix with a different registeredPrefixId, even if it has the same prefix name. If there is no entry with the registeredPrefixId, do nothing. :param int registeredPrefixId: The ID returned from registerPrefix. """ self._node.removeRegisteredPrefix(registeredPrefixId) def processEvents(self): """ Process any packets to receive and call callbacks such as onData, onInterest or onTimeout. This returns immediately if there is no data to receive. This blocks while calling the callbacks. You should repeatedly call this from an event loop, with calls to sleep as needed so that the loop doesn't use 100% of the CPU. Since processEvents modifies the pending interest table, your application should make sure that it calls processEvents in the same thread as expressInterest (which also modifies the pending interest table). :raises: This may raise an exception for reading data or in the callback for processing the data. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ # Just call Node's processEvents. self._node.processEvents() def shutdown(self): """ Shut down and disconnect this Face. """ self._node.shutdown()
class Face(object): """ Create a new Face for communication with an NDN hub. This constructor has the forms Face(transport, connectionInfo) or Face(host, port) :param Transport transport: An object of a subclass of Transport used for communication. :param Transport.ConnectionInfo connectionInfo: An object of a subclass of Transport.ConnectionInfo to be used to connect to the transport. :param str host: In the Face(host, port) form of the constructor, host is the host of the NDN hub with a TcpTransport. :param int port: (optional) In the Face(host, port) form of the constructor, port is the port of the NDN hub. If omitted. use 6363. """ def __init__(self, arg1, arg2 = None): if type(arg1) is str: transport = TcpTransport() connectionInfo = TcpTransport.ConnectionInfo( arg1, arg2 if type(arg2) is int else 6363) else: transport = arg1 connectionInfo = arg2 self._node = Node(transport, connectionInfo) def expressInterest( self, interestOrName, arg2, arg3 = None, arg4 = None, arg5 = None): """ Send the Interest through the transport, read the entire response and call onData(interest, data). There are two forms of expressInterest. The first form takes the exact interest (including lifetime): expressInterest(interest, onData [, onTimeout] [, wireFormat]). The second form creates the interest from a name and optional interest template: expressInterest(name [, interestTemplate], onData [, onTimeout] [, wireFormat]). :param Interest interest: The Interest (if the first form is used). This copies the Interest. :param Name name: A name for the Interest (if the second form is used). :param Interest interestTemplate: (optional) if not None, copy interest selectors from the template (if the second form is used). If omitted, use a default interest lifetime. :param onData: A function object to call when a matching data packet is received. :type onData: function object :param onTimeout: (optional) A function object to call if the interest times out. If onTimeout is None or omitted, this does not use it. :type onTimeout: function object :param wireFormat: (optional) A WireFormat object used to encode the message. If omitted, use WireFormat.getDefaultWireFormat(). :type wireFormat: A subclass of WireFormat :return: The pending interest ID which can be used with removePendingInterest. :rtype: int """ # expressInterest(interest, onData) # expressInterest(interest, onData, wireFormat) # expressInterest(interest, onData, onTimeout) # expressInterest(interest, onData, onTimeout, wireFormat) if type(interestOrName) is Interest: # Node.expressInterest requires a copy of the interest. interest = Interest(interestOrName) onData = arg2 if isinstance(arg3, WireFormat): onTimeout = None wireFormat = arg3 else: onTimeout = arg3 wireFormat = arg4 else: # The first argument is a name. Make the interest from the name and # possible template. interest = Interest(interestOrName) # expressInterest(name, interestTemplate, onData) # expressInterest(name, interestTemplate, onData, wireFormat) # expressInterest(name, interestTemplate, onData, onTimeout) # expressInterest(name, interestTemplate, onData, onTimeout, wireFormat) if type(arg2) is Interest: template = arg2 interest.setMinSuffixComponents(template.getMinSuffixComponents()) interest.setMaxSuffixComponents(template.getMaxSuffixComponents()) interest.setKeyLocator(template.getKeyLocator()) interest.setExclude(template.getExclude()) interest.setChildSelector(template.getChildSelector()) interest.setMustBeFresh(template.getMustBeFresh()) interest.setScope(template.getScope()) interest.setInterestLifetimeMilliseconds( template.getInterestLifetimeMilliseconds()) # Don't copy the nonce. onData = arg3 if isinstance(arg4, WireFormat): onTimeout = None wireFormat = arg4 else: onTimeout = arg4 wireFormat = arg5 # expressInterest(name, onData) # expressInterest(name, onData, wireFormat) # expressInterest(name, onData, onTimeout) # expressInterest(name, onData, onTimeout, wireFormat) else: # Set a default interest lifetime. interest.setInterestLifetimeMilliseconds(4000.0) onData = arg2 if isinstance(arg3, WireFormat): onTimeout = None wireFormat = arg3 else: onTimeout = arg3 wireFormat = arg4 if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() return self._node.expressInterest( interest, onData, onTimeout, wireFormat) def removePendingInterest(self, pendingInterestId): """ Remove the pending interest entry with the pendingInterestId from the pending interest table. This does not affect another pending interest with a different pendingInterestId, even if it has the same interest name. If there is no entry with the pendingInterestId, do nothing. :param int pendingInterestId: The ID returned from expressInterest. """ self._node.removePendingInterest(pendingInterestId) def registerPrefix( self, prefix, onInterest, onRegisterFailed, flags = None, wireFormat = None): """ Register prefix with the connected NDN hub and call onInterest when a matching interest is received. :param Name prefix: The Name for the prefix to register which is NOT copied for this internal Node method. The Face registerPrefix is reponsible for making a copy for Node to use.. :param onInterest: A function object to call when a matching interest is received. :type onInterest: function object :param onRegisterFailed: A function object to call if failed to retrieve the connected hub's ID or failed to register the prefix. :type onRegisterFailed: function object :param ForwardingFlags flags: The flags for finer control of which interests are forwardedto the application. :param wireFormat: A WireFormat object used to encode the message. :type wireFormat: a subclass of WireFormat """ if flags == None: flags = ForwardingFlags() if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() # Node.expressInterest requires a copy of the prefix. self._node.registerPrefix( prefix, onInterest, onRegisterFailed, flags, wireFormat) def removeRegisteredPrefix(self, registeredPrefixId): """ Remove the registered prefix entry with the registeredPrefixId from the registered prefix table. This does not affect another registered prefix with a different registeredPrefixId, even if it has the same prefix name. If there is no entry with the registeredPrefixId, do nothing. :param int registeredPrefixId: The ID returned from registerPrefix. """ self._node.removeRegisteredPrefix(registeredPrefixId) def processEvents(self): """ Process any packets to receive and call callbacks such as onData, onInterest or onTimeout. This returns immediately if there is no data to receive. This blocks while calling the callbacks. You should repeatedly call this from an event loop, with calls to sleep as needed so that the loop doesn't use 100% of the CPU. Since processEvents modifies the pending interest table, your application should make sure that it calls processEvents in the same thread as expressInterest (which also modifies the pending interest table). :raises: This may raise an exception for reading data or in the callback for processing the data. If you call this from an main event loop, you may want to catch and log/disregard all exceptions. """ # Just call Node's processEvents. self._node.processEvents() def shutdown(self): """ Shut down and disconnect this Face. """ self._node.shutdown()