Better code organization

parent f4087849
...@@ -941,7 +941,7 @@ def getVoiceCommandList(): ...@@ -941,7 +941,7 @@ def getVoiceCommandList():
def getScreenshotUri(target): def getScreenshotUri(target):
qstring="select screenshot from mediasources where button_name LIKE '"+target+"%' limit 1" qstring="select screenshot from mediasources where button_name LIKE '"+target+"%'"
return runQuery(qstring) return runQuery(qstring)
def getClimaUniques(): def getClimaUniques():
......
...@@ -2455,13 +2455,16 @@ class domotikaService(service.Service): ...@@ -2455,13 +2455,16 @@ class domotikaService(service.Service):
def web_on_getScreenshotList(self, screenshot=True): def web_on_getScreenshotList(self, screenshot=True):
return dmdb.getScreenshotList(screenshot=screenshot) return dmdb.getScreenshotList(screenshot=screenshot)
def web_on_getScreenshot(self, target): def web_on_getScreenshot(self, target, callback=None):
def imageReturn(img): def imageReturn(img):
return img return img
def prepareScreenshot(res): def prepareScreenshot(res):
if res: if callback == None:
return wu.getPage(res[0][0]).addCallback(imageReturn) if res:
return False return wu.getPage(res[0][0]).addCallback(imageReturn)
return False
for r in res:
wu.getPage(r[0]).addCallback(callback)
return dmdb.getScreenshotUri(target).addCallback(prepareScreenshot) return dmdb.getScreenshotUri(target).addCallback(prepareScreenshot)
def web_on_getClimaUniques(self): def web_on_getClimaUniques(self):
......
from zope.interface import Interface, implements
from twisted.python import components
from nevow import rend, inevow from nevow import rend, inevow
from corepost import Response, NotFoundException, AlreadyExistsException from corepost import Response, NotFoundException, AlreadyExistsException
...@@ -16,6 +17,8 @@ from Queue import Queue ...@@ -16,6 +17,8 @@ from Queue import Queue
import uuid import uuid
from domotika.singleton import messengerlinks from domotika.singleton import messengerlinks
from StringIO import StringIO
import imghdr
_MESSENGER_LINKS = messengerlinks.MessengerLinkRegistry() _MESSENGER_LINKS = messengerlinks.MessengerLinkRegistry()
_MESSENGER_PSID = messengerlinks.MessengerPSIDRegistry() _MESSENGER_PSID = messengerlinks.MessengerPSIDRegistry()
...@@ -33,6 +36,114 @@ log = logging.getLogger( 'Webgui' ) ...@@ -33,6 +36,114 @@ log = logging.getLogger( 'Webgui' )
BOTResource = RESTResource BOTResource = RESTResource
class IBotProtoInterface(Interface):
def getUsername(self, uid):
""" get a username from uid """
def isLogged(self, uid):
""" return True if it's a know user """
def sendAPI(self, payload, req_uri):
""" Send request to the API """
def receivedAuthentication(self, msg):
""" receive auth message """
def receivedTextMessage(self, msg):
""" receive text message """
def receivedDeliveryConfirmation(self, msg):
""" receive delivery confirmation """
def receivedPostback(self, msg):
""" receive a postback message """
def receivedAccountLink(self, msg):
""" receive account linking message """
def sendCommandList(self, recipient_id):
""" send command list to the user """
def sendScreenshotList(self, recipient_id):
""" send a list of screenshots available """
def sendScreenshot(self, recipient_id, target):
""" send one or more screenshots """
def sendClima(self, recipient_id):
""" send Clima status """
def sendMessage(self, recipient_id, message):
""" send a text message """
def sendImageMessage(self, recipient_id, imguri):
""" send an image link """
def sendImageMessageData(self, recipient_id, imagedata, mtype):
""" send an image by data """
def sendAuthRequest(self, recipient_id):
""" send login request """
class BotProto(object):
def __init__(self, core):
self.core = core
def botCommandParser(self, uid, txt):
def voiceResult(res):
log.info('VoiceResult: '+str(res))
if len(res) > 0:
if res[0] == 'Ok' and len(res) > 1:
try:
result = 'ho eseguito "'+" ".join(res[1]['clean'])+'"'
except:
pass
else:
result = 'Spiacente, non ho trovato un comando corrispondente'
self.sendMessage(uid, result)
txt = unicode(txt.lower())
if not self.isLogged(uid):
if txt == u'hello' or txt == u'ciao':
self.sendMessage(uid, 'Hello, how can i help you?')
elif txt == u'?' or txt == u'help':
self.sendMessage(uid, 'you can\'t do that.')
elif txt == u'login':
self.sendAuthRequest(uid)
else:
self.sendMessage(uid, txt+u" come se fosse antani")
else:
if txt == u'hello' or txt == u'ciao':
self.sendMessage(uid, 'Hello %s, how can i help you?' %(self.getUsername(uid)))
elif txt == u'?' or txt == u'help':
self.sendMessage(uid, 'Ok, devo ancora implementare l\'aiuto! Sorry for that!')
self.sendMessage(uid, 'Anyway, i comandi che hai sono: "command list", "screenshot list", "screenshot" e "clima".')
self.sendMessage(uid, 'Qualsiasi altro comando viene interpretato come un potenziale comando vocale.')
elif txt == u'logout':
self.sendMessage(uid, 'Ok, devo ancora implementare anche il logout')
elif txt == u'login':
self.sendMessage(uid, 'Sei gia\' loggato, %s!' %(self.getUsername(uid)))
elif txt == u'command list' or txt == 'cmd list':
self.sendCommandList(uid)
elif txt == u'screenshot list' or txt==u'ss list':
self.sendScreenshotList(uid)
elif txt.startswith('screenshot ') or txt.startswith('ss '):
self.sendScreenshot(uid, " ".join(txt.split()[1:]))
elif txt == u'clima':
self.sendClima(uid)
else:
self.core.voiceReceived(txt, confidence=1.0, lang="it").addCallback(voiceResult)
class BotCore(object): class BotCore(object):
path = "" path = ""
...@@ -76,26 +187,30 @@ class MessengerMessage(object): ...@@ -76,26 +187,30 @@ class MessengerMessage(object):
self.payload = payload self.payload = payload
self.uri = uri self.uri = uri
class MessengerCore(object): class MessengerConf(object):
def _cfgGet(self, keyword): def _cfgGet(self, keyword):
return self.core.configGet('messenger', keyword) return self.core.configGet('messenger', keyword)
class MessengerBot(BotCore, MessengerCore): class MessengerBotAdapter(MessengerConf):
implements(IBotProtoInterface)
path = "messenger"
graphuri = 'https://graph.facebook.com/v2.6' graphuri = 'https://graph.facebook.com/v2.6'
sendQueue = Queue() sendQueue = Queue()
sendlock = False sendlock = False
#graphuri = 'http://192.168.4.2/v2.6'
def __init__(self, orig):
self.orig = orig
self.core = orig.core
@property @property
def auth_args(self): def auth_args(self):
if not hasattr(self, '_auth_args'): if not hasattr(self, '_auth_args'):
auth = { auth = {
'access_token': unicode(self._cfgGet('page_token')) 'access_token': unicode(self._cfgGet('page_token'))
} }
if self._cfgGet('app_secret') is not None and len(self._cfgGet('app_secret'))>0: if self._cfgGet('app_secret') is not None and len(self._cfgGet('app_secret'))>0:
appsecret_proof = self._generateAppSecProof() appsecret_proof = self._generateAppSecProof()
auth['appsecret_proof'] = appsecret_proof auth['appsecret_proof'] = appsecret_proof
...@@ -109,6 +224,7 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -109,6 +224,7 @@ class MessengerBot(BotCore, MessengerCore):
hmac_object = hmac.new(bytearray(self._cfgGet('app_secret'), 'utf8'), str(self._cfgGet('page_token')).encode('utf8'), hashlib.sha256) hmac_object = hmac.new(bytearray(self._cfgGet('app_secret'), 'utf8'), str(self._cfgGet('page_token')).encode('utf8'), hashlib.sha256)
return hmac_object.hexdigest() return hmac_object.hexdigest()
def _dataSent(self, res): def _dataSent(self, res):
log.debug('Messenger BOT Datasent OK') log.debug('Messenger BOT Datasent OK')
log.debug(res) log.debug(res)
...@@ -125,10 +241,8 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -125,10 +241,8 @@ class MessengerBot(BotCore, MessengerCore):
def _sendRaw(self): def _sendRaw(self):
if not self.sendQueue.empty() and not self.sendLock: if not self.sendQueue.empty() and not self.sendLock:
message = self.sendQueue.get() message = self.sendQueue.get()
return wu.getPage(message.uri, method='POST', headers=message.headers, return wu.getPage(message.uri, method='POST', headers=message.headers,
postdata=message.payload).addCallbacks(self._dataSent, self._dataError) postdata=message.payload).addCallbacks(self._dataSent, self._dataError)
def sendAPI(self, payload, req_uri='/me/messages'): def sendAPI(self, payload, req_uri='/me/messages'):
request_endpoint = self.graphuri+req_uri request_endpoint = self.graphuri+req_uri
...@@ -137,112 +251,23 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -137,112 +251,23 @@ class MessengerBot(BotCore, MessengerCore):
ctype={"Content-Type": "application/json"} ctype={"Content-Type": "application/json"}
return wu.getPage(request_uri, method='POST', headers=ctype, postdata=convertToJson(payload)).addCallbacks(self._dataSent, self._dataError) return wu.getPage(request_uri, method='POST', headers=ctype, postdata=convertToJson(payload)).addCallbacks(self._dataSent, self._dataError)
def getUsername(self, uid):
return _MESSENGER_PSID.get_link(uid)
@route("/", Http.GET) def isLogged(self, uid):
def rootGet(self, request, *a, **kw): return _MESSENGER_PSID.linkid_exists(uid)
if 'hub.mode' in kw.keys() and kw['hub.mode'] == 'subscribe' and 'hub.challenge' in kw.keys():
if 'hub.verify_token' in kw.keys() and kw['hub.verify_token'] == self._cfgGet('verify_token'):
log.info("New verification request for Messenger BOT: "+str(kw))
return kw['hub.challenge']
return Response(403, "Failed validation." )
@route("/", Http.POST)
@messengerValidator()
def rootPost(self, request, *a, **kw):
log.debug("New messenger bot request: "+str(kw))
if 'object' in kw.keys() and kw['object'] == 'page' and 'entry' in kw.keys():
for entry in kw['entry']:
try:
#if True:
pageID=entry['id']
timestamp=entry['time']
messaging=entry['messaging']
for message in messaging:
msgkeys = message.keys()
if 'optin' in msgkeys:
self.receivedAuthentication(message)
elif 'message' in msgkeys:
self.receivedMessage(message)
elif 'delivery' in msgkeys:
self.receivedDeliveryConfirmation(message)
elif 'postback' in msgkeys:
self.receivedPostback(message)
elif 'read' in msgkeys:
self.receivedMessageRead(message)
elif 'account_linking' in msgkeys:
self.receivedAccountLink(message)
else:
log.info("Received unknow messaging webhook for messenger BOT: "+str(kw))
except:
pass
return Response(200, 'OK')
@route("/loginfailed")
def loginFailed(self, request, *a, **kw):
k = kw.keys()
if 'account_linking_token' in k and 'redirect_uri' in k:
log.info("Passed linking uri "+kw['redirect_uri'])
luri=kw['redirect_uri']
log.info("Authorization failed: redirecting to "+luri)
return Response(302, 'Authorization failed', headers={'Location': luri})
return Response(200, "Authorization failed." )
def receivedAuthentication(self, msg): def receivedAuthentication(self, msg):
log.info("Messenger bot received authentication: "+str(msg)) log.info("Messenger bot received authentication: "+str(msg))
def receivedMessage(self, msg): def receivedTextMessage(self, msg):
def voiceResult(res):
log.info('VoiceResult: '+str(res))
if len(res) > 0:
if res[0] == 'Ok' and len(res) > 1:
try:
result = 'ho eseguito "'+" ".join(res[1]['clean'])+'"'
except:
pass
else:
result = 'Spiacente, non ho trovato un comando corrispondente'
self.sendMessage(msg['sender']['id'], result)
log.info("Messenger bot received message: "+str(msg)) log.info("Messenger bot received message: "+str(msg))
message = u'Received: '+unicode(msg['message']['text'])
txt = unicode(msg['message']['text'])
senderid = msg['sender']['id'] senderid = msg['sender']['id']
if not 'is_echo' in msg['message'].keys() or not msg['message']['is_echo']: if not 'is_echo' in msg['message'].keys() or not msg['message']['is_echo']:
if not _MESSENGER_PSID.linkid_exists(senderid): message = u'Received: '+unicode(msg['message']['text'])
log.info(_MESSENGER_PSID.links) txt = unicode(msg['message']['text']).lower()
if txt == u'hello' or txt == u'ciao': botCommandParser(self, senderid, txt)
self.sendMessage(senderid, 'Hello, how can i help you?')
elif txt == u'?' or txt == u'help':
self.sendMessage(senderid, 'you can\'t do that.')
elif txt == u'login':
self.sendAuthRequest(senderid)
else:
self.sendMessage(senderid, txt+" come se fosse antani")
else:
if txt == u'hello' or txt == u'ciao':
self.sendMessage(senderid, 'Hello %s, how can i help you?' %(_MESSENGER_PSID.get_link(senderid)))
elif txt == u'?' or txt == u'help':
self.sendMessage(senderid, 'Ok, devo ancora implementare l\'aiuto! Sorry for that!')
self.sendMessage(senderid, 'Anyway, i comandi che hai sono: "command list", "screenshot list", "screenshot" e "clima".')
self.sendMessage(senderid, 'Qualsiasi altro comando viene interpretato come un potenziale comando vocale.')
elif txt == u'logout':
self.sendMessage(senderid, 'Ok, devo ancora implementare anche il logout')
elif txt == u'command list' or txt == 'cmd list':
self.sendCommandList(senderid)
elif txt == u'screenshot list' or txt==u'ss list':
self.sendScreenshotList(senderid)
elif txt.startswith('screenshot ') or txt.startswith('ss '):
self.sendScreenshot(senderid, " ".join(txt.split()[1:]))
elif txt == u'clima':
self.sendClima(senderid)
else:
self.core.voiceReceived(txt, confidence=1.0, lang="it").addCallback(voiceResult)
def receivedDeliveryConfirmation(self, msg): def receivedDeliveryConfirmation(self, msg):
log.info("Messenger bot received delivery confirmation: "+str(msg)) log.info("Messenger bot received delivery confirmation: "+str(msg))
...@@ -280,13 +305,13 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -280,13 +305,13 @@ class MessengerBot(BotCore, MessengerCore):
def sendScreenshot(self, recipient_id, target): def sendScreenshot(self, recipient_id, target):
def pushImage(res): def pushImage(res):
if res: if res:
self.sendImageMessageData(recipient_id, res) self.sendImageMessageData(recipient_id, res)
else: else:
self.sendMessage(recipient_id, 'Cannot retrieve image of '+str(target)) self.sendMessage(recipient_id, 'Cannot retrieve image of '+str(target))
if target.endswith('%'): if target.endswith('%'):
target=target[:-1] target=target[:-1]
if len(target) > 0: if len(target) > 0:
self.core.getScreenshot(target).addCallback(pushImage) self.core.getScreenshot(target, pushImage)
def sendClima(self, recipient_id): def sendClima(self, recipient_id):
def pushClima(res): def pushClima(res):
...@@ -318,7 +343,7 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -318,7 +343,7 @@ class MessengerBot(BotCore, MessengerCore):
payload = { payload = {
'recipient': { 'recipient': {
'id': recipient_id 'id': recipient_id
}, },
'message': { 'message': {
'attachment': { 'attachment': {
'type': 'image', 'type': 'image',
...@@ -330,19 +355,22 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -330,19 +355,22 @@ class MessengerBot(BotCore, MessengerCore):
} }
return self.sendAPI(payload) return self.sendAPI(payload)
def sendImageMessageData(self, recipient_id, imagedata): def sendImageMessageData(self, recipient_id, imagedata, mtype=None):
payload = {
'recipient': { if not imagedata:
'id': recipient_id return
}, if mtype == None:
'message': { ft = imghdr.what(None, imagedata)
'attachment': { log.info("FILE TYPE: "+str(ft))
'type': 'image', if ft in ['jpeg', 'gif', 'png']:
'payload': {} mtype=ft
} else:
} log.warning("Image mimetype doesn't seems to be valid: "+str(ft))
} log.warning("Assuming it's a jpeg.")
fname=str(uuid.uuid4().get_hex())+'.jpg' mtype='jpeg'
fname=str(uuid.uuid4().get_hex())+mtype
bond="------------------------"+str(uuid.uuid4().get_hex())[:16] bond="------------------------"+str(uuid.uuid4().get_hex())[:16]
data="--"+bond+"\r\n" data="--"+bond+"\r\n"
data+="Content-Disposition: form-data; name=\"recipient\"\r\n\r\n" data+="Content-Disposition: form-data; name=\"recipient\"\r\n\r\n"
...@@ -352,7 +380,7 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -352,7 +380,7 @@ class MessengerBot(BotCore, MessengerCore):
data+='{"attachment":{"type":"image", "payload":{}}}'+"\r\n" data+='{"attachment":{"type":"image", "payload":{}}}'+"\r\n"
data+="--"+bond+"\r\n" data+="--"+bond+"\r\n"
data+='Content-Disposition: form-data; name="filedata"; filename="'+fname+'"'+"\r\n" data+='Content-Disposition: form-data; name="filedata"; filename="'+fname+'"'+"\r\n"
data+='Content-Type: image/jpeg'+"\r\n\r\n" data+='Content-Type: image/'+mtype+"\r\n\r\n"
data+=str(imagedata) data+=str(imagedata)
data+="\r\n--"+bond+"--\r\n" data+="\r\n--"+bond+"--\r\n"
headers={ headers={
...@@ -362,17 +390,16 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -362,17 +390,16 @@ class MessengerBot(BotCore, MessengerCore):
request_endpoint=self.graphuri+'/me/messages' request_endpoint=self.graphuri+'/me/messages'
request_uri = request_endpoint+'?'+urlencode(self.auth_args) request_uri = request_endpoint+'?'+urlencode(self.auth_args)
return wu.getPage(request_uri, agent="curl/7.50.1", method='POST', headers=headers, return wu.getPage(request_uri, agent="curl/7.50.1", method='POST', headers=headers,
postdata=data, expect100=True).addCallbacks(self._dataSent, self._dataError) postdata=data, expect100=True).addCallbacks(self._dataSent, self._dataError)
def sendAuthRequest(self, recipient_id): def sendAuthRequest(self, recipient_id):
payload = { payload = {
'recipient': { 'recipient': {
'id': recipient_id 'id': recipient_id
}, },
'message': { 'message': {
"attachment": { "attachment": {
"type": "template", "type": "template",
"payload": { "payload": {
"template_type": "generic", "template_type": "generic",
...@@ -389,9 +416,73 @@ class MessengerBot(BotCore, MessengerCore): ...@@ -389,9 +416,73 @@ class MessengerBot(BotCore, MessengerCore):
} }
} }
return self.sendAPI(payload) return self.sendAPI(payload)
components.registerAdapter(
MessengerBotAdapter,
BotProto,
IBotProtoInterface
)
class MessengerBot(BotCore, MessengerConf):
path = "messenger"
@route("/", Http.GET)
def rootGet(self, request, *a, **kw):
if 'hub.mode' in kw.keys() and kw['hub.mode'] == 'subscribe' and 'hub.challenge' in kw.keys():
if 'hub.verify_token' in kw.keys() and kw['hub.verify_token'] == self._cfgGet('verify_token'):
log.info("New verification request for Messenger BOT: "+str(kw))
return kw['hub.challenge']
return Response(403, "Failed validation." )
@route("/", Http.POST)
@messengerValidator()
def rootPost(self, request, *a, **kw):
log.debug("New messenger bot request: "+str(kw))
botproto = BotProto(self.core)
botiface = IBotProtoInterface(botproto)
if 'object' in kw.keys() and kw['object'] == 'page' and 'entry' in kw.keys():
for entry in kw['entry']:
#try:
if True:
pageID=entry['id']
timestamp=entry['time']
messaging=entry['messaging']
for message in messaging:
msgkeys = message.keys()
if 'optin' in msgkeys:
botiface.receivedAuthentication(message)
elif 'message' in msgkeys:
botiface.receivedTextMessage(message)
elif 'delivery' in msgkeys:
botiface.receivedDeliveryConfirmation(message)
elif 'postback' in msgkeys:
botiface.receivedPostback(message)
elif 'read' in msgkeys:
botiface.receivedMessageRead(message)
elif 'account_linking' in msgkeys:
botiface.receivedAccountLink(message)
else:
log.info("Received unknow messaging webhook for messenger BOT: "+str(kw))
#except:
# pass
return Response(200, 'OK')
@route("/loginfailed")
def loginFailed(self, request, *a, **kw):
k = kw.keys()
if 'account_linking_token' in k and 'redirect_uri' in k:
log.info("Passed linking uri "+kw['redirect_uri'])
luri=kw['redirect_uri']
log.info("Authorization failed: redirecting to "+luri)
return Response(302, 'Authorization failed', headers={'Location': luri})
return Response(200, "Authorization failed." )
class MessengerBotAuth(BotCore, MessengerCore): class MessengerBotAuth(BotCore, MessengerConf):
path="messenger" path="messenger"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment