Пример #1
0
class TbIscoutTask(TbSqliteBase):
    __tb_iscouttask: SqliteTable = SqliteTable(
        "iscouttask",
        True,
        SqliteColumn(
            colname="ID",
            coltype="INTEGER",
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True,
        ).set_index_new(),
        SqliteColumn(
            colname="taskid", coltype="CHAR", length=50, nullable=False
        ).set_index_new(),
        SqliteColumn(
            colname="batchid", coltype="CHAR", length=50, nullable=False
        ).set_index_new(),
        SqliteColumn(colname="platform", coltype="CHAR", length=50, nullable=False),
        SqliteColumn(colname="clientid", coltype="CHAR", length=50, nullable=False),
        SqliteColumn(colname="source", coltype="CHAR", nullable=False),
        SqliteColumn(colname="objecttype", coltype="INT", nullable=False),
        SqliteColumn(colname="object", coltype="CHAR", nullable=False),
        SqliteColumn(colname="createtime", coltype="CHAR"),
        SqliteColumn(colname="cmdid", coltype="CHAR", length=50),
        SqliteColumn(colname="lastexecutetime", coltype="INT"),
        SqliteColumn(colname="failtimes", coltype="INT"),
        SqliteColumn(colname="successtimes", coltype="INT"),
        SqliteColumn(colname="taskstatus", coltype="INT"),
        SqliteColumn(colname="sequence", coltype="INT"),
        SqliteColumn(colname="periodnum", coltype="INT"),
    )
    databasename = "task"

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(
            self, TbIscoutTask.__tb_iscouttask._tbname, dbcfg, TbIscoutTask.databasename
        )

    def _append_tables(self):
        self._conn_mngr.append_table(TbIscoutTask.__tb_iscouttask)

    @table_locker(__tb_iscouttask._tbname)
    def query_iscout_task(self, conds: SqlConditions) -> list:
        """
        根据任务状态来取出task表的任务,
        根据不同的状态来查询不同的任务数据
        :param key:
        :param value:
        :return:
        """
        conn: SqliteConn = None
        res = []
        sql = """SELECT 
        taskid,
        batchid,
        iscouttask.platform,
        clientid,
        source,
        objecttype,
        object,
        createtime,
        cmdid,
        cmd,
        taskstatus,
        sequence,
        periodnum
        FROM iscouttask  LEFT OUTER JOIN idowncmd USING (cmdid)
        WHERE  {};""".format(
            conds.text_normal
        )

        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, conds.params)
                    res_data = c.fetchall()
                    if len(res_data) > 0:
                        res.extend(res_data)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query task according to the task status data problem,err:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return res

    def _get_task_update_sql(self, src: dict, new: IscoutTask):
        """拼接更新task的sql,并返回sqlparameters列表"""
        params: list = []
        sql = "UPDATE iscouttask SET taskstatus=?, "
        params.append(new.taskstatus.value)
        sql += "objecttype=?, "
        params.append(new._objecttype.value)
        sql += "object=?, "
        params.append(new._object)

        # 增加一个存入时间
        # sql += 'taskstarttime=?, '
        # params.append(new.taskstarttime)
        if not helper_str.is_none_or_empty(new.cmd_id):
            sql += "cmdid=?, "
            params.append(new.cmd_id)
        if not helper_str.is_none_or_empty(new.source):
            sql += "source=?, "
            params.append(new.source)
        if not helper_str.is_none_or_empty(new.periodnum):
            sql += "periodnum=?, "
            params.append(new.periodnum)

        sql = sql.rstrip().rstrip(",")
        sql += " WHERE batchid=? AND taskid=?"
        params.append(new.batchid)
        params.append(new.taskid)

        return sql, params

    @table_locker(__tb_iscouttask._tbname)
    def __count_iscouttask(self, taskid, batchid):
        """
        对数据库中的任务进行计数
        :param taskid:
        :param batchid:
        :return:
        """
        conn: SqliteConn = None
        res = []
        sql = """
        SELECT count(1) FROM iscouttask
        WHERE taskid=? AND batchid=?
        """
        par = (taskid, batchid)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    # conn._conn.row_factory = self._dict_factory
                    c = conn.cursor
                    c.execute(sql, par)
                    res_data = c.fetchall()
                    # print(res_data)
                    if len(res_data) > 0 and res_data[0][0] > 0:
                        res.extend(res_data)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query task according to the task status data problem\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return res

    @table_locker(__tb_iscouttask._tbname)
    def _updatesamebatchiddata(self, dt: IscoutTask):
        """
        在插入任务数据前,先检查iscouttask表
        是否有相同的batchid, 如果batchid相同那么就更新整条数据的状态
        :param dt:
        :return:
        """
        res = False
        conn: SqliteConn = None
        resdata = self.__count_iscouttask(dt.taskid, dt.batchid)
        if len(resdata) == 0:
            # 没有重复的id直接返回
            return False
        elif len(resdata) > 1:
            raise Exception(
                "The database has duplicated multiple skipids, please check the problem"
            )
        elif len(resdata) == 1:
            self._logger.info(f"Get same task, update scout task info")
            sql, par = self._get_task_update_sql(resdata[0], dt)
            try:
                for conn in self.connect_all(5):
                    try:
                        c = conn.cursor
                        result = c.execute(sql, par)
                        if (
                            result is not None and result.rowcount > 0
                        ):  # or len(result) < 1:
                            res = True
                            self._logger.info(f"Update task status success")
                    except Exception as ex:
                        conn._conn.rollback()
                        raise ex
                    else:
                        conn.commit()
                    finally:
                        if conn is not None:
                            conn.close()
                        if res:
                            break
            except Exception:
                self._logger.error(
                    f"There was a problem updating the iscouttask table\nerr:{traceback.format_exc()}"
                )
            finally:
                if conn is not None:
                    conn.close()
            return res

    @table_locker(__tb_iscouttask._tbname)
    def insert_iscouttask(self, dt: IscoutTask):
        """
        扫描任务目前是直接存入数据库的表
        如果是重复的任务那么就更新
        :param dt:
        :return:
        """
        conn: SqliteConn = None
        # 在插入数据前查询是否有相同的数据(目前只根据taskid查询),如果有相同的数据则不插入。
        repeat = self._updatesamebatchiddata(dt)
        if repeat:
            # 如果已经处理了重复的数据直接就结束了
            return
        sql = """
            INSERT INTO iscouttask(
            taskid,
            batchid,
            platform,
            clientid,
            source,
            objecttype,
            object,
            createtime,
            cmdid,
            taskstatus,
            sequence, 
            periodnum
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """
        params = (
            dt.taskid,
            dt.batchid,
            dt.platform,
            dt._clientid,
            dt.source,
            dt._objecttype.value,
            dt._object,
            dt.createtimestr,
            dt.cmd_id,
            dt.taskstatus.value,
            dt._sequence,
            dt.periodnum,
        )
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.execute(sql, params)
        except Exception:
            self._logger.error(
                f"There was a problem inserting data\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_iscouttask._tbname)
    def update_iscout_status(self, key: str, value: int, batchid, taskid):
        """
        更新iscouttask表的任务状态,根据batchid定位数据
        :param key:
        :param value:
        :param taskid:
        :return:
        """
        res = False
        conn: SqliteConn = None
        sql = """UPDATE iscouttask set {}=? where taskid=? and batchid=?
        """.format(
            key
        )
        pars = (value, taskid, batchid)
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (
                        result is not None and result.rowcount > 0
                    ):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"There was a problem inserting data, and duplicate data might have been inserted\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return

    @table_locker(__tb_iscouttask._tbname)
    def update_iscout_info(self, tsk: IscoutTask):
        """
        更新下载完成后task的信息,作用于iscout的循环下载
        :param tsk:
        :return:
        """
        res = False
        conn: SqliteConn = None
        sql = """UPDATE iscouttask set 
        lastexecutetime=?,
        failtimes=?,
        successtimes=?,
        sequence=?, 
        periodnum=?
        where taskid=? and batchid=?
        """
        pars = (
            tsk.lastexecutetime,
            tsk.failtimes,
            tsk.successtimes,
            tsk._sequence,
            tsk.periodnum,
            tsk.taskid,
            tsk.batchid,
        )
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (
                        result is not None and result.rowcount > 0
                    ):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"There was a problem inserting data\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return
Пример #2
0
class TbInputData(TbSqliteBase):
    __tb_inputdata: SqliteTable = SqliteTable(
        'inputdata',
        True,
        SqliteColumn(colname='ID',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='taskid',
                     coltype='CHAR',
                     length=50,
                     nullable=False).set_index_new(),
        SqliteColumn(colname='platform',
                     coltype='CHAR',
                     length=50,
                     nullable=False),
        SqliteColumn(colname='parenttaskid',
                     coltype='CHAR',
                     length=50,
                     nullable=False),
        SqliteColumn(colname='batchid',
                     coltype='CHAR',
                     length=50,
                     nullable=False),
        SqliteColumn(colname='parentbatchid',
                     coltype='CHAR',
                     length=50,
                     nullable=False),
        SqliteColumn(colname='input',
                     coltype='CHAR',
                     length=50,
                     nullable=False),
    )
    databasename = 'idownverify'

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbInputData.__tb_inputdata._tbname, dbcfg,
                              TbInputData.databasename)

    def _append_tables(self):
        self._conn_mngr.append_table(TbInputData.__tb_inputdata)

    @table_locker(__tb_inputdata._tbname)
    def input_insert(self, tsk: Task):
        """
        将交互输入的验证码存入数据库的inputdata表,
        验证码在取得后就删除在数据库中的记录
        :param tsk:
        :return:
        """
        conn: SqliteConn = None
        sql = '''INSERT INTO inputdata(
        taskid,
        platform,
        parenttaskid,
        batchid,
        parentbatchid,
        input
        )VALUES (?,?,?,?,?,?);
        '''
        params = (tsk.taskid, tsk.platform, tsk.parenttaskid, tsk.batchid,
                  tsk.parentbatchid, tsk.input)
        try:
            conn = self.connect_write()
            c = conn.cursor
            c.execute(sql, params)
        except Exception as err:
            self._logger.error(
                "There was a problem inserting data, err:{}.".format(err))
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
            return

    @table_locker(__tb_inputdata._tbname)
    def query_input(self, task: Task):
        """
        查询数据库的inputdata表,寻找验证码
        根据传入的taskid = parentid,
        查询完成后即时删除这条数据
        :param taskid:
        :return:
        """
        conn: SqliteConn = None
        input = None
        sql = '''SELECT * FROM inputdata
        WHERE platform=? AND parenttaskid=? AND parentbatchid=?;
        '''
        delsql = '''DELETE FROM inputdata
        WHERE platform=? AND parenttaskid=? AND parentbatchid=?;
        '''
        par = (task.platform, task.taskid, task.batchid)
        try:
            for conn in self.connect_all(5):
                conn._conn.row_factory = self._dict_factory
                c = conn._conn.cursor()
                c.execute(sql, par)
                allget: dict = c.fetchall()
                # 以防万一一个任务多个验证码
                if len(allget) > 1:
                    c.execute(delsql, par)
                    conn.commit()
                    conn.close()
                    self._logger.error(
                        "There are multiple verification codes for the same sms task. "
                        "All verification codes have been deleted. Please re-enter and send a valid verification code."
                    )
                    break
                if len(allget) == 0:
                    conn.close()
                    continue
                else:
                    res = allget[0]
                    # 获取验证码
                    input = res.get('input')
                    if input is not None:
                        c.execute(delsql, par)
                    break
        except:
            self._logger.error(
                f"Query verification code error,err:{traceback.format_exc()}")
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return input
Пример #3
0
class TbUnEXPDBData(TbSqliteBase):
    __tb_autodata: SqliteTable = SqliteTable(
        'undata',
        True,
        SqliteColumn(
            colname='Id',
            coltype='INTEGER',
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True).set_index_new(),
        SqliteColumn(colname='UniqueId', nullable=False).set_index_new(),
        SqliteColumn(colname='DownloadTime', coltype='DATETIME', nullable=False),
    )
    databasename = 'expdbdata'

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbUnEXPDBData.__tb_autodata._tbname, dbcfg, TbUnEXPDBData.databasename)

    def _append_tables(self):
        self._conn_mngr.append_table(TbUnEXPDBData.__tb_autodata)

    @table_locker(__tb_autodata._tbname)
    def insert_identify(self, unique_info):
        """
        存储数据的唯一标识
        :param unique_info:
        :return:
        """
        sql = '''
        INSERT INTO undata(
        UniqueId,
        DownloadTime
        )VALUES (?, ?)
        '''
        time_str = datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S')
        pars = (unique_info, time_str)
        res = False
        conn: SqliteConn = None
        try:
            conn: SqliteConn = self.connect_write(5)
            c = conn.cursor
            result = c.execute(sql, pars)
            if result is None or result.rowcount < 1:  # or len(result) < 1:
                res = False
            else:
                res = True
        except:
            self._logger.error(f"Insert auto unique data error,err:{traceback.format_exc()}")
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return res

    @table_locker(__tb_autodata._tbname)
    def identify_count(self, unique_info) -> bool:
        """
        查询数据库中是否已经下载了该数据
        :param unique_info:
        :return:
        """
        conn: SqliteConn = False
        res: bool = False
        sql = """select count(1) from undata where UniqueId=?"""
        pars = (unique_info,)
        try:
            for conn in self.connect_all(5):
                try:
                    conn: SqliteConn = conn
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    for c in result:
                        # print(c)
                        if len(c) > 0 and c[0] > 0:
                            res = True
                            break
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except:
            self._logger.error(f"Count auto unique data error,err:{traceback.format_exc()}")
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return res
Пример #4
0
class TbData(TbSqliteBase):
    __tb_data: SqliteTable = SqliteTable(
        'data',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='UniqueId', nullable=False).set_index_new(),
        SqliteColumn(colname='DataType', nullable=False),
        SqliteColumn(colname='AppType', coltype='INTEGER', nullable=False),
        # SqliteColumn(colname='Account', nullable=False),
        SqliteColumn(colname='DownloadTime',
                     coltype='DATETIME',
                     nullable=False),
    )
    databasename = 'idowndata'

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbData.__tb_data._tbname, dbcfg,
                              TbData.databasename)

    def _append_tables(self):
        self._conn_mngr.append_table(TbData.__tb_data)

    def _get_execute_sql_pars(self, data: FeedDataBase):
        if not isinstance(data, UniqueData):
            raise Exception("Param data is invalid.")
        sqls = []
        if not data._is_muti_seg:
            sql = self.__get_sql_pars(data, data._datatype.value)
            sqls.append(sql)
        else:
            for inner in data:
                sql = self.__get_sql_pars(inner, data._datatype.value)
                sqls.append(sql)
        return sqls

    def __get_sql_pars(self, data: UniqueData, datatype):
        pars = (
            data.get_uniqueid(),
            datatype,
            data._task.apptype,
            # data._task.account,
            helper_time.get_time_sec_tz(),
        )
        return pars

    def _dump_pars(self, pars):
        conn = None
        sql = '''
        SELECT count(1) FROM data 
        WHERE UniqueId=?
        '''
        newdata = []
        for par in pars:
            try:
                # 默认数据不是重复的
                dump_res = False
                for conn in self.connect_all(5):
                    try:
                        conn: SqliteConn = conn
                        c = conn.cursor
                        c.execute(sql, (par[0], ))
                        result = c.fetchall()
                        # 防止没有查出来
                        if len(result) > 0 and result[0][0] > 0:
                            # 数据是重复的
                            dump_res = True
                            break
                    except Exception as ex:
                        conn._conn.rollback()
                        raise ex
                    finally:
                        if conn is not None:
                            conn.close()
                if not dump_res:
                    newdata.append(par)
            except:
                self._logger.error(
                    f'Dump data error, err:{traceback.format_exc()}')
            finally:
                if conn is not None:
                    conn.commit()
                    conn.close()
        return newdata

    @table_locker(__tb_data._tbname)
    def insert_uniquely_identifies(self, data: FeedDataBase) -> bool:
        """
        向数据库存入数据唯一标识,用于去重。返回是否插入成功True/False
        由于存在强制下载,所以可能需要更新已有的资源数据
        """
        conn: SqliteConn = None
        res: bool = False
        sql = """insert into data(
            UniqueId,
            DataType,
            AppType,
            DownloadTime
        ) values(?,?,?,?)"""

        try:
            pars = self._get_execute_sql_pars(data)
            if len(pars) == 0:
                return res
            # 插入前查询数据是否在数据库里
            new_pars = self._dump_pars(pars)
            if len(new_pars) == 0:
                return res
            pars = new_pars
            conn = self.connect_write()
            c = conn._conn.cursor()
            if len(pars) == 1:
                result = c.execute(sql, pars[0])
            else:
                result = c.executemany(sql, pars)
            if result is None or result.rowcount < 1:  # or len(result) < 1:
                res = False
            else:
                res = True
        except Exception:
            self._logger.error(
                f"Insert data to db error:\ndatatype:{data._datatype}\n"
                f"datauniqueid:{data.get_uniqueid()}\nerror:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return res

    @table_locker(__tb_data._tbname)
    def is_data_exists(self, data: UniqueData,
                       datatype: EStandardDataType) -> bool:
        """检查数据是否已存在。返回True/False"""
        conn: SqliteConn = False
        res: bool = False
        try:
            if not isinstance(data, UniqueData):
                raise Exception("Param data is invalid.")
            sql = """select count(1) from data where
            UniqueId=? and
            DataType=? and
            AppType=?"""
            for conn in self.connect_all(5):
                try:
                    conn: SqliteConn = conn
                    c = conn.cursor
                    result = c.execute(sql, (
                        data.get_uniqueid(),
                        datatype.value,
                        data._task.apptype,
                    ))
                    for c in result:
                        # print(c)
                        if len(c) > 0 and c[0] > 0:
                            res = True
                            break
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                "Check data duplication error:\ndatatype:{}\ndataid:{}\nerror:{}"
                .format(data._datatype.name, data.get_uniqueid(),
                        traceback.format_exc()))
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return res
Пример #5
0
class TbIScanTask(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IScanTask: SqliteTable = SqliteTable(
        'IScanTask',
        True,
        SqliteColumn(
            colname='Id',
            coltype='INTEGER',
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True).set_index_new(),
        SqliteColumn(colname='ClientId').set_index_new(),
        SqliteColumn(colname='TaskId', nullable=False).set_index_new(),
        SqliteColumn(colname='CmdId', nullable=False).set_index_new(),
        SqliteColumn(colname='Platform', nullable=False).set_index_new(),
        SqliteColumn(
            colname='Status',
            coltype='INTEGER',
            nullable=False,
            defaultval=ECommandStatus.WaitForSend.value).set_index_new(),
        SqliteColumn(
            colname='Progress',  #0~1浮点数表百分比
            coltype='REAL',
            nullable=True),
        SqliteColumn(colname='ScanType', coltype='INTEGER',
                     defaultval=1).set_index_new(),
        SqliteColumn(
            colname='IsPeriod',
            coltype='INTEGER',
            nullable=False,
            defaultval=0).set_index_new(),
        SqliteColumn(
            colname='PeriodNum',
            coltype='INTEGER',
            nullable=False,
            defaultval=0).set_index_new(),
        SqliteColumn(colname='StartTime', coltype='DATETIME'),
        SqliteColumn(colname='EndTime', coltype='DATETIME'),
        SqliteColumn(colname='Interval', coltype='REAL'),
        SqliteColumn(colname='LastStartTime', coltype='DATETIME'),
        SqliteColumn(colname='LastEndTime', coltype='DATETIME'),
        SqliteColumn(colname='Source').set_index_new(),
        SqliteColumn(colname='CmdRcvMsg'),
        SqliteColumn(
            colname='CreateTime',
            coltype='DATETIME',
            defaultval=helper_time.get_time_sec_tz()),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
        SqliteColumn(
            colname='Sequence',
            nullable=False,
            coltype='INTEGER',
            defaultval=0).set_index_new(),
    )

    # scantype=scansearch 主键  TaskId
    # scantype=scan       主键  TaskId+BatchId
    # 所有列,复制粘贴用...:
    # ClientId
    # TaskId,
    # CmdId,
    # Platform,
    # Status,
    # Progress,
    # ScanType,
    # IsPeriod,
    # PeriodNum,
    # StartTime,
    # EndTime,
    # Interval,
    # LastStartTime,
    # LastEndTime,
    # Source,
    # CmdRcvMsg,
    # CreateTime,
    # UpdateTime,
    # Sequence,

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self, TbIScanTask.__tb_IScanTask._tbname, dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIScanTask.__tb_IScanTask)

    @table_locker(__tb_IScanTask._tbname)
    def save_new_iscantask(
            self,
            client: Client,
            scantask: IscanTask,
            cmdstatus: ECommandStatus = ECommandStatus.WaitForSend,
    ) -> bool:
        """保存新的批处理任务的令牌资源\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        client: Client = client
        scantask: IscanTask = scantask
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            ClientId=? and TaskId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        client._statusbasic._clientid,
                        scantask.taskid,
                        scantask._platform,
                    ))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        res = True
                        cmd = f'''UPDATE {self._tbname} set 
                            IsPeriod=?,
                            PeriodNum=?,
                            StartTime=?,
                            EndTime=?,
                            Interval=?,
                            LastStartTime=?,
                            LastEndTime=?,
                            CmdId=?,
                            Status=?,
                            Progress=?,
                            ScanType=?,
                            Source=?,
                            UpdateTime=?,
                            Sequence=? 
                            WHERE ClientId=? and TaskId=? and Platform=?;'''
                        # and UpdateTime<=? 暂时不判断时间了。因为server端自己也会更新
                        # 这个UpdateTime字段,中心也会更新这个字段,无法保证任务重新下发的
                        # 时候的UpdateTime > 当前server更新过的这个UpdateTime,否则会
                        # 导致明明重新下发了,但server由于任务的UpdateTime小于当前数据库
                        # 中的UpdateTime而更新任务状态失败。

                        result = cursor.execute(
                            cmd,
                            (
                                1 if scantask._is_period else 0,
                                scantask.periodnum,
                                scantask.cmd.stratagy.time_start,
                                scantask.cmd.stratagy.time_end,
                                scantask.cmd.stratagy.interval,
                                scantask.laststarttime,
                                scantask.lastendtime,
                                scantask.cmd_id,
                                cmdstatus.value,
                                scantask.progress,
                                scantask.scantype.value,
                                scantask.source,
                                helper_time.get_time_sec_tz(),
                                0,
                                client._statusbasic._clientid,
                                scantask.taskid,
                                scantask._platform,
                                # scantask.createtime,
                            ))
                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                conn = self.connect_write(5)
                try:
                    # ClientId
                    # TaskId,
                    # CmdId,
                    # Platform,
                    # Status,
                    # Progress,
                    # ScanType,
                    # IsPeriod,
                    # PeriodNum,
                    # StartTime,
                    # EndTime,
                    # Interval,
                    # LastStartTime,
                    # LastEndTime,
                    # Source,
                    # CmdRcvMsg,
                    # CreateTime,
                    # UpdateTime,
                    # Sequence,

                    # insert
                    cmd = f'''INSERT INTO {self._tbname}(
                        ClientId,
                        TaskId,
                        CmdId,
                        Platform,
                        Status,
                        Progress,
                        ScanType,
                        IsPeriod,
                        PeriodNum,
                        StartTime,
                        EndTime,
                        Interval,
                        LastStartTime,
                        LastEndTime,
                        Source,
                        CmdRcvMsg,
                        CreateTime,
                        UpdateTime,
                        Sequence) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        client._statusbasic._clientid,
                        scantask.taskid,
                        scantask.cmd_id,
                        scantask._platform,
                        cmdstatus.value,
                        scantask.progress,
                        scantask.scantype.value,
                        1 if scantask._is_period else 0,
                        scantask.periodnum,
                        scantask.cmd.stratagy.time_start,
                        scantask.cmd.stratagy.time_end,
                        scantask.cmd.stratagy.interval,
                        scantask.laststarttime,
                        scantask.lastendtime,
                        scantask.source,
                        '',
                        helper_time.get_time_sec_tz(),
                        scantask.createtimestr,
                        0,
                    ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "save new iscantask error: %s" % traceback.format_exc())

        return res

    @table_locker(__tb_IScanTask._tbname)
    def select_iscantask(self, conds: SqlConditions) -> IscanTask:
        """按条件搜索任务,返回数据行转换成的字段字典"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            # ClientId
            # TaskId,
            # CmdId,
            # Platform,
            # Status,
            # Progress,
            # ScanType,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''SELECT 
                    ClientId,
                    TaskId,
                    CmdId,
                    Platform,
                    Status,
                    Progress,
                    ScanType,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]

                    return fields

                except Exception:
                    self._logger.error("Get IDownCmd error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "Get IScanTask error: %s" % traceback.format_exc())

    @table_locker(__tb_IScanTask._tbname)
    def select_iscantasks(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            # ClientId
            # TaskId,
            # CmdId,
            # Platform,
            # Status,
            # Progress,
            # ScanType,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''SELECT 
                    ClientId,
                    TaskId,
                    CmdId,
                    Platform,
                    Status,
                    Progress,
                    ScanType,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        fields: dict = {}
                        for i in range(len(result[0])):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error("Get IScanTask error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "Get IScanTask error: %s" % traceback.format_exc())

    @table_locker(__tb_IScanTask._tbname)
    def update_iscantask_status(
            self,
            platform: str,
            taskid: str,
            cmdstatus: ECommandStatus,
    ) -> bool:
        """更新cmd的Status状态字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    Status=? 
                    WHERE Platform=? and Taskid=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        cmdstatus.value,
                        platform,
                        taskid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} Status error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScanTask._tbname)
    def update_iscantask(
            self,
            scantask: IscanTask,
    ) -> bool:
        """更新iscantask,条件为platform+taskid,更新其他可更新字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        scantask: IscanTask = scantask
        try:
            # ClientId
            # TaskId,
            # CmdId,
            # Platform,
            # Status,
            # Progress,
            # ScanType,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,

            cmd = f'''UPDATE {self._tbname} set 
                    Progress=?,
                    IsPeriod=?,
                    PeriodNum=?,
                    StartTime=?,
                    EndTime=?,
                    Interval=?,
                    LastStartTime=?,
                    LastEndTime=?,
                    CmdId=?,
                    Source=?,
                    CreateTime=?,
                    UpdateTime=? 
                    WHERE Platform=? and TaskId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        scantask.progress,
                        1 if scantask._is_period else 0,
                        scantask.periodnum,
                        scantask.cmd.stratagy.time_start,
                        scantask.cmd.stratagy.time_end,
                        scantask.cmd.stratagy.interval,
                        scantask.laststarttime,
                        scantask.lastendtime,
                        scantask.cmd_id,
                        scantask.source,
                        scantask.createtimestr,
                        helper_time.get_time_sec_tz(),
                        scantask._platform,
                        scantask.taskid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScanTask._tbname)
    def update_iscantask2(self, platform: str, taskid: str,
                          updatefields: dict) -> bool:
        """根据taskid+platform更新其他字段\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            TaskId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (taskid, platform))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        # 只根据TaskId、platform作为条件,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        sqlset = ''
                        for k in updatefields.keys():
                            sqlset = sqlset + '{}=?,'.format(k)
                        sqlset = sqlset.rstrip(',')
                        cmd = f'''UPDATE {self._tbname} set {sqlset} WHERE TaskId=? and Platform=?;'''
                        params = [v for v in updatefields.values()]
                        params.append(taskid)
                        params.append(platform)
                        result = cursor.execute(cmd, params)

                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            continue
                        else:
                            res = True

                        break
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "save new IScanTask error: %s" % traceback.format_exc())

        return res

    @table_locker(__tb_IScanTask._tbname)
    def update_iscantask_back(self, scantaskback: IscanTaskBack) -> bool:
        """更新iscantaskback到数据库,条件为platform+taskid,更新其他可更新字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        scantaskback: IscanTaskBack = scantaskback
        try:
            if not isinstance(scantaskback,
                              IscanTaskBack) or scantaskback._platform is None:
                raise Exception("Invalid IScanTaskBack obj")

            # ClientId
            # TaskId,
            # CmdId,
            # Platform,
            # Status,
            # Progress,
            # ScanType,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''UPDATE {self._tbname} set 
                    PeriodNum=?,
                    Status=?,
                    Progress=?,
                    CmdRcvMsg=?,
                    UpdateTime=?,
                    Sequence=? 
                    WHERE Platform=? and TaskId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(cmd, (
                        scantaskback.periodnum,
                        scantaskback._cmdstatus.value,
                        scantaskback.progress,
                        scantaskback.cmdrcvmsg,
                        helper_time.get_time_sec_tz(),
                        scantaskback._sequence,
                        scantaskback._platform,
                        scantaskback._taskid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True
                        break
                    else:
                        self._logger.error(
                            "IScanTask not found in db:\nplatform={}\ntaskid={}"
                            .format(scantaskback._platform,
                                    scantaskback.taskid))

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update CmdFeedBack to db {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res
Пример #6
0
class TbIScoutTask(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IScoutTask: SqliteTable = SqliteTable(
        'IScoutTask',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='Platform', nullable=False),
        SqliteColumn(colname='TaskId', nullable=False).set_index_new(),
        SqliteColumn(colname='IsPeriod',
                     coltype='INTEGER',
                     nullable=False,
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='PeriodNum',
                     coltype='INTEGER',
                     nullable=False,
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='StartTime', coltype='DATETIME'),
        SqliteColumn(colname='EndTime', coltype='DATETIME'),
        SqliteColumn(colname='Interval', coltype='REAL'),
        SqliteColumn(colname='LastStartTime', coltype='DATETIME'),
        SqliteColumn(colname='LastEndTime', coltype='DATETIME'),
        SqliteColumn(colname='Status',
                     coltype='INTEGER',
                     nullable=False,
                     description='采集端执行命令的状态,要反给中心的').set_index_new(),
        SqliteColumn(
            colname='TaskStatus',
            coltype='INTEGER',
            nullable=False,
            description='采集端执行任务的状态(下载状态等),跟CmdStatus不一样').set_index_new(),
        SqliteColumn(colname='BatchTotalCount', coltype='INTEGER'),
        SqliteColumn(colname='BatchCompleteCount',
                     coltype='INTEGER').set_index_new(),
        SqliteColumn(
            colname='Progress',  #0~1浮点数表百分比
            coltype='REAL',
            nullable=True),
        SqliteColumn(
            colname='Elapsed',  #0~1浮点数表百分比
            coltype='REAL',
            nullable=True),
        SqliteColumn(colname='Source'),
        SqliteColumn(colname='CmdRcvMsg'),
        SqliteColumn(colname='CreateTime',
                     coltype='DATETIME',
                     defaultval='1970-01-01 00:00:00'),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='Sequence', coltype='INTEGER',
                     defaultval=0).set_index_new(),
    )

    # scantype=scansearch 主键  TaskId
    # scantype=scan       主键  TaskId+BatchId
    # 所有列,复制粘贴用...:
    # Platform,
    # TaskId,
    # IsPeriod,
    # PeriodNum,
    # StartTime,
    # EndTime,
    # Interval,
    # LastStartTime,
    # LastEndTime,
    # Status,
    # TaskStatus,
    # BatchTotalCount,
    # BatchCompleteCount,
    # Progress,
    # Elapsed,
    # Source,
    # CmdRcvMsg,
    # CreateTime,
    # UpdateTime,
    # Sequence,

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self, TbIScoutTask.__tb_IScoutTask._tbname,
                              dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIScoutTask.__tb_IScoutTask)

    @table_locker(__tb_IScoutTask._tbname)
    def save_new_iscouttask(
            self,
            task: IscoutTask,
            cmdstatus: ECommandStatus = ECommandStatus.WaitForSend,
    ) -> bool:
        """保存新的批处理任务的令牌资源\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        task: IscoutTask = task
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            TaskId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task.taskid,
                        task._platform,
                    ))
                    result = cursor.fetchall()

                    # IsPeriod,
                    # PeriodNum,
                    # StartTime,
                    # EndTime,
                    # Interval,
                    if result[0][0] > 0:
                        res = True
                        cmd = f'''UPDATE {self._tbname} set
                            IsPeriod=?,
                            PeriodNum=?,
                            StartTime=?,
                            EndTime=?,
                            Interval=?,
                            LastStartTime=?,
                            LastEndTime=?,
                            Status=?,
                            TaskStatus=?,
                            BatchTotalCount=?,
                            BatchCompleteCount=?,
                            Progress=?,
                            Elapsed=?,
                            Source=?,
                            CmdRcvMsg=?,
                            CreateTime=?,
                            UpdateTime=?,
                            Sequence=? 
                            WHERE TaskId=? and Platform=? and CreateTime<=?;'''

                        result = cursor.execute(
                            cmd,
                            (
                                1 if task._is_period else 0,
                                task.periodnum,
                                task.cmd.stratagy.time_start,
                                task.cmd.stratagy.time_end,
                                task.cmd.stratagy.interval,
                                task.laststarttime,
                                task.lastendtime,
                                task.cmdstatus.value,
                                task.taskstatus.value,
                                task.batchtotalcount,
                                task.batchcompletecount,
                                task.progress,
                                0,  # 重置消耗时间
                                task.source,
                                task.cmdrcvmsg,
                                task.createtimestr,
                                helper_time.get_time_sec_tz(),
                                0,  #重置sequence
                                task.taskid,
                                task._platform,
                                task.createtimestr,
                            ))

                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                conn = self.connect_write(5)
                try:
                    # Platform,
                    # TaskId,
                    # IsPeriod,
                    # PeriodNum,
                    # StartTime,
                    # EndTime,
                    # Interval,
                    # LastStartTime,
                    # LastEndTime,
                    # Status,
                    # TaskStatus,
                    # BatchTotalCount,
                    # BatchCompleteCount,
                    # Progress,
                    # Elapsed,
                    # Source,
                    # CmdRcvMsg,
                    # CreateTime,
                    # UpdateTime,
                    # Sequence,

                    # insert
                    cmd = f'''INSERT INTO {self._tbname}(
                        Platform,
                        TaskId,
                        IsPeriod,
                        PeriodNum,
                        StartTime,
                        EndTime,
                        Interval,
                        LastStartTime,
                        LastEndTime,
                        Status,
                        TaskStatus,
                        BatchTotalCount,
                        BatchCompleteCount,
                        Progress,
                        Elapsed,
                        Source,
                        CmdRcvMsg,
                        CreateTime,
                        UpdateTime,
                        Sequence) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(
                        cmd,
                        (
                            task._platform,
                            task.taskid,
                            1 if task._is_period else 0,
                            task.periodnum,
                            task.cmd.stratagy.time_start,
                            task.cmd.stratagy.time_end,
                            task.cmd.stratagy.interval,
                            task.laststarttime,
                            task.lastendtime,
                            task.cmdstatus.value,
                            task.taskstatus.value,
                            task.batchtotalcount,
                            task.batchcompletecount,
                            0,  # progress
                            0,  # elapsed
                            task.source,
                            '',
                            task.createtimestr,
                            helper_time.get_time_sec_tz(),
                            0,
                        ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("save new IScoutTask error: %s" %
                               traceback.format_exc())

        return res

    @table_locker(__tb_IScoutTask._tbname)
    def select_iscouttask(self, conds: SqlConditions) -> dict:
        """按条件搜索任务,返回数据行转换成的字段字典"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    Platform,
                    TaskId,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    Status,
                    TaskStatus,
                    BatchTotalCount,
                    BatchCompleteCount,
                    Progress,
                    Elapsed,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]

                    return fields

                except Exception:
                    self._logger.error("Get IScoutTask error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IScanTask error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IScoutTask._tbname)
    def select_iscouttasks(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            # Platform,
            # TaskId,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # Status,
            # TaskStatus,
            # BatchTotalCount,
            # BatchCompleteCount,
            # Progress,
            # Elapsed,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''SELECT 
                    Platform,
                    TaskId,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    Status,
                    TaskStatus,
                    BatchTotalCount,
                    BatchCompleteCount,
                    Progress,
                    Elapsed,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        fields: dict = {}
                        for i in range(len(row)):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error("Get IScoutTask error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IScoutTask error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IScoutTask._tbname)
    def update_iscouttask_status(
            self,
            platform: str,
            taskid: str,
            cmdstatus: ECommandStatus,
    ) -> bool:
        """更新task的Status状态字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    Status=? 
                    WHERE Platform=? and Taskid=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        cmdstatus.value,
                        platform,
                        taskid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} Status error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScoutTask._tbname)
    def update_iscouttask2(self, task: IscoutTask) -> bool:
        """更新IScoutTask表,根据platform,taskid更新其他所有字段"""
        res = False
        conn: SqliteConn = None
        cursor = None
        task: IscoutTask = task
        try:
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (task._platform, task.taskid))
                    result = cursor.fetchall()

                    # Platform,
                    # TaskId,
                    # IsPeriod,
                    # PeriodNum,
                    # StartTime,
                    # EndTime,
                    # Interval,
                    # LastStartTime,
                    # LastEndTime,
                    # Status,
                    # TaskStatus,
                    # BatchTotalCount,
                    # BatchCompleteCount,
                    # Progress,
                    # Elapsed,
                    # Source,
                    # CmdRcvMsg,
                    # CreateTime,
                    # UpdateTime,
                    # Sequence,
                    if result[0][0] > 0:
                        # 只根据TaskId、platform作为条件,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        cmd = f'''UPDATE {self._tbname} set
                            IsPeriod=?,
                            PeriodNum=?,
                            StartTime=?,
                            EndTime=?,
                            Interval=?,
                            LastStartTime=?,
                            LastEndTime=?,
                            Status=?,
                            TaskStatus=?,
                            BatchTotalCount=?,
                            BatchCompleteCount=?,
                            Progress=?,
                            Elapsed=?,
                            Source=?,
                            CmdRcvMsg=?,
                            Sequence=?,
                            CreateTime=?,
                            UpdateTime=? WHERE TaskId=? and Platform=?;'''

                        result = cursor.execute(cmd, (
                            1 if task._is_period else 0,
                            task.periodnum,
                            task.cmd.stratagy.time_start,
                            task.cmd.stratagy.time_end,
                            task.cmd.stratagy.interval,
                            task.laststarttime,
                            task.lastendtime,
                            task.cmdstatus.value,
                            task.taskstatus.value,
                            task.batchtotalcount,
                            task.batchcompletecount,
                            task.progress,
                            task.elapsed,
                            task.source,
                            task.cmdrcvmsg,
                            task.sequence,
                            task.createtimestr,
                            helper_time.get_time_sec_tz(),
                            task.taskid,
                            task.platform,
                        ))

                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            continue
                        else:
                            res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("Update IScoutTask error: %s" %
                               traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def update_iscouttask3(self, platform: str, taskid: str,
                           updatefields: dict) -> bool:
        """更新IScoutTask表,根据platform,taskid更新指定字段"""
        res = False
        conn: SqliteConn = None
        cursor = None
        try:
            if not isinstance(updatefields, dict) or len(updatefields) < 1:
                return True
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (platform, taskid))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        # 只根据TaskId、platform作为条件,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        sqlset = ''
                        for k in updatefields.keys():
                            sqlset = sqlset + '{}=?,'.format(k)
                        sqlset = sqlset.rstrip(',')
                        cmd = f'''UPDATE {self._tbname} set {sqlset} WHERE TaskId=? and Platform=?;'''
                        params = [v for v in updatefields.values()]
                        params.append(taskid)
                        params.append(platform)
                        result = cursor.execute(cmd, params)

                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            continue
                        else:
                            res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("Update IScoutTask error: %s" %
                               traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def get_iscouttask_batch_total_count(self, platform: str,
                                         taskid: str) -> int:
        """查询指定task的batchtotalcount,返回-1表示没找到指定的task"""
        res: int = -1  #返回-1表示没找到指定的task
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT BatchTotalCount FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    res = result[0][0]

                except Exception:
                    self._logger.error(
                        "Get IScoutTask batchtotalcount error: {}".format(
                            traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("Get IScoutTask batchtotalcount error: %s" %
                               traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def get_iscouttask_batch_complete_count(self, platform: str,
                                            taskid: str) -> int:
        """查询指定task的batchtotalcount,返回-1表示没找到指定的task"""
        res: int = -1  #返回-1表示没找到指定的task
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT BatchCompleteCount FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    res = result[0][0]

                except Exception:
                    self._logger.error(
                        "Get IScoutTask batchcompletecount error: {}".format(
                            traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("Get IScoutTask batchcompletecount error: %s" %
                               traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def update_iscouttask_batch_total_count(self, task: IscoutTask) -> bool:
        """更新指定task的batchtotalcount字段,返回bool指示是否成功"""
        res: bool = False
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task._platform,
                        task.taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    cmd = f'''UPDATE {self._tbname} set BatchTotalCount=? WHERE TaskId=? and Platform=?;'''
                    result = cursor.execute(cmd, (
                        task.batchtotalcount,
                        task.taskid,
                        task._platform,
                    ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        continue

                    res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "Update iscout task batch total count error: %s" %
                traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def increace_iscouttask_batch_complete_count(self,
                                                 platform: str,
                                                 taskid: str,
                                                 increment: int = 1) -> int:
        """原子操作,提升指定Task的batchcompletecount数量。
        task:任务对象\n
        increment:在原有基础上要增加多少,默认为1,可以为负数"""
        res: bool = False
        conn: SqliteConn = None
        cursor = None
        try:
            if not isinstance(increment, int):  # 可以为负数
                raise Exception(
                    "Invalid increment count for task batch complete count")

            cmd = f'''SELECT BatchCompleteCount FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    src = result[0][0]

                    target = src + increment
                    cmd = f'''UPDATE {self._tbname} set BatchCompleteCount=? 
                    WHERE Platform=? and TaskId=?;'''

                    result = cursor.execute(cmd, (
                        target,
                        platform,
                        taskid,
                    ))

                    if result is None or result.rowcount < 1:
                        continue

                    res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "increace_iscouttask_batch_complete_count error: %s" %
                traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def get_iscouttask_sequence(self, platform: str, taskid: str) -> int:
        """获取指定的总任务的sequence"""
        res: int = 0
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT Sequence FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    res = result[0][0]
                    if not isinstance(res, int):
                        res = int(res)

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("get_iscouttask_sequence error: %s" %
                               traceback.format_exc())
        return res

    @table_locker(__tb_IScoutTask._tbname)
    def get_iscouttask_elapsed(self, platform: str, taskid: str) -> float:
        """获取指定的总任务的 elapsed"""
        res: float = 0
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT Elapsed FROM {self._tbname} WHERE Platform=? and TaskId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    res = result[0][0]
                    if type(res) in [int, float]:
                        res = float(res)

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("Get iscouttask elapsed error: %s" %
                               traceback.format_exc())
        return res
Пример #7
0
    dft_lvl=MsLogLevels.INFO, msficfg=MsFileLogConfig(fi_dir=r'./_serverlog'))
logger = MsLogManager.get_logger("idownserver")

from commonbaby.sql import (SqlConn, SqliteColumn, SqliteConn,
                            SqliteConnManager, SqliteCursor, SqliteIndex,
                            SqliteTable, table_locker)
from commonbaby.helpers import helper_time
__locker = threading.RLock()
__locker2 = threading.RLock()

tables: dict = {
    "TableA":
    SqliteTable(
        "TableA",
        True,
        SqliteColumn("Col1", 'INTEGER', None, False, True, True,
                     True).set_index_new("Idx1"),
        SqliteColumn("Col2", nullable=False, defaultval='DFT'),
        SqliteColumn("Col3", 'INTEGER', defaultval=1),
    ),
}

# tables: dict = {
#     "ClientStatus":
#     SqliteTable(
#         "ClientStatus",
#         True,
#         SqliteColumn(
#             colname="Id",
#             coltype='INTEGER',
#             nullable=False,
#             is_primary_key=True,
Пример #8
0
class TbIDownBatchToken(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IDownBatchToken: SqliteTable = SqliteTable(
        'IDownBatchToken',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='TokenId', nullable=False).set_index_new(),
        SqliteColumn(colname='TokenType', coltype='INTEGER',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='Input'),
        SqliteColumn(colname='PreGlobalTelCode'),
        SqliteColumn(colname='PreAccount'),
        SqliteColumn(colname='GlobalTelCode'),
        SqliteColumn(colname='Phone'),
        SqliteColumn(colname='Account'),
        SqliteColumn(colname='Password'),
        SqliteColumn(colname='Url'),
        SqliteColumn(colname='Host'),
        SqliteColumn(colname='Cookie'),
        SqliteColumn(colname='CreateTime',
                     coltype='DATETIME',
                     defaultval=helper_time.ts_since_1970_tz()),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
    )

    # 所有列,复制粘贴用...:
    # TokenId,
    # TokenType,
    # Input,
    # PreGlobalTelCode,
    # PreAccount,
    # GlobalTelCode,
    # Phone,
    # Account,
    # Password,
    # Url,
    # Host,
    # Cookie,
    # UpdateTime,
    # CreateTime

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self,
                              TbIDownBatchToken.__tb_IDownBatchToken._tbname,
                              dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIDownBatchToken.__tb_IDownBatchToken)

    @table_locker(__tb_IDownBatchToken._tbname)
    def save_new_idownbatchtoken(
        self,
        task: Task,
    ) -> bool:
        """保存新的批处理任务的令牌资源\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        task: Task = task
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            TokenId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (task.tokenid, ))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        res = True
                        # 只根据TaskId、ParentTaskId和ClientId关联,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        cmd = f'''UPDATE {self._tbname} set
                            TokenType=?,
                            Input=?,
                            PreGlobalTelCode=?,
                            PreAccount=?,
                            GlobalTelCode=?,
                            Phone=?,
                            Account=?,
                            Password=?,
                            Url=?,
                            Host=?,
                            Cookie=?
                            WHERE TokenId=? and UpdateTime<=?;'''

                        result = cursor.execute(cmd, (
                            task.tokentype.value,
                            task.input,
                            task.preglobaltelcode,
                            task.preaccount,
                            task.globaltelcode,
                            task.phone,
                            task.account,
                            task.password,
                            task.url,
                            task.host,
                            task.cookie,
                            task.tokenid,
                            task.time,
                        ))
                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                conn = self.connect_write(5)
                try:
                    # insert
                    cmd = f'''INSERT INTO {self._tbname}(
                        TokenId,
                        TokenType,
                        Input,
                        PreGlobalTelCode,
                        PreAccount,
                        GlobalTelCode,
                        Phone,
                        Account,
                        Password,
                        Url,
                        Host,
                        Cookie,
                        UpdateTime,
                        CreateTime) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        task.tokenid,
                        task.tokentype.value,
                        task.input,
                        task.preglobaltelcode,
                        task.preaccount,
                        task.globaltelcode,
                        task.phone,
                        task.account,
                        task.password,
                        task.url,
                        task.host,
                        task.cookie,
                        task.time,
                        helper_time.ts_since_1970_tz(),
                    ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("save_new_idownbatchtask error: %s" %
                               traceback.format_exc())

        return res

    @table_locker(__tb_IDownBatchToken._tbname)
    def select_token(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    TokenId,
                    TokenType,
                    Input,
                    PreGlobalTelCode,
                    PreAccount,
                    GlobalTelCode,
                    Phone,
                    Account,
                    Password,
                    Url,
                    Host,
                    Cookie,
                    UpdateTime,
                    CreateTime FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        # if len(row) != 15:
                        #     continue
                        fields: dict = {}
                        for i in range(len(row)):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error("save_idown_task error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Save new idown_task error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IDownBatchToken._tbname)
    def select_token_one(self, conds: SqlConditions) -> dict:
        """按条件搜索任务,返回数据行转换成的字段字典"""
        for fields in self.select_token(conds):
            return fields
Пример #9
0
class TbIDownCmd(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IDownCmd: SqliteTable = SqliteTable(
        'IDownCmd',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='ClientId').set_index_new(),
        SqliteColumn(colname='CmdId', nullable=False).set_index_new(),
        SqliteColumn(colname='Platform', nullable=False).set_index_new(),
        SqliteColumn(colname='TaskId').set_index_new(),
        SqliteColumn(colname='BatchId').set_index_new(),
        SqliteColumn(colname='Cmd', nullable=False).set_index_new(),
        SqliteColumn(colname='Status', coltype='INTEGER',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='Source').set_index_new(),
        SqliteColumn(colname='CmdRcvMsg'),
        SqliteColumn(colname='CreateTime',
                     coltype='DATETIME',
                     defaultval=helper_time.ts_since_1970_tz()),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='Sequence',
                     nullable=False,
                     coltype='INTEGER',
                     defaultval=0).set_index_new(),
        SqliteColumn(
            # 指示当前cmd是否是与任何task关联的,0独立的/1关联的
            colname='IsRelative',
            nullable=False,
            coltype='INTEGER',
            defaultval=1).set_index_new(),
    )

    # 主键  ClientId+CmdId
    # 所有列,复制粘贴用...:
    # ClientId
    # CmdId,
    # Platform,
    # TaskId,
    # BatchId,
    # Cmd,
    # Status,
    # Source,
    # CmdRcvMsg,
    # CreateTime,
    # UpdateTime,
    # Sequence,
    # IsRelative

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self, TbIDownCmd.__tb_IDownCmd._tbname, dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIDownCmd.__tb_IDownCmd)

    @table_locker(__tb_IDownCmd._tbname)
    def save_new_idowncmd(
            self,
            platform: str,
            client: Client,
            command: IdownCmd,
            cmdtime: float,
            cmdstatus: ECommandStatus = ECommandStatus.WaitForSend,
            taskid: str = None,
            batchid: str = None,
            isrelative: int = 1,
    ) -> bool:
        """保存新的批处理任务的令牌资源\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        client: Client = client
        command: IdownCmd = command
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            ClientId=? and CmdId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        client._statusbasic._clientid,
                        command.cmd_id,
                        platform,
                    ))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        res = True
                        cmd = f'''UPDATE {self._tbname} set
                            Cmd=?,
                            TaskId=?,
                            BatchId=?,
                            Status=?,
                            Source=?,
                            CreateTime=?,
                            UpdateTime=?,
                            IsRelative=? 
                            WHERE ClientId=? and CmdId=? and Platform=? and CreateTime<=?;'''

                        result = cursor.execute(cmd, (
                            command.cmd_str,
                            taskid,
                            batchid,
                            cmdstatus.value,
                            command.source,
                            helper_time.timespan_to_datestr_tz(cmdtime),
                            helper_time.get_time_sec_tz(),
                            isrelative,
                            client._statusbasic._clientid,
                            command.cmd_id,
                            platform,
                            helper_time.timespan_to_datestr_tz(cmdtime),
                        ))

                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                conn = self.connect_write(5)
                try:
                    # ClientId
                    # CmdId,
                    # Platform,
                    # TaskId,
                    # BatchId,
                    # Cmd,
                    # Status,
                    # Source,
                    # CmdRcvMsg,
                    # CreateTime,
                    # UpdateTime,
                    # Sequence
                    # IsRelative

                    # insert
                    cmd = f'''INSERT INTO {self._tbname}(
                        ClientId,
                        CmdId,
                        Platform,
                        TaskId,
                        BatchId,
                        Cmd,
                        Source,
                        Status,
                        CreateTime,
                        UpdateTime,
                        Sequence,
                        IsRelative) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        client._statusbasic._clientid,
                        command.cmd_id,
                        platform,
                        taskid,
                        batchid,
                        command.cmd_str,
                        command.source,
                        cmdstatus.value,
                        helper_time.timespan_to_datestr_tz(cmdtime),
                        helper_time.get_time_sec_tz(),
                        0,
                        isrelative,
                    ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("save_new_idowncmd error: %s" %
                               traceback.format_exc())

        return res

    @table_locker(__tb_IDownCmd._tbname)
    def select_cmd(self, conds: SqlConditions) -> IdownCmd:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    ClientId,
                    CmdId,
                    Platform,
                    TaskId,
                    BatchId,
                    Cmd,
                    Status,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence,
                    IsRelative 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]

                    return fields

                except Exception:
                    self._logger.error("Get IDownCmd error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IDownCmd error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IDownCmd._tbname)
    def select_cmds(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    ClientId,
                    CmdId,
                    Platform,
                    TaskId,
                    BatchId,
                    Cmd,
                    Status,
                    Source,
                    CmdRcvMsg,
                    CreateTime,
                    UpdateTime,
                    Sequence,
                    IsRelative 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        # if len(row) != 15:
                        #     continue
                        fields: dict = {}
                        for i in range(len(row)):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error("save_idown_task error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IDownCmd error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IDownCmd._tbname)
    def update_cmd_status(self, platform: str, cmdid: str, clientid: str,
                          cmdstatus: ECommandStatus) -> bool:
        """更新cmd的Status状态字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    Status=? 
                    WHERE Platform=? and CmdId=? and ClientId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    result = cursor.execute(
                        cmd, (cmdstatus.value, platform, cmdid, clientid))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} Status error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownCmd._tbname)
    def update_cmd(
            self,
            cmd: IdownCmd,
            taskid: str = None,
            batchid: str = None,
            isrelative: int = 1,
    ) -> bool:
        """更新cmd,条件为platform+cmdid,更新其他可更新字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        cmd: IdownCmd = cmd
        try:
            # ClientId
            # CmdId,
            # Platform,
            # TaskId,
            # BatchId,
            # Cmd,
            # Status,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            # IsRelative

            cmd = f'''UPDATE {self._tbname} set
                    TaskId=?,
                    BatchId=?,
                    Cmd=?,
                    Status=?,
                    Source=?,
                    CmdRcvMsg=?,
                    CreateTime=?,
                    UpdateTime=?,
                    Sequence=?,
                    IsRelative=?  
                    WHERE Platform=? and CmdId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(
                        cmd,
                        (
                            taskid,
                            batchid,
                            cmd.cmd_str,
                            cmd.cmdstatus.value,
                            cmd.source,
                            cmd.cmdrcvmsg,
                            # 假设数据是按时间先后顺序过来的,所以createtime直接取本地时间。
                            # 若后面有问题,需要加idowncmd命令文件字段createtime字段
                            helper_time.get_time_sec_tz(),
                            helper_time.get_time_sec_tz(),
                            cmd._sequence,
                            isrelative,
                            cmd._platform,
                            cmd.cmd_id,
                        ))
                    if not result is None and result.rowcount > 0:
                        res = True
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownCmd._tbname)
    def update_cmdback(self, cmdback: CmdFeedBack) -> bool:
        """更新cmdback到数据库,条件为clientid+cmdid(+platform?),更新其他可更新字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        cmdback: CmdFeedBack = cmdback
        try:
            if cmdback is None or cmdback._platform is None:
                raise Exception("Invalid cmdback obj")

            # ClientId
            # CmdId,
            # Platform,
            # TaskId,
            # BatchId,
            # Cmd,
            # Status,
            # Source,
            # CmdRcvMsg,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            # IsRelative
            cmd = f'''UPDATE {self._tbname} set
                    Status=?,
                    CmdRcvMsg=?,
                    UpdateTime=?,
                    Sequence=? 
                    WHERE ClientId=? and CmdId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(cmd, (
                        cmdback._cmdstatus.value,
                        cmdback._cmdrcvmsg,
                        helper_time.get_time_sec_tz(),
                        cmdback._sequence,
                        cmdback.clientid,
                        cmdback.cmd_id,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True
                        break
                    else:
                        self._logger.error(
                            "Cmd not found in db:\ncmdid={}\nclientid={}".
                            format(cmdback.cmd_id, cmdback.clientid))

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update CmdFeedBack to db {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res
Пример #10
0
class TbTaskCmd(TbSqliteBase):
    __tb_task_cmd: SqliteTable = SqliteTable(
        "idowncmd",
        True,
        SqliteColumn(
            colname="ID",
            coltype="INTEGER",
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True,
        ).set_index_new(),
        SqliteColumn(colname="cmdid"),
        SqliteColumn(colname="platform", defaultval="zplus"),
        SqliteColumn(colname="default_value", coltype="INT", length=5),
        SqliteColumn(colname="cmd", nullable=False),
    )
    databasename = "task"

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbTaskCmd.__tb_task_cmd._tbname, dbcfg,
                              TbTaskCmd.databasename)
        # 初始化自定义下载策略的默认值
        self.cmd_str = json.dumps(cmd_dict)
        self._initial_default_confg()

    def _append_tables(self):
        self._conn_mngr.append_table(TbTaskCmd.__tb_task_cmd)

    @table_locker(__tb_task_cmd._tbname)
    def _initial_default_confg(self):
        """
        初始化cmd,目前来看三个地方都使用了cmd
        但是只有idown目前有修改全局的功能,所以为了不互相影响需要放3份
        """
        # 只需要查询一个是否有
        if self.get_default_idown_cmd() is not None:
            return
        conn: SqliteConn = None

        sql = """
        INSERT INTO idowncmd(cmdid, default_value, cmd)
        VALUES (?, ?, ?);       
        """
        params = [
            ("iscan", 1, self.cmd_str),
            ("iscout", 1, self.cmd_str),
            ("idown", 1, self.cmd_str),
        ]
        # params = ('iscan', 1, self.cmd_str)
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.executemany(sql, params)
            # c.execute(sql, params)
        except Exception:
            self._logger.error(
                f"There was a problem inserting default cmd data, err:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_task_cmd._tbname)
    def get_default_cmd(self, cmdid, default_value=1):
        """
        获取已存储的默认配置
        :return:
        """
        res = None
        conn: SqliteConn = None
        sql = """
        SELECT * FROM idowncmd 
        WHERE cmdid=? and default_value=?;
        """
        params = (cmdid, default_value)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, params)
                    res_data = c.fetchall()
                    if len(res_data) > 0:
                        res = res_data[0]
                        break
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query default idown cmd error,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
            return res

    def get_default_idown_cmd(self):
        """
        只获取idown的默认cmd
        modify by judy 2020/08/12
        """
        res = self.get_default_cmd("idown")
        return res

    def get_default_iscan_cmd(self):
        """
        只获取iscan的默认cmd
        modify by judy 2020/08/12
        """
        res = self.get_default_cmd("iscan")
        return res

    def get_default_iscout_cmd(self):
        """
        只获取iscout的默认cmd
        modify by judy 2020/08/12
        """
        res = self.get_default_cmd("iscout")
        return res

    @table_locker(__tb_task_cmd._tbname)
    def update_cmd_by_cmdid(self, cmdid, cmdr: str):
        """
        根据cmdid更新cmd
        :param cmdid:
        :param cmdr:
        :return:
        """
        res = False
        sql = """
        UPDATE idowncmd SET cmd=? WHERE cmdid=?
        """
        pars = (cmdr, cmdid)
        conn: SqliteConn = None
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (result is not None
                            and result.rowcount > 0):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"Update default cmd error,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
        return

    def _update_the_same_cmdid(self, cmdid, cmd_str: str):
        """
        更新数据库中相同的cmd
        :param cmdid:
        :param cmd_str:
        :return:
        """
        res = False
        repeat_data = self.query_cmd_by_cmdid(cmdid)
        if repeat_data is not None:
            # 表示数据库中已经存储了这个设置,那么就更新数据即可
            # fill_dict = self._filling_default_cmd(json.loads(cmd_str), json.loads(repeat_data.get('cmd')))
            self.update_cmd_by_cmdid(cmdid, cmd_str)
            res = True
        return res

    @table_locker(__tb_task_cmd._tbname)
    def store_task_cmd(self, cmdid, cmd_str):
        """
        补齐默认配置,存储cmd数据
        :param cmdid:
        :param cmd_str:
        :return:
        """
        # 更新相同的cmdid的信息
        repeat = self._update_the_same_cmdid(cmdid, cmd_str)
        if repeat:
            # 如果更新了即可
            return

        sql = """
        INSERT INTO idowncmd(cmdid, cmd)
        VALUES (?, ?)
        """
        # cmd_dict = json.loads(cmd_str)

        # 补齐默认配置
        # fill_dict = self._filling_default_cmd(cmd_dict)
        pars = (cmdid, cmd_str)
        conn: SqliteConn = None
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.execute(sql, pars)
        except Exception:
            self._logger.error(
                f"There was a problem inserting data, err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_task_cmd._tbname)
    def query_cmd_by_cmdid(self, cmdid):
        """
        根据cmdid查询默认的配置
        有结果返回{}
        没有结果返回None
        :return:
        """
        conn: SqliteConn = None
        sql = """
        SELECT * FROM idowncmd
        WHERE cmdid=?;
        """
        pars = (cmdid, )
        try:
            for conn in self.connect_all(5):
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, pars)
                    res: list = c.fetchall()
                    if len(res) > 0:
                        return res[0]
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
        except:
            self._logger.error(
                f"There was a problem query cmd by cmdid\nerr:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.close()
        return

    def _filling_default_idown_cmd(self, icmd: IdownCmd) -> str:
        """
        在存储默认配置的时候可能需要补齐一些默认配置
        补齐默认的配置后再存储
        :param icmd:
        :return:
        """
        default_cmd: str = self.get_default_idown_cmd().get("cmd")
        dcmd = IdownCmd(default_cmd)
        # 如果任务自己带有一些设置,那么补齐一些配置即可,只要调用了fill那么cmd就会是完整的
        icmd.fill_defcmd(dcmd)
        return icmd.filled_cmd_str

    @table_locker(__tb_task_cmd._tbname)
    def update_default_idown_cmd(self, icmd: IdownCmd):
        """
        修改默认的cmd,会自动找寻数据库中最新的cmd补齐
        :param icmd:
        :return:
        """
        res = False
        sql = """
        UPDATE idowncmd SET cmd=? WHERE cmdid=? and default_value=?
        """
        # cmd_dict = json.loads(new_cmdr)
        # 补齐默认配置
        new_cmdr = self._filling_default_idown_cmd(icmd)
        pars = (new_cmdr, "idown", 1)
        conn: SqliteConn = None
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (result is not None
                            and result.rowcount > 0):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"Update default cmd error,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
        return
Пример #11
0
class TbIDownBatchTask(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IDownBatchTask: SqliteTable = SqliteTable(
        'IDownBatchTask',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='Platform', nullable=False).set_index_new(),
        SqliteColumn(colname='TaskId', nullable=False).set_index_new(),
        SqliteColumn(colname='BatchId', nullable=False).set_index_new(),
        SqliteColumn(colname='ParentBatchId', nullable=True).set_index_new(),
        SqliteColumn(colname='ClientId', nullable=False).set_index_new(),
        SqliteColumn(colname='TokenId', coltype='INTEGER',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='AppType', coltype='INTEGER').set_index_new(),
        SqliteColumn(colname='ForceDownload', coltype='INTEGER',
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='CmdRcvMsg'),
        SqliteColumn(colname='Result'),
        SqliteColumn(colname='CmdStatus', coltype='INTEGER',
                     nullable=False).set_index_new(),
        SqliteColumn(
            colname='Progress',  #0~1浮点数表百分比
            coltype='REAL',
            defaultval=0).set_index_new(),
        SqliteColumn(colname='Sequence', coltype='INTEGER',
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='OtherFields').set_index_new(),
        SqliteColumn(colname='CreateTime',
                     coltype='DATETIME',
                     defaultval=helper_time.ts_since_1970_tz()),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
        SqliteColumn(
            # 此字段仅在查询 或 操作IDownTask表的 BatchCompleteCount 字段时使用,
            # 其他时候不要使用
            colname='IsBatchCompleteCountIncreased',
            coltype='BOOLEAN',
            nullable=False,
            defaultval=0),
        SqliteColumn(colname="Source"),  # 新增
        SqliteColumn(colname="CmdId"),  #cmdid字段要更新
    )

    # 所有列,复制粘贴用...:
    # Platform,
    # TaskId,
    # Batchid,
    # ParentBatchId,
    # ClientId,
    # TokenId,
    # AppType,
    # ForceDownload,
    # CmdRcvMsg,
    # Result,
    # CmdStatus,
    # Progress,
    # Sequence,
    # OtherFields,
    # CreateTime,
    # UpdateTime,
    # IsBatchCompleteCountIncreased,
    # Source,
    # CmdId

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self,
                              TbIDownBatchTask.__tb_IDownBatchTask._tbname,
                              dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIDownBatchTask.__tb_IDownBatchTask)

    @table_locker(__tb_IDownBatchTask._tbname)
    def save_new_idownbatchtask(
        self,
        task: Task,
        client: Client,
        cmdstatus: ECommandStatus = ECommandStatus.WaitForSend
    ) -> Tuple[bool, bool]:
        """保存新的批处理任务的子任务\n
        task: 任务对象\n
        tokenid:当前批处理子任务对应的登陆令牌存储在IDownBatchTokens表中的tokenid,关联存储\n
        client: 当前批处理子任务被分配到的client\n
        cmdstatus: 指定当前批处理子任务的命令状态\n
        return: (bool是否成功,bool是否为新增(用于计算batchtotalcount))"""
        res: bool = False
        isnew: bool = False
        conn: SqliteConn = None
        cursor = None
        client: Client = client
        task: Task = task
        try:
            if not isinstance(task.tokenid, str) or task.tokenid == "":
                raise Exception(
                    "Invalid tokenid while save new idownbatchtask:\ntaskid:{}"
                    .format(task.taskid))
            # 搜索每个库,看有没有 taskid和clientid一样,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            Platform=? and TaskId=? and BatchId=? and ClientId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task._platform,
                        task.taskid,
                        task.batchid,
                        client._statusbasic._clientid,
                    ))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        res = True
                        # 只根据TaskId、ParentTaskId和ClientId关联,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        cmd = f'''UPDATE {self._tbname} set
                            TokenId=?,
                            AppType=?,
                            ForceDownload=?,
                            CmdRcvMsg=?,
                            Result=?,
                            CmdStatus=?,
                            Progress=?,
                            Sequence=?,
                            OtherFields=?,
                            CreateTime=?,
                            UpdateTime=?,
                            Source=?,
                            CmdId=? 
                            WHERE Platform=? and TaskId=? and BatchId=? and ClientId=? and CreateTime<=?;'''

                        result = cursor.execute(
                            cmd,
                            (
                                task.tokenid,
                                task.apptype,
                                task.forcedownload,
                                task._cmdrcvmsg,
                                task._result,
                                cmdstatus.value,
                                # 进度置零
                                0,
                                #批量任务完成数也要重置,因为重置了任务下发状态,变为新任务,需要重新执行
                                0,  #sequence重置
                                task.other_fields_json,
                                task.timestr,
                                helper_time.get_time_sec_tz(),
                                task.source,
                                task.cmd_id,
                                # 0 此字段在其他地方重置 #是否总任务已提升batchcompletecount置零,
                                task._platform,
                                task.taskid,
                                task.batchid,
                                client._statusbasic._clientid,
                                task.timestr,
                            ))

                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                isnew = True
                conn = self.connect_write(5)
                try:
                    # insert
                    # Platform,
                    # TaskId,
                    # Batchid,
                    # ParentBatchId,
                    # ClientId,
                    # TokenId,
                    # AppType,
                    # ForceDownload,
                    # CmdRcvMsg,
                    # Result,
                    # CmdStatus,
                    # Progress,
                    # Sequence,
                    # OtherFields,
                    # CreateTime,
                    # UpdateTime
                    # IsBatchCompleteCountIncreased
                    cmd = f'''INSERT INTO {self._tbname}(
                        Platform,
                        TaskId,
                        Batchid,
                        ParentBatchId,
                        ClientId,
                        TokenId,
                        AppType,
                        ForceDownload,
                        CmdRcvMsg,
                        Result,
                        CmdStatus,
                        Progress,
                        Sequence,
                        OtherFields,
                        CreateTime,
                        UpdateTime,
                        Source,
                        CmdId) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(
                        cmd,
                        (
                            task._platform,
                            task.taskid,
                            task.batchid,
                            task.parentbatchid,
                            client._statusbasic._clientid,
                            task.tokenid,
                            task.apptype,
                            task.forcedownload,
                            task._cmdrcvmsg,
                            task._result,
                            cmdstatus.value,
                            0,  # progress初始化为0
                            0,  #sequence初始化为0
                            task.other_fields_json,
                            task.timestr,
                            helper_time.get_time_sec_tz(),
                            task.source,
                            task.cmd_id))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("save_new_idownbatchtask error: %s" %
                               traceback.format_exc())

        return (res, isnew)

    @table_locker(__tb_IDownBatchTask._tbname)
    def get_parent_clientid_of_task(self, task: Task) -> str:
        """获取 指定task的被分配到的采集端 Client对象"""
        res: str = None
        conn: SqliteConn = None
        cursor = None
        task: Task = task
        try:
            if helper_str.is_none_or_empty(task.parenttaskid):
                raise Exception(
                    "Invalid task parent_taskid for task, taskid={} batchid={}"
                    .format(task.taskid, task.batchid))
            if helper_str.is_none_or_empty(task.parentbatchid):
                raise Exception(
                    "Invalid task parent_batchid for task, taskid={} batchid={}"
                    .format(task.taskid, task.batchid))

            # 搜索每个库,看有没有 taskid和clientid一样,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT ClientId FROM {self._tbname} WHERE 
            Platform=? and TaskId=? and BatchId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task._platform,
                        task.parenttaskid,
                        task.parentbatchid,
                    ))
                    result = cursor.fetchall()

                    if result is None or len(result) < 1 or len(result[0]) < 1:
                        continue
                    else:
                        res = result[0][0]
                        break

                except Exception:
                    self._logger.error(
                        "get_parent_client_of_task error: {}".format(
                            traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()
                    if not res is None:
                        break

        except Exception:
            self._logger.error("get_parent_client_of_task error: %s" %
                               traceback.format_exc())

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def get_batch_task(self, conds: SqlConditions) -> dict:
        """按条件搜索指定的一个任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    Platform,
                    TaskId,
                    Batchid,
                    ParentBatchId,
                    ClientId,
                    TokenId,
                    AppType,
                    ForceDownload,
                    CmdRcvMsg,
                    Result,
                    CmdStatus,
                    Progress,
                    Sequence,
                    OtherFields,
                    CreateTime,
                    UpdateTime,
                    IsBatchCompleteCountIncreased,
                    Source,
                    CmdId FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                # conn._conn.text_factory = self._text_factory
                try:
                    cursor = conn.cursor
                    cursor = cursor.execute(cmd, conds.params)

                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]
                    return fields

                except Exception:
                    self._logger.error(
                        "Get BatchTask from {} error: {}".format(
                            self._tbname, traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get BatchTask {} error: {}".format(
                self._tbname, traceback.format_exc()))

    @table_locker(__tb_IDownBatchTask._tbname)
    def get_batch_tasks(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            cmd = f'''SELECT 
                    Platform,
                    TaskId,
                    Batchid,
                    ParentBatchId,
                    ClientId,
                    TokenId,
                    AppType,
                    ForceDownload,
                    CmdRcvMsg,
                    Result,
                    CmdStatus,
                    Progress,
                    Sequence,
                    OtherFields,
                    CreateTime,
                    UpdateTime,
                    IsBatchCompleteCountIncreased,
                    Source,
                    CmdId FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                # conn._conn.text_factory = self._text_factory
                try:
                    cursor = conn.cursor
                    cursor = cursor.execute(cmd, conds.params)

                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        # if len(row) != 15:
                        #     continue
                        fields: dict = {}
                        for i in range(len(row)):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error(
                        "Get BatchTasks from {} error: {}".format(
                            self._tbname, traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get BatchTasks {} error: {}".format(
                self._tbname, traceback.format_exc()))

    @table_locker(__tb_IDownBatchTask._tbname)
    def get_batch_task_count_by_cmdstatus(self, task: Task,
                                          cmdstatus: ECommandStatus) -> int:
        """查询指定总任务taskid下的所有 为指定命令状态的子任务 的数量"""
        res: int = 0  #总数量
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT COUNT() FROM {self._tbname} WHERE Platform=? and TaskId=? and CmdStatus=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task._platform,
                        task.taskid,
                        cmdstatus.value,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    tmp = result[0][0]

                    res = res + tmp

                except Exception:
                    self._logger.error("Select {} error: {}".format(
                        self._tbname, traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Save new {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def update_batchtask(self, task: Task) -> bool:
        """使用指定task对象更新IDownBatchTask表,
        不更新 isbatchcompletecountincreased\n
        task: 表示一个子任务对象"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            task._cmdstatus
            cmd = f'''UPDATE {self._tbname} set
                    ClientId=?,
                    ParentBatchId=?,
                    TokenId=?,
                    AppType=?,
                    ForceDownload=?,
                    CmdRcvMsg=?,
                    Result=?,
                    CmdStatus=?,
                    Progress=?,
                    Sequence=?,
                    OtherFields=?,
                    CreateTime=?,
                    UpdateTime=?,
                    Source=?,
                    CmdId=? 
                    WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(cmd, (
                        task._clientid,
                        task.parentbatchid,
                        task.tokenid,
                        task.apptype,
                        task.forcedownload,
                        task._cmdrcvmsg,
                        task._result,
                        task._cmdstatus.value,
                        task.progress,
                        task._sequence,
                        task.other_fields_json,
                        task.timestr,
                        helper_time.get_time_sec_tz(),
                        task.source,
                        task.cmd_id,
                        task._platform,
                        task.taskid,
                        task.batchid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def update_batchtask_status(self, platform: str, taskid: str, batchid: str,
                                cmdstatus: ECommandStatus) -> bool:
        """使用指定task对象更新IDownBatchTask表,
        不更新 isbatchcompletecountincreased\n
        task: 表示一个子任务对象"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    CmdStatus=? 
                    WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(cmd, (
                        cmdstatus.value,
                        platform,
                        taskid,
                        batchid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def update_batchtask_client(self, platform: str, taskid: str, batchid: str,
                                clientid: str) -> bool:
        """更新batchtask被分配到的采集端"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            if not isinstance(clientid, str) or clientid == "":
                raise Exception(
                    "Invalid clientid for update_batchtask_clientid")
            cmd = f'''UPDATE {self._tbname} set
                    ClientId=? 
                    WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    # task:Task = task
                    result = cursor.execute(cmd, (
                        clientid,
                        platform,
                        taskid,
                        batchid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "update batchtask client to {} error: {}".format(
                    self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def update_batchtask_back(self, tb: TaskBatchBack) -> bool:
        """使用指定 TaskBatchBack 对象更新IDownBatchTask表,
        不更新 isbatchcompletecountincreased\n"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        tb: TaskBatchBack = tb
        try:
            if not isinstance(tb, TaskBatchBack):
                self._logger.error(
                    "Invalid param TaskBatchBack: {}".format(tb))
                return res

            # Platform
            # TaskId,
            # Batchid,
            # ClientId,
            # TokenId,
            # AppType,
            # CmdRcvMsg,
            # Result,
            # CmdStatus,
            # Progress,
            # Sequence,
            # OtherFields,
            # CreateTime,
            # UpdateTime,
            # IsBatchCompleteCountIncreased
            # CmdId
            # 更新策略,先搜一下有没有,并把sequence搜出来,如果
            # 本地sequence和新来的任务的sequence一样,则说明
            # 采集端的sequence出错了,打一句日志并返回False
            cmd = f'''SELECT Sequence FROM {self._tbname} WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:

                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        tb._platform,
                        tb._taskid,
                        tb._batchid,
                    ))
                    result = cursor.fetchall()

                    if result is None or len(result) < 1:
                        continue

                    oldseq = result[0][0]
                    if oldseq >= tb._sequence:
                        self._logger.error(
                            "The comming TaskBatchBack.sequence is {}, but which in local db is {}:\ntaskid:{}\nbatchid:{}\nsequence:{}"
                            .format(tb._sequence, oldseq, tb._taskid,
                                    tb._batchid, oldseq))
                        break

                    cmd = f'''UPDATE {self._tbname} set
                            CmdRcvMsg=?,
                            Result=?,
                            CmdStatus=?,
                            Progress=?,
                            Sequence=?,
                            UpdateTime=? 
                            WHERE Platform=? and TaskId=? and BatchId=? and Sequence<?;'''
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        tb._cmdrcvmsg,
                        tb._result,
                        tb._cmdstatus.value,
                        tb._progress,
                        tb._sequence,
                        helper_time.get_time_sec_tz(),
                        tb._platform,
                        tb._taskid,
                        tb._batchid,
                        tb._sequence,
                    ))

                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def is_batch_complete_count_increaced(self, platform: str, taskid: str,
                                          batchid: str) -> bool:
        """返回 指定的子任务完成情况 是否已更新到 总任务表的 batchcompletecount 字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            # IsBatchCompleteCountIncreased
            cmd = f'''SELECT IsBatchCompleteCountIncreased FROM {self._tbname} 
            WHERE Platform=? and TaskId=? and BatchId=?'''
            found = False
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                        batchid,
                    ))
                    result = cursor.fetchall()
                    if not result is None and len(result) > 0:
                        tmp = result[0][0]
                        res = bool(tmp)  # 一定只有一个子任务
                        found = True
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if found:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IDownBatchTask._tbname)
    def update_batch_complete_count_increaced_flag(
            self, platform: str, taskid: str, batchid: str,
            isbatchcompletecountincreased: bool) -> bool:
        """使用指定 TaskBatchBack 对象的 isbatchcompletecountincreased 字段\n"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:

            # Platform
            # TaskId,
            # Batchid,
            # ClientId,
            # TokenId,
            # AppType,
            # CmdRcvMsg,
            # Result,
            # CmdStatus,
            # Sequence,
            # OtherFields,
            # CreateTime,
            # UpdateTime,
            # IsBatchCompleteCountIncreased
            cmd = f'''UPDATE {self._tbname} set
                    IsBatchCompleteCountIncreased=? 
                    WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:

                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        1 if isbatchcompletecountincreased else 0,
                        platform,
                        taskid,
                        batchid,
                    ))

                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} error: {}".format(
                self._tbname, traceback.format_exc()))

        return res
Пример #12
0
class TbMail(TbSqliteBase):
    __tb_mail_service: SqliteTable = SqliteTable(
        'mailservice',
        True,
        SqliteColumn(
            colname='ID',
            coltype='INTEGER',
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True).set_index_new(),
        SqliteColumn(colname='service_name', nullable=False),
        SqliteColumn(colname='imap_host'),
        SqliteColumn(colname='imap_port'),
        SqliteColumn(colname='pop3_host'),
        SqliteColumn(colname='pop3_port'),
    )
    databasename = 'task'

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbMail.__tb_mail_service._tbname, dbcfg, TbMail.databasename)
        self._xml_path = Path(__file__).parent / 'host.xml'
        self._init_default_service()

    def _append_tables(self):
        self._conn_mngr.append_table(TbMail.__tb_mail_service)

    def _init_default_service(self):
        """
        初始化数据,读取本地的xml文件,然后存入数据库
        :return:
        """
        if len(self._get_default_mail_service()) != 0:
            return
        tree = ET.parse(str(self._xml_path))
        root = tree.getroot()
        childs = iter(root)
        for child in childs:
            tag = child.attrib.get('name')
            server = iter(child)
            imap = next(server)
            pop3 = next(server)
            imap_host = imap.attrib.get('host')
            imap_port = imap.attrib.get('port')
            pop3_host = pop3.attrib.get('host')
            pop3_port = pop3.attrib.get('port')
            self.insert_a_piece_of_data(tag, imap_host, imap_port, pop3_host, pop3_port)
        return

    @table_locker(__tb_mail_service._tbname)
    def _get_default_mail_service(self):
        conn: SqliteConn = None
        res = []
        sql = '''
        SELECT * FROM mailservice
        '''
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql)
                    res_data = c.fetchall()
                    if len(res_data) > 0:
                        res.extend(res_data)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(f"Query task according to the task status data problem,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
        return res

    @table_locker(__tb_mail_service._tbname)
    def insert_a_piece_of_data(self, service_name, imap_host, imap_port, pop3_host, pop3_port):
        """
        向数据库插入一条完整的数据
        :param service_name:
        :param imap_host:
        :param imap_port:
        :param pop3_host:
        :param pop3_port:
        :return:
        """
        conn: SqliteConn = None
        sql = '''
        INSERT INTO mailservice(service_name, imap_host, imap_port, pop3_host, pop3_port)
        VALUES (?, ?, ?, ?, ?);       
        '''
        params = (service_name, imap_host, imap_port, pop3_host, pop3_port)
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.execute(sql, params)
        except Exception:
            self._logger.error(f"There was a problem inserting data, err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_mail_service._tbname)
    def update_service_by_sql(self, sql, pars):
        """
        通过sql更新数据
        :param sql:
        :param pars:
        :return:
        """
        res = False
        conn: SqliteConn = None
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if result is not None and result.rowcount > 0:  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(f"Update default cmd error,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
        return

    @table_locker(__tb_mail_service._tbname)
    def delete_one_mail_service(self, mail):
        """
        删除某个mail
        :param mail:
        :return:
        """
        sql = f'''DELETE FROM mailservice WHERE service_name=?'''
        pars = (mail,)
        res = False
        conn: SqliteConn = None
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if result is not None and result.rowcount > 0:  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(f"Update default cmd error,err:{traceback.format_exc()}.")
        finally:
            if conn is not None:
                conn.close()
        return
Пример #13
0
class TbTaskUserInfo(TbSqliteBase):
    __tb_userinfo: SqliteTable = SqliteTable(
        "userinfo",
        True,
        SqliteColumn(
            colname="Id",
            coltype="INTEGER",
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True,
        ).set_index_new(),
        SqliteColumn(colname="taskid",
                     coltype="CHAR",
                     length=50,
                     nullable=False).set_index_new(),
        SqliteColumn(colname="batchid",
                     coltype="CHAR",
                     length=50,
                     nullable=False).set_index_new(),
        SqliteColumn(colname="userid",
                     coltype="CHAR",
                     length=50,
                     nullable=False),
        SqliteColumn(colname="clientid",
                     coltype="CHAR",
                     length=50,
                     nullable=False),
        # SqliteColumn(colname='Account', nullable=False),
        # SqliteColumn(colname='DownloadTime', coltype='DATETIME', nullable=False),
    )
    databasename = "idownuser"

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(
            self,
            TbTaskUserInfo.__tb_userinfo._tbname,
            dbcfg,
            TbTaskUserInfo.databasename,
        )

    def _append_tables(self):
        self._conn_mngr.append_table(TbTaskUserInfo.__tb_userinfo)

    @table_locker(__tb_userinfo._tbname)
    def __count_userinfo(self, taskid, batchid):
        """
        每个taskid和batchid代表唯一的一个任务
        一个唯一的任务对应唯一的userid
        :param taskid:
        :return:
        """
        conn: SqliteConn = None
        res = []
        sql = """
        SELECT count(1) FROM userinfo
        WHERE taskid=? AND batchid=?
        """
        par = (taskid, batchid)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    # conn._conn.row_factory = self._dict_factory
                    c = conn.cursor
                    c.execute(sql, par)
                    res_data = c.fetchall()
                    # print(res_data)
                    if len(res_data) > 0 and res_data[0][0] > 0:
                        res.extend(res_data)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query user from userinfo error\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return res

    def _get_update_sql(self, taskid, batchid, userid, clientid):
        """
        一个唯一的任务只有唯一的userid和唯一的clientid
        所以直接更新就好
        """
        params: list = []
        sql = "UPDATE userinfo SET userid=?, clientid=?"
        params.append(userid)
        params.append(clientid)
        sql += " WHERE taskid=? and batchid=?"
        params.append(taskid)
        params.append(batchid)
        return sql, params

    @table_locker(__tb_userinfo._tbname)
    def _updatesameuserinfo(self, taskid, batchid, userid, clientid):
        """
        在插入任务数据前,先检查iscantask表
        是否有相同的taskid, 如果taskid相同那么就更新整条数据的状态
        """
        res = False
        conn: SqliteConn = None
        resdata = self.__count_userinfo(taskid, batchid)
        if len(resdata) == 0:
            # 没有重复的id直接返回
            return False
        elif len(resdata) > 1:
            raise Exception(
                "The database has duplicated multiple skipids, please check the problem"
            )
        elif len(resdata) == 1:
            sql, par = self._get_update_sql(taskid, batchid, userid, clientid)
            try:
                for conn in self.connect_all(5):
                    try:
                        c = conn.cursor
                        result = c.execute(sql, par)
                        if result is not None and result.rowcount > 0:
                            res = True
                    except Exception as ex:
                        conn._conn.rollback()
                        raise ex
                    else:
                        conn.commit()
                    finally:
                        if conn is not None:
                            conn.close()
                        if res:
                            break
            except Exception:
                self._logger.error(
                    f"There was a problem updating the userinfo table\nerr:{traceback.format_exc()}"
                )
            finally:
                if conn is not None:
                    conn.close()
            return True

    @table_locker(__tb_userinfo._tbname)
    def save_idown_userinfo(self, taskid, batchid, userid, clientid):
        """
        保存idown的user信息
        主要用于关联idown task给后台反馈目前的cookie状态
        """
        conn: SqliteConn = None
        # 在插入数据前查询是否有相同的数据,一个taskid和一个batchid只能带有一个userid
        repeat = self._updatesameuserinfo(taskid, batchid, userid, clientid)
        if repeat:
            # 如果已经处理了重复的数据直接就结束了
            return
        sql = """insert into userinfo(
            taskid,
            batchid,
            userid,
            clientid
        ) values(?,?,?,?)"""
        pars = (taskid, batchid, userid, clientid)
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.execute(sql, pars)
        except Exception:
            self._logger.error(
                f"There was a problem inserting data\nerr:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_userinfo._tbname)
    def query_idown_userinfo(self, taskid, batchid) -> dict:
        """
        查询每个任务的user信息
        每个任务对应唯一的user
        :return:
        """
        conn: SqliteConn = None
        res = None
        sql = """SELECT 
        *
        FROM userinfo
        WHERE taskid=? and batchid=?;"""
        pars = (taskid, batchid)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, pars)
                    res_data = c.fetchall()
                    if len(res_data) > 0:
                        res = res_data[0]
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query idown userinfo error\nerr:{traceback.format_exc()}")
        finally:
            if conn is not None:
                conn.close()
        return res
Пример #14
0
class TbClient(TbSqliteBase):
    """Client表及相关操作"""

    __tb_Clients: SqliteTable = SqliteTable(
        'Clients',
        True,
        SqliteColumn(
            colname='Id',
            coltype='INTEGER',
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True).set_index_new(),
        SqliteColumn(colname='ClientId', nullable=False).set_index_new(),
        SqliteColumn(colname='SystemVer'),
        SqliteColumn(colname='IP'),
        SqliteColumn(colname='Mac'),
        SqliteColumn(colname='CrossWall', coltype='INTEGER'),
        SqliteColumn(colname='Country'),
        SqliteColumn(colname='Platform'),
        SqliteColumn(
            colname='AppType',
            defaultval='[]',
            description='一个python列表字符串 "[1001,1002]",使用apptype的值'),
        SqliteColumn(
            colname='TaskType',
            defaultval='[]',
            description='一个python列表字符串 "[1,2]",使用ETaskType的值'),
        SqliteColumn(
            colname='AppClassify',
            defaultval='[]',
            description='一个python列表字符串 "[1,2,3]",使用appclassify的值'),
        SqliteColumn(
            colname='ClientBusiness',
            defaultval='[]',
            description='一个python列表字符串 "[1,2,3]",使用EClientBusiness的值'),
        SqliteColumn(colname='CpuSize', coltype='REAL'),
        SqliteColumn(colname='CpuPerc', coltype='REAL'),
        SqliteColumn(colname='MemSize', coltype='REAL'),
        SqliteColumn(colname='MemPerc', coltype='REAL'),
        SqliteColumn(colname='BandWidthd', coltype='REAL'),
        SqliteColumn(colname='BandWidthdPerc', coltype='REAL'),
        SqliteColumn(colname='DiskSize', coltype='REAL'),
        SqliteColumn(colname='DiskPerc', coltype='REAL'),
        SqliteColumn(colname='TaskNewCnt', coltype='INTEGER'),
        SqliteColumn(colname='TaskWaitingCnt', coltype='INTEGER'),
        SqliteColumn(colname='TaskDownloadingCnt', coltype='INTEGER'),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
    )

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self, TbClient.__tb_Clients._tbname, dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbClient.__tb_Clients)

    @table_locker(__tb_Clients._tbname)
    def save_client_status_basic(self, client: StatusBasic) -> bool:
        """保存采集端基础状态"""
        res = False
        conn: SqliteConn = None
        cursor = None
        client: StatusBasic = client
        try:
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE ClientId=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (client._clientid, ))
                    result = cursor.fetchall()

                    # 这里只要找到了就是库里有的,然后只更新UpdateTime比当前库中大的
                    if result[0][0] > 0:
                        res = True
                        # update
                        cmd = f'''UPDATE {self._tbname} set
                            SystemVer=?,
                            IP=?,
                            Mac=?,
                            CrossWall=?,
                            Country=?,
                            Platform=?,
                            AppType=?,
                            TaskType=?,
                            AppClassify=?,
                            ClientBusiness=?,
                            CpuSize=?,
                            CpuPerc=?,
                            MemSize=?,
                            MemPerc=?,
                            BandWidthd=?,
                            BandWidthdPerc=?,
                            DiskSize=?,
                            DiskPerc=?,
                            UpdateTime=?
                            WHERE ClientId=? and UpdateTime<=?'''
                        result = cursor.execute(cmd, (
                            client.systemver,
                            client.ip,
                            client.mac,
                            client.crosswall,
                            client.country,
                            client.platform,
                            str(client.apptype),
                            str(client.tasktype),
                            str(client.appclassify),
                            str(client.clientbusiness),
                            client.cpusize,
                            client.cpuperc,
                            client.memsize,
                            client.memperc,
                            client.bandwidthd,
                            client.bandwidthdperc,
                            client.disksize,
                            client.diskperc,
                            client.time,
                            client._clientid,
                            client.time,
                        ))

                        if not result is None and result.rowcount > 0:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            if not res:
                try:
                    conn = self.connect_write(5)
                    cmd = f'''INSERT INTO {self._tbname}(
                        ClientId,
                        SystemVer,
                        IP,
                        Mac,
                        CrossWall,
                        Country,
                        Platform,
                        AppType,
                        TaskType,
                        AppClassify,
                        ClientBusiness,
                        CpuSize,
                        CpuPerc,
                        MemSize,
                        MemPerc,
                        BandWidthd,
                        BandWidthdPerc,
                        DiskSize,
                        DiskPerc,
                        UpdateTime) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        client._clientid,
                        client.systemver,
                        client.ip,
                        client.mac,
                        client.crosswall,
                        client.country,
                        client.platform,
                        str(client.apptype),
                        str(client.tasktype),
                        str(client.appclassify),
                        str(client.clientbusiness),
                        client.cpusize,
                        client.cpuperc,
                        client.memsize,
                        client.memperc,
                        client.bandwidthd,
                        client.bandwidthdperc,
                        client.disksize,
                        client.diskperc,
                        client.time,
                    ))

                    if not result is None and result.rowcount > 0:  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "Save client status basic error: %s" % traceback.format_exc())
        finally:
            if not conn is None:
                conn.close()
        return res

    @table_locker(__tb_Clients._tbname)
    def save_client_status_task(self, client: StatusTask):
        """保存采集端任务统计数据"""
        res = False
        conn: SqliteConn = None
        cursor = None
        client: StatusTask = client
        try:
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE ClientId=?'''
            for conn in self.connect_all(5):
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (client._clientid, ))
                    result = cursor.fetchall()
                    if result[0][0] > 0:
                        res = True
                        # update
                        cmd = f'''UPDATE {self._tbname} set
                            TaskNewCnt=?,
                            TaskWaitingCnt=?,
                            TaskDownloadingCnt=?,
                            UpdateTime=?
                            WHERE ClientId=? and UpdateTime<=?;'''
                        result = cursor.execute(cmd, (
                            client.tasknewcnt,
                            client.taskwaitingcnt,
                            client.taskdownloadingcnt,
                            client.time,
                            client._clientid,
                            client.time,
                        ))

                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount > 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break
            if not res:
                try:
                    # insert
                    conn = self.connect_write(5)
                    cmd = f'''INSERT INTO {self._tbname}(
                        ClientId,
                        TaskNewCnt,
                        TaskWaitingCnt,
                        TaskDownloadingCnt,
                        UpdateTime) VALUES(?,?,?,?,?)'''
                    cursor = conn.cursor
                    result = cursor.execute(
                        cmd, (client._clientid, client.tasknewcnt,
                              client.taskwaitingcnt, client.taskdownloadingcnt,
                              client.time))
                    if not result is None and result.rowcount > 0:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "Save client status task error: %s" % traceback.format_exc())

        return res

    @table_locker(__tb_Clients._tbname)
    def get_client_status(self, clientid: str) -> dict:
        """获取指定采集端信息数据,返回数据行"""
        res: dict = None
        conn: SqliteConn = None
        cursor = None
        try:
            for conn in self._conn_mngr.connect_all():
                try:

                    conn._conn.row_factory = SqliteConn._row_dict_factory
                    cursor = conn.cursor

                    cmd = f'''SELECT
                        ClientId,
                        SystemVer,
                        IP,
                        Mac,
                        CrossWall,
                        Country,
                        Platform,
                        AppType,
                        TaskType,
                        AppClassify,
                        ClientBusiness,
                        CpuSize,
                        CpuPerc,
                        MemSize,
                        MemPerc,
                        BandWidthd,
                        BandWidthdPerc,
                        DiskSize,
                        DiskPerc,
                        TaskNewCnt,
                        TaskWaitingCnt,
                        TaskDownloadingCnt,
                        UpdateTime
                        FROM {self._tbname} WHERE ClientId=?'''

                    cursor.execute(cmd, (clientid, ))

                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]

                    if isinstance(fields, dict) and len(fields) > 0:
                        res = fields
                        break

                    # result = cursor.fetchall()

                    # for row in result:
                    #     res = row  # 只取第一行
                    #     break

                    if not res is None:
                        break

                except Exception:
                    self._logger.error(
                        "Get client status error: %s" % traceback.format_exc())
                finally:
                    if not conn is None:
                        conn.close()
                    if not res is None:
                        break

        except Exception:
            self._logger.error(
                "Get client status error: %s" % traceback.format_exc())
        return res

    @table_locker(__tb_Clients._tbname)
    def get_client_status_all(self, interval: float = 15) -> iter:
        """获取所有采集端任务状态数据。\n
        interval: 指定心跳间隔,即只读取最近n秒内更新的采集端状态,单位秒。"""
        res: Client = None
        conn: SqliteConn = None
        cursor = None
        try:
            # 如果心跳间隔不对,则使用默认值
            if not type(interval) in [int, float] or interval < 2:
                interval = 15

            for conn in self._conn_mngr.connect_all():
                # conn = DbSqlite._conn_mngr.connect_write()
                conn._conn.row_factory = self._dict_factory
                cursor = conn.cursor

                cmd = f'''SELECT 
                    ClientId,
                    SystemVer,
                    IP,
                    Mac, 
                    CrossWall,
                    Country,
                    Platform,
                    AppType,
                    TaskType,
                    AppClassify,
                    ClientBusiness,
                    CpuSize,
                    CpuPerc,
                    MemSize,
                    MemPerc,
                    BandWidthd,
                    BandWidthdPerc,
                    DiskSize,
                    DiskPerc,
                    TaskNewCnt,
                    TaskWaitingCnt,
                    TaskDownloadingCnt,
                    UpdateTime 
                    FROM {self._tbname} WHERE UpdateTime>=?'''

                # helper_time.ts_since_1970_tz()单位为秒,减去心跳间隔15秒,
                # 就是15秒内状态有更新的才认为是上线的,有效的客户端
                it = helper_time.ts_since_1970_tz() - interval
                cursor.execute(cmd, (it, ))
                result = cursor.fetchall()

                for row in result:
                    # if len(row) != 15:
                    #     continue
                    fields: dict = {}
                    for i in range(len(row)):
                        fields[cursor.description[i][0].lower()] = row[i]

                    sb: StatusBasic = StatusBasic(fields)
                    st: StatusTask = StatusTask(fields)
                    res: Client = Client(sb, st)
                    yield res

        except Exception:
            self._logger.error(
                "Get all client status error: %s" % traceback.format_exc())
        finally:
            if not conn is None:
                conn.close()
Пример #15
0
class TbTask(TbSqliteBase):
    __tb_task: SqliteTable = SqliteTable(
        "task",
        True,
        SqliteColumn(
            colname="ID",
            coltype="INTEGER",
            nullable=False,
            is_primary_key=True,
            is_auto_increament=True,
            is_unique=True,
        ).set_index_new(),
        SqliteColumn(colname="taskid",
                     coltype="CHAR",
                     length=50,
                     nullable=False).set_index_new(),
        SqliteColumn(colname="platform",
                     coltype="CHAR",
                     length=50,
                     nullable=False),
        SqliteColumn(colname="clientid",
                     coltype="CHAR",
                     length=50,
                     nullable=False),
        SqliteColumn(colname="parent_taskid", coltype="CHAR", length=50),
        SqliteColumn(colname="batchid",
                     coltype="CHAR",
                     length=50,
                     nullable=False),
        SqliteColumn(colname="parentbatchid", coltype="CHAR", length=50),
        SqliteColumn(colname="apptype", coltype="INT"),
        SqliteColumn(colname="tasktype", coltype="INT"),
        SqliteColumn(colname="url", coltype="CHAR", length=50),
        SqliteColumn(colname="host", coltype="CHAR", length=50),
        SqliteColumn(colname="cookie", coltype="CHAR"),
        SqliteColumn(colname="preaccount", coltype="CHAR", length=50),
        SqliteColumn(colname="account", coltype="CHAR", length=50),
        SqliteColumn(colname="password", coltype="CHAR", length=50),
        SqliteColumn(colname="phone", coltype="CHAR", length=50),
        SqliteColumn(colname="input", coltype="CHAR", length=50),
        SqliteColumn(colname="taskstatus", coltype="INT"),
        SqliteColumn(colname="createtime", coltype="INT"),
        SqliteColumn(colname="lastexecutetime", coltype="INT"),
        SqliteColumn(colname="failtimes", coltype="INT"),
        SqliteColumn(colname="successtimes", coltype="INT"),
        SqliteColumn(colname="preglobaltelcode", coltype="CHAR", length=10),
        SqliteColumn(colname="globaltelcode", coltype="CHAR", length=10),
        SqliteColumn(colname="otherfileds", coltype="CHAR"),
        SqliteColumn(colname="tokentype", coltype="INT"),
        SqliteColumn(colname="sequence", coltype="INT"),
        SqliteColumn(colname="progress", coltype="REAL"),
        SqliteColumn(colname="forcedownload", coltype="CHAR", length=10),
        SqliteColumn(colname="source", coltype="CHAR", nullable=False),
        SqliteColumn(colname="cmdid", coltype="CHAR", length=50),
        SqliteColumn(colname="cookiealive", coltype="INT"),
        SqliteColumn(colname="cookielastkeeptime", coltype="INT"),
    )

    databasename = "task"

    def __init__(self, dbcfg: SqliteConfig):
        TbSqliteBase.__init__(self, TbTask.__tb_task._tbname, dbcfg,
                              TbTask.databasename)

    def _append_tables(self):
        self._conn_mngr.append_table(TbTask.__tb_task)

    @table_locker(__tb_task._tbname)
    def query_task(self, conds: SqlConditions) -> list:
        """
        根据任务状态来取出task表的任务,
        根据不同的状态来查询不同的任务数据
        :param key:
        :param value:
        :return:
        """
        conn: SqliteConn = None
        res = []
        sql = """SELECT 
        taskid,
        task.platform,
        clientid,
        parent_taskid,
        batchid,
        parentbatchid,
        apptype,
        tasktype,
        url,
        host,
        cookie,
        preaccount,
        account,
        password,
        phone,
        input,
        taskstatus,
        createtime,
        lastexecutetime,
        failtimes,
        successtimes,
        preglobaltelcode,
        globaltelcode,
        otherfileds,
        tokentype,
        sequence,
        progress,
        forcedownload,
        source,
        cmdid,
        cmd,
        cookiealive,
        cookielastkeeptime
        FROM task  LEFT OUTER JOIN idowncmd USING (cmdid)
        WHERE {};""".format(conds.text_normal)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, conds.params)
                    res_data = c.fetchall()
                    if len(res_data) > 0:
                        res.extend(res_data)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query task according to the task status data problem,err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.close()
        return res

    def __modify_task_state(self, oldstate: int, task: Task):
        """
        这里的前置是已经为下载过的任务
        1、一次性任务,除了正在执行,新任务都会去更新状态
        2、循环任务,不会更新状态
        :param task:
        :return:
        """
        # 默认为不更新状态
        res = False
        circule_modle = task.cmd.stratagy.circulation_mode
        # 一次性任务
        if circule_modle == 1 and oldstate not in [0, 1, 2, 3, 5]:
            res = True
        # 循环任务或者其他情况都不去更新状态
        return res

    def _get_task_update_sql(self, src: dict, new: Task):
        """拼接更新task的sql,并返回sqlparameters列表"""
        params: list = []
        sql = "UPDATE task SET "
        # 特定条件更新任务下载状态
        if self.__modify_task_state(src["taskstatus"], new):
            sql += "taskstatus=?, "
            params.append(new.taskstatus.value)
        # 如果cmdid不一致则需要更新下cmd
        if src["cmdid"] != new.cmd_id:
            sql += "cmdid"
            params.append(new.cmd_id)
        # sql += 'otherfileds=?, '
        # params.append(json.dumps(new._other_fields))
        sql += "tasktype=?, "
        params.append(new.tasktype.value)
        if not helper_str.is_none_or_empty(new.cookie):
            sql += "cookie=?, "
            params.append(new.cookie)
        if helper_str.is_none_or_empty(
                src["url"]) and not helper_str.is_none_or_empty(new.url):
            sql += "url=?, "
            params.append(new.url)
        if helper_str.is_none_or_empty(
                src["host"]) and not helper_str.is_none_or_empty(new.host):
            sql += "host=?, "
            params.append(new.host)
        if helper_str.is_none_or_empty(
                src["account"]) and not helper_str.is_none_or_empty(
                    new.account):
            sql += "account=?, "
            params.append(new.account)
        if helper_str.is_none_or_empty(
                src["password"]) and not helper_str.is_none_or_empty(
                    new.password):
            sql += "password=?, "
            params.append(new.password)
        if helper_str.is_none_or_empty(
                src["phone"]) and not helper_str.is_none_or_empty(
                    new.password):
            sql += "phone=?, "
            params.append(new.password)
        if helper_str.is_none_or_empty(
                src["globaltelcode"]) and not helper_str.is_none_or_empty(
                    new.globaltelcode):
            sql += "globaltelcode=?, "
            params.append(new.globaltelcode)
        # if not helper_str.is_none_or_empty(new._sequence):
        #     sql += 'sequence=?, '
        #     params.append(int(new._sequence))
        if not helper_str.is_none_or_empty(new.forcedownload):
            sql += "forcedownload=?, "
            params.append(int(new.forcedownload))

        sql = sql.rstrip().rstrip(",")
        sql += " WHERE batchid=? AND taskid=?"
        params.append(new.batchid)
        params.append(new.taskid)

        return (sql, params)

    @table_locker(__tb_task._tbname)
    def __count_idowntask(self, taskid, batchid):
        """
        对数据库中的任务进行计数
        :param taskid:
        :param batchid:
        :return:
        """
        conn: SqliteConn = None
        res = []
        # sql = '''
        # SELECT count(1) FROM task
        # WHERE taskid=? AND batchid=?
        # '''
        sql = """
        SELECT * FROM task WHERE taskid=? AND batchid=?
        """
        par = (taskid, batchid)
        try:
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    # 只计数
                    # c = conn.cursor
                    # c.execute(sql, par)
                    # res_data = c.fetchall()
                    # print(res_data)
                    # if len(res_data) > 0 and res_data[0][0] > 0:
                    #     res.extend(res_data)
                    # 将数据库中的源数据查询出来
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, par)
                    fres: list = c.fetchall()
                    if len(fres) > 0:
                        res.extend(fres)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                finally:
                    if conn is not None:
                        conn.close()
        except Exception:
            self._logger.error(
                f"Query task according to the task status data problem,err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.close()
        return res

    @table_locker(__tb_task._tbname)
    def _updatesametaskiddata(self, dt: Task):
        """
        在插入任务数据前,先检查task表
        是否有相同的batchid, 如果batchid相同那么就更新整条数据的状态
        :param dt:
        :return:
        """
        res = False
        conn: SqliteConn = None
        resdata = self.__count_idowntask(dt.taskid, dt.batchid)
        if len(resdata) == 0:
            # 没有重复的id直接返回
            return False
        elif len(resdata) > 1:
            raise Exception(
                "The database has duplicated multiple skipids, please check the problem"
            )
        elif len(resdata) == 1:
            sql, par = self._get_task_update_sql(resdata[0], dt)
            try:
                for conn in self.connect_all(5):
                    try:
                        c = conn.cursor
                        result = c.execute(sql, par)
                        if (result is not None and
                                result.rowcount > 0):  # or len(result) < 1:
                            res = True
                    except Exception as ex:
                        conn._conn.rollback()
                        raise ex
                    else:
                        conn.commit()
                    finally:
                        if conn is not None:
                            conn.close()
                        if res:
                            break
            except Exception:
                self._logger.error(
                    f"There was a problem updating the task table task data,err:{traceback.format_exc()}!"
                )
            finally:
                if conn is not None:
                    conn.close()
            return True

    @table_locker(__tb_task._tbname)
    def insert_task_to_sqlit(self, dt: Task):
        """
        通过登录测试的任务
        将有效的任务放入数据库的task表
        只会在这个地方插入一次
        :param dt:
        :return:
        """
        conn: SqliteConn = None
        # 在插入数据前查询是否有相同的数据(目前只根据taskid查询),如果有相同的数据则不插入。
        repeat = self._updatesametaskiddata(dt)
        if repeat:
            # 如果已经处理了重复的数据直接就结束了
            return
        sql = """INSERT INTO task (
               taskid,
               platform,
               clientid,
               parent_taskid,
               batchid,
               parentbatchid,
               apptype,
               tasktype,
               url,
               host,
               cookie,
               preaccount,
               account,
               password,
               phone,
               input,
               taskstatus,
               createtime,
               lastexecutetime,
               failtimes,
               successtimes,
               preglobaltelcode,
               globaltelcode,
               otherfileds,
               tokentype,
               sequence,
               progress,
               forcedownload,
               source,
               cmdid,
               cookiealive,
               cookielastkeeptime
               )
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?,?,?,?,?,?,?,?,?,?);
               """
        params = (
            dt.taskid,
            dt.platform,
            dt._clientid,
            dt.parenttaskid,
            dt.batchid,
            dt.parentbatchid,
            int(dt.apptype),
            dt.tasktype.value,
            dt.url,
            dt.host,
            dt.cookie,
            dt.preaccount,
            dt.account,
            dt.password,
            dt.phone,
            dt.input,
            dt.taskstatus.value,
            dt.createtime,
            dt.lastexecutetime,
            dt.failtimes,
            dt.successtimes,
            dt.preglobaltelcode,
            dt.globaltelcode,
            json.dumps(dt._other_fields),
            dt.tokentype.value,
            int(dt._sequence),
            dt.progress,
            dt.forcedownload,
            dt.source,
            dt.cmd_id,
            dt.cookie_alive,
            dt.cookie_last_keep_alive_time,
        )
        try:
            conn = self.connect_write(5)
            c = conn.cursor
            c.execute(sql, params)
        except Exception:
            self._logger.error(
                f"There was a problem inserting data, err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.commit()
                conn.close()
        return

    @table_locker(__tb_task._tbname)
    def update_status_by_taskid(self, key: str, value: int, batchid, taskid):
        """
        更新task表的任务状态,根据batchid和taskid共同定位数据
        :param key:
        :param value:
        :param taskid:
        :return:
        """
        res = False
        conn: SqliteConn = None
        sql = """UPDATE task set {}=? where taskid=? and batchid=?
        """.format(key)
        pars = (value, taskid, batchid)
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (result is not None
                            and result.rowcount > 0):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"There was a problem inserting data, and duplicate "
                f"data might have been inserted, err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.close()
        return

    @table_locker(__tb_task._tbname)
    def query_task_by_sql(self, sql, pars):
        """
        根据sql来查询数据库,提供一个对外查询的接口
        :param sql:
        :param pars:
        :return:
        """
        conn: SqliteConn = None
        allget = []
        try:
            for conn in self.connect_all(5):
                try:
                    conn._conn.row_factory = self._dict_factory
                    c = conn._conn.cursor()
                    c.execute(sql, pars)
                    res: list = c.fetchall()
                    if len(res) > 0:
                        allget.extend(res)
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
        except:
            self._logger.error(
                f"There was a problem querying data, err:{traceback.format_exc()}."
            )
        finally:
            if conn is not None:
                conn.close()
        return allget

    @table_locker(__tb_task._tbname)
    def update_task_resource(self, tsk: Task):
        """更新Task任务信息"""
        conn: SqliteConn = None
        res = False
        sql = """update task set
        url=?,
        host=?,
        cookie=?,
        account=?,
        password=?,
        phone=?, 
        lastexecutetime=?,
        successtimes=?,
        failtimes=?, 
        sequence=?
        where batchid=? and taskid=?"""
        pars = (
            tsk.url,
            tsk.host,
            tsk.cookie,
            tsk.account,
            tsk.password,
            tsk.phone,
            int(datetime.now(pytz.timezone("Asia/Shanghai")).timestamp()),
            tsk.successtimes,
            tsk.failtimes,
            tsk._sequence,
            tsk.batchid,
            tsk.taskid,
        )
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (result is not None
                            and result.rowcount > 0):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"Update task error:\nbatchid:{tsk.batchid}\nerror:{traceback.format_exc()}"
            )
        finally:
            if conn is not None:
                conn.close()
        return

    @table_locker(__tb_task._tbname)
    def update_task_by_sql(self, sql, pars):
        """
        提供一个对外根据sql更新task的接口,就不管拿来干啥了
        :param sql:
        :param pars:
        :return:
        """
        conn: SqliteConn = None
        res = False
        try:
            for conn in self.connect_all(5):
                try:
                    c = conn.cursor
                    result = c.execute(sql, pars)
                    if (result is not None
                            and result.rowcount > 0):  # or len(result) < 1:
                        res = True
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if conn is not None:
                        conn.close()
                    if res:
                        break
        except Exception:
            self._logger.error(
                f"Update task by sql error, err:{traceback.format_exc()}")
        finally:
            if conn is not None:
                conn.close()
        return
Пример #16
0
class TbIScoutBatchTask(TbSqliteBase):
    """Task表及相关操作"""

    __tb_IScoutBTask: SqliteTable = SqliteTable(
        'IScoutBatchTask',
        True,
        SqliteColumn(colname='Id',
                     coltype='INTEGER',
                     nullable=False,
                     is_primary_key=True,
                     is_auto_increament=True,
                     is_unique=True).set_index_new(),
        SqliteColumn(colname='ClientId', nullable=False).set_index_new(),
        SqliteColumn(colname='Platform', nullable=False).set_index_new(),
        SqliteColumn(colname='Source', nullable=False).set_index_new(),
        SqliteColumn(colname='IsPeriod',
                     coltype='INTEGER',
                     nullable=False,
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='PeriodNum',
                     coltype='INTEGER',
                     nullable=False,
                     defaultval=0).set_index_new(),
        SqliteColumn(colname='StartTime', coltype='DATETIME'),
        SqliteColumn(colname='EndTime', coltype='DATETIME'),
        SqliteColumn(colname='Interval', coltype='REAL'),
        SqliteColumn(colname='LastStartTime', coltype='DATETIME'),
        SqliteColumn(colname='LastEndTime', coltype='DATETIME'),
        SqliteColumn(colname='TaskId', nullable=False).set_index_new(),
        SqliteColumn(colname='BatchId', nullable=False).set_index_new(),
        SqliteColumn(colname='CmdId').set_index_new(),
        SqliteColumn(colname='Status',
                     coltype='INTEGER',
                     nullable=False,
                     description='采集端执行命令的状态,要反给中心的').set_index_new(),
        SqliteColumn(colname='ObjectType', coltype='INTEGER').set_index_new(),
        SqliteColumn(colname='Object', ).set_index_new(),
        SqliteColumn(
            colname='Progress',  #0~1浮点数表百分比
            coltype='REAL',
            nullable=True),
        SqliteColumn(
            colname='Elapsed',  #0~1浮点数表百分比
            coltype='REAL',
            nullable=True),
        SqliteColumn(colname='CmdRcvMsg'),
        SqliteColumn(colname='IsBatchCompleteCountIncreased',
                     coltype='BOOLEAN').set_index_new(),
        SqliteColumn(colname='CreateTime',
                     coltype='DATETIME',
                     defaultval='1970-01-01 00:00:00'),
        SqliteColumn(colname='UpdateTime', coltype='REAL',
                     nullable=False).set_index_new(),
        SqliteColumn(colname='Sequence', coltype='INTEGER',
                     defaultval=0).set_index_new(),
    )

    # scantype=scansearch 主键  TaskId
    # scantype=scan       主键  TaskId+BatchId
    # 所有列,复制粘贴用...:
    # ClientId,
    # Platform,
    # Source,
    # IsPeriod,
    # PeriodNum,
    # StartTime,
    # EndTime,
    # Interval,
    # LastStartTime,
    # LastEndTime
    # TaskId,
    # BatchId,
    # CmdId,
    # Status,
    # ObjectType,
    # Object,
    # Progress,
    # Elapsed,
    # CmdRcvMsg,
    # IsBatchCompleteCountIncreased,
    # CreateTime,
    # UpdateTime,
    # Sequence,

    def __init__(self, dbcfg: SqliteConfig):
        """"""
        TbSqliteBase.__init__(self, TbIScoutBatchTask.__tb_IScoutBTask._tbname,
                              dbcfg)

    def _append_tables(self):
        self._conn_mngr.append_table(TbIScoutBatchTask.__tb_IScoutBTask)

    @table_locker(__tb_IScoutBTask._tbname)
    def save_new_iscoutbtask(
        self,
        task: IscoutTask,
        client: Client,
        cmdstatus: ECommandStatus = ECommandStatus.WaitForSend,
    ) -> Tuple[bool, bool]:
        """保存新的批处理任务的令牌资源\n
        task:任务对象"""
        res = False
        isnew: bool = False
        conn: SqliteConn = None
        cursor = None
        task: IscoutTask = task
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            TaskId=? and BatchId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        task.taskid,
                        task.batchid,
                        task._platform,
                    ))
                    result = cursor.fetchall()
                    if result[0][0] > 0:
                        res = True
                        cmd = f'''UPDATE {self._tbname} set
                            ClientId=?,
                            CmdId=?,
                            Source=?,
                            IsPeriod=?,
                            PeriodNum=?,
                            StartTime=?,
                            EndTime=?,
                            Interval=?,
                            LastStartTime=?,
                            LastEndTime=?,
                            Status=?,
                            ObjectType=?,
                            Object=?,
                            Progress=?,
                            Elapsed=?,
                            CmdRcvMsg=?,
                            IsBatchCompleteCountIncreased=?,
                            UpdateTime=?,
                            CreateTime=?,
                            Sequence=? 
                            WHERE TaskId=? and BatchId=? and Platform=? and CreateTime<=?;'''

                        result = cursor.execute(
                            cmd,
                            (
                                client._statusbasic._clientid,
                                task.cmd_id,
                                task.source,
                                1 if task._is_period else 0,
                                # 这里的update是来了新的任务文件,需要直接覆盖periodnum
                                task.periodnum,
                                task.cmd.stratagy.time_start,
                                task.cmd.stratagy.time_end,
                                task.cmd.stratagy.interval,
                                task.laststarttime,
                                task.lastendtime,
                                cmdstatus.value,
                                task._objecttype.value,
                                task._object,
                                task.progress,
                                0,  # elapsed
                                task.cmdrcvmsg,
                                task.isbatchcompletecountincreased,
                                helper_time.get_time_sec_tz(),
                                task.createtimestr,
                                0,  #重置sequence
                                task.taskid,
                                task.batchid,
                                task._platform,
                                task.createtimestr,
                            ))

                        # 这句没用,就是调试看看结果..
                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            pass

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

            # 若没找到,则insert一条到最新的库
            # res==True表示至少有一个库里面有一条符合条件的任务,且已更新其字段
            if not res:
                isnew = True
                conn = self.connect_write(5)
                try:
                    # insert
                    cmd = f'''INSERT INTO {self._tbname}(
                        ClientId,
                        Platform,
                        Source,
                        IsPeriod,
                        PeriodNum,
                        StartTime,
                        EndTime,
                        Interval,
                        LastStartTime,
                        LastEndTime,
                        TaskId,
                        BatchId,
                        CmdId,
                        Status,
                        ObjectType,
                        Object,
                        Progress,
                        Elapsed,
                        CmdRcvMsg,
                        IsBatchCompleteCountIncreased,
                        CreateTime,
                        UpdateTime,
                        Sequence) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
                    # 有几个属于TaskBack的字段在此不更新
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        client._statusbasic._clientid,
                        task._platform,
                        task.source,
                        1 if task._is_period else 0,
                        task.periodnum,
                        task.cmd.stratagy.time_start,
                        task.cmd.stratagy.time_end,
                        task.cmd.stratagy.interval,
                        task.laststarttime,
                        task.lastendtime,
                        task.taskid,
                        task.batchid,
                        task.cmd_id,
                        cmdstatus.value,
                        task._objecttype.value,
                        task._object,
                        task.progress,
                        0,
                        '',
                        task.isbatchcompletecountincreased,
                        task.createtimestr,
                        helper_time.get_time_sec_tz(),
                        0,
                    ))

                    if result is None or result.rowcount < 1:  # or len(result) < 1:
                        res = False
                    else:
                        res = True

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("save new IScoutTask error: %s" %
                               traceback.format_exc())

        return (res, isnew)

    @table_locker(__tb_IScoutBTask._tbname)
    def select_iscoutbtask(self, conds: SqlConditions) -> dict:
        """按条件搜索任务,返回数据行转换成的字段字典"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            # ClientId,
            # Platform,
            # Source,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime
            # TaskId,
            # BatchId,
            # CmdId,
            # Status,
            # ObjectType,
            # Object,
            # Progress,
            # Elapsed,
            # CmdRcvMsg,
            # IsBatchCompleteCountIncreased,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''select 
                    ClientId,
                    Platform,
                    Source,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    TaskId,
                    BatchId,
                    CmdId,
                    Status,
                    ObjectType,
                    Object,
                    Progress,
                    Elapsed,
                    CmdRcvMsg,
                    IsBatchCompleteCountIncreased,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    fields: dict = {}
                    for i in range(len(result[0])):
                        fields[cursor.description[i][0].lower()] = result[0][i]

                    return fields

                except Exception:
                    self._logger.error("Get IScoutTask error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IScoutTask error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IScoutBTask._tbname)
    def select_iscoutbtasks(self, conds: SqlConditions) -> iter:
        """按条件搜索任务,返回数据行转换成的字段字典迭代器"""
        conn: SqliteConn = None
        cursor = None
        conds: SqlConditions = conds
        try:
            # ClientId,
            # Platform,
            # Source,
            # IsPeriod,
            # PeriodNum,
            # StartTime,
            # EndTime,
            # Interval,
            # LastStartTime,
            # LastEndTime,
            # TaskId,
            # BatchId,
            # CmdId,
            # Status,
            # ObjectType,
            # Object,
            # Progress,
            # Elapsed,
            # CmdRcvMsg,
            # IsBatchCompleteCountIncreased,
            # CreateTime,
            # UpdateTime,
            # Sequence,
            cmd = f'''SELECT 
                    ClientId,
                    Platform,
                    Source,
                    IsPeriod,
                    PeriodNum,
                    StartTime,
                    EndTime,
                    Interval,
                    LastStartTime,
                    LastEndTime,
                    TaskId,
                    BatchId,
                    CmdId,
                    Status,
                    ObjectType,
                    Object,
                    Progress,
                    Elapsed,
                    CmdRcvMsg,
                    IsBatchCompleteCountIncreased,
                    CreateTime,
                    UpdateTime,
                    Sequence 
                    FROM {self._tbname} WHERE {conds.text_normal}'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                conn._conn.row_factory = self._dict_factory
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, conds.params)
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    for row in result:
                        fields: dict = {}
                        for i in range(len(result[0])):
                            fields[cursor.description[i][0].lower()] = row[i]

                        yield fields

                except Exception:
                    self._logger.error("Get IScoutTask error: {}".format(
                        traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error("Get IScoutTask error: %s" %
                               traceback.format_exc())

    @table_locker(__tb_IScoutBTask._tbname)
    def update_iscoutbtask(self, platform: str, taskid: str, batchid: str,
                           updatefields: dict) -> Tuple[bool, bool]:
        """根据taskid+batchid+platform更新其他字段\n
        task:任务对象"""
        res = False
        conn: SqliteConn = None
        cursor = None
        try:
            # 搜索每个库,看有没有 TokenId一样的,且时间更新
            # 的,一样就更新其他所有字段
            cmd = f'''SELECT COUNT(1) FROM {self._tbname} WHERE 
            TaskId=? and BatchId=? and Platform=?'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (taskid, batchid, platform))
                    result = cursor.fetchall()

                    if result[0][0] > 0:
                        # 只根据TaskId、platform作为条件,
                        # 不考虑 任务文件产生时间与现有数据库中已存在任务的时间,每次直接覆盖,以符合用户操作。
                        # 若来了TaskId一样的数据,则必然分配给同一个ClientId
                        sqlset = ''
                        for k in updatefields.keys():
                            sqlset = sqlset + '{}=?,'.format(k)
                        sqlset = sqlset.rstrip(',')
                        cmd = f'''UPDATE {self._tbname} set {sqlset} WHERE TaskId=? and BatchId=? and Platform=?;'''
                        params = [v for v in updatefields.values()]
                        params.append(taskid)
                        params.append(batchid)
                        params.append(platform)
                        result = cursor.execute(cmd, params)

                        if result is None or result.rowcount < 1:  # or len(result) < 1:
                            continue
                        else:
                            res = True

                        break
                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("save new IScoutTask error: %s" %
                               traceback.format_exc())

        return res

    @table_locker(__tb_IScoutBTask._tbname)
    def update_iscoutbtask_status(
        self,
        platform: str,
        taskid: str,
        batchid: str,
        cmdstatus: ECommandStatus,
    ) -> bool:
        """更新task的Status状态字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    Status=? 
                    WHERE Platform=? and Taskid=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        cmdstatus.value,
                        platform,
                        taskid,
                        batchid,
                    ))
                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error("update {} Status error: {}".format(
                self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScoutBTask._tbname)
    def update_batch_complete_count_increaced_flag(
            self, platform: str, taskid: str, batchid: str,
            isbatchcompletecountincreased: bool) -> bool:
        """增加指定iscout子任务isbatchcompletecountincreased 字段\n"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            cmd = f'''UPDATE {self._tbname} set
                    IsBatchCompleteCountIncreased=? 
                    WHERE Platform=? and TaskId=? and BatchId=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:

                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        isbatchcompletecountincreased,
                        platform,
                        taskid,
                        batchid,
                    ))

                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "batch {} batch complete count increaced flag error: {}".
                format(self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScoutBTask._tbname)
    def update_iscoutbtask_back(
        self,
        tb: IscoutBtaskBack,
    ) -> bool:
        """更新iscoutbtask_back"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        tb: IscoutBtaskBack = tb
        try:
            if not isinstance(tb, IscoutBtaskBack):
                self._logger.error(
                    "Invalid param IscoutBtaskBack: {}".format(tb))
                return res

            # 更新策略,先搜一下有没有,并把sequence搜出来,如果
            # 本地sequence和新来的任务的sequence一样,则说明
            # 采集端的sequence出错了,打一句日志并返回False
            cmd = f'''SELECT Sequence FROM {self._tbname} WHERE Platform=? and TaskId=? and BatchId=? and PeriodNum<=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:

                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        tb._platform,
                        tb._taskid,
                        tb._batchid,
                        tb.periodnum,
                    ))
                    result = cursor.fetchall()

                    if result is None or len(result) < 1:
                        continue

                    oldseq = result[0][0]
                    if oldseq >= tb._sequence:
                        self._logger.error(
                            "The comming IscoutBtaskBack.sequence is {}, but which in local db is {}:\ntaskid:{}\nbatchid:{}\nsequence:{}"
                            .format(tb._sequence, oldseq, tb._taskid,
                                    tb._batchid, oldseq))
                        break

                    # ClientId,
                    # Platform,
                    # Source,
                    # IsPeriod,
                    # PeriodNum,
                    # StartTime,
                    # EndTime,
                    # Interval,
                    # TaskId,
                    # BatchId,
                    # CmdId,
                    # Status,
                    # ObjectType,
                    # Object,
                    # Progress,
                    # Elapsed,
                    # CmdRcvMsg,
                    # IsBatchCompleteCountIncreased,
                    # CreateTime,
                    # Sequence,
                    cmd = f'''UPDATE {self._tbname} set
                            PeriodNum=?,
                            Status=?,
                            Progress=?,
                            Elapsed=?,
                            CmdRcvMsg=?,
                            Sequence=?,
                            WHERE Platform=? and TaskId=? and BatchId=? and Sequence<?;'''
                    cursor = conn.cursor
                    result = cursor.execute(cmd, (
                        tb.periodnum,
                        tb._cmdstatus.value,
                        tb._progress,
                        tb.elapsed,
                        tb._cmdrcvmsg,
                        tb._sequence,
                        tb._platform,
                        tb._taskid,
                        tb._batchid,
                        tb._sequence,
                    ))

                    if not result is None and result.rowcount > 0:
                        res = True  # 一定只有一个子任务
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if res:
                        break

        except Exception:
            self._logger.error(
                "update IScoutBatchTaskBack to {} error: {}".format(
                    self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScoutBTask._tbname)
    def get_batch_task_count_by_cmdstatus(self, platform: str, taskid: str,
                                          cmdstatus: ECommandStatus) -> int:
        """查询指定总任务taskid下的所有 为指定命令状态的子任务 的数量"""
        res: int = 0  #总数量
        conn: SqliteConn = None
        cursor = None
        try:
            cmd = f'''SELECT COUNT() FROM {self._tbname} WHERE Platform=? and TaskId=? and Status=?;'''
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                        cmdstatus.value,
                    ))
                    result = cursor.fetchall()
                    if result is None or len(result) < 1:
                        continue

                    tmp = result[0][0]

                    res = res + tmp

                except Exception:
                    self._logger.error(
                        "Select iscoutbtask count by status in {} error: {}".
                        format(self._tbname, traceback.format_exc()))
                finally:
                    if not conn is None:
                        conn.close()

        except Exception:
            self._logger.error(
                "Select iscoutbtask count by status in {} error: {}".format(
                    self._tbname, traceback.format_exc()))

        return res

    @table_locker(__tb_IScoutBTask._tbname)
    def is_iscoutbatch_complete_count_increaced(self, platform: str,
                                                taskid: str,
                                                batchid: str) -> bool:
        """返回 指定的子任务完成情况 是否已更新到 总任务表的 batchcompletecount 字段"""
        conn: SqliteConn = None
        cursor = None
        res: bool = False
        try:
            # IsBatchCompleteCountIncreased
            cmd = f'''SELECT IsBatchCompleteCountIncreased FROM {self._tbname} 
            WHERE Platform=? and TaskId=? and BatchId=?'''
            found = False
            for conn in self.connect_all(5):
                conn: SqliteConn = conn
                try:
                    cursor = conn.cursor
                    cursor.execute(cmd, (
                        platform,
                        taskid,
                        batchid,
                    ))
                    result = cursor.fetchall()
                    if not result is None and len(result) > 0:
                        tmp = result[0][0]
                        res = bool(tmp)  # 一定只有一个子任务
                        found = True
                        break

                except Exception as ex:
                    conn._conn.rollback()
                    raise ex
                else:
                    conn.commit()
                finally:
                    if not conn is None:
                        conn.close()
                    if found:
                        break

        except Exception:
            self._logger.error(
                "Check {} if IsBatchCompleteCountIncreased error: {}".format(
                    self._tbname, traceback.format_exc()))

        return res