def post(self, ns_instance_id): # 1. [WEB->RESTIF] RECEIVE PROCESS try: content = request.get_json(force=True) data = json.dumps(content) except Exception as e: data = '' # 2. [WEB->RESTIF] RECEIVE LOGGING ServiceManager.RecvLogging(self.logger, data, request) # 3. [RESTIF->APP] MAKE SEND STRUCT self.clientId = PLTEManager.getInstance().getClientReqId() reqMsg = ServiceManager.setApiToStructMsg(request, data, self.clientId) # 4. [RESTIF->APP] SEND QUEUE MESSAGE(RELAY) PLTEManager.getInstance().sendCommand(ApiDefine, self, reqMsg) # 5. WAIT self.receiveReqId = -1 while self.clientId != self.receiveReqId: try: time.sleep(1) except Exception as e: self.logger.error(e) # 6. [RESTIF->WEB] SEND LOGGING ServiceManager.SendLogging(self.logger, self.resMsg) # 7. [RESTIF->WEB] SEND RESPONSE return flask.Response( self.resMsg.jsonBody, # mimetype=content_type, status=self.rspCode)
def __init__(self, requestQueue, responseQueue, botID, debug=False) : Thread.__init__(self) self.messageRequestQueue = requestQueue self.messageResponseQueue = responseQueue self.serviceRequestQueue = Queue.Queue() self.serviceResponseQueue = Queue.Queue() self.subscriptionHandler = None self.botID = botID self.debug = debug self.serviceManager = ServiceManager() if(self.debug) : logger.debug('MessageHandler successfully created')
def post(self, nsInstanceId): # 1. [WEB->RESTIF] RECEIVE PROCESS try: content = request.get_json(force=True) data = json.dumps(content) except Exception as e: data = '' # 2. [WEB->RESTIF] RECEIVE LOGGING ServiceManager.RecvLogging(self.logger, data, request) # 3. [RESTIF->APP] MAKE SEND STRUCT header = HttpHeader() header.method = ServiceManager.getMethodType(request.method) header.api_type = ApiType.NSLCM_API_TYPE header.resource_type = ResourceType.NSLCM_INSTANTIATE_NS_TASK header.op_type = OPType.Instantiate_NS_OP_TYPE header.encoding = ContentEncoding.PLAIN Info = ServiceManager.getHttpInfo(nsInstanceId) self.clientId = PLTEManager.getInstance().getClientReqId() reqMsg = ServiceManager.setApiToStructMsg(request, data, self.clientId, header, Info) #reqMsg.info.ns_instance_id = nsInstanceId # 4. [RESTIF->APP] SEND QUEUE MESSAGE(RELAY) PLTEManager.getInstance().sendCommand(ApiDefine.NS_INSTANTIATION, self, reqMsg) # 5. WAIT self.receiveReqId = -1 while self.clientId != self.receiveReqId: try: time.sleep(1) except Exception as e: self.logger.error(e) # 6. [RESTIF->WEB] SEND LOGGING ServiceManager.SendLogging(self.logger, self.resMsg) # 7. [RESTIF->WEB] SEND RESPONSE return flask.Response( self.resMsg.jsonBody, # mimetype=content_type, status=self.rspCode)
def __init__(self, serviceRequestQueue, serviceResponseQueue, debug=False): Thread.__init__(self) # Set up Mongo DB client = pymongo.MongoClient(config.slack['mongoDB']['uri']) db = client[config.slack['mongoDB']['dbName']] self.collection = db[config.slack['mongoDB']['collectionName']] self.running = True self.debug = debug self.serviceRequestQueue = serviceRequestQueue self.serviceResponseQueue = serviceResponseQueue self.serviceManager = ServiceManager() self.serviceFunctions = self.setUpServiceFunctions() self.usersSubscriptions = { } # Determine which users have access to which services if (self.debug): logger.debug('SubscriptionHandler successfully created')
def main(): args = prepCmdArgs() try: ServiceManager().validateConfig() xBot = ExampleBot(config.slack['token'], args.debug) xBot.run() except Exception as e: print("Exception: " + e) sys.exit(1)
from ServiceManager import ServiceManager import xml.etree.ElementTree as ET import requests import datetime import re import sys #from flask import Flask #from flask import request #app = Flask(__name__) myservice = ServiceManager() # test dhl dropoff service # paramdhl = {} # paramdhl["pickup_date"] = "2017-05-26" # paramdhl["ready_by_time"] = "10:20" # paramdhl["close_time"] = "14:20" paramdhl = { "requestor": { "name": "Rikhil", "phone": "23162", "company": "Saurabh" }, "place": { "line1": "123 Test Ave", "line2": "Test Bus Park", "package_location": "Reception", "city": "PARIS", "post_code": "75018", "country_code": "FR"
class CLI: """A command line service manager""" _currentSubDomain = None _currentDomain = None _currentSubDomain = None _serviceManager = ServiceManager() def __init__(self): """Start the interactive cluster editor""" # Start the interactive shell while True: commandReturn = self._getCommand() # Check if the shell should be terminated if commandReturn == CommandReturnCode.Exit: break def _getCommand(self): """Prompt the user to input another command and run it Returns: CommandReturnCode: The run commands return code """ commandString = input(ConsoleMod.HEADER + 'ServiceManager>' + ConsoleMod.ENDC) command = Command(commandString) # No command was specified if len(command) == 0: return CommandReturnCode.Unknown # Exit the shell if command == 'exit': return CommandReturnCode.Exit # Domain commands commandReturnCode = self.__processDomainCommands(command) if commandReturnCode != CommandReturnCode.Unknown: return commandReturnCode # SubDomain commands commandReturnCode = self.__processSubDomainCommands(command) if commandReturnCode != CommandReturnCode.Unknown: return commandReturnCode # Module commands commandReturnCode = self.__processModuleCommands(command) if commandReturnCode != CommandReturnCode.Unknown: return commandReturnCode # The command couldn't be processed print(ConsoleMod.WARNING + 'command "' + commandString + '" couldn\'t be processed' + ConsoleMod.ENDC) return CommandReturnCode.Unknown def __processDomainCommands(self, command): """Process Domain related commands usage: [select|create|exit|delete|get|list|ls|current] [dm|domain] [DOMAIN] Args: command (string): The command input by the user Returns: The processed commands return code """ # Make sure this is a domain command if len(command) not in range(2, 4) or (command[1] != 'dm' and command[1] != 'domain'): return CommandReturnCode.Unknown # Set variables commandName = command[0] domainName = command[2] if len(command) == 3 else '' # Select (and create if it doesn't exist) a domain if commandName == 'select' and domainName != '': # Tell user about possibly leaving a previous domain if self._currentDomain is not None: print('left domain "' + str(self._currentDomain)) # Get the domain from the manager self._currentDomain = self._serviceManager.domain(domainName) print('selected domain "' + str(self._currentDomain) + '"') return CommandReturnCode.Success # Exit the current domain elif commandName == 'exit': print('left domain "' + str(self._currentDomain)) self._currentDomain = None return CommandReturnCode.Success # Create a new domain elif commandName == 'create' and domainName != '': domain = self._serviceManager.domain(domainName) print('created domain "' + str(domain) + '"') return CommandReturnCode.Success # Delete a domain elif commandName == 'delete' and domainName != '': # Get the domain domain = self._serviceManager.domain(domainName) domainName = str(domain) # Now delete it self._serviceManager.deleteDomain(domain) print('deleted domain "' + domainName + '"') return CommandReturnCode.Success # Show the name of the currently selected domain elif commandName == 'current': print('current domain "' + str(self._currentDomain) + '"') return CommandReturnCode.Success # TODO: add a command to show a domains details # List all existing domains elif commandName == 'get' or commandName == 'list' or commandName == 'ls': print('available domains:') for domain in self._serviceManager.domains: print('\t', domain) return CommandReturnCode.Success # No matching command return CommandReturnCode.Unknown def __processSubDomainCommands(self, command): """Process SubDomain related commands usage: [select|create|exit|delete|get|list|ls|current] [sd|subdomain] [SUBDOMAIN] Args: command (string): The command input by the user Returns: The processed commands return code """ # Make sure this is a subdomain command if len(command) not in range(2, 4) or (command[1] != 'sd' and command[1] != 'subdomain'): return CommandReturnCode.Unknown # A domain has to be selected for this if self._currentDomain is None: print(ConsoleMod.FAIL + 'a domain has to be selected' + ConsoleMod.ENDC) return CommandReturnCode.Error # Set variables commandName = command[0] subDomainName = command[2] if len(command) == 3 else '' # Select (and create if it doesn't exist) a subdomain if commandName == 'select' and subDomainName != '': # Tell user about possibly leaving a previous subdomain if self._currentSubDomain is not None: print('left subdomain "' + str(self._currentSubDomain)) # Get the subdomain from the current domain self._currentSubDomain = self._currentDomain.subDomain( subDomainName) print('selected subdomain "' + str(self._currentSubDomain) + '"') return CommandReturnCode.Success # Exit the current domain elif commandName == 'exit': print('left subdomain "' + str(self._currentSubDomain)) self._currentSubDomain = None return CommandReturnCode.Success # Create a new subdomain elif commandName == 'create' and subDomainName != '': subdomain = self._currentDomain.subDomain(subDomainName) print('created subdomain "' + str(subdomain) + '"') return CommandReturnCode.Success # Delete a subdomain elif commandName == 'delete' and subDomainName != '': # Get the subdomain subdomain = self._currentDomain.subDomain(subDomainName) subDomainName = str(subdomain) # Now delete it subdomain.delete() print('deleted subdomain "' + subDomainName + '"') return CommandReturnCode.Success # Show the name of the currently selected subdomain elif commandName == 'current': print('current subdomain "' + str(self._currentSubDomain) + '"') return CommandReturnCode.Success # TODO: add a command to show a subdomains details # List all existing subdomains for this domain elif commandName == 'get' or commandName == 'list' or commandName == 'ls': print('available subdomains:') for subdomain in self._currentDomain.subDomains: print('\t', subdomain) return CommandReturnCode.Success # No matching command return CommandReturnCode.Unknown def __processModuleCommands(self, command): """Process Module related commands usage: [add|create|delete|rm|clean|up|down|get|list|ls|current] [md|module] [MODULE] Args: command (string): The command input by the user Returns: The processed commands return code """ # Make sure this is a module command if len(command) not in range(2, 4) or (command[1] != 'md' and command[1] != 'module'): return CommandReturnCode.Unknown # A subdomain has to be selected for this if self._currentSubDomain is None: print(ConsoleMod.FAIL + 'a subdomain has to be selected' + ConsoleMod.ENDC) return CommandReturnCode.Error # Set variables commandName = command[0] moduleName = command[2] if len(command) == 3 else '' # Add a new module to the current subdomain if (commandName == 'add' or commandName == 'create') and moduleName != '': # Create the module and add it to the subdomain module = ModuleLoader.new(moduleName, self._currentSubDomain) self._currentSubDomain.addModule(module) print('created module "' + str(module) + '"') return CommandReturnCode.Success # Delete a module from the current subdomain elif commandName == 'delete' or commandName == 'rm' or commandName == 'clean': moduleName = str(self._currentSubDomain.activeModule) self._currentSubDomain.deleteModule() print('deleted module "' + moduleName + '" from subdomain "' + str(self._currentSubDomain) + '"') return CommandReturnCode.Success # Bring all containers of this module up elif commandName == 'up': # A module has to be active for this if self._currentSubDomain.activeModule is None: print(ConsoleMod.FAIL + 'the current subdomain "' + str(self._currentSubDomain) + '" has no active module' + ConsoleMod.ENDC) return CommandReturnCode.Error # Bring up the module self._currentSubDomain.activeModule.up() print('module "' + str(self._currentSubDomain.activeModule) + '" is coming up') return CommandReturnCode.Success # Shut all containers of this module down elif commandName == 'down': # A module has to be active for this if self._currentSubDomain.activeModule is None: print(ConsoleMod.FAIL + 'the current subdomain "' + str(self._currentSubDomain) + '" has no active module' + ConsoleMod.ENDC) return CommandReturnCode.Error # Shut the containers down self._currentSubDomain.activeModule.down() print('module "' + str(self._currentSubDomain.activeModule) + '" is going down') return CommandReturnCode.Success # TODO: add a command to show container logs # TODO: add a command to show container status # TODO: add a command to show module status (up/down/warning/error) # TODO: add a command to show a modules details # Show the name of the module for the currently selected subdomain elif commandName == 'get' or commandName == 'list' or commandName == 'ls' or commandName == 'current': print('current module "' + str(self._currentSubDomain.activeModule) + '"') return CommandReturnCode.Success # No matching command return CommandReturnCode.Unknown
class SubscriptionHandler(Thread): def __init__(self, serviceRequestQueue, serviceResponseQueue, debug=False): Thread.__init__(self) # Set up Mongo DB client = pymongo.MongoClient(config.slack['mongoDB']['uri']) db = client[config.slack['mongoDB']['dbName']] self.collection = db[config.slack['mongoDB']['collectionName']] self.running = True self.debug = debug self.serviceRequestQueue = serviceRequestQueue self.serviceResponseQueue = serviceResponseQueue self.serviceManager = ServiceManager() self.serviceFunctions = self.setUpServiceFunctions() self.usersSubscriptions = { } # Determine which users have access to which services if (self.debug): logger.debug('SubscriptionHandler successfully created') # Entry point for thread def run(self): self.loadScheduledJobs() while (self.running): try: schedule.run_pending() self.checkJobQueue() except (KeyboardInterrupt, SystemError): print( "\n~~~~~~~~~~~ SubscriptionHandler KeyboardInterrupt Exception Found~~~~~~~~~~~\n" ) self.running = False # Checks for updates of jobs def checkJobQueue(self): if (not self.serviceRequestQueue.empty()): request = self.serviceRequestQueue.get() self.serviceRequestQueue.task_done() serviceName = request['scheduleJob']['serviceName'] tag = self.produceTag(request) if (self.debug): logger.info( "SubscriptionHandler request found {}".format(request)) if (request['scheduleJob']['action'] == 'add'): scheduleSuccessful = self.scheduleJob(request) dbSaveSuccessful = self.saveJob(request) if (scheduleSuccessful and dbSaveSuccessful): self.addUserToSubscription(tag) response = "Successfully scheduled and saved {} service request of type {} every {} {}.".format( serviceName, request['scheduleJob']['type'], str(request['scheduleJob']['interval']), request['scheduleJob']['frequency']) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) else: print(request) response = "Unable to subscribe you to {} because you are already subscribe to this serivce.".format( serviceName) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) elif (request['scheduleJob']['action'] == 'remove'): unscheduleSuccessful = self.unscheduleJob(request) dbRemoveSuccessful = self.deleteJob(request) if (unscheduleSuccessful and dbRemoveSuccessful): self.removeUserFromSubscription(tag) response = "Successfully unscheduled and removed {} service request of type {} every {} {}.".format( request['scheduleJob']['serviceName'], request['scheduleJob']['type'], str(request['scheduleJob']['interval']), request['scheduleJob']['frequency']) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) else: response = "Unable to unsubscribe you from {} because you are no longer subscribe to this serivce.".format( serviceName) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) elif (request['scheduleJob']['action'] == 'update'): updateSuccessful = self.updateJob(request) if (updateSuccessful): response = "Successfully updated {} service request of type {} every {} {}.".format( request['scheduleJob']['serviceName'], request['scheduleJob']['type'], str(request['scheduleJob']['interval']), request['scheduleJob']['frequency']) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) else: response = "Unable to update your service for service: {}.".format( serviceName) slackResponse = self.generateSlackResponse( request['messageInfo']['slackUserId'], request['messageInfo']['channel'], response) self.serviceResponseQueue.put(slackResponse) else: print("Unknown action for Service request.") # Adds to reoccuring job to DB def saveJob(self, request): #FIXME: Use Mongo Schema to prevent ulgy jobs entrying db userId = request['messageInfo']['slackUserId'] service = request['scheduleJob']['serviceName'] # tag = self.produceTag(userId, service) tag = self.produceTag(request) if (not self.subscriptionExists(tag)): request['scheduleJob']['serviceTag'] = tag dbResult = self.collection.insert_one(request) result = dbResult.acknowledged else: print("User id {} is already subscribed to service {}".format( userId, service)) result = False return result # Removes reoccuring job to DB def deleteJob(self, request): tag = self.produceTag(request) if (self.subscriptionExists(tag)): query = {"scheduleJob.serviceTag": tag} dbStat = self.collection.remove(query) if (dbStat['n'] <= 0): print("ERROR removing document with tag {}.") return False else: print( "Mongdo DB document for tag {} has been properly removed.") return True else: print("Unable to removed tag because it does not exist") return False # NOTE: request contains new services def updateJob(self, request): tag = self.produceTag(request) query = {"scheduleJob.serviceTag": tag} update = { "$set": { "scheduleJob.day": request['scheduleJob']['day'], "scheduleJob.interval": request['scheduleJob']['interval'], "scheduleJob.time": request['scheduleJob']['time'], "scheduleJob.frequency": request['scheduleJob']['frequency'], "scheduleJob.type": request['scheduleJob']['type'] } } result = self.collection.find_one_and_update(query, update) if (result is None): return False else: return True # Adds a job to Scheduler def scheduleJob(self, request): status = True tag = self.produceTag(request) serviceName = request['scheduleJob']['serviceName'] if (not self.subscriptionExists(tag)): if (self.debug): logger.debug("Scheduling Job ...\n{}".format(request)) if (self.isIntraDay(request)): status = self.scheduleIntraDayJob(request) elif (self.isIntraMonth(request)): status = self.scheduleIntraMonthJob(request) elif (self.isIntraYear(request)): pass # Not Implemented # status = self.scheduleIntraYearJob(request) else: if (self.debug): logger.error("Unable to schedule Job") status = False else: print( "You are already Subscribe to {} service".format(serviceName)) status = False return status # Removes schedule jobs from schedule def unscheduleJob(self, job): status = True if (self.debug): logger.debug("Unscheduling Job ...") tag = job['messageInfo']['slackUserId'] + "_" + job['scheduleJob'][ 'serviceName'] # : Figure out if a status can be evaluated schedule.clear(tag) return status # Unschedules a list of users from scheduler def unscheduledJobByTag(self, userIds, service): for userId in userIds: tag = userId + "_" + service # FIXME: Status of removal? schedule.clear(tag) # Loads all jobs from DB into scheduler def loadScheduledJobs(self): jobs = self.collection.find({}) if (self.debug): logger.debug("Found {} logs in db".format(str(jobs))) for job in jobs: self.addUserToSubscription(self.extractTag(job)) self.scheduleJob(job) # loads a tag into local subscription record def loadSubscriptions(self, tag): userId, service = tag.split("_") if (userId in self.usersSubscriptions): if (not (service in self.usersSubscriptions[userId])): self.usersSubscriptions[userId].append(service) else: self.usersSubscriptions[userId] = [service] # Helper method: Adds a new intra-day schedule job def scheduleIntraDayJob(self, request): status = True serviceName = request['scheduleJob']['serviceName'] func = self.serviceFunctions[serviceName] frequency = request['scheduleJob']['frequency'] interval = request['scheduleJob']['interval'] args = {} args['service'] = self.serviceManager.getServiceDetails(serviceName) args['messageInfo'] = request['messageInfo'] args['scheduleJob'] = request['scheduleJob'] # NOTE: When would args be None? if (args is not None): #TODO: remove set value from messagehandler and determine serivceName within this file tag = request['messageInfo']['slackUserId'] + "_" + request[ 'scheduleJob']['serviceName'] if frequency == 'minutes': schedule.every(interval).minutes.do(func, args).tag(tag) elif frequency == 'seconds': schedule.every(interval).seconds.do(func, args).tag(tag) elif frequency == 'hours': schedule.every(interval).hours.do(func, args).tag(tag) else: print("ERROR OCCURRED") status = False else: print("Error Occurred while searching for ServiceDetails") status = False return status # Helper method: Adds a new intra month schedule job def scheduleIntraMonthJob(self, job): pass # Helper method: Adds a new intra year schedule job def scheduleIntraYearJob(self, job): pass # Assigns a runnable function to each of the services in the service config def setUpServiceFunctions(self): serviceFunc = {} services = self.serviceManager.getAllServicesDetails() for service in services: serviceName = service['name'] location = service['path'] if (location.lower() == "internal"): methodName = service['entrypoint'] function = self.getFunction(methodName) if (function is not None): serviceFunc[serviceName] = function else: serviceFunc[serviceName] = self.runExternalService if (self.debug): logger.info("Setup Function list as {}".format(serviceFunc)) return serviceFunc # Returns a function for a give serviceName def getFunction(self, methodName): if (callable(getattr(self, methodName))): return getattr(self, methodName) else: return None # Determines if there is a user subscription that exists for a given tag def subscriptionExists(self, tag): userId, service = tag.split("_") if (userId in self.usersSubscriptions): if (service in self.usersSubscriptions[userId]): return True else: return False # Adds a user to the local user subscription list def addUserToSubscription(self, tag): userId, service = tag.split("_") if (self.debug): logger.debug("service: {} userId: {} userSubscriptions: {}".format( service, userId, self.usersSubscriptions)) if (userId in self.usersSubscriptions): self.usersSubscriptions[userId].append(service) if (self.debug): logger.debug("Added additional service to {}.".format(userId)) else: self.usersSubscriptions[userId] = [] if (self.debug): logger.debug("Adding new userId to usersSubscriptions") self.usersSubscriptions[userId].append(service) if (self.debug): logger.debug( "Service: {} userId: {} added to userSubscriptions: {}". format(service, userId, self.usersSubscriptions)) # Removes a user to the local user subscription list def removeUserFromSubscription(self, tag): userId, service = tag.split("_") if (userId in self.usersSubscriptions): if (service in self.usersSubscriptions[userId]): self.usersSubscriptions[userId].remove(service) else: print("Tag {} does not exits. Can't remove".format(tag)) if (not self.usersSubscriptions[userId]): del self.usersSubscriptions[userId] else: print("No userId {} exists".format(userId)) # def getUserIdsForServiceName(self, serviceName): result = [] for userId, serviceNames in enumerate(self.usersSubscriptions): if (serviceName in serviceNames): result.append(userId) return result def getServicesListForUsersId(self, userId): if (userId in self.usersSubscriptions): return self.usersSubscriptions[userId] else: return [] def runExternalService(self, args): cmd = args['service']['language'] filepath = args['service']['path'] + "/" + args['service']['entrypoint'] serviceName = args['scheduleJob']['serviceName'] output = subprocess.check_output([cmd, filepath]) response = self.serviceManager.generateSlackResponseOutput( output, args['messageInfo']) if (response is not None): if (self.debug): logger.info( "Returning response up to MessageHandler: {}".format( response)) self.serviceResponseQueue.put(response) else: print("The external service {} fail. Disable this service".format( serviceName)) self.serviceManager.makeUnrunnableService(serviceName) userIds = self.getUserIdsForServiceName(serviceName) self.unscheduledJobByTag(userIds, serviceName) # Terminates thread loop def kill(self): self.running = False # Produces an job identifier def produceTag(self, request): return request['messageInfo']['slackUserId'] + "_" + request[ 'scheduleJob']['serviceName'] #FIXME: Redundant method def extractTag(self, job): return job['scheduleJob']['serviceTag'] # Determine if job is an intra day def isIntraDay(self, request): if (request['scheduleJob']['type'] == 'intra-day'): return True else: return False # Determine if job is an intra month def isIntraMonth(self, request): if (request['scheduleJob']['type'] == 'intra-month'): return True else: return False # Determine if job is an intra year def isIntraYear(self, request): if (request['scheduleJob']['type'] == 'intra-year'): return True else: return False # Text based job def helloJob(self, messageInfo): response = 'Hello World Fool!' self.generateSlackResponse(messageInfo['slackUserId'], messageInfo['channel'], response) self.serviceResponseQueue.put(messageInfo) # File based job def fileJob(self, messageInfo): messageInfo['action'] = 'writeToFile' messageInfo['responseType'] = 'file' messageInfo['response'] = './extras/images/slackdroid.png' self.serviceResponseQueue.put(messageInfo) def generateSlackResponse(self, slackUserId, channel, response): messageInfo = {} messageInfo['action'] = "writeToSlack" messageInfo['responseType'] = "text" messageInfo['slackUserId'] = slackUserId messageInfo['channel'] = channel messageInfo['response'] = response return messageInfo
from ServiceManager import ServiceManager import datetime import sys import re import json # from flask import Flask # from flask import request # app = Flask(__name__) myservice = ServiceManager() # test dhl dropoff service # paramdhl = {} # paramdhl["pickup_date"] = "2017-05-26" # paramdhl["ready_by_time"] = "10:20" # paramdhl["close_time"] = "14:20" # myservice.call_service("dhl","pickup", paramdhl) print ("\n") # test parcel pickup service # paramparcel = {} # paramparcel['from'] = "France" # paramparcel['to'] = "Cambodia" # myservice.call_service("parcel", "pickup", paramparcel) #========================= API GETWAY ================================ # @app.route("/<company>/<service>", methods = ["POST"])
class MessageHandler(Thread): def __init__(self, requestQueue, responseQueue, botID, debug=False) : Thread.__init__(self) self.messageRequestQueue = requestQueue self.messageResponseQueue = responseQueue self.serviceRequestQueue = Queue.Queue() self.serviceResponseQueue = Queue.Queue() self.subscriptionHandler = None self.botID = botID self.debug = debug self.serviceManager = ServiceManager() if(self.debug) : logger.debug('MessageHandler successfully created') # Entry point for thread def run(self) : self.running = True self.setUpThreads() # TODO: Figure out multi-threaded solution while(self.running) : try : if(self.messageRequestQueue.qsize() > 0) : message = self.messageRequestQueue.get() if(self.debug) : logger.debug("Message requested received from Bot {}".format(str(message))) self.handle(message) elif(self.serviceResponseQueue.qsize() > 0) : response = self.serviceResponseQueue.get() if(self.debug) : logger.debug("Message response received from SubscriptionHandler {}".format(str(response))) self.messageResponseQueue.put(response) except(KeyboardInterrupt, SystemError) : if(self.debug) : logger.debug("\n~~~~~~~~~~~ MessageHandler KeyboardInterrupt Exception Found~~~~~~~~~~~\n") self.subscriptionHandler.kill() self.running = False def setUpThreads(self) : self.subscriptionHandler = SubscriptionHandler(self.serviceRequestQueue, self.serviceResponseQueue, self.debug) self.subscriptionHandler.setName("SubscriptionHandler Thread 1") self.subscriptionHandler.daemon = True self.subscriptionHandler.start() if(self.debug) : logger.info("Started thread: {}".format("SubscriptionHandler Thread 1")) # Parses all raw input from Slack def handle(self, rawInput): response = None if (not self.isEmpty(rawInput)) : if(self.isAValidMessage(rawInput) or not self.isTyping(rawInput)) : response = self.parseInput(rawInput) if(self.debug) : logger.debug("Handling valid message: {}".format(response)) if(response != None) : self.messageResponseQueue.put(response) else : if(self.debug) : logger.error("Invalid non-empty message received: {}".format(rawInput)) # Kills Thread run method def kill(self) : self.running = False if(self.debug) : logger.info("Terminating MessageHandler") # Parses the raw slack input into parts def parseInput(self, rawInput) : if('user' in rawInput[0] and 'text' in rawInput[0] and 'channel' in rawInput[0]) : user = rawInput[0]['user'] message = rawInput[0]['text'] channel = rawInput[0]['channel'] # Muscle logic action, response = self.determineAction(rawInput[0]) responseObject = self.generateMessageResponse(user, message, channel, action, response) return responseObject else : logger.warning("rawInput not valid. Modify handle criterion. {}".format(str(rawInput[0]))) return None # Determine what action to take depending on the message def determineAction(self, rawInput) : userID = rawInput['user'] message = rawInput['text'] channel = rawInput['channel'] userId = rawInput['user'] if(self.isGreeting(message)) : if(self.debug) : logger.debug("Greeting found return random choice") return ("writeToSlack", random.choice(GREETING_RESPONSES)) elif(self.isServiceListRequest(message)) : serviceList = self.serviceManager.getServicesNames() response = "Available Services\n" for index, service in enumerate(serviceList) : response += "\t{}. {}\n".format(index+1, service) if(self.debug) : logger.debug("Service List Request found {}".format(response)) return ("writeToSlack", response) elif(self.isListAvailableServicesRequest(message)) : myServices = self.subscriptionHandler.getServicesListForUsersId(userId) response = None if(len(myServices) == 0) : response = "You are not subscribed to any services." else : response = "You are currently Subscribed to:\n" for index, myService in enumerate(myServices) : response += "\t{}. {}\n".format(index+1, myService) return("writeToSlack", response) elif(self.isServiceRequest(message)) : # TODO: Determine if the two methods should be combined into one # TODO: Improve to handle all types of services serviceName = self.extractServiceName(message) if(self.serviceManager.isRunnableService(serviceName)) : scheduleAction, scheduleType, frequency, interval = self.determineSchedule(message) if(self.debug) : logger.debug("Service Request for serviceName: {} scheduleAction: {}, scheduleType: {}, frequency: {}, interval {}".format(serviceName, scheduleAction, scheduleType, frequency, interval)) if(serviceName is not None) : serviceRequest = self.createServiceRequest(scheduleAction, userID, channel, serviceName, scheduleType, frequency, interval) self.serviceRequestQueue.put(serviceRequest) return ("writeToSlack", "Working on processing Service for message: " + self.stripTag(message) + " ...") else : return ("writeToSlack", "Sorry I wasn't able to find a service for message: " + self.stripTag(message) + " ...") else : return ("writeToSlack", "Unable to retrieve requested service from message {}.".format(message)) else : return ("writeToSlack", "Im not sure how to decipher \"" + self.stripTag(message) + "\".") def generateMessageResponse(self, user, message, channel, action=None, response=None) : responseObject = {} responseObject["user"] = str(user) responseObject['message'] = str(self.stripTag(message)) responseObject['channel'] = str(channel) responseObject['action'] = action responseObject['response'] = response if(self.debug) : logger.debug("Generating responseObject: {}".format(str(responseObject))) return responseObject # FIXME Determine better way to parse user input and send appropriate service def determineSchedule(self, message) : result = None serviceNames = self.serviceManager.getServicesNames() for serviceName in serviceNames : if(serviceName.lower() in message.lower()) : if("new" in message.lower()) : result = "add" elif("remove" in message.lower()) : result = "remove" elif("update" in message.lower()) : result = "update" break #TODO Figure out a way to parse user messages to determine action, scheduleType, frequency, and interval if(result == "update") : return (result, 'intra-day', 'minutes', 1) return (result, 'intra-day', 'seconds', 30) def createServiceRequest(self, scheduleAction, userId, channel, service, scheduleType, frequency, interval, time = None, day = None ) : if(self.debug) : logger.debug("Create service request with scheduleAction {} userId {} channel {} service {} schedultType {} frequency {} interval {}time {} day {}".format(scheduleAction, userId, channel, service, scheduleType, frequency, interval, time, day)) serviceRequest = { 'messageInfo' : { 'action': None, 'responseType' : None, # Text of file 'slackUserId' : userId, 'channel' : channel, 'response' : None }, 'scheduleJob' : { 'action' : scheduleAction, 'type' : scheduleType, 'serviceName' : service, # Hello World 'serviceTag' : None, 'frequency' : frequency, 'interval' : interval, 'time' : time, 'day' : day } } if(self.debug) : logger.info("Created ServiceRequest {}".format(serviceRequest)) return serviceRequest # FIXME Determine better way to parse user input and send appropriate service def extractServiceName(self, message) : result = None serviceNameList = self.serviceManager.getServicesNames() for serviceName in serviceNameList : if( serviceName.lower() in message.lower() ) : result = serviceName break return result # Determines if a message contains a greeting word def isGreeting(self, message) : for greeting in GREETING_KEYWORDS : if(greeting in message.lower()) : return True return False # #TODO: Improve this def isServiceListRequest(self, message) : if('list' in message.lower() and 'services' in message.lower()) : return True else : return False def isListAvailableServicesRequest(self, message) : if('my' in message.lower() and 'services' in message.lower()) : return True else : return False # TODO Implement to interact Service Manager def isServiceRequest(self, message) : for command in SERVICE_KEYWORDS : if(command in message.lower()) : return True return False # Removes the Slack bot ID from a message def stripTag(self, message) : botTag = "<@" + self.botID + ">" return message.replace(botTag, '').rstrip() # Determines if the raw input was sent by this bot def notSelf(self, rawInput) : if(rawInput[0].get('user') == self.botID) : return False else : return True # Detect if a users is typing def isTyping(self, rawInput) : if(rawInput[0].get('type') == 'user_typing') : return True else : return False # Detects if raw input is Empty def isEmpty(self, rawInput) : if not rawInput : return True else : return False # Detects if the raw input is a message def isAValidMessage(self, rawInput) : if(rawInput[0].get('type') == 'message') : return True else : return False # Determines if the bot is mentioned in the raw input def botMentioned(self, rawInput) : if('text' in rawInput[0]) : if(self.botID in rawInput[0]['text']) : return True else : return False '''Example Message Handling using Textblob'''