parent
9e1f11767a
commit
d358551787
@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @Time : 2023/4/9 14:53
|
|
||||||
# @Author : old tom
|
|
||||||
# @File : __init__.py.py
|
|
||||||
# @Project : futool-tiny-datahub
|
|
||||||
# @Desc :
|
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:15
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_lang.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 字符串相关
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:17
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_math.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 数学计算
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/9/10 10:46
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fu_parser.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 解析器(CSV,JSON,NB文件)
|
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/3 21:46
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : fh_db.py
|
||||||
|
# @Project : futool
|
||||||
|
# @Desc : 数据库通用类
|
||||||
|
|
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/8/31 23:34
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : http_downloader.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 文件下载器
|
||||||
|
import time
|
||||||
|
|
||||||
|
from futool.http.http_request import head
|
||||||
|
from multiprocessing import Pool
|
||||||
|
import urllib.request as req
|
||||||
|
|
||||||
|
|
||||||
|
class HttpDownloader(object):
|
||||||
|
"""
|
||||||
|
HTTP 下载器
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pool=None):
|
||||||
|
self.pool = Pool(16) if not pool else pool
|
||||||
|
|
||||||
|
def download(self, url, dst, chunk_size=1000):
|
||||||
|
"""
|
||||||
|
文件下,自动开启多线程
|
||||||
|
:param url: 下载链接
|
||||||
|
:param dst: 保存路径
|
||||||
|
:param chunk_size: 文件块
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
is_support, content_length = HttpDownloader.is_support_range(url)
|
||||||
|
if is_support:
|
||||||
|
# 每个线程下载字节偏移量
|
||||||
|
offset = self.fork(int(content_length), chunk_size)
|
||||||
|
self.__join(offset, url, dst)
|
||||||
|
else:
|
||||||
|
print('无法获取Content-Length,使用单线程下载')
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_support_range(url):
|
||||||
|
"""
|
||||||
|
判断是否支持range请求
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
wrapper = head(url)
|
||||||
|
header = wrapper.header()
|
||||||
|
h_keys = header.keys()
|
||||||
|
if 'Accept-Ranges' in h_keys and 'Content-Length' in h_keys and header['Accept-Ranges'] != 'none':
|
||||||
|
return True, header['Content-Length']
|
||||||
|
else:
|
||||||
|
return False, 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def fork(content_length: int, chunk_size):
|
||||||
|
"""
|
||||||
|
拆分线程
|
||||||
|
:param chunk_size: 文件块大小
|
||||||
|
:param content_length:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
offset = []
|
||||||
|
if content_length <= chunk_size:
|
||||||
|
offset.append((0, content_length))
|
||||||
|
else:
|
||||||
|
for i in range(content_length // chunk_size):
|
||||||
|
start_offset = chunk_size * i + 1
|
||||||
|
end_offset = start_offset - 1 + chunk_size
|
||||||
|
offset.append((0 if i == 0 else start_offset, end_offset))
|
||||||
|
offset.append((chunk_size * (content_length // chunk_size), content_length))
|
||||||
|
return offset
|
||||||
|
|
||||||
|
def __join(self, offset, url, dst):
|
||||||
|
"""
|
||||||
|
多线程下载
|
||||||
|
:param offset:
|
||||||
|
:param url:
|
||||||
|
:param dst:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
def download_by_thread(part):
|
||||||
|
_request = req.Request(url=url, headers={
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||||
|
"Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70",
|
||||||
|
'Range': f'bytes:{part[0]}-{part[1]}'
|
||||||
|
}, method='GET')
|
||||||
|
response = req.urlopen(_request)
|
||||||
|
with open(dst + f'.{time.time_ns()}', 'wb') as f:
|
||||||
|
f.write(response.read())
|
||||||
|
|
||||||
|
self.pool.map(download_by_thread, offset)
|
||||||
|
self.pool.close()
|
||||||
|
self.pool.join()
|
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2022/8/29 23:14
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : http_response.py
|
||||||
|
# @Project : Futool
|
||||||
|
# @Desc : 响应解析
|
||||||
|
|
||||||
|
from http.client import HTTPResponse
|
||||||
|
from http.cookiejar import CookieJar
|
||||||
|
import json
|
||||||
|
|
||||||
|
DEFAULT_ENCODING = 'UTF-8'
|
||||||
|
|
||||||
|
# 响应类型编码
|
||||||
|
RESPONSE_CONTENT_ENCODING = "Content-Encoding"
|
||||||
|
|
||||||
|
# 压缩类型
|
||||||
|
COMPRESS_TYPE = ('gzip', 'deflate', 'br')
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseWrapper(object):
|
||||||
|
|
||||||
|
def __init__(self, response: HTTPResponse, cookie: CookieJar = None):
|
||||||
|
self.resp = response
|
||||||
|
if cookie and len(cookie) > 0:
|
||||||
|
self.cookie = cookie
|
||||||
|
|
||||||
|
def body(self, encoding=DEFAULT_ENCODING):
|
||||||
|
return self.resp.read().decode(encoding)
|
||||||
|
|
||||||
|
def json_body(self, encoding=DEFAULT_ENCODING):
|
||||||
|
return json.loads(self.body(encoding))
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
return self.resp.status
|
||||||
|
|
||||||
|
def is_ok(self):
|
||||||
|
st_code = self.resp.status
|
||||||
|
return 200 <= st_code <= 300
|
||||||
|
|
||||||
|
def header(self, name=None):
|
||||||
|
return self.resp.getheader(name) if name else self._parse_header_dict()
|
||||||
|
|
||||||
|
def _parse_header_dict(self):
|
||||||
|
headers = self.resp.getheaders()
|
||||||
|
header_dict = {}
|
||||||
|
if headers:
|
||||||
|
for h in headers:
|
||||||
|
header_dict[h[0]] = h[1]
|
||||||
|
return header_dict
|
||||||
|
|
||||||
|
def is_compress(self):
|
||||||
|
"""
|
||||||
|
是否压缩
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.compress_type() in COMPRESS_TYPE
|
||||||
|
|
||||||
|
def compress_type(self):
|
||||||
|
"""
|
||||||
|
压缩格式
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
header = self.header()
|
||||||
|
if RESPONSE_CONTENT_ENCODING in header.keys():
|
||||||
|
res_content_encoding = header[RESPONSE_CONTENT_ENCODING]
|
||||||
|
return res_content_encoding
|
||||||
|
|
||||||
|
def cookies(self):
|
||||||
|
"""
|
||||||
|
获取cookie
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
ck = {}
|
||||||
|
if self.cookie:
|
||||||
|
for item in self.cookie:
|
||||||
|
ck[item.name] = item.value
|
||||||
|
return ck
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/4/2 9:07
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : __init__.py.py
|
||||||
|
# @Project : futool
|
||||||
|
# @Desc : excel、word操作相关
|
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/5/9 13:55
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : main.py
|
||||||
|
# @Project : futool-tiny-datahub
|
||||||
|
# @Desc : 入口文件,定时任务、fastapi、streamlit启动
|
||||||
|
from datahub.scheduletask.scan_task import ScanTaskRunner
|
||||||
|
from datahub.scheduletask.schedule import sch
|
||||||
|
|
||||||
|
# 数据源扫描任务
|
||||||
|
scan_runner = ScanTaskRunner()
|
||||||
|
scan_runner.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# 启动调度
|
||||||
|
sch.start()
|
@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/5/9 14:29
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : metadata_version_dao.py
|
||||||
|
# @Project : futool-tiny-datahub
|
||||||
|
# @Desc :
|
||||||
|
from common.fudb.connectors.connector_factory import ConnFactory
|
||||||
|
from common.fudb.dbapis.fu_dao import BaseDao
|
||||||
|
|
||||||
|
|
||||||
|
class IncreaseVersionError(Exception):
|
||||||
|
"""
|
||||||
|
递增版本号异常
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, msg):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataVersionDao(BaseDao):
|
||||||
|
|
||||||
|
def __init__(self, connector: ConnFactory):
|
||||||
|
super().__init__(connector)
|
||||||
|
|
||||||
|
def init_version(self, source_id):
|
||||||
|
"""
|
||||||
|
初始化版本号
|
||||||
|
:param source_id:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.execute_update(f"insert into metadata_object_version_record (source_id) values ('{source_id}')")
|
||||||
|
|
||||||
|
def query_latest_version(self, source_id):
|
||||||
|
"""
|
||||||
|
查询最新版本号
|
||||||
|
:param source_id:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
result = self.query_one(
|
||||||
|
f"select version_code from metadata_object_version_record where source_id='{source_id}' "
|
||||||
|
f"order by version_code desc limit 1")
|
||||||
|
return result[0] if result else None
|
||||||
|
|
||||||
|
def add_version(self, source_id):
|
||||||
|
"""
|
||||||
|
版本号加1并返回最新
|
||||||
|
:param source_id:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
last_version = self.query_latest_version(source_id)
|
||||||
|
latest_version = last_version + 1
|
||||||
|
flag = self.execute_update(
|
||||||
|
f"insert into metadata_object_version_record (source_id,version_code) values ('{source_id}',{latest_version})")
|
||||||
|
if flag == 1:
|
||||||
|
return latest_version
|
||||||
|
else:
|
||||||
|
raise IncreaseVersionError(f'[{source_id}] 更新版本号失败')
|
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Time : 2023/5/9 14:22
|
||||||
|
# @Author : old tom
|
||||||
|
# @File : metadata_version.py
|
||||||
|
# @Project : futool-tiny-datahub
|
||||||
|
# @Desc : 元数据版本管理
|
||||||
|
from datahub.metadata.metadatadao.metadata_version_dao import MetadataVersionDao
|
||||||
|
from datahub.local_db_conf import local_conn
|
||||||
|
from datahub.log_conf import Logger
|
||||||
|
import threading
|
||||||
|
|
||||||
|
lock = threading.RLock()
|
||||||
|
logger = Logger().get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataVersionKeeper(object):
|
||||||
|
"""
|
||||||
|
元数据版本管理器
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, source_id):
|
||||||
|
self.source_id = source_id
|
||||||
|
self.dao = MetadataVersionDao(local_conn)
|
||||||
|
|
||||||
|
def init_version(self):
|
||||||
|
"""
|
||||||
|
初始化版本号
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
flag = self.dao.init_version(self.source_id) == 1
|
||||||
|
if flag:
|
||||||
|
logger.info(f"[{self.source_id}] 数据源初始化版本成功")
|
||||||
|
else:
|
||||||
|
logger.error(f"[{self.source_id}] 数据源初始化版本失败")
|
||||||
|
|
||||||
|
def get_latest_version(self):
|
||||||
|
"""
|
||||||
|
获取最新版本
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return self.dao.query_latest_version(self.source_id)
|
||||||
|
|
||||||
|
def increase_version(self):
|
||||||
|
"""
|
||||||
|
递增并返回最新版本
|
||||||
|
加锁操作
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
lock.acquire()
|
||||||
|
return self.dao.add_version(self.source_id)
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
version_keeper = MetadataVersionKeeper('834164a2d62de959c0261e6239dd1e55')
|
||||||
|
# 多线程测试
|
||||||
|
|
||||||
|
# for i in range(100):
|
||||||
|
# print(version_keeper.increase_version())
|
Loading…
Reference in new issue