Example #1
0
def keep_alive():
    if not request.is_json:
        log.warn("参数错误...")
        return fail(HTTP_OK, u"need application/json!!")

    record_key = request.json.get('token')
    if record_key is None:
        return fail(HTTP_OK, u"not have token!!!")

    device_code = request.json.get('device_code')
    if device_code is None:
        log.error(
            "无法保持心跳, 没有传入device_code: record_key = {}".format(record_key))
        return fail(HTTP_OK, u"not have device_code!!!")

    # 保持心跳
    DeviceService.keep_device_heart(device_code)

    charging = redis_cache_client.get(record_key)
    if charging is None:
        return success({
            "status": 0,
            "msg": "keepalive failed!reason:token invalid"
        })

    # 获得keep_alive_key 更新最新存活时间
    user_online_key = RedisClient.get_user_online_key(record_key)

    # 设置最新存活时间 最多存在五分钟
    redis_cache_client.setex(user_online_key, settings.MAX_LOST_HEART_TIME,
                             int(time.time()))

    return success({
        "status": 1,
        "msg": "keepalive success",
        "data": WindowsService.get_current_time_charging(charging)
    })
Example #2
0
    def do_online(user, device, charge_mode):
        log.info("用户还未上机可以进行上机: user_id = {} device_id = {}".format(
            user.id, device.id))
        record, is_success = UseRecord.create(user.id, device.id,
                                              device.address.province,
                                              device.address.city,
                                              device.address.area,
                                              device.address.location)
        if not is_success:
            return False

        # 判断是否已经在redis中进行记录
        record_key = RedisClient.get_record_key(user.id, device.id)
        # 获得用户上线key
        user_key = RedisClient.get_user_key(user.id)
        # 获得设备上线key
        device_key = RedisClient.get_device_key(device.id)
        # 获得当前设备token
        device_code_key = RedisClient.get_device_code_key(device.device_code)

        # 获得keep_alive_key 更新最新存活时间
        user_online_key = RedisClient.get_user_online_key(record_key)

        log.info(
            "当前上机时间: user_id:{} device_id:{} record_id:{} ctime:{}".format(
                user.id, device.id, record.id,
                record.ctime.strftime('%Y-%m-%d %H:%M:%S')))

        # 获得计费结构体
        charging = record.to_charging()
        # 得到计费方式
        charging['charge_mode'] = charge_mode
        # 得到当前用户总额
        charging['balance_account'] = user.balance_account
        # 填充设备机器码
        charging['device_code'] = device.device_code
        # 填充用户的openid
        charging['openid'] = user.openid

        # charging = {
        #     'id': self.id,
        #     'user_id': self.user_id,
        #     'device_id': self.device_id,
        #     # 花费金额数目
        #     'cost_money': self.cost_money,
        #     # 上机时间
        #     'ctime': self.ctime.strftime('%Y-%m-%d %H:%M:%S'),
        #     # 更新时间,主要用户同步计费
        #     'utime': self.utime.strftime('%Y-%m-%d %H:%M:%S'),
        #     # 已经上机时间
        #     'cost_time': self.cost_time,
        #     # 计费方式 目前默认 5分钱/分钟
        #     'charge_mode': 5,
        #     # 当前用户余额
        #     'balance_account': 10000,
        #     # 设备机器码
        #     'device_code': 'xx-xx-xx-xx-xx-xx',
        # }

        charge_str = json.dumps(charging)

        # 操作redis 需要加锁
        lock = DistributeLock(user_key, redis_cache_client)
        try:
            lock.acquire()

            # 设置设备当前使用状态
            if not DeviceService.set_device_status(device,
                                                   DeviceStatus.STATUE_BUSY):
                log.error("设置设备状态失败, 上机异常!!!")
                return False

            # 开始上线 把上线信息存储redis
            redis_cache_client.set(record_key, charge_str)
            redis_cache_client.set(user_key, record_key)
            redis_cache_client.set(device_key, record_key)
            # 根据设备机器码获得记录token
            redis_cache_client.set(device_code_key, record_key)
            # 设置最新存活时间 最多存活五分钟
            import time
            redis_cache_client.setex(user_online_key,
                                     settings.MAX_LOST_HEART_TIME,
                                     int(time.time()))

            is_success = True
        except Exception as e:
            is_success = False
            log.exception(e)
        finally:
            lock.release()

        # 判断上线是否成功
        if is_success:
            # 发送上线通知
            TemplateService.online(user.openid, record.ctime, device.address,
                                   user.balance_account, charge_mode)

        return True
