Compare commits
5 commits
wip-proxyR
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df36bdd29d | ||
|
|
9b1ae262a8 | ||
|
|
436830cdd6 | ||
|
|
eece03efd3 | ||
|
|
82d5448eb7 |
23 changed files with 2848 additions and 941 deletions
|
|
@ -1,20 +1,3 @@
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
|
|
||||||
# Tests
|
|
||||||
tests
|
|
||||||
|
|
||||||
# Examples
|
|
||||||
examples
|
|
||||||
|
|
||||||
# Docs
|
|
||||||
docs
|
|
||||||
|
|
||||||
# Certs
|
|
||||||
certs
|
|
||||||
|
|
||||||
.coverage
|
|
||||||
|
|
||||||
# Markdown
|
# Markdown
|
||||||
*.md
|
*.md
|
||||||
|
|
||||||
|
|
|
||||||
10
Dockerfile
10
Dockerfile
|
|
@ -22,11 +22,15 @@ RUN apk add build-base
|
||||||
|
|
||||||
FROM base
|
FROM base
|
||||||
|
|
||||||
COPY . /bumper
|
COPY requirements.txt /requirements.txt
|
||||||
|
|
||||||
WORKDIR /bumper
|
|
||||||
|
|
||||||
# install required python packages
|
# install required python packages
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
WORKDIR /bumper
|
||||||
|
|
||||||
|
# Copy only required folders instead of all
|
||||||
|
COPY create_certs/ create_certs/
|
||||||
|
COPY bumper/ bumper/
|
||||||
|
|
||||||
ENTRYPOINT ["python3", "-m", "bumper"]
|
ENTRYPOINT ["python3", "-m", "bumper"]
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,13 @@ def strtobool(strbool):
|
||||||
# os.environ['PYTHONASYNCIODEBUG'] = '1' # Uncomment to enable ASYNCIODEBUG
|
# os.environ['PYTHONASYNCIODEBUG'] = '1' # Uncomment to enable ASYNCIODEBUG
|
||||||
bumper_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
bumper_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
||||||
|
|
||||||
|
log_to_stdout = os.environ.get("LOG_TO_STDOUT")
|
||||||
|
|
||||||
# Set defaults from environment variables first
|
# Set defaults from environment variables first
|
||||||
# Folders
|
# Folders
|
||||||
logs_dir = os.environ.get("BUMPER_LOGS") or os.path.join(bumper_dir, "logs")
|
if not log_to_stdout:
|
||||||
os.makedirs(logs_dir, exist_ok=True) # Ensure logs directory exists or create
|
logs_dir = os.environ.get("BUMPER_LOGS") or os.path.join(bumper_dir, "logs")
|
||||||
|
os.makedirs(logs_dir, exist_ok=True) # Ensure logs directory exists or create
|
||||||
data_dir = os.environ.get("BUMPER_DATA") or os.path.join(bumper_dir, "data")
|
data_dir = os.environ.get("BUMPER_DATA") or os.path.join(bumper_dir, "data")
|
||||||
os.makedirs(data_dir, exist_ok=True) # Ensure data directory exists or create
|
os.makedirs(data_dir, exist_ok=True) # Ensure data directory exists or create
|
||||||
certs_dir = os.environ.get("BUMPER_CERTS") or os.path.join(bumper_dir, "certs")
|
certs_dir = os.environ.get("BUMPER_CERTS") or os.path.join(bumper_dir, "certs")
|
||||||
|
|
@ -54,6 +57,7 @@ bumper_announce_ip = os.environ.get("BUMPER_ANNOUNCE_IP") or bumper_listen
|
||||||
bumper_debug = strtobool(os.environ.get("BUMPER_DEBUG")) or False
|
bumper_debug = strtobool(os.environ.get("BUMPER_DEBUG")) or False
|
||||||
use_auth = False
|
use_auth = False
|
||||||
token_validity_seconds = 3600 # 1 hour
|
token_validity_seconds = 3600 # 1 hour
|
||||||
|
oauth_validity_days = 15
|
||||||
db = None
|
db = None
|
||||||
|
|
||||||
mqtt_server = None
|
mqtt_server = None
|
||||||
|
|
@ -80,73 +84,102 @@ logformat = logging.Formatter(
|
||||||
)
|
)
|
||||||
|
|
||||||
bumperlog = logging.getLogger("bumper")
|
bumperlog = logging.getLogger("bumper")
|
||||||
bumper_rotate = RotatingFileHandler("logs/bumper.log", maxBytes=5000000, backupCount=5)
|
if not log_to_stdout:
|
||||||
bumper_rotate.setFormatter(logformat)
|
bumper_rotate = RotatingFileHandler("logs/bumper.log", maxBytes=5000000, backupCount=5)
|
||||||
bumperlog.addHandler(bumper_rotate)
|
bumper_rotate.setFormatter(logformat)
|
||||||
|
bumperlog.addHandler(bumper_rotate)
|
||||||
|
else:
|
||||||
|
bumperlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# bumperlog.setLevel(logging.INFO)
|
# bumperlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
confserverlog = logging.getLogger("confserver")
|
confserverlog = logging.getLogger("confserver")
|
||||||
conf_rotate = RotatingFileHandler(
|
if not log_to_stdout:
|
||||||
"logs/confserver.log", maxBytes=5000000, backupCount=5
|
conf_rotate = RotatingFileHandler(
|
||||||
)
|
"logs/confserver.log", maxBytes=5000000, backupCount=5
|
||||||
conf_rotate.setFormatter(logformat)
|
)
|
||||||
confserverlog.addHandler(conf_rotate)
|
conf_rotate.setFormatter(logformat)
|
||||||
|
confserverlog.addHandler(conf_rotate)
|
||||||
|
else:
|
||||||
|
confserverlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# confserverlog.setLevel(logging.INFO)
|
# confserverlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
mqttserverlog = logging.getLogger("mqttserver")
|
mqttserverlog = logging.getLogger("mqttserver")
|
||||||
mqtt_rotate = RotatingFileHandler(
|
if not log_to_stdout:
|
||||||
"logs/mqttserver.log", maxBytes=5000000, backupCount=5
|
mqtt_rotate = RotatingFileHandler(
|
||||||
)
|
"logs/mqttserver.log", maxBytes=5000000, backupCount=5
|
||||||
mqtt_rotate.setFormatter(logformat)
|
)
|
||||||
mqttserverlog.addHandler(mqtt_rotate)
|
mqtt_rotate.setFormatter(logformat)
|
||||||
|
mqttserverlog.addHandler(mqtt_rotate)
|
||||||
|
else:
|
||||||
|
mqttserverlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# mqttserverlog.setLevel(logging.INFO)
|
# mqttserverlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
### Additional MQTT Logs
|
### Additional MQTT Logs
|
||||||
translog = logging.getLogger("transitions")
|
translog = logging.getLogger("transitions")
|
||||||
translog.addHandler(mqtt_rotate)
|
if not log_to_stdout:
|
||||||
|
translog.addHandler(mqtt_rotate)
|
||||||
|
else:
|
||||||
|
translog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
translog.setLevel(logging.CRITICAL + 1) # Ignore this logger
|
translog.setLevel(logging.CRITICAL + 1) # Ignore this logger
|
||||||
logging.getLogger("passlib").setLevel(logging.CRITICAL + 1) # Ignore this logger
|
logging.getLogger("passlib").setLevel(logging.CRITICAL + 1) # Ignore this logger
|
||||||
brokerlog = logging.getLogger("hbmqtt.broker")
|
brokerlog = logging.getLogger("hbmqtt.broker")
|
||||||
#brokerlog.setLevel(
|
#brokerlog.setLevel(
|
||||||
# logging.CRITICAL + 1
|
# logging.CRITICAL + 1
|
||||||
#) # Ignore this logger #There are some sublogs that could be set if needed (.plugins)
|
#) # Ignore this logger #There are some sublogs that could be set if needed (.plugins)
|
||||||
brokerlog.addHandler(mqtt_rotate)
|
if not log_to_stdout:
|
||||||
|
brokerlog.addHandler(mqtt_rotate)
|
||||||
|
else:
|
||||||
|
brokerlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
protolog = logging.getLogger("hbmqtt.mqtt.protocol")
|
protolog = logging.getLogger("hbmqtt.mqtt.protocol")
|
||||||
#protolog.setLevel(
|
#protolog.setLevel(
|
||||||
# logging.CRITICAL + 1
|
# logging.CRITICAL + 1
|
||||||
#) # Ignore this logger
|
#) # Ignore this logger
|
||||||
protolog.addHandler(mqtt_rotate)
|
if not log_to_stdout:
|
||||||
|
protolog.addHandler(mqtt_rotate)
|
||||||
|
else:
|
||||||
|
protolog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
clientlog = logging.getLogger("hbmqtt.client")
|
clientlog = logging.getLogger("hbmqtt.client")
|
||||||
#clientlog.setLevel(logging.CRITICAL + 1) # Ignore this logger
|
#clientlog.setLevel(logging.CRITICAL + 1) # Ignore this logger
|
||||||
clientlog.addHandler(mqtt_rotate)
|
if not log_to_stdout:
|
||||||
|
clientlog.addHandler(mqtt_rotate)
|
||||||
|
else:
|
||||||
|
clientlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
helperbotlog = logging.getLogger("helperbot")
|
helperbotlog = logging.getLogger("helperbot")
|
||||||
helperbot_rotate = RotatingFileHandler(
|
if not log_to_stdout:
|
||||||
"logs/helperbot.log", maxBytes=5000000, backupCount=5
|
helperbot_rotate = RotatingFileHandler(
|
||||||
)
|
"logs/helperbot.log", maxBytes=5000000, backupCount=5
|
||||||
helperbot_rotate.setFormatter(logformat)
|
)
|
||||||
helperbotlog.addHandler(helperbot_rotate)
|
helperbot_rotate.setFormatter(logformat)
|
||||||
|
helperbotlog.addHandler(helperbot_rotate)
|
||||||
|
else:
|
||||||
|
helperbotlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# helperbotlog.setLevel(logging.INFO)
|
# helperbotlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
boterrorlog = logging.getLogger("boterror")
|
boterrorlog = logging.getLogger("boterror")
|
||||||
boterrorlog_rotate = RotatingFileHandler(
|
if not log_to_stdout:
|
||||||
"logs/boterror.log", maxBytes=5000000, backupCount=5
|
boterrorlog_rotate = RotatingFileHandler(
|
||||||
)
|
"logs/boterror.log", maxBytes=5000000, backupCount=5
|
||||||
boterrorlog_rotate.setFormatter(logformat)
|
)
|
||||||
boterrorlog.addHandler(boterrorlog_rotate)
|
boterrorlog_rotate.setFormatter(logformat)
|
||||||
|
boterrorlog.addHandler(boterrorlog_rotate)
|
||||||
|
else:
|
||||||
|
boterrorlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# boterrorlog.setLevel(logging.INFO)
|
# boterrorlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
xmppserverlog = logging.getLogger("xmppserver")
|
xmppserverlog = logging.getLogger("xmppserver")
|
||||||
xmpp_rotate = RotatingFileHandler(
|
if not log_to_stdout:
|
||||||
"logs/xmppserver.log", maxBytes=5000000, backupCount=5
|
xmpp_rotate = RotatingFileHandler(
|
||||||
)
|
"logs/xmppserver.log", maxBytes=5000000, backupCount=5
|
||||||
xmpp_rotate.setFormatter(logformat)
|
)
|
||||||
xmppserverlog.addHandler(xmpp_rotate)
|
xmpp_rotate.setFormatter(logformat)
|
||||||
|
xmppserverlog.addHandler(xmpp_rotate)
|
||||||
|
else:
|
||||||
|
xmppserverlog.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
# Override the logging level
|
# Override the logging level
|
||||||
# xmppserverlog.setLevel(logging.INFO)
|
# xmppserverlog.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
@ -204,7 +237,8 @@ async def start():
|
||||||
xmpp_server = XMPPServer((bumper_listen, xmpp_listen_port))
|
xmpp_server = XMPPServer((bumper_listen, xmpp_listen_port))
|
||||||
|
|
||||||
# Start MQTT Server
|
# Start MQTT Server
|
||||||
asyncio.create_task(mqtt_server.broker_coro())
|
# await start otherwise we get an error connecting the helper bot
|
||||||
|
await asyncio.create_task(mqtt_server.broker_coro())
|
||||||
|
|
||||||
# Start MQTT Helperbot
|
# Start MQTT Helperbot
|
||||||
asyncio.create_task(mqtt_helperbot.start_helper_bot())
|
asyncio.create_task(mqtt_helperbot.start_helper_bot())
|
||||||
|
|
@ -232,6 +266,7 @@ async def start():
|
||||||
|
|
||||||
async def maintenance():
|
async def maintenance():
|
||||||
revoke_expired_tokens()
|
revoke_expired_tokens()
|
||||||
|
revoke_expired_oauths()
|
||||||
|
|
||||||
|
|
||||||
async def shutdown():
|
async def shutdown():
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,16 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import ssl
|
|
||||||
import string
|
|
||||||
import random
|
|
||||||
import bumper
|
|
||||||
import os
|
|
||||||
from bumper.models import *
|
|
||||||
from bumper import plugins
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp import web
|
import logging
|
||||||
|
import os
|
||||||
|
import ssl
|
||||||
|
|
||||||
import aiohttp_jinja2
|
import aiohttp_jinja2
|
||||||
import jinja2
|
import jinja2
|
||||||
import uuid
|
from aiohttp import web
|
||||||
import xml.etree.ElementTree as ET
|
|
||||||
|
from bumper import plugins
|
||||||
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
class aiohttp_filter(logging.Filter):
|
class aiohttp_filter(logging.Filter):
|
||||||
|
|
@ -62,13 +57,12 @@ class ConfServer:
|
||||||
|
|
||||||
self.app.add_routes(
|
self.app.add_routes(
|
||||||
[
|
[
|
||||||
|
|
||||||
web.get("", self.handle_base, name="base"),
|
web.get("", self.handle_base, name="base"),
|
||||||
web.get("/bot/remove/{did}", self.handle_RemoveBot, name='remove-bot'),
|
web.get("/bot/remove/{did}", self.handle_RemoveBot, name='remove-bot'),
|
||||||
web.get("/client/remove/{resource}", self.handle_RemoveClient, name='remove-client'),
|
web.get("/client/remove/{resource}", self.handle_RemoveClient, name='remove-client'),
|
||||||
web.get("/restart_{service}", self.handle_RestartService, name='restart-service'),
|
web.get("/restart_{service}", self.handle_RestartService, name='restart-service'),
|
||||||
web.post("/lookup.do", self.handle_lookup),
|
web.post("/lookup.do", self.handle_lookup),
|
||||||
|
web.post("/newauth.do", self.handle_newauth),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -217,8 +211,18 @@ class ConfServer:
|
||||||
async def log_all_requests(self, request, handler):
|
async def log_all_requests(self, request, handler):
|
||||||
|
|
||||||
if request._match_info.route.name not in self.excludelogging:
|
if request._match_info.route.name not in self.excludelogging:
|
||||||
|
to_log = {
|
||||||
|
"request": {
|
||||||
|
"route_name": f"{request.match_info.route.name}",
|
||||||
|
"method": f"{request.method}",
|
||||||
|
"path": f"{request.path}",
|
||||||
|
"query_string": f"{request.query_string}",
|
||||||
|
"raw_path": f"{request.raw_path}",
|
||||||
|
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
||||||
|
}
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
|
postbody = None
|
||||||
if request.content_length:
|
if request.content_length:
|
||||||
if request.content_type == "application/x-www-form-urlencoded":
|
if request.content_type == "application/x-www-form-urlencoded":
|
||||||
postbody = await request.post()
|
postbody = await request.post()
|
||||||
|
|
@ -232,78 +236,33 @@ class ConfServer:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
postbody = await request.post()
|
postbody = await request.post()
|
||||||
else:
|
|
||||||
postbody = None
|
to_log["request"]["body"] = f"{postbody}"
|
||||||
|
|
||||||
response = await handler(request)
|
response = await handler(request)
|
||||||
|
if response is None:
|
||||||
|
confserverlog.warning("Response was null!")
|
||||||
|
confserverlog.warning(json.dumps(to_log))
|
||||||
|
return response
|
||||||
|
|
||||||
|
to_log["response"] = {
|
||||||
|
"status": f"{response.status}",
|
||||||
|
}
|
||||||
if not "application/octet-stream" in response.content_type:
|
if not "application/octet-stream" in response.content_type:
|
||||||
logall = {
|
to_log["response"]["body"] = f"{json.loads(response.body)}"
|
||||||
"request": {
|
|
||||||
"route_name": f"{request.match_info.route.name}",
|
|
||||||
"method": f"{request.method}",
|
|
||||||
"path": f"{request.path}",
|
|
||||||
"query_string": f"{request.query_string}",
|
|
||||||
"raw_path": f"{request.raw_path}",
|
|
||||||
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
||||||
"body": f"{postbody}",
|
|
||||||
},
|
|
||||||
|
|
||||||
"response": {
|
confserverlog.debug(json.dumps(to_log))
|
||||||
"response_body": f"{json.loads(response.body)}",
|
|
||||||
"status": f"{response.status}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
logall = {
|
|
||||||
"request": {
|
|
||||||
"route_name": f"{request.match_info.route.name}",
|
|
||||||
"method": f"{request.method}",
|
|
||||||
"path": f"{request.path}",
|
|
||||||
"query_string": f"{request.query_string}",
|
|
||||||
"raw_path": f"{request.raw_path}",
|
|
||||||
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
||||||
"body": f"{postbody}",
|
|
||||||
},
|
|
||||||
|
|
||||||
"response": {
|
|
||||||
"status": f"{response.status}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
confserverlog.debug(json.dumps(logall))
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
except web.HTTPNotFound as notfound:
|
except web.HTTPNotFound as notfound:
|
||||||
confserverlog.debug("Request path {} not found".format(request.raw_path))
|
confserverlog.debug("Request path {} not found".format(request.raw_path))
|
||||||
requestlog = {
|
confserverlog.debug(json.dumps(to_log))
|
||||||
"request": {
|
|
||||||
"route_name": f"{request.match_info.route.name}",
|
|
||||||
"method": f"{request.method}",
|
|
||||||
"path": f"{request.path}",
|
|
||||||
"query_string": f"{request.query_string}",
|
|
||||||
"raw_path": f"{request.raw_path}",
|
|
||||||
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
||||||
"body": f"{postbody}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
confserverlog.debug(json.dumps(requestlog))
|
|
||||||
return notfound
|
return notfound
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
confserverlog.exception("{}".format(e))
|
confserverlog.exception("{}".format(e))
|
||||||
requestlog = {
|
confserverlog.error(json.dumps(to_log))
|
||||||
"request": {
|
|
||||||
"route_name": f"{request.match_info.route.name}",
|
|
||||||
"method": f"{request.method}",
|
|
||||||
"path": f"{request.path}",
|
|
||||||
"query_string": f"{request.query_string}",
|
|
||||||
"raw_path": f"{request.raw_path}",
|
|
||||||
"raw_headers": f'{",".join(map("{}".format, request.raw_headers))}',
|
|
||||||
"body": f"{postbody}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
confserverlog.debug(json.dumps(requestlog))
|
|
||||||
return e
|
return e
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
@ -507,6 +466,26 @@ class ConfServer:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
confserverlog.exception("{}".format(e))
|
confserverlog.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_newauth(self, request):
|
||||||
|
# Bumper is only returning the submitted token. No reason yet to create another new token
|
||||||
|
try:
|
||||||
|
if request.content_type == "application/x-www-form-urlencoded":
|
||||||
|
postbody = await request.post()
|
||||||
|
else:
|
||||||
|
postbody = json.loads(await request.text())
|
||||||
|
|
||||||
|
confserverlog.debug(postbody)
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"authCode": postbody["itToken"],
|
||||||
|
"result": "ok",
|
||||||
|
"todo": "result"
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
confserverlog.exception("{}".format(e))
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
89
bumper/db.py
89
bumper/db.py
|
|
@ -1,13 +1,13 @@
|
||||||
#!/usr/bin/env python3
|
#!/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 json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from tinydb import TinyDB, Query
|
||||||
|
|
||||||
|
import bumper
|
||||||
|
from bumper.models import VacBotClient, VacBotDevice, BumperUser, EcoVacsHomeProducts, OAuth
|
||||||
|
|
||||||
bumperlog = logging.getLogger("bumper")
|
bumperlog = logging.getLogger("bumper")
|
||||||
|
|
||||||
|
|
@ -32,6 +32,7 @@ def db_get():
|
||||||
db.table("clients", cache_size=0)
|
db.table("clients", cache_size=0)
|
||||||
db.table("bots", cache_size=0)
|
db.table("bots", cache_size=0)
|
||||||
db.table("tokens", cache_size=0)
|
db.table("tokens", cache_size=0)
|
||||||
|
db.table("oauth", cache_size=0)
|
||||||
|
|
||||||
return db
|
return db
|
||||||
|
|
||||||
|
|
@ -202,6 +203,55 @@ def user_revoke_authcode(userid, token, authcode):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def revoke_expired_oauths():
|
||||||
|
opendb = db_get()
|
||||||
|
with opendb:
|
||||||
|
table = opendb.table("oauth")
|
||||||
|
entries = table.all()
|
||||||
|
|
||||||
|
for i in entries:
|
||||||
|
oauth = OAuth(**i)
|
||||||
|
if datetime.now() >= datetime.fromisoformat(oauth.expire_at):
|
||||||
|
bumperlog.debug(
|
||||||
|
"Removing oauth {} due to expiration".format(oauth.access_token)
|
||||||
|
)
|
||||||
|
table.remove(doc_ids=[i.doc_id])
|
||||||
|
|
||||||
|
|
||||||
|
def user_revoke_expired_oauths(userid):
|
||||||
|
opendb = db_get()
|
||||||
|
with opendb:
|
||||||
|
table = opendb.table("oauth")
|
||||||
|
search = table.search(Query().userid == userid)
|
||||||
|
for i in search:
|
||||||
|
oauth = OAuth(**i)
|
||||||
|
if datetime.now() >= datetime.fromisoformat(oauth.expire_at):
|
||||||
|
bumperlog.debug(
|
||||||
|
"Removing oauth {} due to expiration".format(oauth.access_token)
|
||||||
|
)
|
||||||
|
table.remove(doc_ids=[i.doc_id])
|
||||||
|
|
||||||
|
|
||||||
|
def user_add_oauth(userid) -> OAuth:
|
||||||
|
user_revoke_expired_oauths(userid)
|
||||||
|
opendb = db_get()
|
||||||
|
with opendb:
|
||||||
|
table = opendb.table("oauth")
|
||||||
|
entry = table.get(Query().userid == userid)
|
||||||
|
if entry:
|
||||||
|
return OAuth(**entry)
|
||||||
|
else:
|
||||||
|
oauth = OAuth.create_new(userid)
|
||||||
|
bumperlog.debug("Adding oauth {} for userid {}".format(oauth.access_token, userid))
|
||||||
|
table.insert(oauth.toDB())
|
||||||
|
return oauth
|
||||||
|
|
||||||
|
|
||||||
|
def token_by_authcode(authcode):
|
||||||
|
tokens = db_get().table("tokens")
|
||||||
|
return tokens.get(Query().authcode == authcode)
|
||||||
|
|
||||||
|
|
||||||
def get_disconnected_xmpp_clients():
|
def get_disconnected_xmpp_clients():
|
||||||
clients = db_get().table("clients")
|
clients = db_get().table("clients")
|
||||||
Client = Query()
|
Client = Query()
|
||||||
|
|
@ -214,8 +264,8 @@ def check_authcode(uid, authcode):
|
||||||
tmpauth = tokens.get(
|
tmpauth = tokens.get(
|
||||||
(Query().authcode == authcode)
|
(Query().authcode == authcode)
|
||||||
& ( # Match authcode
|
& ( # Match authcode
|
||||||
(Query().userid == uid.replace("fuid_", ""))
|
(Query().userid == uid.replace("fuid_", ""))
|
||||||
| (Query().userid == "fuid_{}".format(uid))
|
| (Query().userid == "fuid_{}".format(uid))
|
||||||
) # Userid with or without fuid_
|
) # Userid with or without fuid_
|
||||||
)
|
)
|
||||||
if tmpauth:
|
if tmpauth:
|
||||||
|
|
@ -246,8 +296,8 @@ def check_token(uid, token):
|
||||||
tmpauth = tokens.get(
|
tmpauth = tokens.get(
|
||||||
(Query().token == token)
|
(Query().token == token)
|
||||||
& ( # Match token
|
& ( # Match token
|
||||||
(Query().userid == uid.replace("fuid_", ""))
|
(Query().userid == uid.replace("fuid_", ""))
|
||||||
| (Query().userid == "fuid_{}".format(uid))
|
| (Query().userid == "fuid_{}".format(uid))
|
||||||
) # Userid with or without fuid_
|
) # Userid with or without fuid_
|
||||||
)
|
)
|
||||||
if tmpauth:
|
if tmpauth:
|
||||||
|
|
@ -275,7 +325,7 @@ def bot_add(sn, did, devclass, resource, company):
|
||||||
bot = bot_get(did)
|
bot = bot_get(did)
|
||||||
if not bot: # Not existing bot in database
|
if not bot: # Not existing bot in database
|
||||||
if (
|
if (
|
||||||
not devclass == "" or "@" not in sn or "tmp" not in sn
|
not devclass == "" or "@" not in sn or "tmp" not in sn
|
||||||
): # try to prevent bad additions to the bot list
|
): # try to prevent bad additions to the bot list
|
||||||
bumperlog.info(
|
bumperlog.info(
|
||||||
"Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did)
|
"Adding new bot with SN: {} DID: {}".format(newbot.name, newbot.did)
|
||||||
|
|
@ -302,6 +352,21 @@ def bot_toEcoVacsHome_JSON(bot): # EcoVacs Home
|
||||||
bot["UILogicId"] = botprod["product"]["UILogicId"]
|
bot["UILogicId"] = botprod["product"]["UILogicId"]
|
||||||
bot["ota"] = botprod["product"]["ota"]
|
bot["ota"] = botprod["product"]["ota"]
|
||||||
bot["icon"] = botprod["product"]["iconUrl"]
|
bot["icon"] = botprod["product"]["iconUrl"]
|
||||||
|
bot["model"] = botprod["product"]["model"]
|
||||||
|
bot["pip"] = botprod["product"]["_id"]
|
||||||
|
bot["deviceName"] = botprod["product"]["name"]
|
||||||
|
bot["materialNo"] = botprod["product"]["materialNo"]
|
||||||
|
bot["product_category"] = "DEEBOT" if botprod["product"]["name"].startswith("DEEBOT") else "UNKNOWN"
|
||||||
|
# bot["updateInfo"] = {
|
||||||
|
# "changeLog": "",
|
||||||
|
# "needUpdate": False
|
||||||
|
# }
|
||||||
|
# bot["service"] = {
|
||||||
|
# "jmq": "jmq-ngiot-eu.dc.ww.ecouser.net",
|
||||||
|
# "mqs": "api-ngiot.dc-as.ww.ecouser.net"
|
||||||
|
# }
|
||||||
|
bot["status"] = 1 if bot["mqtt_connection"] or bot["xmpp_connection"] else 0
|
||||||
|
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
bot, default=lambda o: o.__dict__, sort_keys=False
|
bot, default=lambda o: o.__dict__, sort_keys=False
|
||||||
) # , indent=4)
|
) # , indent=4)
|
||||||
|
|
@ -345,12 +410,14 @@ def client_add(userid, realm, resource):
|
||||||
bumperlog.info("Adding new client with resource {}".format(newclient.resource))
|
bumperlog.info("Adding new client with resource {}".format(newclient.resource))
|
||||||
client_full_upsert(newclient.asdict())
|
client_full_upsert(newclient.asdict())
|
||||||
|
|
||||||
|
|
||||||
def client_remove(resource):
|
def client_remove(resource):
|
||||||
clients = db_get().table("clients")
|
clients = db_get().table("clients")
|
||||||
client = client_get(resource)
|
client = client_get(resource)
|
||||||
if client:
|
if client:
|
||||||
clients.remove(doc_ids=[client.doc_id])
|
clients.remove(doc_ids=[client.doc_id])
|
||||||
|
|
||||||
|
|
||||||
def client_get(resource):
|
def client_get(resource):
|
||||||
clients = db_get().table("clients")
|
clients = db_get().table("clients")
|
||||||
Client = Query()
|
Client = Query()
|
||||||
|
|
|
||||||
2353
bumper/models.py
2353
bumper/models.py
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +1,10 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import asyncio
|
|
||||||
from aiohttp import web
|
|
||||||
from bumper import plugins
|
|
||||||
import logging
|
import logging
|
||||||
import bumper
|
|
||||||
from bumper.models import *
|
from aiohttp import web
|
||||||
|
|
||||||
from bumper import plugins
|
from bumper import plugins
|
||||||
from datetime import datetime, timedelta
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
class portal_api_appsvr(plugins.ConfServerApp):
|
class portal_api_appsvr(plugins.ConfServerApp):
|
||||||
|
|
@ -17,14 +15,14 @@ class portal_api_appsvr(plugins.ConfServerApp):
|
||||||
self.sub_api = "portal_api"
|
self.sub_api = "portal_api"
|
||||||
|
|
||||||
self.routes = [
|
self.routes = [
|
||||||
|
web.route("*", "/appsvr/app.do", self.handle_appsvr_app, name="portal_api_appsvr_app"),
|
||||||
web.route("*", "/appsvr/app.do", self.handle_appsvr_api, name="portal_api_appsvr_app"),
|
web.route("*", "/appsvr/service/list", self.handle_appsvr_service_list, name="portal_api_appsvr_service_list"),
|
||||||
|
web.route("*", "/appsvr/oauth_callback", self.handle_appsvr_oauth_callback, name="portal_api_appsvr_oauth_callback"),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
||||||
async def handle_appsvr_api(self, request):
|
async def handle_appsvr_app(self, request):
|
||||||
if not request.method == "GET": # Skip GET for now
|
if not request.method == "GET": # Skip GET for now
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
|
@ -157,5 +155,57 @@ class portal_api_appsvr(plugins.ConfServerApp):
|
||||||
body = {"result": "fail", "todo": "result"}
|
body = {"result": "fail", "todo": "result"}
|
||||||
return web.json_response(body)
|
return web.json_response(body)
|
||||||
|
|
||||||
plugin = portal_api_appsvr()
|
async def handle_appsvr_service_list(self, request):
|
||||||
|
try:
|
||||||
|
# original urls comment out as they are sub sub domain, which the current certificate is not valid
|
||||||
|
# using url, where the certs is valid
|
||||||
|
# data = {
|
||||||
|
# "account": "users-base.dc-eu.ww.ecouser.net",
|
||||||
|
# "jmq": "jmq-ngiot-eu.dc.ww.ecouser.net",
|
||||||
|
# "lb": "lbo.ecouser.net",
|
||||||
|
# "magw": "api-app.dc-eu.ww.ecouser.net",
|
||||||
|
# "msgcloud": "msg-eu.ecouser.net:5223",
|
||||||
|
# "ngiotLb": "jmq-ngiot-eu.area.ww.ecouser.net",
|
||||||
|
# "rop": "api-rop.dc-eu.ww.ecouser.net"
|
||||||
|
# }
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"account": "users-base.ecouser.net",
|
||||||
|
"jmq": "jmq-ngiot-eu.ecouser.net",
|
||||||
|
"lb": "lbo.ecouser.net",
|
||||||
|
"magw": "api-app.ecouser.net",
|
||||||
|
"msgcloud": "msg-eu.ecouser.net:5223",
|
||||||
|
"ngiotLb": "jmq-ngiot-eu.ecouser.net",
|
||||||
|
"rop": "api-rop.ecouser.net"
|
||||||
|
}
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"code": 0,
|
||||||
|
"data": data,
|
||||||
|
"ret": "ok",
|
||||||
|
"todo": "result"
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_appsvr_oauth_callback(self, request):
|
||||||
|
try:
|
||||||
|
token = bumper.token_by_authcode(request.query["code"])
|
||||||
|
oauth = bumper.user_add_oauth(token["userid"])
|
||||||
|
body = {
|
||||||
|
"code": 0,
|
||||||
|
"data": oauth.toResponse(),
|
||||||
|
"ret": "ok",
|
||||||
|
"todo": "result"
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
plugin = portal_api_appsvr()
|
||||||
|
|
|
||||||
38
bumper/plugins/bumper_confserver_portal_ecms.py
Normal file
38
bumper/plugins/bumper_confserver_portal_ecms.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from aiohttp import web
|
||||||
|
|
||||||
|
from bumper import plugins
|
||||||
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
|
class portal_api_ecms(plugins.ConfServerApp):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = "portal_api_ecms"
|
||||||
|
self.plugin_type = "sub_api"
|
||||||
|
self.sub_api = "portal_api"
|
||||||
|
|
||||||
|
self.routes = [
|
||||||
|
web.route("*", "/ecms/app/ad/res", self.handle_ad_res, name="portal_api_ecms_ad_res"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
||||||
|
async def handle_ad_res(self, request):
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": 0,
|
||||||
|
"data": [],
|
||||||
|
"message": "success",
|
||||||
|
"success": True
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
plugin = portal_api_ecms()
|
||||||
|
|
@ -29,7 +29,7 @@ class portal_api_iot(plugins.ConfServerApp):
|
||||||
try:
|
try:
|
||||||
json_body = json.loads(await request.text())
|
json_body = json.loads(await request.text())
|
||||||
|
|
||||||
randomid = "".join(random.sample(string.ascii_letters, 6))
|
randomid = "".join(random.sample(string.ascii_letters, 4))
|
||||||
did = ""
|
did = ""
|
||||||
if "toId" in json_body: # Its a command
|
if "toId" in json_body: # Its a command
|
||||||
did = json_body["toId"]
|
did = json_body["toId"]
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import asyncio
|
|
||||||
from aiohttp import web
|
|
||||||
from bumper import plugins
|
|
||||||
import logging
|
import logging
|
||||||
import bumper
|
|
||||||
from bumper.models import *
|
|
||||||
from bumper import plugins
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import os
|
|
||||||
import string
|
|
||||||
import random
|
import random
|
||||||
|
import string
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from aiohttp import web
|
||||||
|
|
||||||
|
from bumper import plugins
|
||||||
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
class portal_api_lg(plugins.ConfServerApp):
|
class portal_api_lg(plugins.ConfServerApp):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -28,10 +26,11 @@ class portal_api_lg(plugins.ConfServerApp):
|
||||||
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
||||||
async def handle_lg_log(self, request): # EcoVacs Home
|
async def handle_lg_log(self, request): # EcoVacs Home
|
||||||
|
randomid = "".join(random.sample(string.ascii_letters, 6))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
json_body = json.loads(await request.text())
|
json_body = json.loads(await request.text())
|
||||||
|
|
||||||
randomid = "".join(random.sample(string.ascii_letters, 6))
|
|
||||||
did = json_body["did"]
|
did = json_body["did"]
|
||||||
|
|
||||||
botdetails = bumper.bot_get(did)
|
botdetails = bumper.bot_get(did)
|
||||||
|
|
@ -53,7 +52,7 @@ class portal_api_lg(plugins.ConfServerApp):
|
||||||
json_body["payloadType"] = "x"
|
json_body["payloadType"] = "x"
|
||||||
|
|
||||||
if not "payload" in json_body:
|
if not "payload" in json_body:
|
||||||
#json_body["payload"] = ""
|
# json_body["payload"] = ""
|
||||||
if json_body["td"] == "GetCleanLogs":
|
if json_body["td"] == "GetCleanLogs":
|
||||||
json_body["td"] = "q"
|
json_body["td"] = "q"
|
||||||
json_body["payload"] = '<ctl count="30"/>'
|
json_body["payload"] = '<ctl count="30"/>'
|
||||||
|
|
@ -77,8 +76,8 @@ class portal_api_lg(plugins.ConfServerApp):
|
||||||
"area": l.attrib['a'],
|
"area": l.attrib['a'],
|
||||||
"last": l.attrib['l'],
|
"last": l.attrib['l'],
|
||||||
"cleanType": l.attrib['t'],
|
"cleanType": l.attrib['t'],
|
||||||
#imageUrl allows for providing images of cleanings, something to look into later
|
# imageUrl allows for providing images of cleanings, something to look into later
|
||||||
#"imageUrl": "https://localhost:8007",
|
# "imageUrl": "https://localhost:8007",
|
||||||
}
|
}
|
||||||
logs.append(cleanlog)
|
logs.append(cleanlog)
|
||||||
body = {
|
body = {
|
||||||
|
|
@ -98,11 +97,12 @@ class portal_api_lg(plugins.ConfServerApp):
|
||||||
json_body["toId"]
|
json_body["toId"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"}
|
|
||||||
return web.json_response(body)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("{}".format(e))
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
plugin = portal_api_lg()
|
body = {"id": randomid, "errno": bumper.ERR_COMMON, "ret": "fail"}
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
|
||||||
|
plugin = portal_api_lg()
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import asyncio
|
|
||||||
from aiohttp import web
|
|
||||||
from bumper import plugins
|
|
||||||
import logging
|
import logging
|
||||||
import bumper
|
|
||||||
from bumper.models import *
|
|
||||||
from bumper import plugins
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from aiohttp import web
|
||||||
|
|
||||||
|
from bumper import plugins
|
||||||
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
class portal_api_pim(plugins.ConfServerApp):
|
class portal_api_pim(plugins.ConfServerApp):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -17,13 +16,12 @@ class portal_api_pim(plugins.ConfServerApp):
|
||||||
self.sub_api = "portal_api"
|
self.sub_api = "portal_api"
|
||||||
|
|
||||||
self.routes = [
|
self.routes = [
|
||||||
|
|
||||||
web.route("*", "/pim/product/getProductIotMap", self.handle_getProductIotMap, name="portal_api_pim_getProductIotMap"),
|
web.route("*", "/pim/product/getProductIotMap", self.handle_getProductIotMap, name="portal_api_pim_getProductIotMap"),
|
||||||
web.route("*", "/pim/file/get/{id}", self.handle_pimFile, name="portal_api_pim_file"),
|
web.route("*", "/pim/file/get/{id}", self.handle_pimFile, name="portal_api_pim_file"),
|
||||||
web.route("*", "/pim/product/getConfignetAll", self.handle_getConfignetAll, name="portal_api_pim_getConfignetAll"),
|
web.route("*", "/pim/product/getConfignetAll", self.handle_getConfignetAll, name="portal_api_pim_getConfignetAll"),
|
||||||
web.route("*", "/pim/product/getConfigGroups", self.handle_getConfigGroups, name="portal_api_pim_getConfigGroups"),
|
web.route("*", "/pim/product/getConfigGroups", self.handle_getConfigGroups, name="portal_api_pim_getConfigGroups"),
|
||||||
web.route("*", "/pim/dictionary/getErrDetail", self.handle_getErrDetail, name="portal_api_pim_getErrDetail"),
|
web.route("*", "/pim/dictionary/getErrDetail", self.handle_getErrDetail, name="portal_api_pim_getErrDetail"),
|
||||||
|
web.route("*", "/pim/product/software/config/batch", self.handle_product_config_batch, name="portal_api_pim_product_config_batch"),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
@ -43,7 +41,7 @@ class portal_api_pim(plugins.ConfServerApp):
|
||||||
try:
|
try:
|
||||||
fileID = request.match_info.get("id", "")
|
fileID = request.match_info.get("id", "")
|
||||||
|
|
||||||
return web.FileResponse(os.path.join(bumper.bumper_dir,"bumper","web","images","robotvac_image.jpg"))
|
return web.FileResponse(os.path.join(bumper.bumper_dir, "bumper", "web", "images", "robotvac_image.jpg"))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("{}".format(e))
|
logging.exception("{}".format(e))
|
||||||
|
|
@ -67,15 +65,43 @@ class portal_api_pim(plugins.ConfServerApp):
|
||||||
async def handle_getErrDetail(self, request):
|
async def handle_getErrDetail(self, request):
|
||||||
try:
|
try:
|
||||||
body = {
|
body = {
|
||||||
"code": -1,
|
"code": -1,
|
||||||
"data": [],
|
"data": [],
|
||||||
"msg": "This errcode's detail is not exists"
|
"msg": "This errcode's detail is not exists"
|
||||||
}
|
}
|
||||||
return web.json_response(body)
|
return web.json_response(body)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("{}".format(e))
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_product_config_batch(self, request):
|
||||||
|
try:
|
||||||
|
json_body = json.loads(await request.text())
|
||||||
|
data = []
|
||||||
|
for pid in json_body["pids"]:
|
||||||
|
for productConfig in productConfigBatch:
|
||||||
|
if pid == productConfig["pid"]:
|
||||||
|
data.append(productConfig)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# not found in productConfigBatch
|
||||||
|
# some devices don't have any product configuration
|
||||||
|
data.append({
|
||||||
|
"cfg": {},
|
||||||
|
"pid": pid
|
||||||
|
})
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"code": 200,
|
||||||
|
"data": data,
|
||||||
|
"message": "success"
|
||||||
|
}
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
plugin = portal_api_pim()
|
plugin = portal_api_pim()
|
||||||
|
|
||||||
confignetAllResponse = {
|
confignetAllResponse = {
|
||||||
|
|
@ -2681,3 +2707,174 @@ configGroupsResponse = {
|
||||||
"contactUS": "helper"
|
"contactUS": "helper"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
productConfigBatch = [
|
||||||
|
{
|
||||||
|
"pid": "5e14196a6e71b80001b60fda",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5e8e8d8a032edd8457c66bfb",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5c19a91ca1e6ee000178224a",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5e8e8d2a032edd3c03c66bf7",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5de0d86ed88546000195239a",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": True,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5c19a8f3a1e6ee0001782247",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5e698a6306f6de52c264c61b",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5e699a4106f6de83ea64c620",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5edd998afdd6a30008da039b",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": True,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5edd9a4075f2fc000636086c",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": True,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5ed5e4d3a719ea460ec3216c",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5f88195e6cf8de0008ed7c11",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5f8819156cf8de0008ed7c0d",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pid": "5fa105c6d16a99000667eb54",
|
||||||
|
"cfg": {
|
||||||
|
"supported": {
|
||||||
|
"tmallstand": False,
|
||||||
|
"video": False,
|
||||||
|
"battery": True,
|
||||||
|
"clean": True,
|
||||||
|
"charge": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
||||||
39
bumper/plugins/bumper_confserver_portal_rapp.py
Normal file
39
bumper/plugins/bumper_confserver_portal_rapp.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from aiohttp import web
|
||||||
|
import logging
|
||||||
|
from bumper.models import *
|
||||||
|
from bumper import plugins
|
||||||
|
|
||||||
|
|
||||||
|
class api_rapp(plugins.ConfServerApp):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = "api_rapp"
|
||||||
|
self.plugin_type = "sub_api"
|
||||||
|
self.sub_api = "portal_api"
|
||||||
|
|
||||||
|
self.routes = [
|
||||||
|
web.route("*", "/rapp/sds/user/data/map/get", self.handle_map_get, name="api_rapp"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
||||||
|
async def handle_map_get(self, request):
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"data": {
|
||||||
|
"name": "My Home"
|
||||||
|
},
|
||||||
|
"tag": None
|
||||||
|
},
|
||||||
|
"message": "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
plugin = api_rapp()
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import asyncio
|
|
||||||
from aiohttp import web
|
|
||||||
from bumper import plugins
|
|
||||||
import logging
|
import logging
|
||||||
import bumper
|
|
||||||
from bumper.models import *
|
from aiohttp import web
|
||||||
|
|
||||||
from bumper import plugins
|
from bumper import plugins
|
||||||
from datetime import datetime, timedelta
|
from bumper.models import *
|
||||||
|
|
||||||
|
|
||||||
class v1_private_common(plugins.ConfServerApp):
|
class v1_private_common(plugins.ConfServerApp):
|
||||||
|
|
@ -21,6 +19,10 @@ class v1_private_common(plugins.ConfServerApp):
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/checkVersion", self.handle_checkVersion, name="v1_common_checkVersion"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/checkVersion", self.handle_checkVersion, name="v1_common_checkVersion"),
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/uploadDeviceInfo", self.handle_uploadDeviceInfo, name="v1_common_uploadDeviceInfo"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/uploadDeviceInfo", self.handle_uploadDeviceInfo, name="v1_common_uploadDeviceInfo"),
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getSystemReminder", self.handle_getSystemReminder, name="v1_common_getSystemReminder"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getSystemReminder", self.handle_getSystemReminder, name="v1_common_getSystemReminder"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getConfig",self.handle_getConfig, name="v1_common_getConfig"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getAreas",self.handle_getAreas, name="v1_common_getAreas"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getAgreementURLBatch", self.handle_getAgreementURLBatch, name="v1_common_getAgreementURLBatch"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/common/getTimestamp", self.handle_getTimestamp, name="v1_common_getTimestamp"),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -110,6 +112,351 @@ class v1_private_common(plugins.ConfServerApp):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("{}".format(e))
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_getConfig(self, request):
|
||||||
|
try:
|
||||||
|
data = []
|
||||||
|
for key in request.query["keys"].split(','):
|
||||||
|
data.append({
|
||||||
|
"key": key,
|
||||||
|
"value": "Y"
|
||||||
|
})
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": data,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_getAreas(self, request):
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": AREA_LIST,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_getAgreementURLBatch(self, request): # EcoVacs Home
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"acceptTime": None,
|
||||||
|
"force": None,
|
||||||
|
"id": "20180804040641_7d746faf18b8cb22a50d145598fe4c90",
|
||||||
|
"type": "USER",
|
||||||
|
"url": "https://gl-eu-wap.ecovacs.com/content/agreement?id=20180804040641_7d746faf18b8cb22a50d145598fe4c90&language=EN",
|
||||||
|
"version": "1.03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"acceptTime": None,
|
||||||
|
"force": None,
|
||||||
|
"id": "20180804040245_4e7c56dfb7ebd3b81b1f2747d0859fac",
|
||||||
|
"type": "PRIVACY",
|
||||||
|
"url": "https://gl-eu-wap.ecovacs.com/content/agreement?id=20180804040245_4e7c56dfb7ebd3b81b1f2747d0859fac&language=EN",
|
||||||
|
"version": "1.03"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_getTimestamp(self, request): # EcoVacs Home
|
||||||
|
try:
|
||||||
|
time = self.get_milli_time(datetime.utcnow().timestamp())
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": {
|
||||||
|
"timestamp": time
|
||||||
|
},
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": time,
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
plugin = v1_private_common()
|
plugin = v1_private_common()
|
||||||
|
|
||||||
|
AREA_LIST = {"currentVersion": 231,
|
||||||
|
"areaList": [{"areaKey": "JP", "chsName": "日本", "enName": "Japan", "pyFirst": "R"},
|
||||||
|
{"areaKey": "MY", "chsName": "马来西亚", "enName": "Malaysia", "pyFirst": "M"},
|
||||||
|
{"areaKey": "DE", "chsName": "德国", "enName": "Germany", "pyFirst": "D"},
|
||||||
|
{"areaKey": "LI", "chsName": "列支敦斯登", "enName": "Liechtenstein", "pyFirst": "L"},
|
||||||
|
{"areaKey": "AT", "chsName": "奥地利", "enName": "Austria", "pyFirst": "A"},
|
||||||
|
{"areaKey": "TW", "chsName": "台湾", "enName": "Taiwan", "pyFirst": "T"},
|
||||||
|
{"areaKey": "FR", "chsName": "法国", "enName": "France", "pyFirst": "F"},
|
||||||
|
{"areaKey": "CN", "chsName": "中国大陆", "enName": "China Mainland", "pyFirst": "Z"},
|
||||||
|
{"areaKey": "SG", "chsName": "新加坡", "enName": "Singapore", "pyFirst": "X"},
|
||||||
|
{"areaKey": "RE", "chsName": "留尼汪岛", "enName": "Reunion Island", "pyFirst": "L"},
|
||||||
|
{"areaKey": "EH", "chsName": "西撒哈拉", "enName": "Western Sahara", "pyFirst": "X"},
|
||||||
|
{"areaKey": "WF", "chsName": "瓦利斯群岛和富图纳群岛", "enName": "Wallis and Futuna Islands",
|
||||||
|
"pyFirst": "W"},
|
||||||
|
{"areaKey": "KP", "chsName": "朝鲜", "enName": "North Korea", "pyFirst": "C"},
|
||||||
|
{"areaKey": "ZW", "chsName": "津巴布韦", "enName": "Zimbabwe", "pyFirst": "J"},
|
||||||
|
{"areaKey": "VI", "chsName": "美属维尔京群岛", "enName": "United States Virgin Islands",
|
||||||
|
"pyFirst": "M"},
|
||||||
|
{"areaKey": "PF", "chsName": "法属玻里尼西亚", "enName": "French Polynesia",
|
||||||
|
"pyFirst": "F"},
|
||||||
|
{"areaKey": "DJ", "chsName": "吉布提", "enName": "Djibouti", "pyFirst": "J"},
|
||||||
|
{"areaKey": "KZ", "chsName": "哈萨克斯坦", "enName": "Kazakhstan", "pyFirst": "H"},
|
||||||
|
{"areaKey": "TV", "chsName": "图瓦卢", "enName": "Tuvalu", "pyFirst": "T"},
|
||||||
|
{"areaKey": "VU", "chsName": "瓦努阿图", "enName": "Vanuatu", "pyFirst": "W"},
|
||||||
|
{"areaKey": "IN", "chsName": "印度", "enName": "India", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "CM", "chsName": "喀麦隆", "enName": "Cameroon", "pyFirst": "K"},
|
||||||
|
{"areaKey": "LK", "chsName": "斯里兰卡", "enName": "Sri Lanka", "pyFirst": "S"},
|
||||||
|
{"areaKey": "CC", "chsName": "科科斯群岛", "enName": "Cocos Islands", "pyFirst": "K"},
|
||||||
|
{"areaKey": "KY", "chsName": "开曼群岛", "enName": "Cayman Islands", "pyFirst": "K"},
|
||||||
|
{"areaKey": "QA", "chsName": "卡塔尔", "enName": "Qatar", "pyFirst": "K"},
|
||||||
|
{"areaKey": "AZ", "chsName": "阿塞拜疆", "enName": "Azerbaijan", "pyFirst": "A"},
|
||||||
|
{"areaKey": "HN", "chsName": "洪都拉斯", "enName": "Honduras", "pyFirst": "H"},
|
||||||
|
{"areaKey": "AW", "chsName": "阿鲁巴岛", "enName": "Aruba", "pyFirst": "A"},
|
||||||
|
{"areaKey": "KH", "chsName": "柬埔寨", "enName": "Cambodia", "pyFirst": "J"},
|
||||||
|
{"areaKey": "CO", "chsName": "哥伦比亚", "enName": "Colombia", "pyFirst": "G"},
|
||||||
|
{"areaKey": "IR", "chsName": "伊朗", "enName": "Iran", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "ZA", "chsName": "南非", "enName": "South Africa", "pyFirst": "N"},
|
||||||
|
{"areaKey": "UY", "chsName": "乌拉圭", "enName": "Uruguay", "pyFirst": "W"},
|
||||||
|
{"areaKey": "GU", "chsName": "关岛", "enName": "Guam", "pyFirst": "G"},
|
||||||
|
{"areaKey": "GH", "chsName": "加纳", "enName": "Ghana", "pyFirst": "J"},
|
||||||
|
{"areaKey": "GN", "chsName": "几内亚", "enName": "Guynea", "pyFirst": "J"},
|
||||||
|
{"areaKey": "MH", "chsName": "马绍尔群岛", "enName": "Marshall Islands",
|
||||||
|
"pyFirst": "M"},
|
||||||
|
{"areaKey": "SE", "chsName": "瑞典", "enName": "Sweden", "pyFirst": "R"},
|
||||||
|
{"areaKey": "SB", "chsName": "所罗门群岛", "enName": "Solomon Islands",
|
||||||
|
"pyFirst": "S"},
|
||||||
|
{"areaKey": "NE", "chsName": "尼日尔", "enName": "Niger", "pyFirst": "N"},
|
||||||
|
{"areaKey": "HT", "chsName": "海地", "enName": "Haiti", "pyFirst": "H"},
|
||||||
|
{"areaKey": "PL", "chsName": "波兰", "enName": "Poland", "pyFirst": "B"},
|
||||||
|
{"areaKey": "DO", "chsName": "多米尼加共和国", "enName": "Dominican Republic",
|
||||||
|
"pyFirst": "D"},
|
||||||
|
{"areaKey": "PS", "chsName": "巴勒斯坦", "enName": "Palestine", "pyFirst": "B"},
|
||||||
|
{"areaKey": "KW", "chsName": "科威特", "enName": "Kuwait", "pyFirst": "K"},
|
||||||
|
{"areaKey": "UZ", "chsName": "乌兹别克斯坦", "enName": "Republic of Uzbekistan",
|
||||||
|
"pyFirst": "W"},
|
||||||
|
{"areaKey": "GD", "chsName": "格林纳达", "enName": "Grenada", "pyFirst": "G"},
|
||||||
|
{"areaKey": "KG", "chsName": "吉尔吉斯斯坦", "enName": "Kyrgyzstan", "pyFirst": "J"},
|
||||||
|
{"areaKey": "JO", "chsName": "约旦", "enName": "Jordan", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "IL", "chsName": "以色列", "enName": "Israel", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "UK", "chsName": "英国", "enName": "United Kingdom", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "MW", "chsName": "马拉维", "enName": "Malawi", "pyFirst": "M"},
|
||||||
|
{"areaKey": "MC", "chsName": "摩纳哥", "enName": "Monaco", "pyFirst": "M"},
|
||||||
|
{"areaKey": "IC", "chsName": "加那利群岛", "enName": "Canary Islands", "pyFirst": "J"},
|
||||||
|
{"areaKey": "JM", "chsName": "牙买加", "enName": "Jamaica", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "MP", "chsName": "北马里亚纳群岛", "enName": "The Northern Mariana Islands",
|
||||||
|
"pyFirst": "B"},
|
||||||
|
{"areaKey": "BH", "chsName": "巴林岛", "enName": "Bahrain", "pyFirst": "B"},
|
||||||
|
{"areaKey": "MK", "chsName": "马其顿", "enName": "Macedonia", "pyFirst": "M"},
|
||||||
|
{"areaKey": "ET", "chsName": "埃塞俄比亚", "enName": "Ethiopia", "pyFirst": "A"},
|
||||||
|
{"areaKey": "CL", "chsName": "智利", "enName": "Chile", "pyFirst": "Z"},
|
||||||
|
{"areaKey": "GP", "chsName": "瓜德罗普岛", "enName": "Guadeloupe", "pyFirst": "G"},
|
||||||
|
{"areaKey": "FK", "chsName": "福克兰群岛", "enName": "Falkland Islands",
|
||||||
|
"pyFirst": "F"},
|
||||||
|
{"areaKey": "GL", "chsName": "格陵兰", "enName": "Greenland", "pyFirst": "G"},
|
||||||
|
{"areaKey": "BF", "chsName": "布基纳法索", "enName": "Burkina Faso", "pyFirst": "B"},
|
||||||
|
{"areaKey": "GI", "chsName": "直布罗陀", "enName": "Gibraltar", "pyFirst": "Z"},
|
||||||
|
{"areaKey": "MV", "chsName": "马尔代夫", "enName": "Maldives", "pyFirst": "M"},
|
||||||
|
{"areaKey": "CU", "chsName": "古巴", "enName": "Cuba", "pyFirst": "G"},
|
||||||
|
{"areaKey": "LS", "chsName": "莱索托", "enName": "Lesotho", "pyFirst": "L"},
|
||||||
|
{"areaKey": "MA", "chsName": "摩洛哥", "enName": "Morocco", "pyFirst": "M"},
|
||||||
|
{"areaKey": "AL", "chsName": "阿尔巴尼亚", "enName": "Albania", "pyFirst": "A"},
|
||||||
|
{"areaKey": "AF", "chsName": "阿富汗", "enName": "Afghanistan", "pyFirst": "A"},
|
||||||
|
{"areaKey": "CA", "chsName": "加拿大", "enName": "Canada", "pyFirst": "J"},
|
||||||
|
{"areaKey": "BB", "chsName": "巴巴多斯", "enName": "Barbados", "pyFirst": "B"},
|
||||||
|
{"areaKey": "LC", "chsName": "圣卢西亚岛", "enName": "Saint Lucia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "PN", "chsName": "皮特克恩岛", "enName": "Pitcairn Island",
|
||||||
|
"pyFirst": "P"},
|
||||||
|
{"areaKey": "LV", "chsName": "拉脱维亚", "enName": "Latvia", "pyFirst": "L"},
|
||||||
|
{"areaKey": "NO", "chsName": "挪威", "enName": "Norway", "pyFirst": "N"},
|
||||||
|
{"areaKey": "BE", "chsName": "比利时", "enName": "Belgium", "pyFirst": "B"},
|
||||||
|
{"areaKey": "VE", "chsName": "委内瑞拉", "enName": "Venezuela", "pyFirst": "W"},
|
||||||
|
{"areaKey": "MQ", "chsName": "马提尼克", "enName": "Martinique", "pyFirst": "M"},
|
||||||
|
{"areaKey": "GY", "chsName": "圭亚那", "enName": "Guyana", "pyFirst": "G"},
|
||||||
|
{"areaKey": "AM", "chsName": "亚美尼亚", "enName": "Armenia", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "EC", "chsName": "厄瓜多尔", "enName": "Ecuador", "pyFirst": "E"},
|
||||||
|
{"areaKey": "CV", "chsName": "佛得角", "enName": "Cape Verde", "pyFirst": "F"},
|
||||||
|
{"areaKey": "NZ", "chsName": "新西兰", "enName": "New Zealand", "pyFirst": "X"},
|
||||||
|
{"areaKey": "RO", "chsName": "罗马尼亚", "enName": "Romania", "pyFirst": "L"},
|
||||||
|
{"areaKey": "DM", "chsName": "多米尼加", "enName": "Dominica", "pyFirst": "D"},
|
||||||
|
{"areaKey": "TZ", "chsName": "坦桑尼亚", "enName": "Tanzania", "pyFirst": "T"},
|
||||||
|
{"areaKey": "BD", "chsName": "孟加拉国", "enName": "Bangladesh", "pyFirst": "M"},
|
||||||
|
{"areaKey": "TD", "chsName": "乍得", "enName": "Chad", "pyFirst": "Z"},
|
||||||
|
{"areaKey": "LT", "chsName": "立陶宛", "enName": "Lithuania", "pyFirst": "L"},
|
||||||
|
{"areaKey": "TJ", "chsName": "塔吉克斯坦", "enName": "Tajikistan", "pyFirst": "T"},
|
||||||
|
{"areaKey": "TK", "chsName": "托克劳", "enName": "Tokelau", "pyFirst": "T"},
|
||||||
|
{"areaKey": "BS", "chsName": "巴哈马群岛", "enName": "Bahamas", "pyFirst": "B"},
|
||||||
|
{"areaKey": "MM", "chsName": "缅甸", "enName": "Myanmar", "pyFirst": "M"},
|
||||||
|
{"areaKey": "BI", "chsName": "布隆迪", "enName": "Burundi", "pyFirst": "B"},
|
||||||
|
{"areaKey": "PY", "chsName": "巴拉圭", "enName": "Paraguay", "pyFirst": "B"},
|
||||||
|
{"areaKey": "SK", "chsName": "斯洛伐克", "enName": "Slovakia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "FI", "chsName": "芬兰", "enName": "Finland", "pyFirst": "F"},
|
||||||
|
{"areaKey": "GA", "chsName": "加蓬", "enName": "Gabon", "pyFirst": "J"},
|
||||||
|
{"areaKey": "DZ", "chsName": "阿尔及利亚", "enName": "Algeria", "pyFirst": "A"},
|
||||||
|
{"areaKey": "FO", "chsName": "法罗群岛", "enName": "Faroe Islands", "pyFirst": "F"},
|
||||||
|
{"areaKey": "ZM", "chsName": "赞比亚", "enName": "Zambia", "pyFirst": "Z"},
|
||||||
|
{"areaKey": "NU", "chsName": "纽埃", "enName": "Niue", "pyFirst": "N"},
|
||||||
|
{"areaKey": "ER", "chsName": "厄立特里亚国", "enName": "Eritrea", "pyFirst": "E"},
|
||||||
|
{"areaKey": "HK", "chsName": "香港", "enName": "Hong Kong", "pyFirst": "X"},
|
||||||
|
{"areaKey": "IT", "chsName": "意大利", "enName": "Italy", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "MS", "chsName": "蒙特色拉特岛", "enName": "Montserrat", "pyFirst": "M"},
|
||||||
|
{"areaKey": "EE", "chsName": "爱沙尼亚", "enName": "Estonia", "pyFirst": "A"},
|
||||||
|
{"areaKey": "WS", "chsName": "萨摩亚", "enName": "Samoa", "pyFirst": "S"},
|
||||||
|
{"areaKey": "TG", "chsName": "多哥", "enName": "Togo", "pyFirst": "D"},
|
||||||
|
{"areaKey": "ML", "chsName": "马里", "enName": "Mali", "pyFirst": "M"},
|
||||||
|
{"areaKey": "GF", "chsName": "法属圭亚那", "enName": "French Guyana", "pyFirst": "F"},
|
||||||
|
{"areaKey": "KM", "chsName": "科摩罗", "enName": "Comoros", "pyFirst": "K"},
|
||||||
|
{"areaKey": "ID", "chsName": "印度尼西亚", "enName": "Indonesia", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "KE", "chsName": "肯尼亚", "enName": "Kenya", "pyFirst": "K"},
|
||||||
|
{"areaKey": "EG", "chsName": "埃及", "enName": "Egypt", "pyFirst": "A"},
|
||||||
|
{"areaKey": "NF", "chsName": "诺福克岛", "enName": "Norfolk Island", "pyFirst": "N"},
|
||||||
|
{"areaKey": "RS", "chsName": "塞尔维亚", "enName": "Serbia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "TR", "chsName": "土耳其", "enName": "Turkey", "pyFirst": "T"},
|
||||||
|
{"areaKey": "DK", "chsName": "丹麦", "enName": "Denmark", "pyFirst": "D"},
|
||||||
|
{"areaKey": "AD", "chsName": "安道尔", "enName": "Andorra", "pyFirst": "A"},
|
||||||
|
{"areaKey": "LR", "chsName": "利比里亚", "enName": "Liberia", "pyFirst": "L"},
|
||||||
|
{"areaKey": "AE", "chsName": "阿拉伯联合酋长国", "enName": "United Arab Emirates",
|
||||||
|
"pyFirst": "A"},
|
||||||
|
{"areaKey": "CH", "chsName": "瑞士", "enName": "Switzerland", "pyFirst": "R"},
|
||||||
|
{"areaKey": "AU", "chsName": "澳大利亚", "enName": "Australia", "pyFirst": "A"},
|
||||||
|
{"areaKey": "TP", "chsName": "东帝汶", "enName": "East Timor", "pyFirst": "D"},
|
||||||
|
{"areaKey": "LY", "chsName": "利比亚", "enName": "Libya", "pyFirst": "L"},
|
||||||
|
{"areaKey": "RW", "chsName": "卢旺达", "enName": "Rwanda", "pyFirst": "L"},
|
||||||
|
{"areaKey": "SA", "chsName": "沙特阿拉伯", "enName": "Saudi Arabia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "AR", "chsName": "阿根廷", "enName": "Argentina", "pyFirst": "A"},
|
||||||
|
{"areaKey": "GM", "chsName": "冈比亚", "enName": "Gambia", "pyFirst": "G"},
|
||||||
|
{"areaKey": "BY", "chsName": "白俄罗斯", "enName": "Belarus", "pyFirst": "B"},
|
||||||
|
{"areaKey": "SL", "chsName": "塞拉利昂", "enName": "Sierra Leone", "pyFirst": "S"},
|
||||||
|
{"areaKey": "TM", "chsName": "土库曼斯坦", "enName": "Turkmenistan", "pyFirst": "T"},
|
||||||
|
{"areaKey": "AG", "chsName": "安提瓜和巴布达", "enName": "Antigua and Barbuda",
|
||||||
|
"pyFirst": "A"},
|
||||||
|
{"areaKey": "MR", "chsName": "毛里塔尼亚", "enName": "Mauritania", "pyFirst": "M"},
|
||||||
|
{"areaKey": "PT", "chsName": "葡萄牙", "enName": "Portugal", "pyFirst": "P"},
|
||||||
|
{"areaKey": "BW", "chsName": "博茨瓦纳", "enName": "Botswana", "pyFirst": "B"},
|
||||||
|
{"areaKey": "GT", "chsName": "危地马拉", "enName": "Guatemala", "pyFirst": "W"},
|
||||||
|
{"areaKey": "BT", "chsName": "不丹", "enName": "Bhutan", "pyFirst": "B"},
|
||||||
|
{"areaKey": "AI", "chsName": "安圭拉岛", "enName": "Anguilla", "pyFirst": "A"},
|
||||||
|
{"areaKey": "OM", "chsName": "阿曼", "enName": "Oman", "pyFirst": "A"},
|
||||||
|
{"areaKey": "KI", "chsName": "基里巴斯", "enName": "Kiribati", "pyFirst": "J"},
|
||||||
|
{"areaKey": "UA", "chsName": "乌克兰", "enName": "Ukraine", "pyFirst": "W"},
|
||||||
|
{"areaKey": "YE", "chsName": "也门", "enName": "Yemen", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "DR", "chsName": "刚果民主共和国",
|
||||||
|
"enName": "Democratic Republic of the Congo", "pyFirst": "G"},
|
||||||
|
{"areaKey": "MD", "chsName": "摩尔多瓦", "enName": "Moldova", "pyFirst": "M"},
|
||||||
|
{"areaKey": "GW", "chsName": "几内亚比绍", "enName": "Guinea-Bissau", "pyFirst": "J"},
|
||||||
|
{"areaKey": "CG", "chsName": "刚果布共和国", "enName": "Congo Brazzaville",
|
||||||
|
"pyFirst": "G"},
|
||||||
|
{"areaKey": "SN", "chsName": "塞内加尔", "enName": "Senegal", "pyFirst": "S"},
|
||||||
|
{"areaKey": "BA", "chsName": "波黑", "enName": "Bosnia Hercegovina",
|
||||||
|
"pyFirst": "B"},
|
||||||
|
{"areaKey": "MO", "chsName": "澳门", "enName": "Macao", "pyFirst": "A"},
|
||||||
|
{"areaKey": "KN", "chsName": "圣基茨和尼维斯", "enName": "Saint Kitts and Nevis",
|
||||||
|
"pyFirst": "S"},
|
||||||
|
{"areaKey": "TO", "chsName": "汤加", "enName": "Tonga", "pyFirst": "T"},
|
||||||
|
{"areaKey": "NG", "chsName": "尼日利亚", "enName": "Nigeria", "pyFirst": "N"},
|
||||||
|
{"areaKey": "TT", "chsName": "特立尼达和多巴哥", "enName": "Trinidad and Tobago",
|
||||||
|
"pyFirst": "T"},
|
||||||
|
{"areaKey": "CF", "chsName": "中非共和国", "enName": "Central African Republic",
|
||||||
|
"pyFirst": "Z"},
|
||||||
|
{"areaKey": "PE", "chsName": "秘鲁", "enName": "Peru", "pyFirst": "M"},
|
||||||
|
{"areaKey": "PG", "chsName": "巴布亚新几内亚", "enName": "Papua New Guinea",
|
||||||
|
"pyFirst": "B"},
|
||||||
|
{"areaKey": "CX", "chsName": "圣延岛", "enName": "Christmas Island", "pyFirst": "S"},
|
||||||
|
{"areaKey": "AN", "chsName": "安的列斯", "enName": "Netherlands Antilles",
|
||||||
|
"pyFirst": "A"},
|
||||||
|
{"areaKey": "BO", "chsName": "玻利维亚", "enName": "Bolivia", "pyFirst": "B"},
|
||||||
|
{"areaKey": "IQ", "chsName": "伊拉克", "enName": "Iraq", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "NP", "chsName": "尼泊尔", "enName": "Nepal", "pyFirst": "N"},
|
||||||
|
{"areaKey": "BJ", "chsName": "贝宁", "enName": "Benin", "pyFirst": "B"},
|
||||||
|
{"areaKey": "VN", "chsName": "越南", "enName": "Vietnam", "pyFirst": "Y"},
|
||||||
|
{"areaKey": "NI", "chsName": "尼加拉瓜", "enName": "Nicaragua", "pyFirst": "N"},
|
||||||
|
{"areaKey": "PW", "chsName": "帕劳群岛", "enName": "Palau", "pyFirst": "P"},
|
||||||
|
{"areaKey": "SO", "chsName": "索马里", "enName": "Somalia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "SM", "chsName": "圣马力诺", "enName": "San Marino", "pyFirst": "S"},
|
||||||
|
{"areaKey": "NR", "chsName": "瑙鲁", "enName": "Nauru", "pyFirst": "N"},
|
||||||
|
{"areaKey": "BN", "chsName": "文莱", "enName": "Brunei Darussalam", "pyFirst": "W"},
|
||||||
|
{"areaKey": "MZ", "chsName": "莫桑比克", "enName": "Mozambique", "pyFirst": "M"},
|
||||||
|
{"areaKey": "GR", "chsName": "希腊", "enName": "Greece", "pyFirst": "X"},
|
||||||
|
{"areaKey": "TN", "chsName": "突尼斯", "enName": "Tunisia", "pyFirst": "T"},
|
||||||
|
{"areaKey": "RU", "chsName": "俄罗斯", "enName": "Russian Federation",
|
||||||
|
"pyFirst": "E"},
|
||||||
|
{"areaKey": "MG", "chsName": "马达加斯加岛", "enName": "Madagascar", "pyFirst": "M"},
|
||||||
|
{"areaKey": "NA", "chsName": "纳米比亚", "enName": "Namibia", "pyFirst": "N"},
|
||||||
|
{"areaKey": "CQ", "chsName": "赤道几内亚", "enName": "Equatorial Guinea",
|
||||||
|
"pyFirst": "C"},
|
||||||
|
{"areaKey": "SR", "chsName": "苏里南", "enName": "Suriname", "pyFirst": "S"},
|
||||||
|
{"areaKey": "MU", "chsName": "毛里求斯", "enName": "Mauritius", "pyFirst": "M"},
|
||||||
|
{"areaKey": "LA", "chsName": "老挝", "enName": "Laos", "pyFirst": "L"},
|
||||||
|
{"areaKey": "US", "chsName": "美国", "enName": "United States", "pyFirst": "M"},
|
||||||
|
{"areaKey": "ST", "chsName": "圣多美与普林希比共和国", "enName": "Sao Tome and Principe",
|
||||||
|
"pyFirst": "S"},
|
||||||
|
{"areaKey": "BM", "chsName": "百慕大群岛", "enName": "Bermuda", "pyFirst": "B"},
|
||||||
|
{"areaKey": "LU", "chsName": "卢森堡", "enName": "Luxembourg", "pyFirst": "L"},
|
||||||
|
{"areaKey": "CR", "chsName": "哥斯达黎加", "enName": "Costa Rica", "pyFirst": "G"},
|
||||||
|
{"areaKey": "KR", "chsName": "韩国", "enName": "South Korea", "pyFirst": "H"},
|
||||||
|
{"areaKey": "CZ", "chsName": "捷克", "enName": "Czech Republic", "pyFirst": "J"},
|
||||||
|
{"areaKey": "MX", "chsName": "墨西哥", "enName": "Mexico", "pyFirst": "M"},
|
||||||
|
{"areaKey": "SH", "chsName": "圣赫勒拿岛", "enName": "St Helena", "pyFirst": "S"},
|
||||||
|
{"areaKey": "AO", "chsName": "安哥拉", "enName": "Angola", "pyFirst": "A"},
|
||||||
|
{"areaKey": "MN", "chsName": "蒙古", "enName": "Mongolia", "pyFirst": "M"},
|
||||||
|
{"areaKey": "VC", "chsName": "圣文森特和格林纳丁斯",
|
||||||
|
"enName": "Saint Vincent and the Grenadines", "pyFirst": "S"},
|
||||||
|
{"areaKey": "PH", "chsName": "菲律宾", "enName": "Philippines", "pyFirst": "F"},
|
||||||
|
{"areaKey": "SC", "chsName": "塞舌尔", "enName": "Seychelles", "pyFirst": "S"},
|
||||||
|
{"areaKey": "CK", "chsName": "库克群岛", "enName": "Cook Islands", "pyFirst": "K"},
|
||||||
|
{"areaKey": "PK", "chsName": "巴基斯坦", "enName": "Pakistan", "pyFirst": "B"},
|
||||||
|
{"areaKey": "HR", "chsName": "克罗地亚", "enName": "Croatia", "pyFirst": "K"},
|
||||||
|
{"areaKey": "TH", "chsName": "泰国", "enName": "Thailand", "pyFirst": "T"},
|
||||||
|
{"areaKey": "SI", "chsName": "斯洛文尼亚", "enName": "Slovenia", "pyFirst": "S"},
|
||||||
|
{"areaKey": "VG", "chsName": "英属维尔京群岛", "enName": "British Virgin Islands",
|
||||||
|
"pyFirst": "Y"},
|
||||||
|
{"areaKey": "SY", "chsName": "阿拉伯叙利亚共和国", "enName": "Syrian Arab Republic",
|
||||||
|
"pyFirst": "A"},
|
||||||
|
{"areaKey": "CY", "chsName": "塞浦路斯", "enName": "Cyprus", "pyFirst": "S"},
|
||||||
|
{"areaKey": "BR", "chsName": "巴西", "enName": "Brazil", "pyFirst": "B"},
|
||||||
|
{"areaKey": "LB", "chsName": "黎巴嫩", "enName": "Lebanon", "pyFirst": "L"},
|
||||||
|
{"areaKey": "IS", "chsName": "冰岛", "enName": "Iceland", "pyFirst": "B"},
|
||||||
|
{"areaKey": "PA", "chsName": "巴拿马", "enName": "Panama", "pyFirst": "B"},
|
||||||
|
{"areaKey": "FM", "chsName": "密克罗尼西亚", "enName": "Micronesia", "pyFirst": "M"},
|
||||||
|
{"areaKey": "VA", "chsName": "梵蒂冈", "enName": "Vatican City State",
|
||||||
|
"pyFirst": "F"},
|
||||||
|
{"areaKey": "NC", "chsName": "新喀里多尼亚", "enName": "New Caledonia", "pyFirst": "X"},
|
||||||
|
{"areaKey": "MT", "chsName": "马尔他", "enName": "Malta", "pyFirst": "M"},
|
||||||
|
{"areaKey": "BG", "chsName": "保加利亚", "enName": "Bulgaria", "pyFirst": "B"},
|
||||||
|
{"areaKey": "ES", "chsName": "西班牙", "enName": "Spain", "pyFirst": "X"},
|
||||||
|
{"areaKey": "CI", "chsName": "象牙海岸", "enName": "Ivory Coast", "pyFirst": "X"},
|
||||||
|
{"areaKey": "IE", "chsName": "爱尔兰", "enName": "Ireland", "pyFirst": "A"},
|
||||||
|
{"areaKey": "BZ", "chsName": "伯利兹城", "enName": "Belize", "pyFirst": "B"},
|
||||||
|
{"areaKey": "SZ", "chsName": "斯威士兰", "enName": "Swaziland", "pyFirst": "S"},
|
||||||
|
{"areaKey": "SV", "chsName": "萨尔瓦多", "enName": "EI Salvador", "pyFirst": "S"},
|
||||||
|
{"areaKey": "GE", "chsName": "格鲁吉亚", "enName": "Georgia", "pyFirst": "G"},
|
||||||
|
{"areaKey": "SD", "chsName": "苏丹", "enName": "Sudan", "pyFirst": "S"},
|
||||||
|
{"areaKey": "PR", "chsName": "波多黎各", "enName": "Puerto Rico", "pyFirst": "B"},
|
||||||
|
{"areaKey": "FJ", "chsName": "斐济", "enName": "Fiji", "pyFirst": "F"},
|
||||||
|
{"areaKey": "NL", "chsName": "荷兰", "enName": "Netherlands", "pyFirst": "H"},
|
||||||
|
{"areaKey": "UG", "chsName": "乌干达", "enName": "Uganda", "pyFirst": "W"},
|
||||||
|
{"areaKey": "HU", "chsName": "匈牙利", "enName": "Hungary", "pyFirst": "X"},
|
||||||
|
{"areaKey": "TC", "chsName": "特克斯和凯科斯群岛", "enName": "Turks and Caicos Islands",
|
||||||
|
"pyFirst": "T"}]}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ class v1_private_user(plugins.ConfServerApp):
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkAgreementBatch", self.handle_checkAgreement,name="v1_user_checkAgreementBatch"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/checkAgreementBatch", self.handle_checkAgreement,name="v1_user_checkAgreementBatch"),
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getUserAccountInfo", authhandler.getUserAccountInfo,name="v1_user_getUserAccountInfo"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getUserAccountInfo", authhandler.getUserAccountInfo,name="v1_user_getUserAccountInfo"),
|
||||||
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getUserMenuInfo", self.handle_getUserMenuInfo,name="v1_user_getUserMenuInfo"),
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/getUserMenuInfo", self.handle_getUserMenuInfo,name="v1_user_getUserMenuInfo"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/changeArea", self.handle_changeArea, name="v1_user_changeArea"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/queryChangeArea", self.handle_changeArea, name="v1_user_queryChangeArea"),
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/acceptAgreementBatch", self.handle_acceptAgreementBatch, name="v1_user_acceptAgreementBatch"),
|
||||||
# Direct register from app:
|
# Direct register from app:
|
||||||
# /{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/directRegister
|
# /{apiversion}/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/user/directRegister
|
||||||
#Register by email
|
#Register by email
|
||||||
|
|
@ -144,5 +147,37 @@ class v1_private_user(plugins.ConfServerApp):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception("{}".format(e))
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_changeArea(self, request):
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": {
|
||||||
|
"isNeedReLogin": "N"
|
||||||
|
},
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
async def handle_acceptAgreementBatch(self, request):
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": None,
|
||||||
|
"msg": "操作成功",
|
||||||
|
"success": True,
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
plugin = v1_private_user()
|
plugin = v1_private_user()
|
||||||
|
|
||||||
|
|
|
||||||
58
bumper/plugins/bumper_confserver_v1_private_userSetting.py
Normal file
58
bumper/plugins/bumper_confserver_v1_private_userSetting.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from aiohttp import web
|
||||||
|
import logging
|
||||||
|
import bumper
|
||||||
|
from bumper import plugins
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class v1_private_userSetting(plugins.ConfServerApp):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.name = "v1_private_userSetting"
|
||||||
|
self.plugin_type = "sub_api"
|
||||||
|
self.sub_api = "api_v1"
|
||||||
|
|
||||||
|
self.routes = [
|
||||||
|
web.route("*", "/private/{country}/{language}/{devid}/{apptype}/{appversion}/{devtype}/{aid}/userSetting/getSuggestionSetting", self.handle_getSuggestionSetting,name="v1_userSetting_getSuggestionSetting"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.get_milli_time = bumper.ConfServer.ConfServer_GeneralFunctions().get_milli_time
|
||||||
|
|
||||||
|
async def handle_getSuggestionSetting(self, request):
|
||||||
|
try:
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"code": bumper.RETURN_API_SUCCESS,
|
||||||
|
"data": {
|
||||||
|
"acceptSuggestion": "Y",
|
||||||
|
"itemList": [
|
||||||
|
{
|
||||||
|
"name": "Aktionen/Angebote/Ereignisse",
|
||||||
|
"settingKey": "MARKETING",
|
||||||
|
"val": "Y"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benutzerbefragung",
|
||||||
|
"settingKey": "QUESTIONNAIRE",
|
||||||
|
"val": "Y"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Produkt-Upgrade/Hilfe für Benutzer",
|
||||||
|
"settingKey": "INTRODUCTION",
|
||||||
|
"val": "Y"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": "操作成功",
|
||||||
|
"time": self.get_milli_time(datetime.utcnow().timestamp()),
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("{}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
plugin = v1_private_userSetting()
|
||||||
|
|
@ -4,3 +4,7 @@ ecouser.net
|
||||||
*.ecouser.net
|
*.ecouser.net
|
||||||
ecovacs.net
|
ecovacs.net
|
||||||
*.ecovacs.net
|
*.ecovacs.net
|
||||||
|
*.ww.ecouser.net
|
||||||
|
*.dc-eu.ww.ecouser.net
|
||||||
|
*.dc.ww.ecouser.net
|
||||||
|
*.area.ww.ecouser.net
|
||||||
|
|
@ -53,9 +53,9 @@ I get it, you don't trust create_certs and want to do it manually. The easiest
|
||||||
|
|
||||||
### Create a Root CA
|
### Create a Root CA
|
||||||
|
|
||||||
1. Create csrconfig.txt for use in later commands
|
1. Create csrconfig_ca.txt for use in later commands
|
||||||
|
|
||||||
***csrconfig.txt***
|
***csrconfig_ca.txt***
|
||||||
````
|
````
|
||||||
[ req ]
|
[ req ]
|
||||||
default_md = sha256
|
default_md = sha256
|
||||||
|
|
@ -70,9 +70,9 @@ keyUsage=critical,keyCertSign,cRLSign
|
||||||
basicConstraints=critical,CA:true,pathlen:1
|
basicConstraints=critical,CA:true,pathlen:1
|
||||||
````
|
````
|
||||||
|
|
||||||
1. Create certconfig.txt for use in later commands
|
1. Create certconfig_ca.txt for use in later commands
|
||||||
|
|
||||||
***certconfig.txt***
|
***certconfig_ca.txt***
|
||||||
````
|
````
|
||||||
[ req ]
|
[ req ]
|
||||||
default_md = sha256
|
default_md = sha256
|
||||||
|
|
@ -91,21 +91,21 @@ basicConstraints=critical,CA:true,pathlen:1
|
||||||
|
|
||||||
1. Generate the RSA private key
|
1. Generate the RSA private key
|
||||||
|
|
||||||
`openssl genpkey -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out priv.key`
|
`openssl genrsa -out ca.key 4096`
|
||||||
|
|
||||||
1. Create the CSR
|
1. Create the CSR
|
||||||
|
|
||||||
`openssl req -new -nodes -key priv.key -config csrconfig.txt -out cert.csr`
|
`openssl req -new -nodes -key ca.key -config csrconfig_ca.txt -out ca.csr`
|
||||||
|
|
||||||
1. Self-sign your CSR
|
1. Self-sign your CSR
|
||||||
|
|
||||||
`openssl req -x509 -nodes -in cert.csr -days 3650 -key priv.key -config certconfig.txt -extensions req_ext -out cert.crt`
|
`openssl req -x509 -nodes -in ca.csr -days 1095 -key ca.key -config certconfig_ca.txt -extensions req_ext -out ca.crt`
|
||||||
|
|
||||||
### Create the Server Certificate
|
### Create the Server Certificate
|
||||||
|
|
||||||
1. Create csrconfig.txt for use in later commands
|
1. Create csrconfig_bumper.txt for use in later commands
|
||||||
|
|
||||||
***csrconfig.txt***
|
***csrconfig_bumper.txt***
|
||||||
````
|
````
|
||||||
[ req ]
|
[ req ]
|
||||||
default_md = sha256
|
default_md = sha256
|
||||||
|
|
@ -127,11 +127,15 @@ DNS.2 = ecouser.net
|
||||||
DNS.3 = *.ecouser.net
|
DNS.3 = *.ecouser.net
|
||||||
DNS.4 = ecovacs.net
|
DNS.4 = ecovacs.net
|
||||||
DNS.5 = *.ecovacs.net
|
DNS.5 = *.ecovacs.net
|
||||||
|
DNS.6 = *.ww.ecouser.net
|
||||||
|
DNS.7 = *.dc-eu.ww.ecouser.net
|
||||||
|
DNS.8 = *.dc.ww.ecouser.net
|
||||||
|
DNS.9 = *.area.ww.ecouser.net
|
||||||
````
|
````
|
||||||
|
|
||||||
1. Create certconfig.txt for use in later commands
|
1. Create certconfig_bumper.txt for use in later commands
|
||||||
|
|
||||||
***certconfig.txt***
|
***certconfig_bumper.txt***
|
||||||
````
|
````
|
||||||
[ req ]
|
[ req ]
|
||||||
default_md = sha256
|
default_md = sha256
|
||||||
|
|
@ -155,19 +159,23 @@ DNS.2 = ecouser.net
|
||||||
DNS.3 = *.ecouser.net
|
DNS.3 = *.ecouser.net
|
||||||
DNS.4 = ecovacs.net
|
DNS.4 = ecovacs.net
|
||||||
DNS.5 = *.ecovacs.net
|
DNS.5 = *.ecovacs.net
|
||||||
|
DNS.6 = *.ww.ecouser.net
|
||||||
|
DNS.7 = *.dc-eu.ww.ecouser.net
|
||||||
|
DNS.8 = *.dc.ww.ecouser.net
|
||||||
|
DNS.9 = *.area.ww.ecouser.net
|
||||||
````
|
````
|
||||||
|
|
||||||
1. Generate the RSA private key
|
1. Generate the RSA private key
|
||||||
|
|
||||||
`openssl genpkey -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out priv.key`
|
`openssl genrsa -out bumper.key 4096`
|
||||||
|
|
||||||
1. Create the CSR
|
1. Create the CSR
|
||||||
|
|
||||||
`openssl req -new -nodes -key priv.key -config csrconfig.txt -out cert.csr`
|
`openssl req -new -nodes -key bumper.key -config csrconfig_bumper.txt -out bumper.csr`
|
||||||
|
|
||||||
1. Sign your CSR with a root CA cert
|
1. Sign your CSR with a root CA cert
|
||||||
|
|
||||||
`openssl x509 -req -in cert.csr -days 3650 -CA ca.crt -CAkey priv.key -extfile certconfig.txt -extensions req_ext -CAserial /tmp/tmp-10593TSH1OlVSxC7C -CAcreateserial -out cert.crt`
|
`openssl x509 -req -in bumper.csr -days 365 -CA ca.crt -CAkey ca.key -extfile certconfig_bumper.txt -extensions req_ext -CAcreateserial -out bumper.crt`
|
||||||
|
|
||||||
## Using a Custom CA/Self
|
## Using a Custom CA/Self
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ If overriding DNS for the top-level domains isn't an option, you'll need to conf
|
||||||
**Note:** Depending on country, your phone/robot may be using a different domain. Most of these domains contain country-specific placeholders.
|
**Note:** Depending on country, your phone/robot may be using a different domain. Most of these domains contain country-specific placeholders.
|
||||||
|
|
||||||
Not all domains have been documented at this point, and this list will be updated as more are identified/seen. The preferred way to ensure Bumper works is to override the full domains as above.
|
Not all domains have been documented at this point, and this list will be updated as more are identified/seen. The preferred way to ensure Bumper works is to override the full domains as above.
|
||||||
|
**Note:** The app dynamically gets the required domains from the endpoint `api/appsvr/service/list` and therefore ecovacs can use different domains for different models.
|
||||||
|
|
||||||
Replacement Examples:
|
Replacement Examples:
|
||||||
|
|
||||||
|
|
@ -46,6 +47,7 @@ Replacement Examples:
|
||||||
| `eco-{countrycode}-api.ecovacs.com` | Used for Login |
|
| `eco-{countrycode}-api.ecovacs.com` | Used for Login |
|
||||||
| `gl-{countrycode}-api.ecovacs.com` | Used by EcoVacs Home app |
|
| `gl-{countrycode}-api.ecovacs.com` | Used by EcoVacs Home app |
|
||||||
| `gl-{countrycode}-openapi.ecovacs.com` | Used by EcoVacs Home app |
|
| `gl-{countrycode}-openapi.ecovacs.com` | Used by EcoVacs Home app |
|
||||||
|
| `portal.ecouser.net` | Used for Login and Rest API |
|
||||||
| `portal-{countrycode}.ecouser.net` | Used for Login and Rest API |
|
| `portal-{countrycode}.ecouser.net` | Used for Login and Rest API |
|
||||||
| `portal-{region}.ecouser.net` | Used for Login and Rest API |
|
| `portal-{region}.ecouser.net` | Used for Login and Rest API |
|
||||||
| `portal-ww.ecouser.net` | Used for various Rest APIs |
|
| `portal-ww.ecouser.net` | Used for various Rest APIs |
|
||||||
|
|
@ -59,4 +61,11 @@ Replacement Examples:
|
||||||
| `recommender.ecovacs.com` | Used by Ecovacs Home app |
|
| `recommender.ecovacs.com` | Used by Ecovacs Home app |
|
||||||
| `bigdata-international.ecovacs.com` | Telemetry/tracking |
|
| `bigdata-international.ecovacs.com` | Telemetry/tracking |
|
||||||
| `bigdata-northamerica.ecovacs.com` | Telemetry/tracking |
|
| `bigdata-northamerica.ecovacs.com` | Telemetry/tracking |
|
||||||
|
| `bigdata-europe.ecovacs.com` | Telemetry/tracking |
|
||||||
| `bigdata-{unknown regions}.ecovacs.com` | Telemetry/tracking |
|
| `bigdata-{unknown regions}.ecovacs.com` | Telemetry/tracking |
|
||||||
|
| `api-app.ww.ecouser.net` | Api for App (v2+) |
|
||||||
|
| `api-app.dc-{region}.ww.ecouser.net` | Api for App (v2+) |
|
||||||
|
| `users-base.dc-{region}.ww.ecouser.net` | Accounts for App (v2+) |
|
||||||
|
| `jmq-ngiot-{region}.dc.ww.ecouser.net` | MQTT for App (v2+) |
|
||||||
|
| `api-rop.dc-{region}.ww.ecouser.net` | App (v2+) |
|
||||||
|
| `jmq-ngiot-{region}.area.ww.ecouser.net`| App (v2+) |
|
||||||
|
|
@ -42,3 +42,13 @@ Optionally you can map existing directories for logs, data, and certs.
|
||||||
````
|
````
|
||||||
docker run -it -e "BUMPER_ANNOUNCE_IP=X.X.X.X" -p 443:443 -p 8007:8007 -p 8883:8883 -p 5223:5223 -v /home/user/bumper/data:/bumper/data --name bumper bmartin5692/bumper
|
docker run -it -e "BUMPER_ANNOUNCE_IP=X.X.X.X" -p 443:443 -p 8007:8007 -p 8883:8883 -p 5223:5223 -v /home/user/bumper/data:/bumper/data --name bumper bmartin5692/bumper
|
||||||
````
|
````
|
||||||
|
|
||||||
|
# Docker-compose
|
||||||
|
|
||||||
|
A docker-compose example can be found in the ["example" folder](https://github.com/bmartin5692/bumper/tree/master/example/docker-compose).
|
||||||
|
|
||||||
|
The docker-compose starts two services:
|
||||||
|
- bumper itself
|
||||||
|
- nginx proxy, which redirects MQTT traffic on port `443` to port `8883`
|
||||||
|
|
||||||
|
The redirection is required as the app v2+ and robots with a newer firmware are connecting to the mqtt server on port 433.
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,4 @@ Bumper has a number of environment variables to help with custom deployments and
|
||||||
| BUMPER_LOGS | {full path to logs directory} | The directory where logs should be stored |
|
| BUMPER_LOGS | {full path to logs directory} | The directory where logs should be stored |
|
||||||
| BUMPER_DATA | {full path to data directory} | The directory where persistent data should be stored (bumper.db) |
|
| BUMPER_DATA | {full path to data directory} | The directory where persistent data should be stored (bumper.db) |
|
||||||
| BUMPER_DEBUG | true | Run Bumper with debug mode/logging |
|
| BUMPER_DEBUG | true | Run Bumper with debug mode/logging |
|
||||||
|
| LOG_TO_STDOUT | true | Instead of logging to logs/, logs to to STDOUT |
|
||||||
45
example/docker-compose/docker-compose.yaml
Normal file
45
example/docker-compose/docker-compose.yaml
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
version: "3.6"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
bumper:
|
||||||
|
internal: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
depends_on:
|
||||||
|
- bumper
|
||||||
|
image: nginx:alpine
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
bumper:
|
||||||
|
ports:
|
||||||
|
- 443:443
|
||||||
|
- 5223:5223
|
||||||
|
- 8007:8007
|
||||||
|
- 8883:8883
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- ./nginx/:/etc/nginx:ro # See config file below
|
||||||
|
|
||||||
|
bumper:
|
||||||
|
image: bmartin5692/bumper
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
bumper:
|
||||||
|
|
||||||
|
environment:
|
||||||
|
PUID: 1000
|
||||||
|
PGID: 1000
|
||||||
|
TZ: Europe/Rome
|
||||||
|
BUMPER_ANNOUNCE_IP: XXX # Insert your IP
|
||||||
|
BUMPER_LISTEN: 0.0.0.0
|
||||||
|
# BUMPER_DEBUG: "true"
|
||||||
|
LOG_TO_STDOUT: "true"
|
||||||
|
volumes:
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- ./config:/bumper/data
|
||||||
|
- ./certs:/bumper/certs
|
||||||
41
example/docker-compose/nginx/nginx.conf
Normal file
41
example/docker-compose/nginx/nginx.conf
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
error_log stderr;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events { }
|
||||||
|
|
||||||
|
stream {
|
||||||
|
resolver 127.0.0.11 ipv6=off; #docker dns server
|
||||||
|
map_hash_bucket_size 64;
|
||||||
|
|
||||||
|
map $ssl_preread_server_name $internalport {
|
||||||
|
# redirect all requests, which contain "mq" in the SNI -> MQTT
|
||||||
|
~^.*(mq).*\.eco(vacs|user)\.(net|com)$ 8883;
|
||||||
|
|
||||||
|
# the rest of eco(user|vacs) requests
|
||||||
|
~^.*eco(vacs|user)\.(net|com)$ 443;
|
||||||
|
|
||||||
|
# mapping default to MQTT as the bots are connecting directly to the ip without SNI
|
||||||
|
default 8883;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443;
|
||||||
|
ssl_preread on;
|
||||||
|
proxy_pass bumper:$internalport;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 5223;
|
||||||
|
proxy_pass bumper:5223;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8007;
|
||||||
|
proxy_pass bumper:8007;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8883;
|
||||||
|
proxy_pass bumper:8883;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
tests/test_models.py
Normal file
14
tests/test_models.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
from bumper import OAuth
|
||||||
|
|
||||||
|
|
||||||
|
def test_oauth():
|
||||||
|
userId = "test"
|
||||||
|
o_auth = OAuth.create_new(userId)
|
||||||
|
assert o_auth is not None
|
||||||
|
assert o_auth.userId == userId
|
||||||
|
assert o_auth.access_token is not None
|
||||||
|
assert o_auth.expire_at is not None
|
||||||
|
assert o_auth.refresh_token is not None
|
||||||
|
|
||||||
|
data = o_auth.toResponse()
|
||||||
|
assert data is not None
|
||||||
Loading…
Add table
Add a link
Reference in a new issue