D901 #2

Merged
bmartin5692 merged 34 commits from D901 into dev 2019-02-22 05:37:44 +01:00
4 changed files with 172 additions and 104 deletions
Showing only changes of commit 134d698eeb - Show all commits

View file

@ -4,14 +4,20 @@ import logging
import bumper import bumper
import sys, socket import sys, socket
logging.basicConfig(level=logging.INFO, logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(levelname)-8s %(message)s') format='%(asctime)s %(levelname)-8s %(message)s')
conf_address = (socket.gethostbyname(socket.gethostname()), 8007) #conf_address = (socket.gethostbyname(socket.gethostname()), 443)
xmpp_address = (socket.gethostbyname(socket.gethostname()), 5223) 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)
# start conf server (async) # start conf server (async)
conf_server = bumper.ConfServer(conf_address, ssl=False, async=True) conf_server = bumper.ConfServer(conf_address, usessl=True, run_async=True)
# start mqtt server (async)
mqtt_server = bumper.MQTTServer(mqtt_address, run_async=True)
# start xmpp server (sync) # start xmpp server (sync)
xmpp_server = bumper.XMPPServer(xmpp_address) xmpp_server = bumper.XMPPServer(xmpp_address)

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from .confserver import ConfServer from .confserver import ConfServer
from .mqttserver import MQTTServer
from .xmppserver import XMPPServer from .xmppserver import XMPPServer

View file