Example #3
0
    def do_offline(charging):

        # offline_lock_key = None
        lock = None
        if charging is None:
            log.error("charging is None 下机异常!!")
            return fail(HTTP_OK, u"下机异常!")

        try:
            charge_dict = json.loads(charging)
            record_id = charge_dict.get('id')
            user_id = charge_dict.get('user_id')
            device_id = charge_dict.get('device_id')
            charge_mode = charge_dict.get('charge_mode')
            device_code = charge_dict.get('device_code')
            openid = charge_dict.get('openid')
            log.info(
                "当前下线信息: user_id = {} device_id = {} charge_mode = {} device_code = {}"
                .format(user_id, device_id, charge_mode, device_code))

            # 获得用户上线key
            user_key = RedisClient.get_user_key(user_id)

            #  下机需要加锁
            lock = DistributeLock(user_key, redis_cache_client)

            log.info("开始加锁下机: user_key = {}".format(user_key))

            # 加锁下机
            lock.acquire()

            # 判断是否已经在redis中进行记录
            record_key = RedisClient.get_record_key(user_id, device_id)
            if redis_cache_client.get(record_key) is None:
                log.warn("当前用户或者设备已经下机: user_id = {} device_id = {}".format(
                    user_id, device_id))
                return success({'status': 1, 'msg': 'logout successed!'})

            # 结账下机
            result, record, user = WindowsService.cal_offline(
                user_id=user_id,
                device_id=device_id,
                record_id=record_id,
                charge_mode=charge_mode)
            if not result:
                log.error(
                    "下机扣费失败: user_id = {} device_id = {} charge_mode = {}".
                    format(user_id, device_id, charge_mode))
                return fail(HTTP_OK, u"下机失败!")

            # 获得设备上线key
            device_key = RedisClient.get_device_key(device_id)
            # 获得当前设备token
            device_code_key = RedisClient.get_device_code_key(device_code)
            # 获得keep_alive_key 更新最新存活时间
            user_online_key = RedisClient.get_user_online_key(record_key)

            # 从redis中删除上机记录
            redis_cache_client.delete(record_key)
            redis_cache_client.delete(user_key)
            redis_cache_client.delete(device_key)
            redis_cache_client.delete(device_code_key)
            redis_cache_client.delete(user_online_key)
            is_success = True
        except Exception as e:
            log.error("数据解析失败: {}".format(charging))
            log.exception(e)
            return fail(HTTP_OK, u"数据解析失败!!")
        finally:
            # 解锁
            if lock is not None:
                lock.release()
                log.info("下机完成: lock_key = {}".format(lock.lock_key))

        # 如果成功则进行下机提醒
        if is_success and openid is not None:
            TemplateService.offline(openid, record, user.balance_account)

        log.info("下机成功: user_id = {} device_id = {}".format(
            user_id, device_id))
        return success({'status': 1, 'msg': 'logout successed!'})
