From f0c13dc8e2dbb066617e9e6e9dc787b56019b4a9 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 18 Jun 2019 20:18:54 -0400 Subject: [PATCH 01/10] db with open switch to using with open --- bumper/__init__.py | 171 ++++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 78 deletions(-) diff --git a/bumper/__init__.py b/bumper/__init__.py index f9eb47a..efa22b0 100644 --- a/bumper/__init__.py +++ b/bumper/__init__.py @@ -291,54 +291,61 @@ def user_by_deviceid(deviceid): def user_full_upsert(user): - users = db_get().table("users") - User = Query() - users.upsert(user, User.did == user["userid"]) + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + users.upsert(user, User.did == user["userid"]) def user_add_device(userid, devid): - users = db_get().table("users") - User = Query() - user = users.get(User.userid == userid) - userdevices = list(user["devices"]) - if not devid in userdevices: - userdevices.append(devid) + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userdevices = list(user["devices"]) + if not devid in userdevices: + userdevices.append(devid) - users.upsert({"devices": userdevices}, User.userid == userid) + users.upsert({"devices": userdevices}, User.userid == userid) def user_remove_device(userid, devid): - users = db_get().table("users") - User = Query() - user = users.get(User.userid == userid) - userdevices = list(user["devices"]) - if devid in userdevices: - userdevices.remove(devid) - - users.upsert({"devices": userdevices}, User.userid == userid) + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userdevices = list(user["devices"]) + if devid in userdevices: + userdevices.remove(devid) + users.upsert({"devices": userdevices}, User.userid == userid) def user_add_bot(userid, did): - users = db_get().table("users") - User = Query() - user = users.get(User.userid == userid) - userbots = list(user["bots"]) - if not did in userbots: - userbots.append(did) - - users.upsert({"bots": userbots}, User.userid == userid) + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userbots = list(user["bots"]) + if not did in userbots: + userbots.append(did) + users.upsert({"bots": userbots}, User.userid == userid) def user_remove_bot(userid, did): - users = db_get().table("users") - User = Query() - user = users.get(User.userid == userid) - userbots = list(user["bots"]) - if did in userbots: - userbots.remove(did) - - users.upsert({"bots": userbots}, User.userid == userid) + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userbots = list(user["bots"]) + if did in userbots: + userbots.remove(did) + users.upsert({"bots": userbots}, User.userid == userid) def user_get_tokens(userid): tokens = db_get().table("tokens") @@ -351,61 +358,69 @@ def user_get_token(userid, token): def user_add_token(userid, token): - tokens = db_get().table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if not tmptoken: - bumperlog.debug("Adding token {} for userid {}".format(token, userid)) - tokens.insert( - { - "userid": userid, - "token": token, - "expiration": "{}".format( - datetime.now() + timedelta(seconds=token_validity_seconds) - ), - } - ) - + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if not tmptoken: + bumperlog.debug("Adding token {} for userid {}".format(token, userid)) + tokens.insert( + { + "userid": userid, + "token": token, + "expiration": "{}".format( + datetime.now() + timedelta(seconds=token_validity_seconds) + ), + } + ) def user_revoke_all_tokens(userid): - tokens = db_get().table("tokens") - tsearch = tokens.search(Query().userid == userid) - for i in tsearch: - tokens.remove(doc_ids=[i.doc_id]) - + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tsearch = tokens.search(Query().userid == userid) + for i in tsearch: + tokens.remove(doc_ids=[i.doc_id]) def user_revoke_expired_tokens(userid): - tokens = db_get().table("tokens") - tsearch = tokens.search(Query().userid == userid) - for i in tsearch: - if datetime.now() >= datetime.fromisoformat(i["expiration"]): - bumperlog.debug("Removing token {} due to expiration".format(i["token"])) - tokens.remove(doc_ids=[i.doc_id]) + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tsearch = tokens.search(Query().userid == userid) + for i in tsearch: + if datetime.now() >= datetime.fromisoformat(i["expiration"]): + bumperlog.debug("Removing token {} due to expiration".format(i["token"])) + tokens.remove(doc_ids=[i.doc_id]) def user_revoke_token(userid, token): - tokens = db_get().table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.remove(doc_ids=[tmptoken.doc_id]) - + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.remove(doc_ids=[tmptoken.doc_id]) def user_add_authcode(userid, token, authcode): - tokens = db_get().table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.upsert( - {"authcode": authcode}, - ((Query().userid == userid) & (Query().token == token)), - ) - + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.upsert( + {"authcode": authcode}, + ((Query().userid == userid) & (Query().token == token)), + ) def user_revoke_authcode(userid, token, authcode): - tokens = db_get().table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.upsert( - {"authcode": ""}, ((Query().userid == userid) & (Query().token == token)) - ) + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.upsert( + {"authcode": ""}, ((Query().userid == userid) & (Query().token == token)) + ) class VacBotDevice(object): From 4fe7f056f4a78db9927f7abd63e978d86e3398f7 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Tue, 18 Jun 2019 20:21:01 -0400 Subject: [PATCH 02/10] test api testing api pulling from db --- bumper/confserver.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bumper/confserver.py b/bumper/confserver.py index afc9fe1..1c3bb3b 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -210,9 +210,14 @@ class ConfServer: async def handle_base(self, request): try: # TODO - API Options here for viewing clients, tokens, restarting the server, etc. - text = "Bumper!" - - return web.json_response(text) + #text = "Bumper!" + bots = bumper.db_get().table("bots").all() + clients = bumper.db_get().table("clients").all() + helperbot = self.helperbot.Client.session.transitions.state + all = {'bots':bots, 'clients':clients, 'helperbot': [{'state': helperbot}]} + + + return web.json_response(all) except Exception as e: confserverlog.exception("{}".format(e)) From b48905b4e4f3a9dfe35c66f0009110d43fa95565 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Wed, 19 Jun 2019 07:29:12 -0400 Subject: [PATCH 03/10] catch bot errors in log Close #10 - New boterror log - Works for MQTT and XMPP --- bumper/__init__.py | 9 +++++++++ bumper/confserver.py | 2 +- bumper/mqttserver.py | 7 +++++++ bumper/xmppserver.py | 10 ++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/bumper/__init__.py b/bumper/__init__.py index efa22b0..8ee6006 100644 --- a/bumper/__init__.py +++ b/bumper/__init__.py @@ -100,6 +100,15 @@ helperbotlog.addHandler(helperbot_rotate) # Override the logging level # helperbotlog.setLevel(logging.INFO) +boterrorlog = logging.getLogger("boterror") +boterrorlog_rotate = RotatingFileHandler( + "logs/boterror.log", maxBytes=5000000, backupCount=5 +) +boterrorlog_rotate.setFormatter(logformat) +boterrorlog.addHandler(boterrorlog_rotate) +# Override the logging level +# boterrorlog.setLevel(logging.INFO) + xmppserverlog = logging.getLogger("xmppserver") xmpp_rotate = RotatingFileHandler( "logs/xmppserver.log", maxBytes=5000000, backupCount=5 diff --git a/bumper/confserver.py b/bumper/confserver.py index 1c3bb3b..c211ba4 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -1093,7 +1093,7 @@ class ConfServer: if did != "": bot = bumper.bot_get(did) - if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True: + if bot["company"] == "eco-ng": body = "" retcmd = await self.helperbot.send_command(json_body, randomid) confserverlog.debug("Send Bot - {}".format(json_body)) diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py index 5e247a4..843397e 100644 --- a/bumper/mqttserver.py +++ b/bumper/mqttserver.py @@ -15,6 +15,7 @@ from datetime import datetime, timedelta import bumper helperbotlog = logging.getLogger("helperbot") +boterrorlog = logging.getLogger("boterror") mqttserverlog = logging.getLogger("mqttserver") logging.getLogger("transitions").setLevel(logging.CRITICAL + 1) # Ignore this logger @@ -107,6 +108,12 @@ class MQTTHelperBot: message.topic, str(message.data.decode("utf-8")) ) ) + if str(message.topic).split("/")[2] == "errors": + boterrorlog.error( + "Received Error - Topic: {} - Message: {}".format( + message.topic, str(message.data.decode("utf-8")) + ) + ) else: helperbotlog.debug( "Received Message - Topic: {} - Message: {}".format( diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index ef43a58..81d5a6a 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -10,6 +10,7 @@ import bumper import asyncio xmppserverlog = logging.getLogger("xmppserver") +boterrorlog = logging.getLogger("boterror") class XMPPServer: @@ -721,6 +722,15 @@ class XMPPAsyncClient: ).replace("ns0:", ""), ) ) + if 'td="error"' in newdata or 'errs=' in newdata: + boterrorlog.error( + "Received Error from ({}:{} | {}) - {}".format( + self.address[0], + self.address[1], + self.bumper_jid, + newdata, + ) + ) self._handle_iq(item, newdata) item.clear() From d54123460076debac1aa98c4fefb08bb4639bf8b Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Wed, 19 Jun 2019 07:52:39 -0400 Subject: [PATCH 04/10] add devicealert as boterror add devicealert as boterror --- bumper/xmppserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index 81d5a6a..e4f0ba3 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -722,7 +722,7 @@ class XMPPAsyncClient: ).replace("ns0:", ""), ) ) - if 'td="error"' in newdata or 'errs=' in newdata: + if 'td="error"' in newdata or 'errs=' in newdata or 'k="DeviceAlert' in newdata: boterrorlog.error( "Received Error from ({}:{} | {}) - {}".format( self.address[0], From 76528d1500fc8c561be7cbf185e053e6832afb63 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Wed, 19 Jun 2019 08:10:11 -0400 Subject: [PATCH 05/10] fix tests during wip - Comment out test_base until api stablizes --- tests/test_confserver.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/test_confserver.py b/tests/test_confserver.py index 15fdac7..0bb6f43 100644 --- a/tests/test_confserver.py +++ b/tests/test_confserver.py @@ -42,8 +42,8 @@ async def test_confserver_no_ssl(): conf_server.confserver_app() asyncio.create_task(conf_server.start_server()) - -async def test_base(aiohttp_client): +# Comment out test_base until api changes are complete +""" async def test_base(aiohttp_client): remove_existing_db() bumper.db = "tests/tmp.db" # Set db location for testing client = await aiohttp_client(create_app) @@ -51,7 +51,7 @@ async def test_base(aiohttp_client): resp = await client.get("/") assert resp.status == 200 text = await resp.text() - assert "Bumper!" in text + assert "Bumper!" in text """ async def test_login(aiohttp_client): @@ -726,14 +726,6 @@ async def test_lg_logs(aiohttp_client): jsonresp = json.loads(text) assert jsonresp["ret"] == "ok" - # Not bot online - bumper.bot_set_mqtt("did_1234", False) - resp = await client.post("/api/lg/log.do", json=postbody) - assert resp.status == 200 - text = await resp.text() - jsonresp = json.loads(text) - assert jsonresp["ret"] == "fail" - async def test_postLookup(aiohttp_client): remove_existing_db() From 58b35678876201acfe55b309dea61b478cb97213 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Wed, 19 Jun 2019 09:29:45 -0400 Subject: [PATCH 06/10] split models and db from init Move models into their own file Move db functions into their own file Update tests --- bumper/__init__.py | 744 +-------------------------------------- bumper/confserver.py | 90 ++--- bumper/db.py | 373 ++++++++++++++++++++ bumper/models.py | 401 +++++++++++++++++++++ bumper/mqttserver.py | 12 +- tests/test_confserver.py | 14 + tests/test_db.py | 145 ++++++++ tests/test_init.py | 156 +------- tests/test_mqttserver.py | 60 ++-- tests/test_xmppserver.py | 49 ++- tests/test_z_problem.py | 1 - 11 files changed, 1064 insertions(+), 981 deletions(-) create mode 100644 bumper/db.py create mode 100644 bumper/models.py create mode 100644 tests/test_db.py diff --git a/bumper/__init__.py b/bumper/__init__.py index 8ee6006..f7e73c2 100644 --- a/bumper/__init__.py +++ b/bumper/__init__.py @@ -3,14 +3,12 @@ from bumper.confserver import ConfServer from bumper.mqttserver import MQTTServer, MQTTHelperBot from bumper.xmppserver import XMPPServer +from bumper.models import * +from bumper.db import * import asyncio -import json -from datetime import datetime, timedelta import os import logging from logging.handlers import RotatingFileHandler -from tinydb import TinyDB, Query -from tinydb.storages import MemoryStorage import socket import sys @@ -171,7 +169,7 @@ async def start(): global conf_server_2 conf_server_2 = ConfServer( (bumper_listen, conf2_listen_port), usessl=False, helperbot=mqtt_helperbot - ) + ) global xmpp_server xmpp_server = XMPPServer((bumper_listen, xmpp_listen_port)) @@ -232,739 +230,6 @@ async def shutdown(): bumperlog.info("Shutdown complete") -def get_milli_time(timetoconvert): - return int(round(timetoconvert * 1000)) - - -def db_file(): - if db: - return db - - return os_db_path() - - -def os_db_path(): # createdir=True): - return os.path.join(data_dir, "bumper.db") - - -def db_get(): - try: - # Will create the database if it doesn't exist - db = TinyDB(db_file()) - - # Will create the tables if they don't exist - db.table("users", cache_size=0) - db.table("clients", cache_size=0) - db.table("bots", cache_size=0) - db.table("tokens", cache_size=0) - - return db - - except json.decoder.JSONDecodeError as jerr: - bumperlog.error("JsonErr: {} - Doc: {}".format(jerr.msg, jerr.doc)) - - except Exception as ex: - bumperlog.error(ex) - - -class BumperUser(object): - def __init__(self, userid=""): - self.userid = userid - self.devices = [] - self.bots = [] - - def asdict(self): - return {"userid": self.userid, "devices": self.devices, "bots": self.bots} - - -def user_add(userid): - newuser = BumperUser() - newuser.userid = userid - - user = user_get(userid) - if not user: - bumperlog.info("Adding new user with userid: {}".format(newuser.userid)) - user_full_upsert(newuser.asdict()) - - -def user_get(userid): - users = db_get().table("users") - User = Query() - return users.get(User.userid == userid) - - -def user_by_deviceid(deviceid): - users = db_get().table("users") - User = Query() - return users.get(User.devices.any([deviceid])) - - -def user_full_upsert(user): - opendb = db_get() - with opendb: - users = opendb.table("users") - User = Query() - users.upsert(user, User.did == user["userid"]) - - -def user_add_device(userid, devid): - opendb = db_get() - with opendb: - users = opendb.table("users") - User = Query() - user = users.get(User.userid == userid) - userdevices = list(user["devices"]) - if not devid in userdevices: - userdevices.append(devid) - - users.upsert({"devices": userdevices}, User.userid == userid) - - -def user_remove_device(userid, devid): - opendb = db_get() - with opendb: - users = opendb.table("users") - User = Query() - user = users.get(User.userid == userid) - userdevices = list(user["devices"]) - if devid in userdevices: - userdevices.remove(devid) - - users.upsert({"devices": userdevices}, User.userid == userid) - -def user_add_bot(userid, did): - opendb = db_get() - with opendb: - users = opendb.table("users") - User = Query() - user = users.get(User.userid == userid) - userbots = list(user["bots"]) - if not did in userbots: - userbots.append(did) - - users.upsert({"bots": userbots}, User.userid == userid) - -def user_remove_bot(userid, did): - opendb = db_get() - with opendb: - users = opendb.table("users") - User = Query() - user = users.get(User.userid == userid) - userbots = list(user["bots"]) - if did in userbots: - userbots.remove(did) - - users.upsert({"bots": userbots}, User.userid == userid) - -def user_get_tokens(userid): - tokens = db_get().table("tokens") - return tokens.search((Query().userid == userid)) - - -def user_get_token(userid, token): - tokens = db_get().table("tokens") - return tokens.get((Query().userid == userid) & (Query().token == token)) - - -def user_add_token(userid, token): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if not tmptoken: - bumperlog.debug("Adding token {} for userid {}".format(token, userid)) - tokens.insert( - { - "userid": userid, - "token": token, - "expiration": "{}".format( - datetime.now() + timedelta(seconds=token_validity_seconds) - ), - } - ) - -def user_revoke_all_tokens(userid): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tsearch = tokens.search(Query().userid == userid) - for i in tsearch: - tokens.remove(doc_ids=[i.doc_id]) - -def user_revoke_expired_tokens(userid): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tsearch = tokens.search(Query().userid == userid) - for i in tsearch: - if datetime.now() >= datetime.fromisoformat(i["expiration"]): - bumperlog.debug("Removing token {} due to expiration".format(i["token"])) - tokens.remove(doc_ids=[i.doc_id]) - - -def user_revoke_token(userid, token): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.remove(doc_ids=[tmptoken.doc_id]) - -def user_add_authcode(userid, token, authcode): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.upsert( - {"authcode": authcode}, - ((Query().userid == userid) & (Query().token == token)), - ) - -def user_revoke_authcode(userid, token, authcode): - opendb = db_get() - with opendb: - tokens = opendb.table("tokens") - tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) - if tmptoken: - tokens.upsert( - {"authcode": ""}, ((Query().userid == userid) & (Query().token == token)) - ) - - -class VacBotDevice(object): - def __init__( - self, did="", vac_bot_device_class="", resource="", name="", nick="", company="" - ): - self.vac_bot_device_class = vac_bot_device_class - self.company = company - self.did = did - self.name = name - self.nick = nick - self.resource = resource - self.mqtt_connection = False - self.xmpp_connection = False - - def asdict(self): - return { - "class": self.vac_bot_device_class, - "company": self.company, - "did": self.did, - "name": self.name, - "nick": self.nick, - "resource": self.resource, - "mqtt_connection": self.mqtt_connection, - "xmpp_connection": self.xmpp_connection, - } - - -class GlobalVacBotDevice(VacBotDevice): # EcoVacs Home - UILogicId = "" - ota = True - updateInfo = {"changeLog": "", "needUpdate": False} - icon = "" - deviceName = "" - - -# EcoVacs Home Product IOT Map - 2019-05-20 -# https://portal-ww.ecouser.net/api/pim/product/getProductIotMap -EcoVacsHomeProducts = [ - { - "classid": "dl8fht", - "product": { - "UILogicId": "D_600", - "_id": "5acb0fa87c295c0001876ecf", - "icon": "5acc32067c295c0001876eea", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5acc32067c295c0001876eea", - "materialNo": "702-0000-0170", - "name": "DEEBOT 600 Series", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "02uwxm", - "product": { - "UILogicId": "D_OZMO_SLIM10", - "_id": "5ae1481e7ccd1a0001e1f69e", - "icon": "5b1dddc48bc45700014035a1", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b1dddc48bc45700014035a1", - "materialNo": "110-1715-0201", - "name": "DEEBOT OZMO Slim10 Series", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "y79a7u", - "product": { - "UILogicId": "D_OZMO_900", - "_id": "5b04c0227ccd1a0001e1f6a8", - "icon": "5b04c0217ccd1a0001e1f6a7", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b04c0217ccd1a0001e1f6a7", - "materialNo": "110-1810-0101", - "name": "DEEBOT OZMO 900 Series", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "jr3pqa", - "product": { - "UILogicId": "D_700", - "_id": "5b43077b8bc457000140363e", - "icon": "5b5ac4cc8d5a56000111e769", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4cc8d5a56000111e769", - "materialNo": "702-0000-0202", - "name": "DEEBOT 711", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "uv242z", - "product": { - "UILogicId": "D_700", - "_id": "5b5149b4ac0b87000148c128", - "icon": "5b5ac4e45f21100001882bb9", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4e45f21100001882bb9", - "materialNo": "702-0000-0205", - "name": "DEEBOT 710", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "ls1ok3", - "product": { - "UILogicId": "D_900", - "_id": "5b6561060506b100015c8868", - "icon": "5ba4a2cb6c2f120001c32839", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5ba4a2cb6c2f120001c32839", - "materialNo": "110-1711-0201", - "name": "DEEBOT 900 Series", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "eyi9jv", - "product": { - "UILogicId": "D_700", - "_id": "5b7b65f364e1680001a08b54", - "icon": "5b7b65f176f7f10001e9a0c2", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b7b65f176f7f10001e9a0c2", - "materialNo": "715", - "name": "DEEBOT 715", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "4zfacv", - "product": { - "UILogicId": "DN_2G", - "_id": "5bf2596f23244a00013f2f13", - "icon": "5c778731280fda0001770ba0", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c778731280fda0001770ba0", - "materialNo": "910", - "name": "DEEBOT 910", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "vi829v", - "product": { - "UILogicId": "DX_5G", - "_id": "5c19a8f3a1e6ee0001782247", - "icon": "5c9c7995e9e9270001354ab4", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c9c7995e9e9270001354ab4", - "materialNo": "920", - "name": "DEEBOT OZMO 920 Series", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "gd4uut", - "product": { - "UILogicId": "DR_935G", - "_id": "5bc8189d68142800016a6937", - "icon": "5c7384767b93c700013f12e7", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c7384767b93c700013f12e7", - "materialNo": "960", - "name": "DEEBOT OZMO 960", - "ota": True, - "supportType": { - "alexa": True, - "assistant": True, - "share": False, - "tmjl": False, - }, - }, - }, - { - "classid": "9akc61", - "product": { - "UILogicId": "D_500", - "_id": "5c763f8263023c0001e7f855", - "icon": "5c932067280fda0001770d7f", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c932067280fda0001770d7f", - "materialNo": "D505", - "name": "DEEBOT 505", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "r8ead0", - "product": { - "UILogicId": "D_500", - "_id": "5c763f63280fda0001770b88", - "icon": "5c93204b63023c0001e7faa7", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c93204b63023c0001e7faa7", - "materialNo": "D502", - "name": "DEEBOT 502", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "emzppx", - "product": { - "UILogicId": "D_500", - "_id": "5c763f35280fda0001770b84", - "icon": "5c931fef280fda0001770d7e", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c931fef280fda0001770d7e", - "materialNo": "D501", - "name": "DEEBOT 501", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "vsc5ia", - "product": { - "UILogicId": "D_500", - "_id": "5c763eba280fda0001770b81", - "icon": "5c874326280fda0001770d2a", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c874326280fda0001770d2a", - "materialNo": "D500", - "name": "DEEBOT 500", - "ota": False, - "supportType": { - "alexa": True, - "assistant": True, - "share": True, - "tmjl": False, - }, - }, - }, - { - "classid": "aqdd5p", - "product": { - "UILogicId": "D_900", - "_id": "5cb7cfba179839000114d762", - "icon": "5cb7cfbab72c4d00010e5fc7", - "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5cb7cfbab72c4d00010e5fc7", - "materialNo": "110-1711-0001", - "name": "DEEBOT DE55", - "ota": True, - "supportType": { - "alexa": False, - "assistant": False, - "share": False, - "tmjl": False, - }, - }, - }, -] - - -class VacBotClient(object): - def __init__(self, userid="", realm="", token=""): - self.userid = userid - self.realm = realm - self.resource = token - self.mqtt_connection = False - self.xmpp_connection = False - - def asdict(self): - return { - "userid": self.userid, - "realm": self.realm, - "resource": self.resource, - "mqtt_connection": self.mqtt_connection, - "xmpp_connection": self.xmpp_connection, - } - - -def get_disconnected_xmpp_clients(): - clients = db_get().table("clients") - Client = Query() - return clients.search(Client.xmpp_connection == False) - - -def check_authcode(uid, authcode): - bumperlog.debug("Checking for authcode: {}".format(authcode)) - tokens = db_get().table("tokens") - tmpauth = tokens.get( - (Query().authcode == authcode) - & ( # Match authcode - (Query().userid == uid.replace("fuid_", "")) - | (Query().userid == "fuid_{}".format(uid)) - ) # Userid with or without fuid_ - ) - if tmpauth: - return True - - return False - - -def loginByItToken(authcode): - bumperlog.debug("Checking for authcode: {}".format(authcode)) - tokens = db_get().table("tokens") - tmpauth = tokens.get( - (Query().authcode == authcode) - # & ( # Match authcode - # (Query().userid == uid.replace("fuid_", "")) - # | (Query().userid == "fuid_{}".format(uid)) - # ) # Userid with or without fuid_ - ) - if tmpauth: - return {"token": tmpauth["token"], "userid": tmpauth["userid"]} - - return {} - - -def check_token(uid, token): - bumperlog.debug("Checking for token: {}".format(token)) - tokens = db_get().table("tokens") - tmpauth = tokens.get( - (Query().token == token) - & ( # Match token - (Query().userid == uid.replace("fuid_", "")) - | (Query().userid == "fuid_{}".format(uid)) - ) # Userid with or without fuid_ - ) - if tmpauth: - return True - - return False - - -def revoke_expired_tokens(): - tokens = db_get().table("tokens").all() - for i in tokens: - if datetime.now() >= datetime.fromisoformat(i["expiration"]): - bumperlog.debug("Removing token {} due to expiration".format(i["token"])) - db_get().table("tokens").remove(doc_ids=[i.doc_id]) - - -def bot_add(sn, did, devclass, resource, company): - newbot = VacBotDevice() - newbot.did = did - newbot.name = sn - newbot.vac_bot_device_class = devclass - newbot.resource = resource - newbot.company = company - - bot = bot_get(did) - if not bot: # Not existing bot in database - if ( - not devclass == "" or "@" not in sn or "tmp" not in sn - ): # try to prevent bad additions to the bot list - bumperlog.info( - "Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did) - ) - bot_full_upsert(newbot.asdict()) - - -def bot_remove(did): - bots = db_get().table("bots") - bot = bot_get(did) - bots.remove(doc_ids=[bot.doc_id]) - - -def bot_get(did): - bots = db_get().table("bots") - Bot = Query() - return bots.get(Bot.did == did) - - -def bot_toEcoVacsHome_JSON(bot): # EcoVacs Home - for botprod in EcoVacsHomeProducts: - if botprod["classid"] == bot["class"]: - bot["UILogicId"] = botprod["product"]["UILogicId"] - bot["ota"] = botprod["product"]["ota"] - bot["icon"] = botprod["product"]["iconUrl"] - return json.dumps( - bot, default=lambda o: o.__dict__, sort_keys=False - ) # , indent=4) - - -def bot_full_upsert(vacbot): - bots = db_get().table("bots") - Bot = Query() - bots.upsert(vacbot, Bot.did == vacbot["did"]) - - -def bot_set_nick(did, nick): - bots = db_get().table("bots") - Bot = Query() - bots.upsert({"nick": nick}, Bot.did == did) - - -def bot_set_mqtt(did, mqtt): - bots = db_get().table("bots") - Bot = Query() - bots.upsert({"mqtt_connection": mqtt}, Bot.did == did) - - -def bot_set_xmpp(did, xmpp): - bots = db_get().table("bots") - Bot = Query() - bots.upsert({"xmpp_connection": xmpp}, Bot.did == did) - - -def client_add(userid, realm, resource): - newclient = VacBotClient() - newclient.userid = userid - newclient.realm = realm - newclient.resource = resource - - client = client_get(resource) - if not client: - bumperlog.info("Adding new client with resource {}".format(newclient.resource)) - client_full_upsert(newclient.asdict()) - - -def client_get(resource): - clients = db_get().table("clients") - Client = Query() - return clients.get(Client.resource == resource) - - -def client_full_upsert(client): - clients = db_get().table("clients") - Client = Query() - clients.upsert(client, Client.resource == client["resource"]) - - -def client_set_mqtt(resource, mqtt): - clients = db_get().table("clients") - Client = Query() - clients.upsert({"mqtt_connection": mqtt}, Client.resource == resource) - - -def client_set_xmpp(resource, xmpp): - clients = db_get().table("clients") - Client = Query() - clients.upsert({"xmpp_connection": xmpp}, Client.resource == resource) - - -RETURN_API_SUCCESS = "0000" -ERR_ACTIVATE_TOKEN_TIMEOUT = "1006" -ERR_COMMON = "0001" -ERR_DEFAULT = "9000" -ERR_EMAIL_NON_EXIST = "1002" -ERR_EMAIL_SEND_TIME_LIMIT = "1011" -ERR_EMAIL_USED = "1001" -ERR_INTERFACE_AUTH = "0002" -ERR_PARAM_INVALID = "0003" -ERR_PWD_WRONG = "1005" -ERR_RESET_PWD_TOKEN_TIMEOUT = "1007" -ERR_TIMESTAMP_INVALID = "0005" -ERR_TOKEN_INVALID = "0004" -ERR_USER_DISABLE = "1004" -ERR_USER_NOT_ACTIVATED = "1003" -ERR_WRONG_COMFIRM_PWD = "10010" -ERR_WRONG_EMAIL_ADDRESS = "1008" -ERR_WRONG_PWD_FROMATE = "1009" - -API_ERRORS = { - RETURN_API_SUCCESS: "0000", - ERR_ACTIVATE_TOKEN_TIMEOUT: "1006", - ERR_COMMON: "0001", - ERR_DEFAULT: "9000", - ERR_EMAIL_NON_EXIST: "1002", - ERR_EMAIL_SEND_TIME_LIMIT: "1011", - ERR_EMAIL_USED: "1001", - ERR_INTERFACE_AUTH: "0002", - ERR_PARAM_INVALID: "0003", - ERR_PWD_WRONG: "1005", - ERR_RESET_PWD_TOKEN_TIMEOUT: "1007", - ERR_TIMESTAMP_INVALID: "0005", - ERR_TOKEN_INVALID: "0004", - ERR_USER_DISABLE: "1004", - ERR_USER_NOT_ACTIVATED: "1003", - ERR_WRONG_COMFIRM_PWD: "10010", - ERR_WRONG_EMAIL_ADDRESS: "1008", - ERR_WRONG_PWD_FROMATE: "1009", -} - - def create_certs(): import platform import os @@ -1002,7 +267,7 @@ def create_certs(): print("Certificates created") os.chdir(odir) - + if "__main__.py" in sys.argv[0]: os.execv( sys.executable, ["python", "-m", "bumper"] + sys.argv[1:] @@ -1015,6 +280,7 @@ def create_certs(): def first_run(): create_certs() + def main(argv=None): import argparse diff --git a/bumper/confserver.py b/bumper/confserver.py index c211ba4..f1fab45 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -6,6 +6,7 @@ import ssl import string import random import bumper +from bumper.models import * from datetime import datetime, timedelta import asyncio from aiohttp import web @@ -36,25 +37,6 @@ logging.getLogger("aiohttp.access").addFilter( ) # Add logging filter above to aiohttp.access -class EcoVacs_Login: - accessToken = "" - country = "" - email = "" - uid = "" - username = "" - - def toJSON(self): - return json.dumps( - self, default=lambda o: o.__dict__, sort_keys=False - ) # , indent=4) - - -class EcoVacsHome_Login(EcoVacs_Login): - loginName = "" - mobile = "" - ucUid = "" - - class ConfServer: def __init__(self, address, usessl=False, helperbot=None): self.helperbot = helperbot @@ -66,6 +48,9 @@ class ConfServer: self.site = None self.runner = None + def get_milli_time(self, timetoconvert): + return int(round(timetoconvert * 1000)) + def confserver_app(self): self.app = web.Application(loop=asyncio.get_event_loop()) @@ -190,9 +175,9 @@ class ConfServer: await self.site.start() except PermissionError as e: - confserverlog.error(e.strerror) + confserverlog.error(e.strerror) asyncio.create_task(bumper.shutdown()) - + except asyncio.CancelledError: pass @@ -202,7 +187,7 @@ class ConfServer: async def stop_server(self): try: - await self.runner.shutdown() + await self.runner.shutdown() except Exception as e: confserverlog.exception("{}".format(e)) @@ -210,13 +195,16 @@ class ConfServer: async def handle_base(self, request): try: # TODO - API Options here for viewing clients, tokens, restarting the server, etc. - #text = "Bumper!" + # text = "Bumper!" bots = bumper.db_get().table("bots").all() clients = bumper.db_get().table("clients").all() helperbot = self.helperbot.Client.session.transitions.state - all = {'bots':bots, 'clients':clients, 'helperbot': [{'state': helperbot}]} - - + all = { + "bots": bots, + "clients": clients, + "helperbot": [{"state": helperbot}], + } + return web.json_response(all) except Exception as e: @@ -261,7 +249,7 @@ class ConfServer: login_details.email = "null@null.com" body = { - "code": bumper.RETURN_API_SUCCESS, + "code": API_ERRORS[RETURN_API_SUCCESS], "data": json.loads(login_details.toJSON()), # { # "accessToken": self.generate_token(tmpuser), # Generate a token @@ -271,7 +259,7 @@ class ConfServer: # "username": "fusername_{}".format(tmpuser["userid"]), # }, "msg": "操作成功", - "time": bumper.get_milli_time( + "time": self.self.get_milli_time( datetime.utcnow().timestamp() ), } @@ -282,7 +270,7 @@ class ConfServer: "code": bumper.ERR_USER_NOT_ACTIVATED, "data": None, "msg": "当前密码错误", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -328,7 +316,7 @@ class ConfServer: "loginName": login_details.loginName, }, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -364,7 +352,7 @@ class ConfServer: # "username": "fusername_{}".format(tmpuser["userid"]), # }, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -373,7 +361,7 @@ class ConfServer: "code": bumper.ERR_TOKEN_INVALID, "data": None, "msg": "当前密码错误", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -464,7 +452,7 @@ class ConfServer: # "username": "fusername_{}".format(tmpuser["userid"]), # }, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return body @@ -488,7 +476,7 @@ class ConfServer: "code": bumper.RETURN_API_SUCCESS, "data": None, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -530,7 +518,7 @@ class ConfServer: }, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time( + "time": self.get_milli_time( datetime.utcnow().timestamp() ), } @@ -542,7 +530,7 @@ class ConfServer: "ecovacsUid": request.query["uid"], }, "msg": "操作成功", - "time": bumper.get_milli_time( + "time": self.get_milli_time( datetime.utcnow().timestamp() ), } @@ -552,7 +540,7 @@ class ConfServer: "code": bumper.ERR_TOKEN_INVALID, "data": None, "msg": "当前密码错误", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -574,7 +562,7 @@ class ConfServer: "v": None, }, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -599,7 +587,7 @@ class ConfServer: }, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -614,7 +602,7 @@ class ConfServer: "data": None, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -629,7 +617,7 @@ class ConfServer: "data": None, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -644,7 +632,7 @@ class ConfServer: "data": None, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -659,7 +647,7 @@ class ConfServer: "data": "N", "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -683,7 +671,7 @@ class ConfServer: "data": {"hasNextPage": 0, "items": []}, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -703,7 +691,7 @@ class ConfServer: }, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -725,7 +713,7 @@ class ConfServer: }, "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -757,14 +745,14 @@ class ConfServer: ], "msg": "操作成功", "success": True, - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } else: body = { "code": bumper.RETURN_API_SUCCESS, "data": [], "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -774,7 +762,7 @@ class ConfServer: async def handle_homePageAlert(self, request): try: - nextAlert = bumper.get_milli_time( + nextAlert = self.get_milli_time( (datetime.now() + timedelta(hours=12)).timestamp() ) @@ -786,10 +774,10 @@ class ConfServer: "hasCampaign": "N", "imageUrl": None, "nextAlertTime": nextAlert, - "serverTime": bumper.get_milli_time(datetime.utcnow().timestamp()), + "serverTime": self.get_milli_time(datetime.utcnow().timestamp()), }, "msg": "操作成功", - "time": bumper.get_milli_time(datetime.utcnow().timestamp()), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) diff --git a/bumper/db.py b/bumper/db.py new file mode 100644 index 0000000..e33574a --- /dev/null +++ b/bumper/db.py @@ -0,0 +1,373 @@ +#!/usr/bin/env python3 +import bumper +from bumper.models import VacBotClient, VacBotDevice, BumperUser, EcoVacsHomeProducts +from tinydb import TinyDB, Query +from tinydb.storages import MemoryStorage +from datetime import datetime, timedelta +import os +import json +import logging + + +bumperlog = logging.getLogger("bumper") + + +def db_file(): + if bumper.db: + return bumper.db + + return os_db_path() + + +def os_db_path(): # createdir=True): + return os.path.join(bumper.data_dir, "bumper.db") + + +def db_get(): + try: + # Will create the database if it doesn't exist + db = TinyDB(db_file()) + + # Will create the tables if they don't exist + db.table("users", cache_size=0) + db.table("clients", cache_size=0) + db.table("bots", cache_size=0) + db.table("tokens", cache_size=0) + + return db + + except json.decoder.JSONDecodeError as jerr: + bumperlog.error("JsonErr: {} - Doc: {}".format(jerr.msg, jerr.doc)) + + except Exception as ex: + bumperlog.error(ex) + + +def user_add(userid): + newuser = BumperUser() + newuser.userid = userid + + user = user_get(userid) + if not user: + bumperlog.info("Adding new user with userid: {}".format(newuser.userid)) + user_full_upsert(newuser.asdict()) + + +def user_get(userid): + users = db_get().table("users") + User = Query() + return users.get(User.userid == userid) + + +def user_by_deviceid(deviceid): + users = db_get().table("users") + User = Query() + return users.get(User.devices.any([deviceid])) + + +def user_full_upsert(user): + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + users.upsert(user, User.did == user["userid"]) + + +def user_add_device(userid, devid): + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userdevices = list(user["devices"]) + if not devid in userdevices: + userdevices.append(devid) + + users.upsert({"devices": userdevices}, User.userid == userid) + + +def user_remove_device(userid, devid): + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userdevices = list(user["devices"]) + if devid in userdevices: + userdevices.remove(devid) + + users.upsert({"devices": userdevices}, User.userid == userid) + + +def user_add_bot(userid, did): + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userbots = list(user["bots"]) + if not did in userbots: + userbots.append(did) + + users.upsert({"bots": userbots}, User.userid == userid) + + +def user_remove_bot(userid, did): + opendb = db_get() + with opendb: + users = opendb.table("users") + User = Query() + user = users.get(User.userid == userid) + userbots = list(user["bots"]) + if did in userbots: + userbots.remove(did) + + users.upsert({"bots": userbots}, User.userid == userid) + + +def user_get_tokens(userid): + tokens = db_get().table("tokens") + return tokens.search((Query().userid == userid)) + + +def user_get_token(userid, token): + tokens = db_get().table("tokens") + return tokens.get((Query().userid == userid) & (Query().token == token)) + + +def user_add_token(userid, token): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if not tmptoken: + bumperlog.debug("Adding token {} for userid {}".format(token, userid)) + tokens.insert( + { + "userid": userid, + "token": token, + "expiration": "{}".format( + datetime.now() + + timedelta(seconds=bumper.token_validity_seconds) + ), + } + ) + + +def user_revoke_all_tokens(userid): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tsearch = tokens.search(Query().userid == userid) + for i in tsearch: + tokens.remove(doc_ids=[i.doc_id]) + + +def user_revoke_expired_tokens(userid): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tsearch = tokens.search(Query().userid == userid) + for i in tsearch: + if datetime.now() >= datetime.fromisoformat(i["expiration"]): + bumperlog.debug( + "Removing token {} due to expiration".format(i["token"]) + ) + tokens.remove(doc_ids=[i.doc_id]) + + +def user_revoke_token(userid, token): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.remove(doc_ids=[tmptoken.doc_id]) + + +def user_add_authcode(userid, token, authcode): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.upsert( + {"authcode": authcode}, + ((Query().userid == userid) & (Query().token == token)), + ) + + +def user_revoke_authcode(userid, token, authcode): + opendb = db_get() + with opendb: + tokens = opendb.table("tokens") + tmptoken = tokens.get((Query().userid == userid) & (Query().token == token)) + if tmptoken: + tokens.upsert( + {"authcode": ""}, + ((Query().userid == userid) & (Query().token == token)), + ) + + +def get_disconnected_xmpp_clients(): + clients = db_get().table("clients") + Client = Query() + return clients.search(Client.xmpp_connection == False) + + +def check_authcode(uid, authcode): + bumperlog.debug("Checking for authcode: {}".format(authcode)) + tokens = db_get().table("tokens") + tmpauth = tokens.get( + (Query().authcode == authcode) + & ( # Match authcode + (Query().userid == uid.replace("fuid_", "")) + | (Query().userid == "fuid_{}".format(uid)) + ) # Userid with or without fuid_ + ) + if tmpauth: + return True + + return False + + +def loginByItToken(authcode): + bumperlog.debug("Checking for authcode: {}".format(authcode)) + tokens = db_get().table("tokens") + tmpauth = tokens.get( + (Query().authcode == authcode) + # & ( # Match authcode + # (Query().userid == uid.replace("fuid_", "")) + # | (Query().userid == "fuid_{}".format(uid)) + # ) # Userid with or without fuid_ + ) + if tmpauth: + return {"token": tmpauth["token"], "userid": tmpauth["userid"]} + + return {} + + +def check_token(uid, token): + bumperlog.debug("Checking for token: {}".format(token)) + tokens = db_get().table("tokens") + tmpauth = tokens.get( + (Query().token == token) + & ( # Match token + (Query().userid == uid.replace("fuid_", "")) + | (Query().userid == "fuid_{}".format(uid)) + ) # Userid with or without fuid_ + ) + if tmpauth: + return True + + return False + + +def revoke_expired_tokens(): + tokens = db_get().table("tokens").all() + for i in tokens: + if datetime.now() >= datetime.fromisoformat(i["expiration"]): + bumperlog.debug("Removing token {} due to expiration".format(i["token"])) + db_get().table("tokens").remove(doc_ids=[i.doc_id]) + + +def bot_add(sn, did, devclass, resource, company): + newbot = VacBotDevice() + newbot.did = did + newbot.name = sn + newbot.vac_bot_device_class = devclass + newbot.resource = resource + newbot.company = company + + bot = bot_get(did) + if not bot: # Not existing bot in database + if ( + not devclass == "" or "@" not in sn or "tmp" not in sn + ): # try to prevent bad additions to the bot list + bumperlog.info( + "Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did) + ) + bot_full_upsert(newbot.asdict()) + + +def bot_remove(did): + bots = db_get().table("bots") + bot = bot_get(did) + bots.remove(doc_ids=[bot.doc_id]) + + +def bot_get(did): + bots = db_get().table("bots") + Bot = Query() + return bots.get(Bot.did == did) + + +def bot_toEcoVacsHome_JSON(bot): # EcoVacs Home + for botprod in EcoVacsHomeProducts: + if botprod["classid"] == bot["class"]: + bot["UILogicId"] = botprod["product"]["UILogicId"] + bot["ota"] = botprod["product"]["ota"] + bot["icon"] = botprod["product"]["iconUrl"] + return json.dumps( + bot, default=lambda o: o.__dict__, sort_keys=False + ) # , indent=4) + + +def bot_full_upsert(vacbot): + bots = db_get().table("bots") + Bot = Query() + bots.upsert(vacbot, Bot.did == vacbot["did"]) + + +def bot_set_nick(did, nick): + bots = db_get().table("bots") + Bot = Query() + bots.upsert({"nick": nick}, Bot.did == did) + + +def bot_set_mqtt(did, mqtt): + bots = db_get().table("bots") + Bot = Query() + bots.upsert({"mqtt_connection": mqtt}, Bot.did == did) + + +def bot_set_xmpp(did, xmpp): + bots = db_get().table("bots") + Bot = Query() + bots.upsert({"xmpp_connection": xmpp}, Bot.did == did) + + +def client_add(userid, realm, resource): + newclient = VacBotClient() + newclient.userid = userid + newclient.realm = realm + newclient.resource = resource + + client = client_get(resource) + if not client: + bumperlog.info("Adding new client with resource {}".format(newclient.resource)) + client_full_upsert(newclient.asdict()) + + +def client_get(resource): + clients = db_get().table("clients") + Client = Query() + return clients.get(Client.resource == resource) + + +def client_full_upsert(client): + clients = db_get().table("clients") + Client = Query() + clients.upsert(client, Client.resource == client["resource"]) + + +def client_set_mqtt(resource, mqtt): + clients = db_get().table("clients") + Client = Query() + clients.upsert({"mqtt_connection": mqtt}, Client.resource == resource) + + +def client_set_xmpp(resource, xmpp): + clients = db_get().table("clients") + Client = Query() + clients.upsert({"xmpp_connection": xmpp}, Client.resource == resource) diff --git a/bumper/models.py b/bumper/models.py new file mode 100644 index 0000000..25e091b --- /dev/null +++ b/bumper/models.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python3 +import json + + +class VacBotDevice(object): + def __init__( + self, did="", vac_bot_device_class="", resource="", name="", nick="", company="" + ): + self.vac_bot_device_class = vac_bot_device_class + self.company = company + self.did = did + self.name = name + self.nick = nick + self.resource = resource + self.mqtt_connection = False + self.xmpp_connection = False + + def asdict(self): + return { + "class": self.vac_bot_device_class, + "company": self.company, + "did": self.did, + "name": self.name, + "nick": self.nick, + "resource": self.resource, + "mqtt_connection": self.mqtt_connection, + "xmpp_connection": self.xmpp_connection, + } + + +class BumperUser(object): + def __init__(self, userid=""): + self.userid = userid + self.devices = [] + self.bots = [] + + def asdict(self): + return {"userid": self.userid, "devices": self.devices, "bots": self.bots} + + +class GlobalVacBotDevice(VacBotDevice): # EcoVacs Home + UILogicId = "" + ota = True + updateInfo = {"changeLog": "", "needUpdate": False} + icon = "" + deviceName = "" + + +class VacBotClient(object): + def __init__(self, userid="", realm="", token=""): + self.userid = userid + self.realm = realm + self.resource = token + self.mqtt_connection = False + self.xmpp_connection = False + + def asdict(self): + return { + "userid": self.userid, + "realm": self.realm, + "resource": self.resource, + "mqtt_connection": self.mqtt_connection, + "xmpp_connection": self.xmpp_connection, + } + + +class EcoVacs_Login: + accessToken = "" + country = "" + email = "" + uid = "" + username = "" + + def toJSON(self): + return json.dumps( + self, default=lambda o: o.__dict__, sort_keys=False + ) # , indent=4) + + +class EcoVacsHome_Login(EcoVacs_Login): + loginName = "" + mobile = "" + ucUid = "" + + +# EcoVacs Home Product IOT Map - 2019-05-20 +# https://portal-ww.ecouser.net/api/pim/product/getProductIotMap +EcoVacsHomeProducts = [ + { + "classid": "dl8fht", + "product": { + "UILogicId": "D_600", + "_id": "5acb0fa87c295c0001876ecf", + "icon": "5acc32067c295c0001876eea", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5acc32067c295c0001876eea", + "materialNo": "702-0000-0170", + "name": "DEEBOT 600 Series", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "02uwxm", + "product": { + "UILogicId": "D_OZMO_SLIM10", + "_id": "5ae1481e7ccd1a0001e1f69e", + "icon": "5b1dddc48bc45700014035a1", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b1dddc48bc45700014035a1", + "materialNo": "110-1715-0201", + "name": "DEEBOT OZMO Slim10 Series", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "y79a7u", + "product": { + "UILogicId": "D_OZMO_900", + "_id": "5b04c0227ccd1a0001e1f6a8", + "icon": "5b04c0217ccd1a0001e1f6a7", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b04c0217ccd1a0001e1f6a7", + "materialNo": "110-1810-0101", + "name": "DEEBOT OZMO 900 Series", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "jr3pqa", + "product": { + "UILogicId": "D_700", + "_id": "5b43077b8bc457000140363e", + "icon": "5b5ac4cc8d5a56000111e769", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4cc8d5a56000111e769", + "materialNo": "702-0000-0202", + "name": "DEEBOT 711", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "uv242z", + "product": { + "UILogicId": "D_700", + "_id": "5b5149b4ac0b87000148c128", + "icon": "5b5ac4e45f21100001882bb9", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4e45f21100001882bb9", + "materialNo": "702-0000-0205", + "name": "DEEBOT 710", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "ls1ok3", + "product": { + "UILogicId": "D_900", + "_id": "5b6561060506b100015c8868", + "icon": "5ba4a2cb6c2f120001c32839", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5ba4a2cb6c2f120001c32839", + "materialNo": "110-1711-0201", + "name": "DEEBOT 900 Series", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "eyi9jv", + "product": { + "UILogicId": "D_700", + "_id": "5b7b65f364e1680001a08b54", + "icon": "5b7b65f176f7f10001e9a0c2", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5b7b65f176f7f10001e9a0c2", + "materialNo": "715", + "name": "DEEBOT 715", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "4zfacv", + "product": { + "UILogicId": "DN_2G", + "_id": "5bf2596f23244a00013f2f13", + "icon": "5c778731280fda0001770ba0", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c778731280fda0001770ba0", + "materialNo": "910", + "name": "DEEBOT 910", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "vi829v", + "product": { + "UILogicId": "DX_5G", + "_id": "5c19a8f3a1e6ee0001782247", + "icon": "5c9c7995e9e9270001354ab4", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c9c7995e9e9270001354ab4", + "materialNo": "920", + "name": "DEEBOT OZMO 920 Series", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "gd4uut", + "product": { + "UILogicId": "DR_935G", + "_id": "5bc8189d68142800016a6937", + "icon": "5c7384767b93c700013f12e7", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c7384767b93c700013f12e7", + "materialNo": "960", + "name": "DEEBOT OZMO 960", + "ota": True, + "supportType": { + "alexa": True, + "assistant": True, + "share": False, + "tmjl": False, + }, + }, + }, + { + "classid": "9akc61", + "product": { + "UILogicId": "D_500", + "_id": "5c763f8263023c0001e7f855", + "icon": "5c932067280fda0001770d7f", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c932067280fda0001770d7f", + "materialNo": "D505", + "name": "DEEBOT 505", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "r8ead0", + "product": { + "UILogicId": "D_500", + "_id": "5c763f63280fda0001770b88", + "icon": "5c93204b63023c0001e7faa7", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c93204b63023c0001e7faa7", + "materialNo": "D502", + "name": "DEEBOT 502", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "emzppx", + "product": { + "UILogicId": "D_500", + "_id": "5c763f35280fda0001770b84", + "icon": "5c931fef280fda0001770d7e", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c931fef280fda0001770d7e", + "materialNo": "D501", + "name": "DEEBOT 501", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "vsc5ia", + "product": { + "UILogicId": "D_500", + "_id": "5c763eba280fda0001770b81", + "icon": "5c874326280fda0001770d2a", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5c874326280fda0001770d2a", + "materialNo": "D500", + "name": "DEEBOT 500", + "ota": False, + "supportType": { + "alexa": True, + "assistant": True, + "share": True, + "tmjl": False, + }, + }, + }, + { + "classid": "aqdd5p", + "product": { + "UILogicId": "D_900", + "_id": "5cb7cfba179839000114d762", + "icon": "5cb7cfbab72c4d00010e5fc7", + "iconUrl": "https://portal-ww.ecouser.net/api/pim/file/get/5cb7cfbab72c4d00010e5fc7", + "materialNo": "110-1711-0001", + "name": "DEEBOT DE55", + "ota": True, + "supportType": { + "alexa": False, + "assistant": False, + "share": False, + "tmjl": False, + }, + }, + }, +] + + +RETURN_API_SUCCESS = "0000" +ERR_ACTIVATE_TOKEN_TIMEOUT = "1006" +ERR_COMMON = "0001" +ERR_DEFAULT = "9000" +ERR_EMAIL_NON_EXIST = "1002" +ERR_EMAIL_SEND_TIME_LIMIT = "1011" +ERR_EMAIL_USED = "1001" +ERR_INTERFACE_AUTH = "0002" +ERR_PARAM_INVALID = "0003" +ERR_PWD_WRONG = "1005" +ERR_RESET_PWD_TOKEN_TIMEOUT = "1007" +ERR_TIMESTAMP_INVALID = "0005" +ERR_TOKEN_INVALID = "0004" +ERR_USER_DISABLE = "1004" +ERR_USER_NOT_ACTIVATED = "1003" +ERR_WRONG_COMFIRM_PWD = "10010" +ERR_WRONG_EMAIL_ADDRESS = "1008" +ERR_WRONG_PWD_FROMATE = "1009" + +API_ERRORS = { + RETURN_API_SUCCESS: "0000", + ERR_ACTIVATE_TOKEN_TIMEOUT: "1006", + ERR_COMMON: "0001", + ERR_DEFAULT: "9000", + ERR_EMAIL_NON_EXIST: "1002", + ERR_EMAIL_SEND_TIME_LIMIT: "1011", + ERR_EMAIL_USED: "1001", + ERR_INTERFACE_AUTH: "0002", + ERR_PARAM_INVALID: "0003", + ERR_PWD_WRONG: "1005", + ERR_RESET_PWD_TOKEN_TIMEOUT: "1007", + ERR_TIMESTAMP_INVALID: "0005", + ERR_TOKEN_INVALID: "0004", + ERR_USER_DISABLE: "1004", + ERR_USER_NOT_ACTIVATED: "1003", + ERR_WRONG_COMFIRM_PWD: "10010", + ERR_WRONG_EMAIL_ADDRESS: "1008", + ERR_WRONG_PWD_FROMATE: "1009", +} + diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py index 843397e..9e5de56 100644 --- a/bumper/mqttserver.py +++ b/bumper/mqttserver.py @@ -103,17 +103,19 @@ class MQTTHelperBot: ) elif str(message.topic).split("/")[1] == "atr": # Broadcast message received on atr - helperbotlog.debug( - "Received Broadcast - Topic: {} - Message: {}".format( - message.topic, str(message.data.decode("utf-8")) - ) - ) if str(message.topic).split("/")[2] == "errors": boterrorlog.error( "Received Error - Topic: {} - Message: {}".format( message.topic, str(message.data.decode("utf-8")) ) ) + else: + helperbotlog.debug( + "Received Broadcast - Topic: {} - Message: {}".format( + message.topic, str(message.data.decode("utf-8")) + ) + ) + else: helperbotlog.debug( "Received Message - Topic: {} - Message: {}".format( diff --git a/tests/test_confserver.py b/tests/test_confserver.py index 0bb6f43..abfaa57 100644 --- a/tests/test_confserver.py +++ b/tests/test_confserver.py @@ -7,6 +7,7 @@ import json import tinydb import pytest_aiohttp import pytest_asyncio +import datetime, time from aiohttp import web @@ -42,6 +43,19 @@ async def test_confserver_no_ssl(): conf_server.confserver_app() asyncio.create_task(conf_server.start_server()) + +def test_get_milli_time(): + cserv = create_confserver() + assert ( + cserv.get_milli_time( + datetime.datetime( + 2018, 1, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc + ).timestamp() + ) + == 1514768400000 + ) + + # Comment out test_base until api changes are complete """ async def test_base(aiohttp_client): remove_existing_db() diff --git a/tests/test_db.py b/tests/test_db.py new file mode 100644 index 0000000..52c49a4 --- /dev/null +++ b/tests/test_db.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +import bumper +from bumper.models import VacBotClient, VacBotDevice, BumperUser, EcoVacsHomeProducts +from tinydb import TinyDB, Query +from tinydb.storages import MemoryStorage +from datetime import datetime, timedelta +import os +import json +import logging + + +def test_db_path(): + bumper.db = None + assert bumper.db_file() == os.path.join(bumper.data_dir, "bumper.db") + + +def test_user_db(): + + bumper.db = "tests/tmp.db" # Set db location for testing + bumper.user_add("testuser") # Add testuser + + assert ( + bumper.user_get("testuser")["userid"] == "testuser" + ) # Test that testuser was created and returned + + bumper.user_add_device("testuser", "dev_1234") # Add device to testuser + + assert ( + bumper.user_by_deviceid("dev_1234")["userid"] == "testuser" + ) # Test that testuser was found by deviceid + + bumper.user_remove_device("testuser", "dev_1234") # Remove device from testuser + + assert "dev_1234" not in bumper.user_get("testuser")["devices"] + # Test that dev_1234 was not found in testuser devices + + bumper.user_add_bot("testuser", "bot_1234") # Add bot did to testuser + + assert "bot_1234" in bumper.user_get("testuser")["bots"] + # Test that bot was found in testuser's bot list + + bumper.user_remove_bot("testuser", "bot_1234") # Remove bot did from testuser + + assert "bot_1234" not in bumper.user_get("testuser")["bots"] + # Test that bot was not found in testuser's bot list + + bumper.user_add_token("testuser", "token_1234") # Add token to testuser + + assert bumper.check_token("testuser", "token_1234") + # Test that token was found for testuser + + assert bumper.user_get_token("testuser", "token_1234") + # Test that token was returned for testuser + + bumper.user_add_authcode( + "testuser", "token_1234", "auth_1234" + ) # Add authcode to token_1234 for testuser + assert bumper.check_authcode("testuser", "auth_1234") + # Test that authcode was found for testuser + + bumper.user_revoke_authcode( + "testuser", "token_1234", "auth_1234" + ) # Remove authcode from testuser + assert bumper.check_authcode("testuser", "auth_1234") == False + # Test that authcode was not found for testuser + bumper.user_revoke_token("testuser", "token_1234") # Remove token from testuser + assert ( + bumper.check_token("testuser", "token_1234") == False + ) # Test that token was not found for testuser + bumper.user_add_token("testuser", "token_1234") # Add token_1234 + bumper.user_add_token("testuser", "token_4321") # Add token_4321 + assert len(bumper.user_get_tokens("testuser")) == 2 # Test 2 tokens are available + bumper.user_revoke_all_tokens("testuser") # Revoke all tokens + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available + + db = TinyDB("tests/tmp.db") + tokens = db.table("tokens") + tokens.insert( + { + "userid": "testuser", + "token": "token_1234", + "expiration": "{}".format(datetime.now() + timedelta(seconds=-10)), + } + ) # Add expired token + db.close() + assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available + bumper.user_revoke_expired_tokens("testuser") # Revoke expired tokens + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available + + db = TinyDB("tests/tmp.db") + tokens = db.table("tokens") + tokens.insert( + { + "userid": "testuser", + "token": "token_1234", + "expiration": "{}".format(datetime.now() + timedelta(seconds=-10)), + } + ) # Add expired token + db.close() + assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available + bumper.revoke_expired_tokens() # Revoke expired tokens + assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available + + +def test_bot_db(): + bumper.db = "tests/tmp.db" # Set db location for testing + bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "co_123") + assert bumper.bot_get("did_123") # Test that bot was added to db + + bumper.bot_set_nick("did_123", "nick_123") + assert ( + bumper.bot_get("did_123")["nick"] == "nick_123" + ) # Test that nick was added to bot + + bumper.bot_set_mqtt("did_123", True) + assert bumper.bot_get("did_123")[ + "mqtt_connection" + ] # Test that mqtt was set True for bot + + bumper.bot_set_xmpp("did_123", True) + assert bumper.bot_get("did_123")[ + "xmpp_connection" + ] # Test that xmpp was set True for bot + + bumper.bot_remove("did_123") + assert bumper.bot_get("did_123") == None # Test that bot is no longer in db + + +def test_client_db(): + bumper.db = "tests/tmp.db" # Set db location for testing + bumper.client_add("user_123", "realm_123", "resource_123") + assert bumper.client_get("resource_123") # Test client was added + + bumper.client_set_mqtt("resource_123", True) + assert bumper.client_get("resource_123")[ + "mqtt_connection" + ] # Test that mqtt was set True for client + + bumper.client_set_xmpp("resource_123", False) + assert ( + bumper.client_get("resource_123")["xmpp_connection"] == False + ) # Test that xmpp was set False for client + assert ( + len(bumper.get_disconnected_xmpp_clients()) == 1 + ) # Test len of connected xmpp clients is 1 diff --git a/tests/test_init.py b/tests/test_init.py index 7c1218e..67779e0 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -5,29 +5,18 @@ from tinydb.storages import MemoryStorage from tinydb import TinyDB, Query import bumper import os -import datetime, time import platform import json import asyncio from testfixtures import LogCapture -def test_get_milli_time(): - assert ( - bumper.get_milli_time( - datetime.datetime( - 2018, 1, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc - ).timestamp() - ) - == 1514768400000 - ) - - def test_strtobool(): assert bumper.strtobool("t") == True assert bumper.strtobool("f") == False assert bumper.strtobool(0) == False + async def test_start_stop(): with LogCapture() as l: if os.path.exists("tests/tmp.db"): @@ -36,12 +25,12 @@ async def test_start_stop(): b = bumper b.db = "tests/tmp.db" # Set db location for testing b.conf1_listen_address = "127.0.0.1" - b.conf1_listen_port = 444 + b.conf1_listen_port = 444 asyncio.create_task(b.start()) await asyncio.sleep(0.1) l.check_present(("bumper", "INFO", "Starting Bumper")) l.clear() - + asyncio.create_task(b.shutdown()) await asyncio.sleep(0.1) l.check_present( @@ -71,142 +60,3 @@ async def test_start_stop_debug(): ) assert b.shutting_down == True - -def test_db_path(): - bumper.db = None - assert bumper.db_file() == os.path.join(bumper.data_dir, "bumper.db") - - -def test_user_db(): - - bumper.db = "tests/tmp.db" # Set db location for testing - bumper.user_add("testuser") # Add testuser - - assert ( - bumper.user_get("testuser")["userid"] == "testuser" - ) # Test that testuser was created and returned - - bumper.user_add_device("testuser", "dev_1234") # Add device to testuser - - assert ( - bumper.user_by_deviceid("dev_1234")["userid"] == "testuser" - ) # Test that testuser was found by deviceid - - bumper.user_remove_device("testuser", "dev_1234") # Remove device from testuser - - assert "dev_1234" not in bumper.user_get("testuser")["devices"] - # Test that dev_1234 was not found in testuser devices - - bumper.user_add_bot("testuser", "bot_1234") # Add bot did to testuser - - assert "bot_1234" in bumper.user_get("testuser")["bots"] - # Test that bot was found in testuser's bot list - - bumper.user_remove_bot("testuser", "bot_1234") # Remove bot did from testuser - - assert "bot_1234" not in bumper.user_get("testuser")["bots"] - # Test that bot was not found in testuser's bot list - - bumper.user_add_token("testuser", "token_1234") # Add token to testuser - - assert bumper.check_token("testuser", "token_1234") - # Test that token was found for testuser - - assert bumper.user_get_token("testuser", "token_1234") - # Test that token was returned for testuser - - bumper.user_add_authcode( - "testuser", "token_1234", "auth_1234" - ) # Add authcode to token_1234 for testuser - assert bumper.check_authcode("testuser", "auth_1234") - # Test that authcode was found for testuser - - bumper.user_revoke_authcode( - "testuser", "token_1234", "auth_1234" - ) # Remove authcode from testuser - assert bumper.check_authcode("testuser", "auth_1234") == False - # Test that authcode was not found for testuser - bumper.user_revoke_token("testuser", "token_1234") # Remove token from testuser - assert ( - bumper.check_token("testuser", "token_1234") == False - ) # Test that token was not found for testuser - bumper.user_add_token("testuser", "token_1234") # Add token_1234 - bumper.user_add_token("testuser", "token_4321") # Add token_4321 - assert len(bumper.user_get_tokens("testuser")) == 2 # Test 2 tokens are available - bumper.user_revoke_all_tokens("testuser") # Revoke all tokens - assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available - - db = TinyDB("tests/tmp.db") - tokens = db.table("tokens") - tokens.insert( - { - "userid": "testuser", - "token": "token_1234", - "expiration": "{}".format( - datetime.datetime.now() + datetime.timedelta(seconds=-10) - ), - } - ) # Add expired token - db.close() - assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available - bumper.user_revoke_expired_tokens("testuser") # Revoke expired tokens - assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available - - db = TinyDB("tests/tmp.db") - tokens = db.table("tokens") - tokens.insert( - { - "userid": "testuser", - "token": "token_1234", - "expiration": "{}".format( - datetime.datetime.now() + datetime.timedelta(seconds=-10) - ), - } - ) # Add expired token - db.close() - assert len(bumper.user_get_tokens("testuser")) == 1 # Test 1 tokens are available - bumper.revoke_expired_tokens() # Revoke expired tokens - assert len(bumper.user_get_tokens("testuser")) == 0 # Test 0 tokens are available - - -def test_bot_db(): - bumper.db = "tests/tmp.db" # Set db location for testing - bumper.bot_add("sn_123", "did_123", "dev_123", "res_123", "co_123") - assert bumper.bot_get("did_123") # Test that bot was added to db - - bumper.bot_set_nick("did_123", "nick_123") - assert ( - bumper.bot_get("did_123")["nick"] == "nick_123" - ) # Test that nick was added to bot - - bumper.bot_set_mqtt("did_123", True) - assert bumper.bot_get("did_123")[ - "mqtt_connection" - ] # Test that mqtt was set True for bot - - bumper.bot_set_xmpp("did_123", True) - assert bumper.bot_get("did_123")[ - "xmpp_connection" - ] # Test that xmpp was set True for bot - - bumper.bot_remove("did_123") - assert bumper.bot_get("did_123") == None # Test that bot is no longer in db - - -def test_client_db(): - bumper.db = "tests/tmp.db" # Set db location for testing - bumper.client_add("user_123", "realm_123", "resource_123") - assert bumper.client_get("resource_123") # Test client was added - - bumper.client_set_mqtt("resource_123", True) - assert bumper.client_get("resource_123")[ - "mqtt_connection" - ] # Test that mqtt was set True for client - - bumper.client_set_xmpp("resource_123", False) - assert ( - bumper.client_get("resource_123")["xmpp_connection"] == False - ) # Test that xmpp was set False for client - assert ( - len(bumper.get_disconnected_xmpp_clients()) == 1 - ) # Test len of connected xmpp clients is 1 diff --git a/tests/test_mqttserver.py b/tests/test_mqttserver.py index cf2232b..0f0ccb2 100644 --- a/tests/test_mqttserver.py +++ b/tests/test_mqttserver.py @@ -14,10 +14,11 @@ import time async def test_helperbot_message(): - with LogCapture("helperbot") as l: - mqtt_address = ("127.0.0.1", 8883) - mqtt_server = bumper.MQTTServer(mqtt_address) - await mqtt_server.broker_coro() + mqtt_address = ("127.0.0.1", 8883) + mqtt_server = bumper.MQTTServer(mqtt_address) + await mqtt_server.broker_coro() + + with LogCapture() as l: # Test broadcast message mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) @@ -125,20 +126,42 @@ async def test_helperbot_message(): ) # Check received message was logged l.clear() mqtt_helperbot.Client.disconnect() - await mqtt_server.broker.shutdown() + + # Received error message + mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) + await mqtt_helperbot.start_helper_bot() + assert ( + mqtt_helperbot.Client._connected_state._value == True + ) # Check helperbot is connected + msg_payload = "" + msg_topic_name = "iot/atr/errors/bot_serial/ls1ok3/wC3g/x" + await mqtt_helperbot.Client.publish( + msg_topic_name, msg_payload.encode(), hbmqtt.client.QOS_0 + ) + try: + await asyncio.wait_for(mqtt_helperbot.Client.deliver_message(), timeout=0.1) + except asyncio.TimeoutError: + pass + + l.check_present( + ( + "boterror", + "ERROR", + "Received Error - Topic: iot/atr/errors/bot_serial/ls1ok3/wC3g/x - Message: ", + ) + ) # Check received message was logged + l.clear() + mqtt_helperbot.Client.disconnect() + + await mqtt_server.broker.shutdown() async def test_helperbot_expire_message(): + mqtt_address = ("127.0.0.1", 8883) + mqtt_server = bumper.MQTTServer(mqtt_address) + await mqtt_server.broker_coro() + with LogCapture("helperbot") as l: - mqtt_address = ("127.0.0.1", 8883) - mqtt_server = bumper.MQTTServer(mqtt_address) - await mqtt_server.broker_coro() - # mqtt_address = ("127.0.0.1", 8883) - # mqtt_server = bumper.MQTTServer(mqtt_address) - # broker = hbmqtt.broker.Broker( - # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" - # ) - # await broker.start() # Test broadcast message mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) @@ -195,19 +218,14 @@ async def test_helperbot_expire_message(): ) ) # Check received message was logged mqtt_helperbot.Client.disconnect() - await mqtt_server.broker.shutdown() + + await mqtt_server.broker.shutdown() async def test_helperbot_sendcommand(): mqtt_address = ("127.0.0.1", 8883) mqtt_server = bumper.MQTTServer(mqtt_address) await mqtt_server.broker_coro() - # mqtt_address = ("127.0.0.1", 8883) - # mqtt_server = bumper.MQTTServer(mqtt_address) - # broker = hbmqtt.broker.Broker( - # mqtt_server.default_config, plugin_namespace="hbmqtt.test.plugins" - # ) - # await broker.start() mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address) await mqtt_helperbot.start_helper_bot() diff --git a/tests/test_xmppserver.py b/tests/test_xmppserver.py index 74d2a0c..ef48025 100644 --- a/tests/test_xmppserver.py +++ b/tests/test_xmppserver.py @@ -21,10 +21,11 @@ def mock_transport_extra_info(*args, **kwargs): async def test_xmpp_server(): + xmpp_address = ("127.0.0.1", 5223) + xmpp_server = bumper.XMPPServer(xmpp_address) + await xmpp_server.start_async_server() + with LogCapture("xmppserver") as l: - xmpp_address = ("127.0.0.1", 5223) - xmpp_server = bumper.XMPPServer(xmpp_address) - await xmpp_server.start_async_server() reader, writer = await asyncio.open_connection("127.0.0.1", 5223) @@ -52,10 +53,8 @@ async def test_xmpp_server(): await writer.drain() await asyncio.sleep(0.1) - xmpp_server.disconnect() - await asyncio.sleep(0.1) - assert len(xmpp_server.clients) == 0 # Client count decreased - print(l) + + xmpp_server.disconnect() async def test_client_connect_no_starttls(*args, **kwargs): @@ -209,6 +208,11 @@ async def test_client_connect_starttls_called(*args, **kwargs): async def test_xmpp_server_client_tls(): + + xmpp_address = ("127.0.0.1", 5223) + xmpp_server = bumper.XMPPServer(xmpp_address) + await xmpp_server.start_async_server() + with LogCapture("xmppserver") as l: async def do_stuff_after_start_tls( @@ -227,10 +231,6 @@ async def test_xmpp_server_client_tls(): await writer.drain() - xmpp_address = ("127.0.0.1", 5223) - xmpp_server = bumper.XMPPServer(xmpp_address) - await xmpp_server.start_async_server() - reader, writer = await asyncio.open_connection("127.0.0.1", 5223) writer.write( @@ -616,3 +616,30 @@ async def test_client_send_iq(*args, **kwargs): # Reset mock calls mock_send.reset_mock() + # Bot error report + test_data = "".encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # result sent to ecouser.net + + # Reset mock calls + mock_send.reset_mock() + + # Bot "DorpError" to all + test_data = "".encode( + "utf-8" + ) + xmppclient2._parse_data(test_data) + assert ( + mock_send.mock_calls[0].args[0] + == '' + ) # result sent to ecouser.net + + # Reset mock calls + mock_send.reset_mock() + diff --git a/tests/test_z_problem.py b/tests/test_z_problem.py index f3f00f2..3bd2ca5 100644 --- a/tests/test_z_problem.py +++ b/tests/test_z_problem.py @@ -100,4 +100,3 @@ def test_main(mock_firstrun): bumper.main() assert mock_firstrun.called == True bumper.ca_cert = "tests/test_certs/ca.crt" - From 7fc7cb80cbae04056965c53759caa58bbe8cb9c2 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Thu, 20 Jun 2019 08:48:01 -0400 Subject: [PATCH 07/10] api - restart_{service} add restart_{service} - restart_Helperbot - restart_MQTTServer - Removed a few outstanding references to threads --- bumper/__init__.py | 29 +++-- bumper/confserver.py | 292 +++++++++++++++++++++++++++---------------- bumper/mqttserver.py | 51 ++++---- bumper/xmppserver.py | 8 +- 4 files changed, 229 insertions(+), 151 deletions(-) diff --git a/bumper/__init__.py b/bumper/__init__.py index f7e73c2..f379e97 100644 --- a/bumper/__init__.py +++ b/bumper/__init__.py @@ -163,23 +163,12 @@ async def start(): global mqtt_helperbot mqtt_helperbot = MQTTHelperBot((bumper_listen, mqtt_listen_port)) global conf_server - conf_server = ConfServer( - (bumper_listen, conf1_listen_port), usessl=True, helperbot=mqtt_helperbot - ) + conf_server = ConfServer((bumper_listen, conf1_listen_port), usessl=True) global conf_server_2 - conf_server_2 = ConfServer( - (bumper_listen, conf2_listen_port), usessl=False, helperbot=mqtt_helperbot - ) + conf_server_2 = ConfServer((bumper_listen, conf2_listen_port), usessl=False) global xmpp_server xmpp_server = XMPPServer((bumper_listen, xmpp_listen_port)) - # Start web servers - conf_server.confserver_app() - asyncio.create_task(conf_server.start_server()) - - conf_server_2.confserver_app() - asyncio.create_task(conf_server_2.start_server()) - # Start MQTT Server asyncio.create_task(mqtt_server.broker_coro()) @@ -189,6 +178,20 @@ async def start(): # Start XMPP Server asyncio.create_task(xmpp_server.start_async_server()) + # Wait for helperbot to connect first + while mqtt_helperbot.Client is None: + await asyncio.sleep(0.1) + + while not mqtt_helperbot.Client.session.transitions.state == "connected": + await asyncio.sleep(0.1) + + # Start web servers + conf_server.confserver_app() + asyncio.create_task(conf_server.start_server()) + + conf_server_2.confserver_app() + asyncio.create_task(conf_server_2.start_server()) + # Start maintenance while not shutting_down: asyncio.create_task(maintenance()) diff --git a/bumper/confserver.py b/bumper/confserver.py index f1fab45..11b451d 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -38,12 +38,9 @@ logging.getLogger("aiohttp.access").addFilter( class ConfServer: - def __init__(self, address, usessl=False, helperbot=None): - self.helperbot = helperbot + def __init__(self, address, usessl=False): self.usessl = usessl self.address = address - self.confthread = None - self.run_async = False self.app = None self.site = None self.runner = None @@ -57,6 +54,7 @@ class ConfServer: self.app.add_routes( [ web.get("", self.handle_base), + web.get("/restart_{service}", self.handle_RestartService), web.get( "/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/login", self.handle_login, @@ -198,11 +196,29 @@ class ConfServer: # text = "Bumper!" bots = bumper.db_get().table("bots").all() clients = bumper.db_get().table("clients").all() - helperbot = self.helperbot.Client.session.transitions.state + helperbot = bumper.mqtt_helperbot.Client.session.transitions.state + mqttserver = bumper.mqtt_server.broker + mq_sessions = [] + for sess in mqttserver._sessions: + tmpsess = [] + tmpsess.append({"client_id": mqttserver._sessions[sess][0].client_id}) + tmpsess.append( + {"state": mqttserver._sessions[sess][0].transitions.state} + ) + mq_sessions.append(tmpsess) all = { "bots": bots, "clients": clients, "helperbot": [{"state": helperbot}], + "mqtt_server": [ + {"state": mqttserver.transitions.state}, + { + "sessions": [ + {"count": len(mqttserver._sessions)}, + {"clients": mq_sessions}, + ] + }, + ], } return web.json_response(all) @@ -210,6 +226,49 @@ class ConfServer: except Exception as e: confserverlog.exception("{}".format(e)) + async def restart_Helper(self): + + await bumper.mqtt_helperbot.Client.disconnect() + await bumper.mqtt_helperbot.start_helper_bot() + + + + async def restart_MQTT(self): + mqttserver = bumper.mqtt_server.broker + + for sess in list(mqttserver._sessions): + sessobj = mqttserver._sessions[sess][1] + await sessobj.writer.close() + mqttserver.delete_session(sess) + + await bumper.mqtt_server.broker.shutdown() + while not bumper.mqtt_server.broker.transitions.state == "stopped": + await asyncio.sleep(0.1) + + await bumper.mqtt_server.broker_coro() + while not bumper.mqtt_server.broker.transitions.state == "started": + await asyncio.sleep(0.1) + + async def handle_RestartService(self, request): + try: + service = request.match_info.get("service", "") + if service == "Helperbot": + await self.restart_Helper() + return web.json_response({"status": "complete"}) + elif service == "MQTTServer": + await self.restart_MQTT() + aloop = asyncio.get_event_loop() + aloop.call_later( + 2, lambda: asyncio.create_task(self.restart_Helper()) + ) # In 2 seconds restart Helperbot + + return web.json_response({"status": "complete"}) + else: + return web.json_response({"status": "invalid service"}) + + except Exception as e: + confserverlog.exception("{}".format(e)) + async def handle_login(self, request): try: user_devid = request.match_info.get("devid", "") @@ -259,9 +318,7 @@ class ConfServer: # "username": "fusername_{}".format(tmpuser["userid"]), # }, "msg": "操作成功", - "time": self.self.get_milli_time( - datetime.utcnow().timestamp() - ), + "time": self.get_milli_time(datetime.utcnow().timestamp()), } return web.json_response(body) @@ -1048,122 +1105,136 @@ class ConfServer: confserverlog.exception("{}".format(e)) async def handle_lg_log(self, request): # EcoVacs Home - try: - json_body = json.loads(await request.text()) + if ( + not bumper.mqtt_helperbot.Client._handler.writer is None + ): # Ignore if the Helperbot writer is none + try: + json_body = json.loads(await request.text()) - randomid = "".join(random.sample(string.ascii_letters, 6)) - did = json_body["did"] + randomid = "".join(random.sample(string.ascii_letters, 6)) + did = json_body["did"] - botdetails = bumper.bot_get(did) - if botdetails: - if not "cmdName" in json_body: - if "td" in json_body: - json_body["cmdName"] = json_body["td"] - # json_body["td"] = "q" + botdetails = bumper.bot_get(did) + if botdetails: + if not "cmdName" in json_body: + if "td" in json_body: + json_body["cmdName"] = json_body["td"] + # json_body["td"] = "q" - if not "toId" in json_body: - json_body["toId"] = did + if not "toId" in json_body: + json_body["toId"] = did - if not "toType" in json_body: - json_body["toType"] = botdetails["class"] + if not "toType" in json_body: + json_body["toType"] = botdetails["class"] - if not "toRes" in json_body: - json_body["toRes"] = botdetails["resource"] + if not "toRes" in json_body: + json_body["toRes"] = botdetails["resource"] - if not "payloadType" in json_body: - json_body["payloadType"] = "x" + if not "payloadType" in json_body: + json_body["payloadType"] = "x" - if not "payload" in json_body: - json_body["payload"] = "" - if json_body["td"] == "GetCleanLogs": - json_body["td"] = "q" - json_body["payload"] = '' # " + if not "payload" in json_body: + json_body["payload"] = "" + if json_body["td"] == "GetCleanLogs": + json_body["td"] = "q" + json_body["payload"] = '' # " - if did != "": - bot = bumper.bot_get(did) - if bot["company"] == "eco-ng": - body = "" - retcmd = await self.helperbot.send_command(json_body, randomid) - confserverlog.debug("Send Bot - {}".format(json_body)) - confserverlog.debug("Bot Response - {}".format(body)) - logs = [] - logsroot = ET.fromstring(retcmd["resp"]) - if logsroot.attrib["ret"] == "ok": - cleanlogs = logsroot.getchildren() - for l in cleanlogs: - logs.append(l.attrib) - - body = { - "ret": "ok", - # "logs": logs, #TODO: Doesn't parse correctly, new protocol & server side processing - "logs": [], - } - - else: - body = {"ret": "ok", "logs": []} - - confserverlog.debug( - "POST: {} - Response: {}".format(json_body, body) - ) - - return web.json_response(body) - else: - # No response, send error back - confserverlog.error( - "No bots with DID: {} connected to MQTT".format( - json_body["toId"] + if did != "": + bot = bumper.bot_get(did) + if bot["company"] == "eco-ng": + body = "" + retcmd = await bumper.mqtt_helperbot.send_command( + json_body, randomid ) - ) - body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"} - return web.json_response(body) + confserverlog.debug("Send Bot - {}".format(json_body)) + confserverlog.debug("Bot Response - {}".format(body)) + logs = [] + logsroot = ET.fromstring(retcmd["resp"]) + if logsroot.attrib["ret"] == "ok": + cleanlogs = logsroot.getchildren() + for l in cleanlogs: + logs.append(l.attrib) - except Exception as e: - confserverlog.exception("{}".format(e)) + body = { + "ret": "ok", + # "logs": logs, #TODO: Doesn't parse correctly, new protocol & server side processing + "logs": [], + } + + else: + body = {"ret": "ok", "logs": []} + + confserverlog.debug( + "POST: {} - Response: {}".format(json_body, body) + ) + + return web.json_response(body) + else: + # No response, send error back + confserverlog.error( + "No bots with DID: {} connected to MQTT".format( + json_body["toId"] + ) + ) + body = { + "id": randomid, + "errno": bumper.ERR_COMMON, + "ret": "fail", + } + return web.json_response(body) + + except Exception as e: + confserverlog.exception("{}".format(e)) async def handle_devmanager_botcommand(self, request): - try: - json_body = json.loads(await request.text()) + if ( + not bumper.mqtt_helperbot.Client._handler.writer is None + ): # Ignore if the helperbot object isn't set + try: + json_body = json.loads(await request.text()) - randomid = "".join(random.sample(string.ascii_letters, 6)) - did = "" - if "toId" in json_body: # Its a command - did = json_body["toId"] + randomid = "".join(random.sample(string.ascii_letters, 6)) + did = "" + if "toId" in json_body: # Its a command + did = json_body["toId"] - if did != "": - bot = bumper.bot_get(did) - if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True: - retcmd = await self.helperbot.send_command(json_body, randomid) - body = retcmd - confserverlog.debug("Send Bot - {}".format(json_body)) - confserverlog.debug("Bot Response - {}".format(body)) - return web.json_response(body) - else: - # No response, send error back - confserverlog.error( - "No bots with DID: {} connected to MQTT".format( - json_body["toId"] + if did != "": + bot = bumper.bot_get(did) + if bot["company"] == "eco-ng": + retcmd = await bumper.mqtt_helperbot.send_command( + json_body, randomid ) - ) - body = { - "id": randomid, - "errno": 500, - "ret": "fail", - "debug": "wait for response timed out", - } - return web.json_response(body) - - else: - if "td" in json_body: # Seen when doing initial wifi config - if json_body["td"] == "PollSCResult": - body = {"ret": "ok"} + body = retcmd + confserverlog.debug("Send Bot - {}".format(json_body)) + confserverlog.debug("Bot Response - {}".format(body)) + return web.json_response(body) + else: + # No response, send error back + confserverlog.error( + "No bots with DID: {} connected to MQTT".format( + json_body["toId"] + ) + ) + body = { + "id": randomid, + "errno": 500, + "ret": "fail", + "debug": "wait for response timed out", + } return web.json_response(body) - if json_body["td"] == "HasUnreadMsg": # EcoVacs Home - body = {"ret": "ok", "unRead": False} - return web.json_response(body) + else: + if "td" in json_body: # Seen when doing initial wifi config + if json_body["td"] == "PollSCResult": + body = {"ret": "ok"} + return web.json_response(body) - except Exception as e: - confserverlog.exception("{}".format(e)) + if json_body["td"] == "HasUnreadMsg": # EcoVacs Home + body = {"ret": "ok", "unRead": False} + return web.json_response(body) + + except Exception as e: + confserverlog.exception("{}".format(e)) async def handle_dim_devmanager(self, request): # Used in EcoVacs Home App try: @@ -1177,7 +1248,9 @@ class ConfServer: if did != "": bot = bumper.bot_get(did) if bot["company"] == "eco-ng" and bot["mqtt_connection"] == True: - retcmd = await self.helperbot.send_command(json_body, randomid) + retcmd = await bumper.mqtt_helperbot.send_command( + json_body, randomid + ) body = retcmd confserverlog.debug("Send Bot - {}".format(json_body)) confserverlog.debug("Bot Response - {}".format(body)) @@ -1208,10 +1281,7 @@ class ConfServer: async def disconnect(self): try: confserverlog.info("shutting down") - if self.run_async: - self.confthread.join() - else: - await self.app.shutdown() + await self.app.shutdown() except Exception as e: confserverlog.exception("{}".format(e)) diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py index 9e5de56..6b18a75 100644 --- a/bumper/mqttserver.py +++ b/bumper/mqttserver.py @@ -31,7 +31,7 @@ logging.getLogger("hbmqtt.client").setLevel(logging.CRITICAL + 1) # Ignore this class MQTTHelperBot: - Client = MQTTClient() + Client = None wait_resp_timeout_seconds = 10 expire_msg_seconds = 10 @@ -39,14 +39,14 @@ class MQTTHelperBot: self.address = address self.client_id = "helper1@bumper/helper1" self.command_responses = [] - self.helperthread = None async def start_helper_bot(self): try: - self.Client = MQTTClient( - client_id=self.client_id, config={"check_hostname": False} - ) + if self.Client is None: + self.Client = MQTTClient( + client_id=self.client_id, config={"check_hostname": False} + ) await self.Client.connect( "mqtts://{}:{}/".format(self.address[0], self.address[1]), @@ -183,29 +183,30 @@ class MQTTHelperBot: } async def send_command(self, cmdjson, requestid): - try: - ttopic = "iot/p2p/{}/helper1/bumper/helper1/{}/{}/{}/q/{}/{}".format( - cmdjson["cmdName"], - cmdjson["toId"], - cmdjson["toType"], - cmdjson["toRes"], - requestid, - cmdjson["payloadType"], - ) + if not self.Client._handler.writer is None: try: - await self.Client.publish( - ttopic, str(cmdjson["payload"]).encode(), QOS_0 + ttopic = "iot/p2p/{}/helper1/bumper/helper1/{}/{}/{}/q/{}/{}".format( + cmdjson["cmdName"], + cmdjson["toId"], + cmdjson["toType"], + cmdjson["toRes"], + requestid, + cmdjson["payloadType"], ) + try: + await self.Client.publish( + ttopic, str(cmdjson["payload"]).encode(), QOS_0 + ) + except Exception as e: + helperbotlog.exception("{}".format(e)) + + resp = await self.wait_for_resp(requestid) + + return resp + except Exception as e: helperbotlog.exception("{}".format(e)) - - resp = await self.wait_for_resp(requestid) - - return resp - - except Exception as e: - helperbotlog.exception("{}".format(e)) - return {} + return {} class MQTTServer: @@ -233,7 +234,6 @@ class MQTTServer: def __init__(self, address): try: - self.mqttserverthread = None self.address = address # The below adds a plugin to the hbmqtt.broker.plugins without having to futz with setup.py @@ -355,6 +355,7 @@ class BumperMQTTServer_Plugin: async def on_broker_client_connected(self, client_id): try: + didsplit = str(client_id).split("@") bot = bumper.bot_get(didsplit[0]) diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index e4f0ba3..ca52455 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -52,7 +52,7 @@ class XMPPServer: def disconnect(self): try: - xmppserverlog.debug("waiting for all client threads to exit") + xmppserverlog.debug("waiting for all clients to disconnect") for client in self.clients: client._disconnect() @@ -722,7 +722,11 @@ class XMPPAsyncClient: ).replace("ns0:", ""), ) ) - if 'td="error"' in newdata or 'errs=' in newdata or 'k="DeviceAlert' in newdata: + if ( + 'td="error"' in newdata + or "errs=" in newdata + or 'k="DeviceAlert' in newdata + ): boterrorlog.error( "Received Error from ({}:{} | {}) - {}".format( self.address[0], From 40d4af3f8045bb12fbdf4df9b601b22cb17925e8 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Thu, 20 Jun 2019 08:59:15 -0400 Subject: [PATCH 08/10] fixing the broken tests leftover helperbot= in tests causing failures.... --- bumper/confserver.py | 6 ------ tests/test_confserver.py | 34 +++++++++++++--------------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/bumper/confserver.py b/bumper/confserver.py index 11b451d..d9c7aac 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -1105,9 +1105,6 @@ class ConfServer: confserverlog.exception("{}".format(e)) async def handle_lg_log(self, request): # EcoVacs Home - if ( - not bumper.mqtt_helperbot.Client._handler.writer is None - ): # Ignore if the Helperbot writer is none try: json_body = json.loads(await request.text()) @@ -1187,9 +1184,6 @@ class ConfServer: confserverlog.exception("{}".format(e)) async def handle_devmanager_botcommand(self, request): - if ( - not bumper.mqtt_helperbot.Client._handler.writer is None - ): # Ignore if the helperbot object isn't set try: json_body = json.loads(await request.text()) diff --git a/tests/test_confserver.py b/tests/test_confserver.py index abfaa57..2d0a70b 100644 --- a/tests/test_confserver.py +++ b/tests/test_confserver.py @@ -12,11 +12,11 @@ from aiohttp import web def create_confserver(): - return bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) + return bumper.ConfServer("127.0.0.1:11111", False) def create_app(loop): - confserver = bumper.ConfServer("127.0.0.1:11111", False, mock.MagicMock) + confserver = bumper.ConfServer("127.0.0.1:11111", False) confserver.confserver_app() return confserver.app @@ -33,13 +33,13 @@ def remove_existing_db(): async def test_confserver_ssl(): - conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=True, helperbot=None) + conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=True) conf_server.confserver_app() asyncio.create_task(conf_server.start_server()) async def test_confserver_no_ssl(): - conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=False, helperbot=None) + conf_server = bumper.ConfServer(("127.0.0.1", 111111), usessl=False) conf_server.confserver_app() asyncio.create_task(conf_server.start_server()) @@ -710,6 +710,7 @@ async def test_lg_logs(aiohttp_client): bumper.bot_set_mqtt("did_1234", True) confserver = create_confserver() client = await aiohttp_client(create_app) + bumper.mqtt_helperbot = bumper.mqttserver.MQTTHelperBot("127.0.0.1") # Test return get status command_getstatus_resp = { @@ -717,7 +718,7 @@ async def test_lg_logs(aiohttp_client): "resp": "", "ret": "ok", } - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) @@ -768,6 +769,7 @@ async def test_devmgr(aiohttp_client): bumper.db = "tests/tmp.db" # Set db location for testing confserver = create_confserver() client = await aiohttp_client(create_app) + bumper.mqtt_helperbot = bumper.mqttserver.MQTTHelperBot("127.0.0.1") # Test PollSCResult postbody = {"td": "PollSCResult"} @@ -797,7 +799,7 @@ async def test_devmgr(aiohttp_client): "resp": "", "ret": "ok", } - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) resp = await client.post("/api/iot/devmanager.do", json=postbody) @@ -808,7 +810,7 @@ async def test_devmgr(aiohttp_client): # Test return fail timeout command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"} - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_timeout_resp) ) resp = await client.post("/api/iot/devmanager.do", json=postbody) @@ -817,23 +819,13 @@ async def test_devmgr(aiohttp_client): test_resp = json.loads(text) assert test_resp["ret"] == "fail" - # Set bot not on mqtt - bumper.bot_set_mqtt("did_1234", False) - confserver.helperbot.send_command = mock.MagicMock( - return_value=async_return(command_getstatus_resp) - ) - resp = await client.post("/api/iot/devmanager.do", json=postbody) - assert resp.status == 200 - text = await resp.text() - test_resp = json.loads(text) - assert test_resp["ret"] == "fail" - async def test_dim_devmanager(aiohttp_client): remove_existing_db() bumper.db = "tests/tmp.db" # Set db location for testing confserver = create_confserver() client = await aiohttp_client(create_app) + bumper.mqtt_helperbot = bumper.mqttserver.MQTTHelperBot("127.0.0.1") # Test PollSCResult postbody = {"td": "PollSCResult"} @@ -863,7 +855,7 @@ async def test_dim_devmanager(aiohttp_client): "resp": "", "ret": "ok", } - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) resp = await client.post("/api/dim/devmanager.do", json=postbody) @@ -874,7 +866,7 @@ async def test_dim_devmanager(aiohttp_client): # Test return fail timeout command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"} - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_timeout_resp) ) resp = await client.post("/api/dim/devmanager.do", json=postbody) @@ -886,7 +878,7 @@ async def test_dim_devmanager(aiohttp_client): # Set bot not on mqtt bumper.bot_set_mqtt("did_1234", False) - confserver.helperbot.send_command = mock.MagicMock( + bumper.mqtt_helperbot.send_command = mock.MagicMock( return_value=async_return(command_getstatus_resp) ) resp = await client.post("/api/dim/devmanager.do", json=postbody) From 9be1ba83217209262285c0d2f0fab3e26f2cdeea Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Thu, 20 Jun 2019 20:39:45 -0400 Subject: [PATCH 09/10] restart_XMPP restart_XMPPServer --- bumper/confserver.py | 216 +++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/bumper/confserver.py b/bumper/confserver.py index d9c7aac..be64d59 100644 --- a/bumper/confserver.py +++ b/bumper/confserver.py @@ -231,8 +231,6 @@ class ConfServer: await bumper.mqtt_helperbot.Client.disconnect() await bumper.mqtt_helperbot.start_helper_bot() - - async def restart_MQTT(self): mqttserver = bumper.mqtt_server.broker @@ -249,6 +247,10 @@ class ConfServer: while not bumper.mqtt_server.broker.transitions.state == "started": await asyncio.sleep(0.1) + async def restart_XMPP(self): + bumper.xmpp_server.disconnect() + await bumper.xmpp_server.start_async_server() + async def handle_RestartService(self, request): try: service = request.match_info.get("service", "") @@ -261,7 +263,9 @@ class ConfServer: aloop.call_later( 2, lambda: asyncio.create_task(self.restart_Helper()) ) # In 2 seconds restart Helperbot - + return web.json_response({"status": "complete"}) + elif service == "XMPPServer": + await self.restart_XMPP() return web.json_response({"status": "complete"}) else: return web.json_response({"status": "invalid service"}) @@ -1105,130 +1109,126 @@ class ConfServer: confserverlog.exception("{}".format(e)) async def handle_lg_log(self, request): # EcoVacs Home - try: - json_body = json.loads(await request.text()) + try: + json_body = json.loads(await request.text()) - randomid = "".join(random.sample(string.ascii_letters, 6)) - did = json_body["did"] + randomid = "".join(random.sample(string.ascii_letters, 6)) + did = json_body["did"] - botdetails = bumper.bot_get(did) - if botdetails: - if not "cmdName" in json_body: - if "td" in json_body: - json_body["cmdName"] = json_body["td"] - # json_body["td"] = "q" + botdetails = bumper.bot_get(did) + if botdetails: + if not "cmdName" in json_body: + if "td" in json_body: + json_body["cmdName"] = json_body["td"] + # json_body["td"] = "q" - if not "toId" in json_body: - json_body["toId"] = did + if not "toId" in json_body: + json_body["toId"] = did - if not "toType" in json_body: - json_body["toType"] = botdetails["class"] + if not "toType" in json_body: + json_body["toType"] = botdetails["class"] - if not "toRes" in json_body: - json_body["toRes"] = botdetails["resource"] + if not "toRes" in json_body: + json_body["toRes"] = botdetails["resource"] - if not "payloadType" in json_body: - json_body["payloadType"] = "x" + if not "payloadType" in json_body: + json_body["payloadType"] = "x" - if not "payload" in json_body: - json_body["payload"] = "" - if json_body["td"] == "GetCleanLogs": - json_body["td"] = "q" - json_body["payload"] = '' # " + if not "payload" in json_body: + json_body["payload"] = "" + if json_body["td"] == "GetCleanLogs": + json_body["td"] = "q" + json_body["payload"] = '' # " - if did != "": - bot = bumper.bot_get(did) - if bot["company"] == "eco-ng": - body = "" - retcmd = await bumper.mqtt_helperbot.send_command( - json_body, randomid - ) - confserverlog.debug("Send Bot - {}".format(json_body)) - confserverlog.debug("Bot Response - {}".format(body)) - logs = [] - logsroot = ET.fromstring(retcmd["resp"]) - if logsroot.attrib["ret"] == "ok": - cleanlogs = logsroot.getchildren() - for l in cleanlogs: - logs.append(l.attrib) + if did != "": + bot = bumper.bot_get(did) + if bot["company"] == "eco-ng": + body = "" + retcmd = await bumper.mqtt_helperbot.send_command( + json_body, randomid + ) + confserverlog.debug("Send Bot - {}".format(json_body)) + confserverlog.debug("Bot Response - {}".format(body)) + logs = [] + logsroot = ET.fromstring(retcmd["resp"]) + if logsroot.attrib["ret"] == "ok": + cleanlogs = logsroot.getchildren() + for l in cleanlogs: + logs.append(l.attrib) - body = { - "ret": "ok", - # "logs": logs, #TODO: Doesn't parse correctly, new protocol & server side processing - "logs": [], - } - - else: - body = {"ret": "ok", "logs": []} - - confserverlog.debug( - "POST: {} - Response: {}".format(json_body, body) - ) - - return web.json_response(body) - else: - # No response, send error back - confserverlog.error( - "No bots with DID: {} connected to MQTT".format( - json_body["toId"] - ) - ) body = { - "id": randomid, - "errno": bumper.ERR_COMMON, - "ret": "fail", + "ret": "ok", + # "logs": logs, #TODO: Doesn't parse correctly, new protocol & server side processing + "logs": [], } - return web.json_response(body) - except Exception as e: - confserverlog.exception("{}".format(e)) + else: + body = {"ret": "ok", "logs": []} + + confserverlog.debug( + "POST: {} - Response: {}".format(json_body, body) + ) + + return web.json_response(body) + else: + # No response, send error back + confserverlog.error( + "No bots with DID: {} connected to MQTT".format( + json_body["toId"] + ) + ) + body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"} + return web.json_response(body) + + except Exception as e: + confserverlog.exception("{}".format(e)) async def handle_devmanager_botcommand(self, request): - try: - json_body = json.loads(await request.text()) + try: + json_body = json.loads(await request.text()) - randomid = "".join(random.sample(string.ascii_letters, 6)) - did = "" - if "toId" in json_body: # Its a command - did = json_body["toId"] - - if did != "": - bot = bumper.bot_get(did) - if bot["company"] == "eco-ng": - retcmd = await bumper.mqtt_helperbot.send_command( - json_body, randomid - ) - body = retcmd - confserverlog.debug("Send Bot - {}".format(json_body)) - confserverlog.debug("Bot Response - {}".format(body)) - return web.json_response(body) - else: - # No response, send error back - confserverlog.error( - "No bots with DID: {} connected to MQTT".format( - json_body["toId"] - ) - ) - body = { - "id": randomid, - "errno": 500, - "ret": "fail", - "debug": "wait for response timed out", - } - return web.json_response(body) + randomid = "".join(random.sample(string.ascii_letters, 6)) + did = "" + if "toId" in json_body: # Its a command + did = json_body["toId"] + if did != "": + bot = bumper.bot_get(did) + if bot["company"] == "eco-ng": + retcmd = await bumper.mqtt_helperbot.send_command( + json_body, randomid + ) + body = retcmd + confserverlog.debug("Send Bot - {}".format(json_body)) + confserverlog.debug("Bot Response - {}".format(body)) + return web.json_response(body) else: - if "td" in json_body: # Seen when doing initial wifi config - if json_body["td"] == "PollSCResult": - body = {"ret": "ok"} - return web.json_response(body) + # No response, send error back + confserverlog.error( + "No bots with DID: {} connected to MQTT".format( + json_body["toId"] + ) + ) + body = { + "id": randomid, + "errno": 500, + "ret": "fail", + "debug": "wait for response timed out", + } + return web.json_response(body) - if json_body["td"] == "HasUnreadMsg": # EcoVacs Home - body = {"ret": "ok", "unRead": False} - return web.json_response(body) + else: + if "td" in json_body: # Seen when doing initial wifi config + if json_body["td"] == "PollSCResult": + body = {"ret": "ok"} + return web.json_response(body) - except Exception as e: - confserverlog.exception("{}".format(e)) + if json_body["td"] == "HasUnreadMsg": # EcoVacs Home + body = {"ret": "ok", "unRead": False} + return web.json_response(body) + + except Exception as e: + confserverlog.exception("{}".format(e)) async def handle_dim_devmanager(self, request): # Used in EcoVacs Home App try: From 2663c46d524d600e89316f9e1101b677740f1384 Mon Sep 17 00:00:00 2001 From: Brian Martin Date: Thu, 20 Jun 2019 21:05:36 -0400 Subject: [PATCH 10/10] remove a few try remove a few try --- bumper/db.py | 23 ++---- bumper/mqttserver.py | 52 ++++++------- bumper/xmppserver.py | 172 ++++++++++++++++++++----------------------- 3 files changed, 108 insertions(+), 139 deletions(-) diff --git a/bumper/db.py b/bumper/db.py index e33574a..20181f9 100644 --- a/bumper/db.py +++ b/bumper/db.py @@ -24,23 +24,16 @@ def os_db_path(): # createdir=True): def db_get(): - try: - # Will create the database if it doesn't exist - db = TinyDB(db_file()) + # Will create the database if it doesn't exist + db = TinyDB(db_file()) - # Will create the tables if they don't exist - db.table("users", cache_size=0) - db.table("clients", cache_size=0) - db.table("bots", cache_size=0) - db.table("tokens", cache_size=0) + # Will create the tables if they don't exist + db.table("users", cache_size=0) + db.table("clients", cache_size=0) + db.table("bots", cache_size=0) + db.table("tokens", cache_size=0) - return db - - except json.decoder.JSONDecodeError as jerr: - bumperlog.error("JsonErr: {} - Doc: {}".format(jerr.msg, jerr.doc)) - - except Exception as ex: - bumperlog.error(ex) + return db def user_add(userid): diff --git a/bumper/mqttserver.py b/bumper/mqttserver.py index 6b18a75..72b1feb 100644 --- a/bumper/mqttserver.py +++ b/bumper/mqttserver.py @@ -354,41 +354,33 @@ class BumperMQTTServer_Plugin: return authenticated async def on_broker_client_connected(self, client_id): - try: - didsplit = str(client_id).split("@") + didsplit = str(client_id).split("@") - bot = bumper.bot_get(didsplit[0]) - if bot: - bumper.bot_set_mqtt(bot["did"], True) - return + bot = bumper.bot_get(didsplit[0]) + if bot: + bumper.bot_set_mqtt(bot["did"], True) + return - # clientuserid = didsplit[0] - clientresource = didsplit[1].split("/")[1] - client = bumper.client_get(clientresource) - if client: - bumper.client_set_mqtt(client["resource"], True) - return - - except Exception as e: - mqttserverlog.exception("{}".format(e)) + # clientuserid = didsplit[0] + clientresource = didsplit[1].split("/")[1] + client = bumper.client_get(clientresource) + if client: + bumper.client_set_mqtt(client["resource"], True) + return async def on_broker_client_disconnected(self, client_id): - try: - didsplit = str(client_id).split("@") - bot = bumper.bot_get(didsplit[0]) - if bot: - bumper.bot_set_mqtt(bot["did"], False) - return + didsplit = str(client_id).split("@") - # clientuserid = didsplit[0] - clientresource = didsplit[1].split("/")[1] - client = bumper.client_get(clientresource) - if client: - bumper.client_set_mqtt(client["resource"], False) - return - - except Exception as e: - mqttserverlog.exception("{}".format(e)) + bot = bumper.bot_get(didsplit[0]) + if bot: + bumper.bot_set_mqtt(bot["did"], False) + return + # clientuserid = didsplit[0] + clientresource = didsplit[1].split("/")[1] + client = bumper.client_get(clientresource) + if client: + bumper.client_set_mqtt(client["resource"], False) + return diff --git a/bumper/xmppserver.py b/bumper/xmppserver.py index ca52455..be932a9 100644 --- a/bumper/xmppserver.py +++ b/bumper/xmppserver.py @@ -51,17 +51,14 @@ class XMPPServer: asyncio.create_task(bumper.shutdown()) def disconnect(self): - try: - xmppserverlog.debug("waiting for all clients to disconnect") - for client in self.clients: - client._disconnect() - self.exit_flag = True - xmppserverlog.debug("shutting down") - self.server_coro.cancel() + xmppserverlog.debug("waiting for all clients to disconnect") + for client in self.clients: + client._disconnect() - except Exception as e: - xmppserverlog.error("{}".format(e)) + self.exit_flag = True + xmppserverlog.debug("shutting down") + self.server_coro.cancel() class XMPPServer_Protocol(asyncio.Protocol): @@ -615,80 +612,70 @@ class XMPPAsyncClient: xmppserverlog.exception("{}".format(e)) def _handle_session(self, xml): - try: - res = ''.format(xml.get("id")) - self._set_state("READY") - self.send(res) - asyncio.Task(self.schedule_ping(30)) - - except Exception as e: - xmppserverlog.exception("{}".format(e)) + res = ''.format(xml.get("id")) + self._set_state("READY") + self.send(res) + asyncio.Task(self.schedule_ping(30)) def _handle_presence(self, xml): - try: - if len(xml) and xml[0].tag == "status": + if len(xml) and xml[0].tag == "status": + xmppserverlog.debug( + "bot presence {} ".format( + ET.tostring(xml, encoding="utf-8").decode("utf-8") + ) + ) + # Most likely a bot, possibly hello world in text + + # Send dummy return + self.send(' dummy '.format(self.bumper_jid)) + + # If it is a BOT, send extras + if self.type == self.BOT: + # get device info + self.send( + ''.format( + self.bumper_jid, XMPPServer.server_id + ) + ) + + else: + xmppserverlog.debug( + "client presence - {} ".format( + ET.tostring(xml, encoding="utf-8").decode("utf-8") + ) + ) + + if xml.get("type") == "available": xmppserverlog.debug( - "bot presence {} ".format( + "client presence available - {} ".format( ET.tostring(xml, encoding="utf-8").decode("utf-8") ) ) - # Most likely a bot, possibly hello world in text # Send dummy return self.send( ' dummy '.format(self.bumper_jid) ) - - # If it is a BOT, send extras - if self.type == self.BOT: - # get device info - self.send( - ''.format( - self.bumper_jid, XMPPServer.server_id - ) - ) - - else: + elif xml.get("type") == "unavailable": xmppserverlog.debug( - "client presence - {} ".format( + "client presence unavailable (DISCONNECT) - {} ".format( ET.tostring(xml, encoding="utf-8").decode("utf-8") ) ) - if xml.get("type") == "available": - xmppserverlog.debug( - "client presence available - {} ".format( - ET.tostring(xml, encoding="utf-8").decode("utf-8") - ) + self._set_state("DISCONNECT") + else: + # Sometimes the android app sends these + xmppserverlog.debug( + "client presence (UNKNOWN) - {} ".format( + ET.tostring(xml, encoding="utf-8") ) - - # Send dummy return - self.send( - ' dummy '.format(self.bumper_jid) - ) - elif xml.get("type") == "unavailable": - xmppserverlog.debug( - "client presence unavailable (DISCONNECT) - {} ".format( - ET.tostring(xml, encoding="utf-8").decode("utf-8") - ) - ) - - self._set_state("DISCONNECT") - else: - # Sometimes the android app sends these - xmppserverlog.debug( - "client presence (UNKNOWN) - {} ".format( - ET.tostring(xml, encoding="utf-8") - ) - ) - # Send dummy return - self.send( - ' dummy '.format(self.bumper_jid) - ) - - except Exception as e: - xmppserverlog.exception("{}".format(e)) + ) + # Send dummy return + self.send( + ' dummy '.format(self.bumper_jid) + ) def _parse_data(self, data): @@ -804,34 +791,31 @@ class XMPPAsyncClient: xmppserverlog.exception("{}".format(e)) def _handle_iq(self, xml, data): - try: - if len(xml): - child = self._tag_strip_uri(xml[0].tag) - else: - child = None - if xml.tag == "iq": - if child == "bind": - self._handle_bind(xml) - elif child == "session": - self._handle_session(xml) - elif child == "ping": - self._handle_ping(xml, data) - elif child == "query": - if self.type == self.BOT: - self._handle_result(xml, data) - else: - self._handle_ctl(xml, data) - elif xml.get("type") == "result": - if self.type == self.BOT: - self._handle_result(xml, data) - else: - self._handle_result(xml, data) - elif xml.get("type") == "set": - if self.type == self.BOT: - self._handle_result(xml, data) - else: - self._handle_result(xml, data) + if len(xml): + child = self._tag_strip_uri(xml[0].tag) + else: + child = None - except Exception as e: - xmppserverlog.exception("{}".format(e)) + if xml.tag == "iq": + if child == "bind": + self._handle_bind(xml) + elif child == "session": + self._handle_session(xml) + elif child == "ping": + self._handle_ping(xml, data) + elif child == "query": + if self.type == self.BOT: + self._handle_result(xml, data) + else: + self._handle_ctl(xml, data) + elif xml.get("type") == "result": + if self.type == self.BOT: + self._handle_result(xml, data) + else: + self._handle_result(xml, data) + elif xml.get("type") == "set": + if self.type == self.BOT: + self._handle_result(xml, data) + else: + self._handle_result(xml, data)