# -*- coding: utf-8 -*- #!/usr/bin/env python import os from typing import List from functools import partial from dotenv import load_dotenv from passlib.context import CryptContext load_dotenv('.env.simulator') class CMD(object): HAND_SHAKE = 200 GET_INFO = 201 CONFIG_DEVICE = 202 #: init mobile payment, publish by app MOBILE_PAY_INIT = 203 #: finish mobile payment, publish by the device smartbox MOBILE_PAY_FIN = 204 PUT_COIN = 205 HEARTBEAT = 207 OFFLINE = 208 DEVICE_TOPIC_PREFIX = 'smart_box' SERVER_TOPIC_PREFIX = 'server' MQTT_QOS = 0 MQTT_QOS1 = 1 MQTT_HOSTNAME = os.environ.get('MQTT_HOSTNAME', '127.0.0.1') MQTT_PORT = int(os.environ.get('MQTT_PORT', 1999)) MQTT_BROKER_URL = os.environ.get('MQTT_BROKER_URL', 'localhost') MQTT_BROKER_SCHEME = os.environ.get('MQTT_BROKER_SCHEME', 'tcp') DEFAULT_DEVICE_IMEI = os.environ.get('DEFAULT_DEVICE_IMEI') # constants SINGLE_LEVEL_ALL = '+' MULTI_LEVEL_ALL = '#' def get_topic(prefix, imei, cmd): # type: (str, str, int)->str return '{prefix}/{imei}/{cmd}'.format(prefix=prefix, imei=imei, cmd=cmd) def get_device_topic(imei, cmd): # type: (str, int)->str return get_topic(prefix=DEVICE_TOPIC_PREFIX, imei=imei, cmd=cmd) def get_server_topic(imei, cmd): # type: (str, int)->str return get_topic(prefix=SERVER_TOPIC_PREFIX, imei=imei, cmd=cmd) #: topics handshake_topic = partial(get_server_topic, cmd=CMD.HAND_SHAKE) get_info_topic = partial(get_server_topic, cmd=CMD.GET_INFO) config_device_topic = partial(get_server_topic, cmd=CMD.CONFIG_DEVICE) mobile_pay_init_topic = partial(get_server_topic, cmd=CMD.MOBILE_PAY_INIT) mobile_pay_finish_topic = partial(get_server_topic, cmd=CMD.MOBILE_PAY_FIN) put_coin_topic = partial(get_server_topic, cmd=CMD.PUT_COIN) heartbeat_topic = partial(get_server_topic, cmd=CMD.HEARTBEAT) offline_topic = partial(get_server_topic, cmd=CMD.OFFLINE) SERVER_TOPICS = [ get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.HAND_SHAKE), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.GET_INFO), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.CONFIG_DEVICE), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.MOBILE_PAY_INIT), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.MOBILE_PAY_FIN), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.PUT_COIN), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.HEARTBEAT), get_server_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.OFFLINE), ] # type: List[str] DEVICE_TOPICS = [ get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.HAND_SHAKE), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.GET_INFO), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.CONFIG_DEVICE), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.MOBILE_PAY_INIT), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.MOBILE_PAY_FIN), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.PUT_COIN), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.HEARTBEAT), get_device_topic(imei=SINGLE_LEVEL_ALL, cmd=CMD.OFFLINE), ] DEV_STATUS_IDLE = 0 DEV_STATUS_BUSY = 1 DEV_OFFLINE = 0 DEV_ONLINE = 1 class BaseProtocolHandler(object): def handle(self, payload): methname = 'handle_{cmd}'.format(cmd=payload['cmd']) method = getattr(self, methname) if not method: raise RuntimeError('no command {} handler found!') else: method(payload) #: encryption pwd_context = CryptContext( schemes=["pbkdf2_sha256"], default="pbkdf2_sha256", pbkdf2_sha256__default_rounds=30000 ) def encrypt_password(password): return pwd_context.hash(password) def check_encrypted_password(password, hashed): return pwd_context.verify(password, hashed)