def uPnPDiscover(service, timeout=2, retries=1): group = ("239.255.255.250", 1900) message = "\r\n".join([ "M-SEARCH * HTTP/1.1", "HOST: " + group[0] + ":" + RPFrameworkUtils.to_str(group[1]), "MAN: ""ssdp:discover""", "ST: " + service,"MX: 3","",""]) socket.setdefaulttimeout(timeout) responses = {} for _ in range(retries): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) sock.sendto(message, group) while True: try: response = SSDPResponse(sock.recv(1024)) responses[response.location] = response except socket.timeout: break return responses.values()
def uPnPDiscover(service, timeout=3, retries=1): group = ("239.255.255.250", 1900) message = "\r\n".join([ "M-SEARCH * HTTP/1.1", "HOST: " + group[0] + ":" + RPFrameworkUtils.to_str(group[1]), "MAN: ""ssdp:discover""", "ST: " + service,"MX: 3","",""]) socket.setdefaulttimeout(timeout) responses = {} for _ in range(retries): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) sock.sendto(message, group) while True: try: response = SSDPResponse(sock.recv(1024)) responses[response.location] = response except socket.timeout: break return responses.values()
def concurrentCommandProcessingThread(self, commandQueue): try: self.hostPlugin.logDebugMessage(u'Concurrent Processing Thread started for device ' + RPFrameworkUtils.to_unicode(self.indigoDevice.id), RPFrameworkPlugin.DEBUGLEVEL_MED) # obtain the IP or host address that will be used in connecting to the # RESTful service via a function call to allow overrides deviceHTTPAddress = self.getRESTfulDeviceAddress() if deviceHTTPAddress is None: indigo.server.log(u'No IP address specified for device ' + RPFrameworkUtils.to_unicode(self.indigoDevice.id) + u'; ending command processing thread.', isError=True) return # retrieve any configuration information that may have been setup in the # plugin configuration and/or device configuration updateStatusPollerPropertyName = self.hostPlugin.getGUIConfigValue(self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_INTERVALPROPERTY, u'updateInterval') updateStatusPollerInterval = int(self.indigoDevice.pluginProps.get(updateStatusPollerPropertyName, u'90')) updateStatusPollerNextRun = None updateStatusPollerActionId = self.hostPlugin.getGUIConfigValue(self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_ACTIONID, u'') emptyQueueReducedWaitCycles = int(self.hostPlugin.getGUIConfigValue(self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULDEV_EMPTYQUEUE_SPEEDUPCYCLES, u'80')) # spin up the database connection, if this plugin supports databases self.dbConn = self.hostPlugin.openDatabaseConnection(self.indigoDevice.deviceTypeId) # begin the infinite loop which will run as long as the queue contains commands # and we have not received an explicit shutdown request continueProcessingCommands = True lastQueuedCommandCompleted = 0 while continueProcessingCommands == True: # process pending commands now... while not commandQueue.empty(): lenQueue = commandQueue.qsize() self.hostPlugin.logDebugMessage(u'Command queue has ' + RPFrameworkUtils.to_unicode(lenQueue) + u' command(s) waiting', RPFrameworkPlugin.DEBUGLEVEL_HIGH) # the command name will identify what action should be taken... we will handle the known # commands and dispatch out to the device implementation, if necessary, to handle unknown # commands command = commandQueue.get() if command.commandName == RPFrameworkCommand.CMD_INITIALIZE_CONNECTION: # specialized command to instanciate the concurrent thread # safely ignore this... just used to spin up the thread self.hostPlugin.logDebugMessage(u'Create connection command de-queued', RPFrameworkPlugin.DEBUGLEVEL_MED) # if the device supports polling for status, it may be initiated here now; however, we should implement a pause to ensure that # devices are created properly (RESTFul devices may respond too fast since no connection need be established) statusUpdateStartupDelay = float(self.hostPlugin.getGUIConfigValue(self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_STARTUPDELAY, u'3')) if statusUpdateStartupDelay > 0.0: commandQueue.put(RPFrameworkCommand.RPFrameworkCommand(RPFrameworkCommand.CMD_PAUSE_PROCESSING, commandPayload=str(statusUpdateStartupDelay))) commandQueue.put(RPFrameworkCommand.RPFrameworkCommand(RPFrameworkCommand.CMD_UPDATE_DEVICE_STATUS_FULL, parentAction=updateStatusPollerActionId)) elif command.commandName == RPFrameworkCommand.CMD_TERMINATE_PROCESSING_THREAD: # a specialized command designed to stop the processing thread indigo # the event of a shutdown continueProcessingCommands = False elif command.commandName == RPFrameworkCommand.CMD_PAUSE_PROCESSING: # the amount of time to sleep should be a float found in the # payload of the command try: pauseTime = float(command.commandPayload) self.hostPlugin.logDebugMessage(u'Initiating sleep of ' + RPFrameworkUtils.to_unicode(pauseTime) + u' seconds from command.', RPFrameworkPlugin.DEBUGLEVEL_MED) time.sleep(pauseTime) except: indigo.server.log(u'Invalid pause time requested', isError=True) elif command.commandName == RPFrameworkCommand.CMD_UPDATE_DEVICE_STATUS_FULL: # this command instructs the plugin to update the full status of the device (all statuses # that may be read from the device should be read) if updateStatusPollerActionId != u'': self.hostPlugin.logDebugMessage(u'Executing full status update request...', RPFrameworkPlugin.DEBUGLEVEL_MED) self.hostPlugin.executeAction(None, indigoActionId=updateStatusPollerActionId, indigoDeviceId=self.indigoDevice.id, paramValues=None) updateStatusPollerNextRun = time.time() + updateStatusPollerInterval else: self.hostPlugin.logDebugMessage(u'Ignoring status update request, no action specified to update device status', RPFrameworkPlugin.DEBUGLEVEL_HIGH) elif command.commandName == RPFrameworkCommand.CMD_NETWORKING_WOL_REQUEST: # this is a request to send a Wake-On-LAN request to a network-enabled device # the command payload should be the MAC address of the device to wake up try: RPFrameworkNetworkingWOL.sendWakeOnLAN(command.commandPayload) except: self.hostPlugin.logErrorMessage(u'Failed to send Wake-on-LAN packet') elif command.commandName == CMD_RESTFUL_GET or command.commandName == CMD_RESTFUL_PUT or command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: try: self.hostPlugin.logDebugMessage(u'Processing GET operation: ' + RPFrameworkUtils.to_unicode(command.commandPayload), RPFrameworkPlugin.DEBUGLEVEL_MED) # gather all of the parameters from the command payload # the payload should have the following format: # [0] => request method (http|https|etc.) # [1] => path for the GET operation # [2] => authentication type: none|basic|digest # [3] => username # [4] => password # # CMD_DOWNLOADFILE or CMD_DOWNLOADIMAGE # [5] => download filename/path # [6] => image resize width # [7] => image resize height # # CMD_RESTFUL_PUT # [5] => data to post as the body (if any, may be blank) commandPayloadList = command.getPayloadAsList() fullGetUrl = commandPayloadList[0] + u'://' + deviceHTTPAddress[0] + u':' + RPFrameworkUtils.to_unicode(deviceHTTPAddress[1]) + commandPayloadList[1] customHeaders = {} self.addCustomHTTPHeaders(customHeaders) authenticationParam = None authenticationType = u'none' username = u'' password = u'' if len(commandPayloadList) >= 3: authenticationType = commandPayloadList[2] if len(commandPayloadList) >= 4: username = commandPayloadList[3] if len(commandPayloadList) >= 5: password = commandPayloadList[4] if authenticationType != 'none' and username != u'': self.hostPlugin.logDebugMessage(u'Using login credentials... Username=> ' + username + u'; Password=>' + RPFrameworkUtils.to_unicode(len(password)) + u' characters long', RPFrameworkPlugin.DEBUGLEVEL_HIGH) authenticationParam = (username, password) # execute the URL fetching depending upon the method requested if command.commandName == CMD_RESTFUL_GET or command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: responseObj = requests.get(fullGetUrl, auth=authenticationParam, headers=customHeaders, verify=False) elif command.commandName == CMD_RESTFUL_PUT: dataToPost = None if len(commandPayloadList) >= 6: dataToPost = commandPayloadList[5] responseObj = requests.post(fullGetUrl, auth=authenticationParam, headers=customHeaders, verify=False, data=dataToPost) # if the network command failed then allow the error processor to handle the issue if responseObj.status_code == 200: # the response handling will depend upon the type of command... binary returns must be # handled separately from (expected) text-based ones if command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: # this is a binary return that should be saved to the file system without modification if len(commandPayloadList) >= 6: saveLocation = commandPayloadList[5] # execute the actual save from the binary response stream try: localFile = open(RPFrameworkUtils.to_str(saveLocation), "wb") localFile.write(responseObj.content) self.hostPlugin.logDebugMessage(u'Command Response: [' + RPFrameworkUtils.to_unicode(responseObj.status_code) + u'] -=- binary data written to ' + RPFrameworkUtils.to_unicode(saveLocation) + u'-=-', RPFrameworkPlugin.DEBUGLEVEL_HIGH) if command.commandName == CMD_DOWNLOADIMAGE: imageResizeWidth = 0 imageResizeHeight = 0 if len(command.commandPayload) >= 7: imageResizeWidth = int(command.commandPayload[6]) if len(command.commandPayload) >= 8: imageResizeHeight = int(command.commandPayload[7]) resizeCommandLine = u'' if imageResizeWidth > 0 and imageResizeHeight > 0: # we have a specific size as a target... resizeCommandLine = u'sips -z ' + RPFrameworkUtils.to_unicode(imageResizeHeight) + u' ' + RPFrameworkUtils.to_unicode(imageResizeWidth) + u' ' + saveLocation elif imageResizeWidth > 0: # we have a maximum size measurement resizeCommandLine = u'sips -Z ' + RPFrameworkUtils.to_unicode(imageResizeWidth) + u' ' + saveLocation # if a command line has been formed, fire that off now... if resizeCommandLine == u'': self.hostPlugin.logDebugMessage(u'No image size specified for ' + RPFrameworkUtils.to_unicode(saveLocation) + u'; skipping resize.', RPFrameworkPlugin.DEBUGLEVEL_MED) else: self.hostPlugin.logDebugMessage(u'Executing resize via command line "' + resizeCommandLine + u'"', RPFrameworkPlugin.DEBUGLEVEL_HIGH) try: subprocess.Popen(resizeCommandLine, shell=True) self.hostPlugin.logDebugMessage(saveLocation + u' resized via sip shell command', RPFrameworkPlugin.DEBUGLEVEL_HIGH) except: self.hostPlugin.logErrorMessage(u'Error resizing image via sips') finally: if not localFile is None: localFile.close() else: indigo.server.log(u'Unable to complete download action - no filename specified', isError=True) else: # handle this return as a text-based return self.hostPlugin.logDebugMessage(u'Command Response: [' + RPFrameworkUtils.to_unicode(responseObj.status_code) + u'] ' + RPFrameworkUtils.to_unicode(responseObj.text), RPFrameworkPlugin.DEBUGLEVEL_HIGH) self.hostPlugin.logDebugMessage(command.commandName + u' command completed; beginning response processing', RPFrameworkPlugin.DEBUGLEVEL_HIGH) self.handleDeviceTextResponse(responseObj, command) self.hostPlugin.logDebugMessage(command.commandName + u' command response processing completed', RPFrameworkPlugin.DEBUGLEVEL_HIGH) elif responseObj.status_code == 401: self.handleRESTfulError(command, u'401 - Unauthorized', responseObj) else: self.handleRESTfulError(command, str(responseObj.status_code), responseObj) except Exception, e: self.handleRESTfulError(command, e, responseObj) elif command.commandName == CMD_SOAP_REQUEST or command.commandName == CMD_JSON_REQUEST: responseObj = None try: # this is to post a SOAP request to a web service... this will be similar to a restful put request # but will contain a body payload self.hostPlugin.logDebugMessage(u'Received SOAP/JSON command request: ' + command.commandPayload, RPFrameworkPlugin.DEBUGLEVEL_HIGH) soapPayloadParser = re.compile("^\s*([^\n]+)\n\s*([^\n]+)\n(.*)$", re.DOTALL) soapPayloadData = soapPayloadParser.match(command.commandPayload) soapPath = soapPayloadData.group(1).strip() soapAction = soapPayloadData.group(2).strip() soapBody = soapPayloadData.group(3).strip() fullGetUrl = u'http://' + deviceHTTPAddress[0] + u':' + RPFrameworkUtils.to_str(deviceHTTPAddress[1]) + RPFrameworkUtils.to_str(soapPath) self.hostPlugin.logDebugMessage(u'Processing SOAP/JSON operation to ' + fullGetUrl, RPFrameworkPlugin.DEBUGLEVEL_MED) customHeaders = {} self.addCustomHTTPHeaders(customHeaders) if command.commandName == CMD_SOAP_REQUEST: customHeaders["Content-type"] = "text/xml; charset=\"UTF-8\"" customHeaders["SOAPAction"] = RPFrameworkUtils.to_str(soapAction) else: customHeaders["Content-type"] = "application/json" # execute the URL post to the web service self.hostPlugin.logDebugMessage(u'Sending SOAP/JSON request:\n' + RPFrameworkUtils.to_str(soapBody), RPFrameworkPlugin.DEBUGLEVEL_HIGH) responseObj = requests.post(fullGetUrl, headers=customHeaders, verify=False, data=RPFrameworkUtils.to_str(soapBody)) if responseObj.status_code == 200: # handle this return as a text-based return self.hostPlugin.logDebugMessage(u'Command Response: [' + RPFrameworkUtils.to_unicode(responseObj.status_code) + u'] ' + RPFrameworkUtils.to_unicode(responseObj.text), RPFrameworkPlugin.DEBUGLEVEL_HIGH) self.hostPlugin.logDebugMessage(command.commandName + u' command completed; beginning response processing', RPFrameworkPlugin.DEBUGLEVEL_HIGH) self.handleDeviceTextResponse(responseObj, command) self.hostPlugin.logDebugMessage(command.commandName + u' command response processing completed', RPFrameworkPlugin.DEBUGLEVEL_HIGH) else: self.handleRESTfulError(command, str(responseObj.status_code), responseObj) except Exception, e: self.handleRESTfulError(command, e, responseObj) else:
def concurrentCommandProcessingThread(self, commandQueue): try: self.hostPlugin.logger.debug( u'Concurrent Processing Thread started for device ' + RPFrameworkUtils.to_unicode(self.indigoDevice.id)) # obtain the IP or host address that will be used in connecting to the # RESTful service via a function call to allow overrides deviceHTTPAddress = self.getRESTfulDeviceAddress() if deviceHTTPAddress is None: self.hostPlugin.logger.error( u'No IP address specified for device ' + RPFrameworkUtils.to_unicode(self.indigoDevice.id) + u'; ending command processing thread.') return # retrieve any configuration information that may have been setup in the # plugin configuration and/or device configuration updateStatusPollerPropertyName = self.hostPlugin.getGUIConfigValue( self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_INTERVALPROPERTY, u'updateInterval') updateStatusPollerInterval = int( self.indigoDevice.pluginProps.get( updateStatusPollerPropertyName, u'90')) updateStatusPollerNextRun = None updateStatusPollerActionId = self.hostPlugin.getGUIConfigValue( self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_ACTIONID, u'') emptyQueueReducedWaitCycles = int( self.hostPlugin.getGUIConfigValue( self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULDEV_EMPTYQUEUE_SPEEDUPCYCLES, u'80')) # spin up the database connection, if this plugin supports databases self.dbConn = self.hostPlugin.openDatabaseConnection( self.indigoDevice.deviceTypeId) # begin the infinite loop which will run as long as the queue contains commands # and we have not received an explicit shutdown request continueProcessingCommands = True lastQueuedCommandCompleted = 0 while continueProcessingCommands == True: # process pending commands now... while not commandQueue.empty(): lenQueue = commandQueue.qsize() self.hostPlugin.logger.threaddebug( u'Command queue has ' + RPFrameworkUtils.to_unicode(lenQueue) + u' command(s) waiting') # the command name will identify what action should be taken... we will handle the known # commands and dispatch out to the device implementation, if necessary, to handle unknown # commands command = commandQueue.get() if command.commandName == RPFrameworkCommand.CMD_INITIALIZE_CONNECTION: # specialized command to instanciate the concurrent thread # safely ignore this... just used to spin up the thread self.hostPlugin.logger.threaddebug( u'Create connection command de-queued') # if the device supports polling for status, it may be initiated here now; however, we should implement a pause to ensure that # devices are created properly (RESTFul devices may respond too fast since no connection need be established) statusUpdateStartupDelay = float( self.hostPlugin.getGUIConfigValue( self.indigoDevice.deviceTypeId, GUI_CONFIG_RESTFULSTATUSPOLL_STARTUPDELAY, u'3')) if statusUpdateStartupDelay > 0.0: commandQueue.put( RPFrameworkCommand.RPFrameworkCommand( RPFrameworkCommand.CMD_PAUSE_PROCESSING, commandPayload=str( statusUpdateStartupDelay))) commandQueue.put( RPFrameworkCommand.RPFrameworkCommand( RPFrameworkCommand. CMD_UPDATE_DEVICE_STATUS_FULL, parentAction=updateStatusPollerActionId)) elif command.commandName == RPFrameworkCommand.CMD_TERMINATE_PROCESSING_THREAD: # a specialized command designed to stop the processing thread indigo # the event of a shutdown continueProcessingCommands = False elif command.commandName == RPFrameworkCommand.CMD_PAUSE_PROCESSING: # the amount of time to sleep should be a float found in the # payload of the command try: pauseTime = float(command.commandPayload) self.hostPlugin.logger.threaddebug( u'Initiating sleep of ' + RPFrameworkUtils.to_unicode(pauseTime) + u' seconds from command.') time.sleep(pauseTime) except: self.hostPlugin.logger.warning( u'Invalid pause time requested') elif command.commandName == RPFrameworkCommand.CMD_UPDATE_DEVICE_STATUS_FULL: # this command instructs the plugin to update the full status of the device (all statuses # that may be read from the device should be read) if updateStatusPollerActionId != u'': self.hostPlugin.logger.debug( u'Executing full status update request...') self.hostPlugin.executeAction( None, indigoActionId=updateStatusPollerActionId, indigoDeviceId=self.indigoDevice.id, paramValues=None) updateStatusPollerNextRun = time.time( ) + updateStatusPollerInterval else: self.hostPlugin.logger.threaddebug( u'Ignoring status update request, no action specified to update device status' ) elif command.commandName == RPFrameworkCommand.CMD_NETWORKING_WOL_REQUEST: # this is a request to send a Wake-On-LAN request to a network-enabled device # the command payload should be the MAC address of the device to wake up try: RPFrameworkNetworkingWOL.sendWakeOnLAN( command.commandPayload) except: self.hostPlugin.logger.error( u'Failed to send Wake-on-LAN packet') elif command.commandName == CMD_RESTFUL_GET or command.commandName == CMD_RESTFUL_PUT or command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: try: self.hostPlugin.logger.debug( u'Processing GET operation: ' + RPFrameworkUtils.to_unicode( command.commandPayload)) # gather all of the parameters from the command payload # the payload should have the following format: # [0] => request method (http|https|etc.) # [1] => path for the GET operation # [2] => authentication type: none|basic|digest # [3] => username # [4] => password # # CMD_DOWNLOADFILE or CMD_DOWNLOADIMAGE # [5] => download filename/path # [6] => image resize width # [7] => image resize height # # CMD_RESTFUL_PUT # [5] => data to post as the body (if any, may be blank) commandPayloadList = command.getPayloadAsList() fullGetUrl = commandPayloadList[ 0] + u'://' + deviceHTTPAddress[ 0] + u':' + RPFrameworkUtils.to_unicode( deviceHTTPAddress[1] ) + commandPayloadList[1] customHeaders = {} self.addCustomHTTPHeaders(customHeaders) authenticationParam = None authenticationType = u'none' username = u'' password = u'' if len(commandPayloadList) >= 3: authenticationType = commandPayloadList[2] if len(commandPayloadList) >= 4: username = commandPayloadList[3] if len(commandPayloadList) >= 5: password = commandPayloadList[4] if authenticationType != 'none' and username != u'': self.hostPlugin.logger.threaddebug( u'Using login credentials... Username=> ' + username + u'; Password=>' + RPFrameworkUtils.to_unicode(len( password)) + u' characters long') if authenticationType.lower() == 'digest': self.hostPlugin.logger.threaddebug( u'Enabling digest authentication') authenticationParam = HTTPDigestAuth( username, password) else: authenticationParam = (username, password) # execute the URL fetching depending upon the method requested if command.commandName == CMD_RESTFUL_GET or command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: responseObj = requests.get( fullGetUrl, auth=authenticationParam, headers=customHeaders, verify=False) elif command.commandName == CMD_RESTFUL_PUT: dataToPost = None if len(commandPayloadList) >= 6: dataToPost = commandPayloadList[5] responseObj = requests.post( fullGetUrl, auth=authenticationParam, headers=customHeaders, verify=False, data=dataToPost) # if the network command failed then allow the error processor to handle the issue if responseObj.status_code == 200: # the response handling will depend upon the type of command... binary returns must be # handled separately from (expected) text-based ones if command.commandName == CMD_DOWNLOADFILE or command.commandName == CMD_DOWNLOADIMAGE: # this is a binary return that should be saved to the file system without modification if len(commandPayloadList) >= 6: saveLocation = commandPayloadList[5] # execute the actual save from the binary response stream try: localFile = open( RPFrameworkUtils.to_str( saveLocation), "wb") localFile.write( responseObj.content) self.hostPlugin.logger.threaddebug( u'Command Response: [' + RPFrameworkUtils.to_unicode( responseObj.status_code) + u'] -=- binary data written to ' + RPFrameworkUtils.to_unicode( saveLocation) + u'-=-') if command.commandName == CMD_DOWNLOADIMAGE: imageResizeWidth = 0 imageResizeHeight = 0 if len(command.commandPayload ) >= 7: imageResizeWidth = int( command. commandPayload[6]) if len(command.commandPayload ) >= 8: imageResizeHeight = int( command. commandPayload[7]) resizeCommandLine = u'' if imageResizeWidth > 0 and imageResizeHeight > 0: # we have a specific size as a target... resizeCommandLine = u'sips -z ' + RPFrameworkUtils.to_unicode( imageResizeHeight ) + u' ' + RPFrameworkUtils.to_unicode( imageResizeWidth ) + u' ' + saveLocation elif imageResizeWidth > 0: # we have a maximum size measurement resizeCommandLine = u'sips -Z ' + RPFrameworkUtils.to_unicode( imageResizeWidth ) + u' ' + saveLocation # if a command line has been formed, fire that off now... if resizeCommandLine == u'': self.hostPlugin.logger.debug( u'No image size specified for ' + RPFrameworkUtils. to_unicode( saveLocation) + u'; skipping resize.') else: self.hostPlugin.logger.threaddebug( u'Executing resize via command line "' + resizeCommandLine + u'"') try: subprocess.Popen( resizeCommandLine, shell=True) self.hostPlugin.logger.debug( saveLocation + u' resized via sip shell command' ) except: self.hostPlugin.logger.error( u'Error resizing image via sips' ) # we have completed the download and processing successfully... allow the # device (or its descendants) to process successful operations self.notifySuccessfulDownload( command, saveLocation) finally: if not localFile is None: localFile.close() else: self.hostPlugin.logger.error( u'Unable to complete download action - no filename specified' ) else: # handle this return as a text-based return self.hostPlugin.logger.threaddebug( u'Command Response: [' + RPFrameworkUtils.to_unicode( responseObj.status_code) + u'] ' + RPFrameworkUtils.to_unicode( responseObj.text)) self.hostPlugin.logger.threaddebug( command.commandName + u' command completed; beginning response processing' ) self.handleDeviceTextResponse( responseObj, command) self.hostPlugin.logger.threaddebug( command.commandName + u' command response processing completed' ) elif responseObj.status_code == 401: self.handleRESTfulError( command, u'401 - Unauthorized', responseObj) else: self.handleRESTfulError( command, str(responseObj.status_code), responseObj) except Exception, e: # the response value really should not be defined here as it bailed without # catching any of our response error conditions self.handleRESTfulError(command, e, None) elif command.commandName == CMD_SOAP_REQUEST or command.commandName == CMD_JSON_REQUEST: responseObj = None try: # this is to post a SOAP request to a web service... this will be similar to a restful put request # but will contain a body payload self.hostPlugin.logger.threaddebug( u'Received SOAP/JSON command request: ' + command.commandPayload) soapPayloadParser = re.compile( "^\s*([^\n]+)\n\s*([^\n]+)\n(.*)$", re.DOTALL) soapPayloadData = soapPayloadParser.match( command.commandPayload) soapPath = soapPayloadData.group(1).strip() soapAction = soapPayloadData.group(2).strip() soapBody = soapPayloadData.group(3).strip() fullGetUrl = u'http://' + deviceHTTPAddress[ 0] + u':' + RPFrameworkUtils.to_str( deviceHTTPAddress[1] ) + RPFrameworkUtils.to_str(soapPath) self.hostPlugin.logger.debug( u'Processing SOAP/JSON operation to ' + fullGetUrl) customHeaders = {} self.addCustomHTTPHeaders(customHeaders) if command.commandName == CMD_SOAP_REQUEST: customHeaders[ "Content-type"] = "text/xml; charset=\"UTF-8\"" customHeaders[ "SOAPAction"] = RPFrameworkUtils.to_str( soapAction) else: customHeaders[ "Content-type"] = "application/json" # execute the URL post to the web service self.hostPlugin.logger.threaddebug( u'Sending SOAP/JSON request:\n' + RPFrameworkUtils.to_unicode(soapBody)) self.hostPlugin.logger.threaddebug( u'Using headers: \n' + RPFrameworkUtils.to_unicode(customHeaders)) responseObj = requests.post( fullGetUrl, headers=customHeaders, verify=False, data=RPFrameworkUtils.to_str(soapBody)) if responseObj.status_code == 200: # handle this return as a text-based return self.hostPlugin.logger.threaddebug( u'Command Response: [' + RPFrameworkUtils.to_unicode( responseObj.status_code) + u'] ' + RPFrameworkUtils.to_unicode( responseObj.text)) self.hostPlugin.logger.threaddebug( command.commandName + u' command completed; beginning response processing' ) self.handleDeviceTextResponse( responseObj, command) self.hostPlugin.logger.threaddebug( command.commandName + u' command response processing completed') else: self.hostPlugin.logger.threaddebug( u'Command Response was not HTTP OK, handling RESTful error' ) self.handleRESTfulError( command, str(responseObj.status_code), responseObj) except Exception, e: self.handleRESTfulError(command, e, responseObj) else:
def isValueValid(self, proposedValue): # if the value is required but empty then error here if proposedValue == None or proposedValue == u'': return not self.isRequired # now validate that the type is correct... if self.paramType == ParamTypeInteger: try: proposedIntValue = int(proposedValue) if proposedIntValue < self.minValue or proposedIntValue > self.maxValue: raise u'Param value not in range' return True except: return False elif self.paramType == ParamTypeFloat: try: proposedFltValue = float(proposedValue) if proposedFltValue < self.minValue or proposedFltValue > self.maxValue: raise u'Param value not in range' return True except: return False elif self.paramType == ParamTypeBoolean: if type(proposedValue) is bool: return True else: return proposedValue.lower() == u'true' elif self.paramType == ParamTypeOSDirectoryPath: # validate that the path exists... and that it is a directory return os.path.isdir(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeOSFilePath: # validate that the file exists (and that it is a file) return os.path.isfile(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeIPAddress: # validate the IP address using IPv4 standards for now... return self.isIPv4Valid(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeList: # validate that the list contains between the minimum and maximum # number of entries if len(proposedValue) < self.minValue or len( proposedValue) > self.maxValue: return False else: return True else: # default is a string value... so this will need to check against the # validation expression, if set, and string length if self.validationExpression != u'': if re.search(self.validationExpression, proposedValue, re.I) == None: return False strLength = len(proposedValue) if strLength < self.minValue or strLength > self.maxValue: return False # if string processing makes it here then all is good return True
def isValueValid(self, proposedValue): # if the value is required but empty then error here if proposedValue == None or proposedValue == u'': return not self.isRequired # now validate that the type is correct... if self.paramType == ParamTypeInteger: try: proposedIntValue = int(proposedValue) if proposedIntValue < self.minValue or proposedIntValue > self.maxValue: raise u'Param value not in range' return True except: return False elif self.paramType == ParamTypeFloat: try: proposedFltValue = float(proposedValue) if proposedFltValue < self.minValue or proposedFltValue > self.maxValue: raise u'Param value not in range' return True except: return False elif self.paramType == ParamTypeBoolean: if type(proposedValue) is bool: return True else: return proposedValue.lower() == u'true' elif self.paramType == ParamTypeOSDirectoryPath: # validate that the path exists... and that it is a directory return os.path.isdir(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeOSFilePath: # validate that the file exists (and that it is a file) return os.path.isfile(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeIPAddress: # validate the IP address using IPv4 standards for now... return self.isIPv4Valid(RPFrameworkUtils.to_str(proposedValue)) elif self.paramType == ParamTypeList: # validate that the list contains between the minimum and maximum # number of entries if len(proposedValue) < self.minValue or len(proposedValue) > self.maxValue: return False else: return True else: # default is a string value... so this will need to check against the # validation expression, if set, and string length if self.validationExpression != u'': if re.search(self.validationExpression, proposedValue, re.I) == None: return False strLength = len(proposedValue) if strLength < self.minValue or strLength > self.maxValue: return False # if string processing makes it here then all is good return True