@ -2,12 +2,14 @@
from http.server import HTTPServer from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
#from http.server import SimpleHTTPRequestHandler
from http import HTTPStatus from http import HTTPStatus
from threading import Thread from threading import Thread
import socket, logging, ssl, json, sys import socket, logging, ssl, json, sys
class RequestHandler(BaseHTTPRequestHandler): class RequestHandler(BaseHTTPRequestHandler):
#class RequestHandler(SimpleHTTPRequestHandler):
def do_POST(self): def do_POST(self):
try: try:
self.protocol_version = 'HTTP/1.1' self.protocol_version = 'HTTP/1.1'
@ -17,17 +19,44 @@ class RequestHandler(BaseHTTPRequestHandler):
request_body = post_data.decode('utf-8') request_body = post_data.decode('utf-8')
logging.debug("Request: " + request_body) logging.debug("Request: " + request_body)
json_body = json.loads(request_body) json_body = json.loads(request_body)
todo = json_body['todo'] if "getProductIotMap" in str(self.path):
if todo == 'FindBest': 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"}}]}
service = json_body['service'] elif "notify_engine.do" in str(self.path):
if service == 'EcoMsgNew': body = {"ret":"ok"}
body = '{{"result":"ok","ip":"{}","port":5223}}'.format(socket.gethostbyname(socket.gethostname())) else:
elif service == 'EcoUpdate': todo = json_body['todo']
body = '{"result":"ok","ip":"47.88.66.164","port":8005}' if todo == 'FindBest':
elif todo == 'loginByItToken': service = json_body['service']
body = "{{'todo': 'result', 'result': 'ok', 'userId': '{}', 'resource': '{}', 'token': '{}'}}".format(json_body['userId'], json_body['resource'], json_body['token']) if service == 'EcoMsgNew':
elif todo == 'GetDeviceList': body = {"result":"ok","ip":socket.gethostbyname(socket.gethostname()),"port":5223}
body = "{'todo': 'result', 'result': 'ok', 'devices': [{'did': '{}', 'name': '{}', 'class': '{}', 'resource': 'atom', 'nick': None, 'company': 'eco'}]}" elif service == 'EcoUpdate':
body = {"result":"ok","ip":"47.88.66.164","port":8005}
elif todo == 'loginByItToken':
body = {
"todo": "result",
"result": "ok",
"userId": json_body["userId"],
"resource": json_body["resource"],
"token": json_body["token"]
}
elif todo == 'GetDeviceList':
#Find a way to handle this automatically
#Maybe keep a list of devices from those that have checked into MQTT/XMPP/etc and return them
body = {
"devices": [
{
"class": "tmpClass",
"company": "eco-ng",
"did": "tmpDeviceID",
"name": "tmpName",
"nick": "tmpNick",
"resource": "tmpResource"
}
],
"result": "ok",
"todo": "result"
}
body = json.dumps(body)
logging.debug("Response: " + body) logging.debug("Response: " + body)
body = body.encode() body = body.encode()
self.send_response(HTTPStatus.OK) self.send_response(HTTPStatus.OK)
@ -37,7 +66,73 @@ class RequestHandler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(body) self.wfile.write(body)
except Exception as e: except Exception as e:
logging.error('ConfServer: {}'.format(e)) logging.error('ConfServer POST: {}'.format(e))
def do_GET(self):
try:
self.protocol_version = 'HTTP/1.1'
logging.debug("Path: " + self.path)
if "/login?" in str(self.path):
#Could implement basic auth if you wanted, or just accept anything
#Next up parse the path for variables
body = {
"code": "0000",
"data": {
"accessToken": "temp_accesstoken",
"country": "us",
"email": "null@null.com",
"uid": "fuid_1",
"username": "fusername_1"
},
"msg": "操作成功",
"time": 1547211900690
}
elif "/getAuthCode?" in str(self.path):
body = {
"code": "0000",
"data": {
"authCode": "temp_authcode",
"ecovacsUid": "fuid_1"
},
"msg": "操作成功",
"time": 1547211900808
}
elif "/checkVersion?" in str(self.path):
body = {
"code": "0000",
"data": {
"c": None,
"img": None,
"r": 0,
"t": None,
"u": None,
"ut": 0,
"v": None
},
"msg": "操作成功",
"time": 1548829850462
}
elif "/logout?" in str(self.path):
body = {"code": "0000","data": None,"msg": "操作成功","time": 1548830041460}
else:
body = {}
body = json.dumps(body)
logging.debug("Response: " + body)
body = body.encode()
self.send_response(HTTPStatus.OK)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.send_header('Connection', 'keep-alive')
self.send_header('Content-Length', len(body))
self.end_headers()
self.wfile.write(body)
except Exception as e:
logging.error('ConfServer GET: {}'.format(e))
class HTTPServerThread(HTTPServer, Thread): class HTTPServerThread(HTTPServer, Thread):
@ -46,11 +141,12 @@ class HTTPServerThread(HTTPServer, Thread):
self.server_address = server_address self.server_address = server_address
self.handler = RequestHandler self.handler = RequestHandler
self.exit_flag = False self.exit_flag = False
HTTPServer.__init__(self, self.server_address, self.handler)
def handle_error(self, request, client_address): def handle_error(self, request, client_address):
self.close_request(request) self.close_request(request)
def run(self): def run(self):
try: try:
HTTPServer.__init__(self, self.server_address, self.handler)
logging.info('ConfServer: listening on {}:{}'.format(self.server_address[0], self.server_address[1])) logging.info('ConfServer: listening on {}:{}'.format(self.server_address[0], self.server_address[1]))
while not self.exit_flag: while not self.exit_flag:
self.handle_request() self.handle_request()
@ -65,13 +161,13 @@ class HTTPServerThread(HTTPServer, Thread):
class ConfServer(): class ConfServer():
def __init__(self, address, ssl=False, async=True): def __init__(self, address, usessl=False, run_async=True):
try: self.run_async = run_async
self.async = async self.server = HTTPServerThread(address)
self.server = HTTPServerThread(address) try:
if ssl: if usessl:
self.server.socket = ssl.wrap_socket(self.server.socket, keyfile='./certs/key.pem', certfile='./certs/cert.pem', server_side=True) self.server.socket = ssl.wrap_socket(self.server.socket, keyfile='./certs/key.pem', certfile='./certs/cert.pem', server_side=True)
if self.async: if self.run_async:
self.server.start() self.server.start()
else: else:
try: try:
@ -83,6 +179,6 @@ class ConfServer():
def disconnect(self): def disconnect(self):
logging.info('ConfServer: shutting down...') logging.info('ConfServer: shutting down...')
self.server.disconnect() self.server.disconnect()
if(self.async): if(self.run_async):
self.server.join() self.server.join()
logging.info('ConfServer: bye') logging.info('ConfServer: bye')

