Beginning bumper's new journey #4

Merged
bmartin5692 merged 37 commits from dev into master 2019-02-22 14:34:25 +01:00
4 changed files with 456 additions and 313 deletions
Showing only changes of commit eb4cb2b996 - Show all commits

View file

@ -4,23 +4,18 @@ import logging
import bumper
import sys, socket
import time
import platform
args = sys.argv
if len(args) > 0:
if '--debug' in args:
logging.basicConfig(level=logging.DEBUG,
format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s")
format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(module)s :: %(funcName)s :: %(lineno)d :: %(message)s")
else:
logging.basicConfig(level=logging.INFO,
format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s")
#conf_address = (socket.gethostbyname(socket.gethostname()), 443)
conf_address = ("0.0.0.0", 443)
#xmpp_address = (socket.gethostbyname(socket.gethostname()), 5223)
xmpp_address = ("0.0.0.0", 5223)
#mqtt_address = (socket.gethostbyname(socket.gethostname()), 8883)
mqtt_address = ("0.0.0.0", 8883)
#format="[%(asctime)s] :: %(levelname)s :: %(name)s :: %(module)s :: %(funcName)s :: %(lineno)d :: %(message)s")
# A default bot could be set here to automatically add it as available
# dbot = bumper.VacBotDevice("did", "class", "resource", "name","nick" )
@ -29,13 +24,26 @@ mqtt_address = ("0.0.0.0", 8883)
# bclienttemp.append(dbot.asdict())
# bclient.set(bclienttemp)
# start mqtt server (async)
if platform.system() == "Darwin":
listen_host = "0.0.0.0"
else:
listen_host = socket.gethostbyname(socket.gethostname())
#listen_host = "localhost" #Try this if the above doesn't work
conf_address_443 = (listen_host, 443)
conf_address_8007 = (listen_host, 8007)
xmpp_address = (listen_host, 5223)
mqtt_address = (listen_host, 8883)
# start mqtt server on port 8883 (async)
mqtt_server = bumper.MQTTServer(mqtt_address, run_async=True,bumper_bots=bumper.bumper_bots_var,bumper_clients=bumper.bumper_clients_var)
time.sleep(1.5) #Wait for broker startup
# start mqtt server (async)
# start mqtt_helperbot (async)
mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address, run_async=True,bumper_bots=bumper.bumper_bots_var,bumper_clients=bumper.bumper_clients_var)
# start conf server (async)
conf_server = bumper.ConfServer(conf_address, usessl=True, run_async=True,bumper_bots=bumper.bumper_bots_var,bumper_clients=bumper.bumper_clients_var, helperbot=mqtt_helperbot)
# start xmpp server (sync)
# start conf server on port 443 (async) - Used for most https calls
conf_server = bumper.ConfServer(conf_address_443, usessl=True, run_async=True,bumper_bots=bumper.bumper_bots_var,bumper_clients=bumper.bumper_clients_var, helperbot=mqtt_helperbot)
# start conf server on port 8007 (async) - Used for a load balancer request
conf_server_2 = bumper.ConfServer(conf_address_8007, usessl=False, run_async=True,bumper_bots=bumper.bumper_bots_var,bumper_clients=bumper.bumper_clients_var, helperbot=mqtt_helperbot)
# start xmpp server on port 5223 (sync)
xmpp_server = bumper.XMPPServer(xmpp_address)

View file

@ -47,11 +47,15 @@ class ConfServer():
except:
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(self.start_server())
loop.run_forever()
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def start_server(self):
try:
app = web.Application()
app.add_routes([
@ -64,12 +68,15 @@ class ConfServer():
web.get('/{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/campaign/homePageAlert', self.handle_homePageAlert),
web.post('/api/users/user.do', self.handle_usersapi),
web.get('/api/users/user.do', self.handle_usersapi),
web.post('/api/pim/product/getProductIotMap', self.handle_getProductIotMap),
web.post('/api/iot/devmanager.do', self.handle_devmanager_botcommand)
web.post('/api/iot/devmanager.do', self.handle_devmanager_botcommand),
web.post('/lookup.do', self.handle_lookup),
])
runner = web.AppRunner(app, access_log=None) #access_log=None so the output isn't nuts
runner = web.AppRunner(app)#, access_log=None) #access_log=None so the output isn't nuts
await runner.setup()
if self.usessl:
@ -82,8 +89,17 @@ class ConfServer():
await site.start()
except PermissionError as e:
if "bind" in e.strerror:
logging.exception("Error binding confserver, exiting. Try using a different hostname or IP.\r\n {}".format(e))
exit(1)
except Exception as e:
logging.exception('ConfServer: {}'.format(e))
exit(1)
async def handle_login(self, request):
try:
#Could implement basic auth if you wanted, or just accept anything
countrycode = request.match_info.get('country', "us")
body = {
@ -101,7 +117,11 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_checkLogin(self, request):
try:
# The app seems to remember it's last uid and accessToken
# If these don't match, it fails
countrycode = request.match_info.get('country', "us")
@ -120,13 +140,21 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_logout(self, request):
try:
body = {"code": "0000","data": None,"msg": "操作成功", "time": bumper.get_milli_time(time.time())}
#TODO - when logging out close out any other connections MQTT/XMPP
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_getAuthCode(self, request):
try:
countrycode = request.match_info.get('country', "us")
body = {
"code": "0000",
@ -140,7 +168,11 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_checkVersion(self, request):
try:
body = {
"code": "0000",
"data": {
@ -158,7 +190,11 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_checkAgreement(self, request):
try:
body = {
"code": "0000",
"data": [],
@ -169,7 +205,11 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_homePageAlert(self, request):
try:
nextAlert = bumper.get_milli_time((datetime.now() + timedelta(hours=12)).timestamp())
body = {
@ -188,12 +228,21 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_getProductIotMap(self, request):
try:
#json_body = json.loads(await request.text())
body = {"code":0,"data":[{"classid":"dl8fht","product":{"_id":"5acb0fa87c295c0001876ecf","name":"DEEBOT 600 Series","icon":"5acc32067c295c0001876eea","UILogicId":"dl8fht","ota":False,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5acc32067c295c0001876eea"}},{"classid":"02uwxm","product":{"_id":"5ae1481e7ccd1a0001e1f69e","name":"DEEBOT OZMO Slim10 Series","icon":"5b1dddc48bc45700014035a1","UILogicId":"02uwxm","ota":False,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5b1dddc48bc45700014035a1"}},{"classid":"y79a7u","product":{"_id":"5b04c0227ccd1a0001e1f6a8","name":"DEEBOT OZMO 900","icon":"5b04c0217ccd1a0001e1f6a7","UILogicId":"y79a7u","ota":True,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5b04c0217ccd1a0001e1f6a7"}},{"classid":"jr3pqa","product":{"_id":"5b43077b8bc457000140363e","name":"DEEBOT 711","icon":"5b5ac4cc8d5a56000111e769","UILogicId":"jr3pqa","ota":True,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4cc8d5a56000111e769"}},{"classid":"uv242z","product":{"_id":"5b5149b4ac0b87000148c128","name":"DEEBOT 710","icon":"5b5ac4e45f21100001882bb9","UILogicId":"uv242z","ota":True,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5b5ac4e45f21100001882bb9"}},{"classid":"ls1ok3","product":{"_id":"5b6561060506b100015c8868","name":"DEEBOT 900 Series","icon":"5ba4a2cb6c2f120001c32839","UILogicId":"ls1ok3","ota":True,"iconUrl":"https://portal-ww.ecouser.net/api/pim/file/get/5ba4a2cb6c2f120001c32839"}}]}
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_usersapi(self, request):
try:
body = {}
postbody = {}
if request.content_type == "application/x-www-form-urlencoded":
@ -229,15 +278,51 @@ class ConfServer():
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_lookup(self, request):
try:
body = {}
postbody = {}
if request.content_type == "application/x-www-form-urlencoded":
postbody = await request.post()
else:
postbody = json.loads(await request.text())
logging.debug(postbody)
todo = postbody['todo']
if todo == 'FindBest':
service = postbody['service']
if service == 'EcoMsgNew':
body = {"result":"ok","ip":socket.gethostbyname(socket.gethostname()),"port":5223}
elif service == 'EcoUpdate':
body = {"result":"ok","ip":"47.88.66.164","port":8005}
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
async def handle_devmanager_botcommand(self, request):
try:
json_body = json.loads(await request.text())
logging.info("Device Request: {}".format(json_body))
randomid = ''.join(random.sample(string.ascii_letters,6))
retcmd = await self.helperbot.send_command(json_body, randomid)
body = retcmd
logging.info("Device Response: {}".format(body))
return web.json_response(body)
except Exception as e:
logging.error('ConfServer: {}'.format(e))
def disconnect(self):
try:
logging.info('ConfServer: shutting down...')
if(self.run_async):
self.server.join()
@ -245,3 +330,5 @@ class ConfServer():
self.server.disconnect()
logging.info('ConfServer: bye')
except Exception as e:
logging.error('ConfServer: {}'.format(e))

View file

@ -36,17 +36,19 @@ class MQTTHelperBot():
else:
self.run_helperbot()
except:
logging.exception("Exception")
except Exception as e:
logging.error('Helperbot: {}'.format(e))
pass
def run_helperbot(self, loop):
try:
asyncio.set_event_loop(loop)
self.Client = MQTTClient(client_id=self.client_id, config={'check_hostname':False})
loop.run_until_complete(self.start_helper_bot())
loop.run_until_complete(self.get_msg())
loop.run_forever()
except Exception as e:
logging.error('Helperbot: {}'.format(e))
async def start_helper_bot(self):
@ -56,8 +58,11 @@ class MQTTHelperBot():
('iot/p2p/+/+/+/+/helper1/bumper/helper1/+/+/+',QOS_0),
('iot/p2p/+',QOS_0)
])
except hbmqtt.client.ClientException as ce:
logging.exception("Client exception: %s" % ce)
except Exception as e:
logging.error('Helperbot: {}'.format(e))
#except hbmqtt.client.ClientException as ce:
# logging.exception("Client exception: %s" % ce)
async def get_msg(self):
@ -78,11 +83,15 @@ class MQTTHelperBot():
cresp.append({"time": time.time() ,"topic": message.topic,"payload":str(message.data.decode("utf-8"))})
self.command_responses.set(cresp)
logging.debug("MQTT Command Response List Count: %s" %len(cresp))
except hbmqtt.client.ClientException as ce:
logging.error("Client exception: %s" % ce)
except Exception as e:
logging.error('Helperbot: {}'.format(e))
#except hbmqtt.client.ClientException as ce:
# logging.error("Client exception: %s" % ce)
async def wait_for_resp(self, requestid):
try:
t_end = (datetime.now() + timedelta(seconds=10)).timestamp()
while time.time() < t_end:
await asyncio.sleep(0.1)
@ -108,8 +117,11 @@ class MQTTHelperBot():
return { "id": requestid, "errno": "timeout", "ret": "fail" }
async def send_command(self, cmdjson, requestid):
except Exception as e:
logging.error('Helperbot: {}'.format(e))
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"])
try:
@ -121,6 +133,9 @@ class MQTTHelperBot():
return resp
except Exception as e:
logging.error('Helperbot: {}'.format(e))
class MQTTServer():
default_config = {}
@ -128,16 +143,30 @@ class MQTTServer():
bumper_bots = []
async def broker_coro(self):
try:
broker = hbmqtt.broker.Broker(config=self.default_config)
await broker.start()
except PermissionError as e:
if "bind" in e.strerror:
logging.exception("Error binding mqttserver, exiting. Try using a different hostname or IP.\r\n {}".format(e))
exit(1)
except Exception as e:
logging.exception('MQTTServer: {}'.format(e))
exit(1)
async def active_bot_listing(self):
try:
while True:
await asyncio.sleep(5)
logging.debug('Connected bots: %s' % self.bumper_bots.get())
def __init__(self, address, run_async=False, bumper_bots=contextvars.ContextVar, bumper_clients=contextvars.ContextVar):
except Exception as e:
logging.error('MQTTServer: {}'.format(e))
def __init__(self, address, run_async=False, bumper_bots=contextvars.ContextVar, bumper_clients=contextvars.ContextVar):
try:
#The below adds a plugin to the hbmqtt.broker.plugins without having to futz with setup.py
distribution = pkg_resources.Distribution("hbmqtt.broker.plugins")
bumper_plugin = pkg_resources.EntryPoint.parse('bumper = bumper.mqttserver:BumperMQTTServer_Plugin', dist=distribution)
@ -145,7 +174,6 @@ class MQTTServer():
pkg_resources.working_set.add(distribution)
self.bumper_bots = bumper_bots
self.bumper_clients = bumper_clients
try:
# Initialize bot server
self.default_config = {
'listeners': {
@ -186,17 +214,24 @@ class MQTTServer():
else:
self.run_server()
except:
logging.exception("Exception")
pass
except Exception as e:
logging.error('MQTTServer: {}'.format(e))
#except:
# logging.exception("Exception")
# pass
def run_server(self, loop):
try:
asyncio.set_event_loop(loop)
loop.run_until_complete(self.broker_coro())
#loop.run_until_complete(self.active_bot_listing())
loop.run_forever()
except Exception as e:
logging.error('MQTTServer: {}'.format(e))
class BumperMQTTServer_Plugin:
def __init__(self, context):
self.context = context
@ -204,10 +239,11 @@ class BumperMQTTServer_Plugin:
self.clients = self.context.config['clients']
except KeyError:
self.context.logger.warning("'clients' section not found in context configuration")
except Exception as e:
logging.error('MQTTServer: {}'.format(e))
async def on_broker_client_connected(self, client_id):
try:
logging.debug('Bumper Connection: %s connected' % client_id)
connected_bots = self.clients['connected_bots'].get()
connected_clients = self.clients['connected_clients'].get()
@ -251,9 +287,13 @@ class BumperMQTTServer_Plugin:
logging.debug('Connected Bots: %s' %self.clients['connected_bots'].get())
logging.debug('Connected Clients: %s' %self.clients['connected_clients'].get())
except Exception as e:
logging.error('MQTTServer: {}'.format(e))
async def on_broker_client_disconnected(self, client_id):
try:
logging.debug('Bumper Connection: %s disconnected' % client_id)
connected_bots = self.clients['connected_bots'].get()
connected_clients = self.clients['connected_clients'].get()
@ -274,3 +314,6 @@ class BumperMQTTServer_Plugin:
self.clients['connected_clients'].set(connected_clients)
logging.debug('Connected Clients: %s' %self.clients['connected_clients'].get())
except Exception as e:
logging.error('MQTTServer: {}'.format(e))

View file

@ -32,10 +32,15 @@ class XMPPServer():
client.start()
self.clients.append(client)
self.socket.close()
except PermissionError as e:
if "bind" in e.strerror:
logging.exception("Error binding xmppserver, exiting. Try using a different hostname or IP.\r\n {}".format(e))
exit(1)
except Exception as e:
logging.error('XMPPServer: {}'.format(e))
logging.exception('XMPPServer: {}'.format(e))
exit(1)
except KeyboardInterrupt:
logging.debug('XMPPServer: Keyboard interrupt')
logging.exception('XMPPServer: Keyboard interrupt')
finally:
self.disconnect()
logging.info('XMPPServer: bye')