def do_charging(record_key_list):
    if not isinstance(record_key_list, list):
        log.error("当前传入参数不正确: type = {}".format(type(record_key_list)))
        return

    if len(record_key_list) <= 0:
        log.info("当前没有上线用户,不需要计费...")
        return

    # 开始针对用户进行扣费
    for record_key in record_key_list:

        charge_str = cache_client.get(record_key)
        if charge_str is None:
            log.info("当前用户已经下线,不需要再计费: record_key = {}".format(record_key))
            continue

        try:
            charge_dict = json.loads(charge_str)

            user_id = charge_dict.get('user_id')
            if user_id is None:
                log.error("没有关键信息 user_id: charge_str = {}".format(charge_str))
                continue

            device_id = charge_dict.get('device_id')
            if device_id is None:
                log.error(
                    "没有关键信息 device_id: charge_str = {}".format(charge_str))
                continue

            record_key = RedisClient.get_record_key(user_id, device_id)

            # 判断是否已经有5分钟没有收到心跳
            user_online_key = RedisClient.get_user_online_key(record_key)
            last_timestamp = cache_client.get(user_online_key)
            if last_timestamp is None:
                log.info(
                    "没有收到任何心跳信息, 强制下机, 当前上线用户没有最后存活时间: user_id = {} device_id = {}"
                    .format(user_id, device_id))
                # 执行下机流程
                if WindowsService.do_offline_order(record_key):
                    log.info("没有收到任何心跳信息,强制下机完成: record_key = {}".format(
                        record_key))
                else:
                    log.error("强制下机失败: record_key = {}".format(record_key))
                continue

            # # 获得当前时间戳
            # last_timestamp = int(last_timestamp)
            # now_timestamp = int(time.time())
            #
            # # 如果当前丢失心跳的时间超过阈值,则默认离线,需要下机
            # if now_timestamp - last_timestamp >= settings.MAX_LOST_HEART_TIME:
            #     # 下机
            #     log.info("当前用户与机器没有收到任何心跳信息,强制下机: record_key = {} last_timestamp = {}".format(
            #         record_key, last_timestamp))
            #     # 执行下机流程
            #     do_offline_order(record_key)
            #     log.info("没有收到任何心跳信息,强制下机完成: record_key = {}".format(record_key))
            #     continue

            # charge_dict = {
            #     'id': self.id,
            #     'user_id': self.user_id,
            #     'device_id': self.device_id,
            #     # 花费金额数目
            #     'cost_money': self.cost_money,
            #     # 上机时间
            #     'ctime': self.ctime.strftime('%Y-%m-%d %H:%M:%S'),
            #     # 更新时间,主要用户同步计费
            #     'utime': self.utime.strftime('%Y-%m-%d %H:%M:%S'),
            #     # 已经上机时间
            #     'cost_time': self.cost_time,
            #     # 计费方式 目前默认 5分钱/分钟
            #     'charge_mode': 5,
            #     # 当前用户余额
            #     'balance_account': 10000,
            #     # 设备机器码
            #     'device_code': 'xx-xx-xx-xx-xx-xx',
            # }
            # 如果用户余额不足上机了,则强制下机
            ctime = charge_dict.get('ctime')
            if ctime is None:
                log.error("没有关键信息 ctime: charge_str = {}".format(charge_str))
                continue

            charge_mode = charge_dict.get('charge_mode')
            if charge_mode is None:
                log.error(
                    "没有关键信息 charge_mode: charge_str = {}".format(charge_str))
                continue

            balance_account = charge_dict.get('balance_account')
            if balance_account is None:
                log.error("没有关键信息 balance_account: charge_str = {}".format(
                    charge_str))
                continue

            now_timestamp = int(time.time())
            start_time = int(
                time.mktime(time.strptime(ctime, "%Y-%m-%d %H:%M:%S")))
            cost_time = cal_cost_time(now_timestamp - start_time)
            cost_money = cost_time * int(charge_mode)
            # 如果使用的费用超额半分钟的费用,则强制下机
            if cost_money - balance_account >= 0.75 * int(charge_mode):
                log.info(
                    "当前用户余额不足,强制下机: record_key = {} balance_account = {} "
                    "cost_time = {}分钟 cost_money = {} start_time = {} now_time = {}"
                    .format(record_key, balance_account, cost_time, cost_money,
                            start_time, now_timestamp))
                # 执行下机流程
                if WindowsService.do_offline_order(record_key):
                    log.info(
                        "当前用户余额不足, 强制下机完成: record_key = {}".format(record_key))
                else:
                    log.error("强制下机失败: record_key = {}".format(record_key))
                continue

        except Exception as e:
            log.error("当前存入的计费数据格式不正确: charge_str = {}".format(charge_str))
            log.exception(e)
            continue