View file

@ -6,87 +6,52 @@ import os
from hbmqtt.broker import Broker from hbmqtt.broker import Broker
import hbmqtt import hbmqtt
default_config = { class MQTTServer():
'listeners': { clients = []
'default': { exit_flag = False
'type': 'tcp', default_config = {}
'bind': '0.0.0.0:1883',
},
'tls1': {
'bind': '0.0.0.0:8883',
'ssl': 'on',
#'cafile': '/some/cafile',
#'capath': '/some/folder',
#'capath': 'certificate data',
'certfile': './certs/cert.pem',
'keyfile': './certs/key.pem',
},
},
'sys_interval': 10,
'auth': {
'allow-anonymous': True,
'password-file': os.path.join(os.path.dirname(os.path.realpath(__file__)), "passwd"),
'plugins': [
'VacBotAuth'
]
},
'topic-check': {
'enabled': False
}
}
class BaseAuthPlugin:
def __init__(self, context):
self.context = context
try:
self.auth_config = self.context.config['auth']
except KeyError:
self.context.logger.warning("'auth' section not found in context configuration")
def authenticate(self, *args, **kwargs):
if not self.auth_config:
# auth config section not found
self.context.logger.warning("'auth' section not found in context configuration")
return False
return True
class VacBotAuth(BaseAuthPlugin):
def __init__(self, context):
super().__init__(context)
@asyncio.coroutine @asyncio.coroutine
def authenticate(self, *args, **kwargs): def broker_coro(self):
authenticated = super().authenticate(*args, **kwargs) broker = hbmqtt.broker.Broker(config=self.default_config, plugin_namespace=".")
if authenticated:
allow_anonymous = self.auth_config.get('allow-anonymous', True) # allow anonymous by default
if allow_anonymous:
authenticated = True
self.context.logger.debug("Authentication success: config allows anonymous")
else:
try:
session = kwargs.get('session', None)
authenticated = True if session.username else False
if self.context.logger.isEnabledFor(logging.DEBUG):
if authenticated:
self.context.logger.debug("Authentication success: session has a non empty username")
else:
self.context.logger.debug("Authentication failure: session has an empty username")
except KeyError:
self.context.logger.warning("Session informations not available")
authenticated = False
return authenticated
@asyncio.coroutine
def broker_coro():
broker = hbmqtt.broker.Broker(config=default_config, plugin_namespace=".")
print(broker.plugins_manager) yield from broker.start()
yield from broker.start()
def __init__(self, address, run_async=False):
try:
# Initialize bot server
self.default_config = {
'listeners': {
'default': {
'type': 'tcp',
},
'tls1': {
'bind': "{}:{}".format(address[0], address[1]),
'ssl': 'on',
'certfile': './certs/cert.pem',
'keyfile': './certs/key.pem',
},
},
'sys_interval': 10,
'auth': {
'allow-anonymous': True,
'password-file': os.path.join(os.path.dirname(os.path.realpath(__file__)), "passwd"),
'plugins': [
'VacBotAuth'
]
},
'topic-check': {
'enabled': False
}
}
if run_async:
self.run()
finally:
print("Done")
def run(self):
formatter = "[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s"
logging.basicConfig(level=logging.DEBUG, format=formatter)
eloop = asyncio.get_event_loop().run_until_complete(self.broker_coro())
asyncio.get_event_loop().run_forever()
if __name__ == '__main__':
formatter = "[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s"
logging.basicConfig(level=logging.DEBUG, format=formatter)
eloop = asyncio.get_event_loop().run_until_complete(broker_coro())
asyncio.get_event_loop().run_forever()