gomyck-tools 1.2.12__py3-none-any.whl → 1.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. gomyck_tools-1.3.1.dist-info/METADATA +66 -0
  2. gomyck_tools-1.3.1.dist-info/RECORD +4 -0
  3. {gomyck_tools-1.2.12.dist-info → gomyck_tools-1.3.1.dist-info}/WHEEL +1 -1
  4. gomyck_tools-1.3.1.dist-info/top_level.txt +1 -0
  5. ctools/__init__.py +0 -0
  6. ctools/aes_tools.py +0 -35
  7. ctools/api_result.py +0 -55
  8. ctools/application.py +0 -386
  9. ctools/b64.py +0 -7
  10. ctools/bashPath.py +0 -13
  11. ctools/bottle_web_base.py +0 -169
  12. ctools/bottle_webserver.py +0 -143
  13. ctools/bottle_websocket.py +0 -75
  14. ctools/browser_element_tools.py +0 -314
  15. ctools/call.py +0 -71
  16. ctools/cftp.py +0 -74
  17. ctools/cjson.py +0 -54
  18. ctools/ckafka.py +0 -159
  19. ctools/compile_tools.py +0 -18
  20. ctools/console.py +0 -55
  21. ctools/coord_trans.py +0 -127
  22. ctools/credis.py +0 -111
  23. ctools/cron_lite.py +0 -252
  24. ctools/ctoken.py +0 -34
  25. ctools/cword.py +0 -30
  26. ctools/czip.py +0 -19
  27. ctools/database.py +0 -185
  28. ctools/date_utils.py +0 -43
  29. ctools/dict_wrapper.py +0 -20
  30. ctools/douglas_rarefy.py +0 -136
  31. ctools/download_tools.py +0 -57
  32. ctools/enums.py +0 -4
  33. ctools/ex.py +0 -31
  34. ctools/excelOpt.py +0 -36
  35. ctools/html_soup.py +0 -35
  36. ctools/http_utils.py +0 -24
  37. ctools/images_tools.py +0 -27
  38. ctools/imgDialog.py +0 -44
  39. ctools/metrics.py +0 -131
  40. ctools/mqtt_utils.py +0 -289
  41. ctools/obj.py +0 -20
  42. ctools/pacth.py +0 -74
  43. ctools/plan_area_tools.py +0 -97
  44. ctools/process_pool.py +0 -36
  45. ctools/pty_tools.py +0 -72
  46. ctools/resource_bundle_tools.py +0 -121
  47. ctools/rsa.py +0 -70
  48. ctools/screenshot_tools.py +0 -127
  49. ctools/sign.py +0 -20
  50. ctools/sm_tools.py +0 -49
  51. ctools/snow_id.py +0 -76
  52. ctools/str_diff.py +0 -20
  53. ctools/string_tools.py +0 -85
  54. ctools/sys_info.py +0 -157
  55. ctools/sys_log.py +0 -89
  56. ctools/thread_pool.py +0 -35
  57. ctools/upload_tools.py +0 -40
  58. ctools/win_canvas.py +0 -83
  59. ctools/win_control.py +0 -106
  60. ctools/word_fill.py +0 -562
  61. ctools/word_fill_entity.py +0 -46
  62. ctools/work_path.py +0 -69
  63. gomyck_tools-1.2.12.dist-info/METADATA +0 -57
  64. gomyck_tools-1.2.12.dist-info/RECORD +0 -62
  65. gomyck_tools-1.2.12.dist-info/top_level.txt +0 -1
ctools/call.py DELETED
@@ -1,71 +0,0 @@
1
- import sched
2
- import threading
3
- import time
4
- from functools import wraps
5
-
6
- # annotation
7
- def once(func):
8
- """
9
- decorator to initialize a function once
10
- :param func: function to be initialized
11
- :return: the real decorator for return the result
12
- """
13
- initialized = False
14
- res = None
15
-
16
- def wrapper(*args, **kwargs):
17
- nonlocal initialized, res
18
- if not initialized:
19
- res = func(*args, **kwargs)
20
- initialized = True
21
- return res
22
- else:
23
- return res
24
-
25
- return wrapper
26
-
27
- # annotation
28
- def init(func):
29
- """
30
- decorator to initialize a function automic
31
- :param func: function to be initialized
32
- :return: the real decorator for return the result
33
- """
34
- res = func()
35
-
36
- def wrapper():
37
- return res
38
-
39
- return wrapper
40
-
41
- # annotation
42
- def schd(interval_seconds, start_by_call: bool = False):
43
- start_flag = False
44
- run_flag = False
45
- scheduler = sched.scheduler(time.time, time.sleep)
46
-
47
- def decorator(func):
48
- @wraps(func)
49
- def wrapper(*args, **kwargs):
50
- nonlocal start_flag
51
- if start_by_call and not start_flag:
52
- start_flag = True
53
- threading.Thread(target=wrapper, args=args, kwargs=kwargs, daemon=True).start()
54
- return
55
-
56
- def job():
57
- func(*args, **kwargs)
58
- scheduler.enter(interval_seconds, 1, job)
59
-
60
- nonlocal run_flag
61
- if not run_flag:
62
- scheduler.enter(interval_seconds, 1, job)
63
- run_flag = True
64
- scheduler.run()
65
- else:
66
- func(*args, **kwargs)
67
-
68
- if not start_by_call: threading.Thread(target=wrapper, daemon=True).start()
69
- return wrapper
70
-
71
- return decorator
ctools/cftp.py DELETED
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: UTF-8 -*-
3
- __author__ = 'haoyang'
4
- __date__ = '2025/1/24 08:53'
5
-
6
- import io
7
- import time
8
- from ftplib import FTP, error_perm, error_temp
9
-
10
- class CFTP:
11
- """
12
- with open('xx/xx.md', 'rb') as file:
13
- ftp_host = 'x.x.x.x'
14
- ftp_username = 'x'
15
- ftp_password = 'x'
16
- CFTP(ftp_host, ftp_username, ftp_password).upload_file_to_ftp('xx.md', file)
17
- """
18
- def __init__(self, host, username, password, timeout=30, max_retries=3, retry_delay=5):
19
- self.host = host
20
- self.username = username
21
- self.password = password
22
- self.ftp:FTP = None
23
- self.timeout = timeout
24
- self.max_retries = max_retries
25
- self.retry_delay = retry_delay
26
-
27
- def upload_file_to_ftp(self, file_name, file:io.BytesIO, ftp_directory='/'):
28
- if not file_name: raise Exception('文件名不能为空')
29
- if not file: raise Exception('文件不能为空')
30
- for attempt in range(self.max_retries):
31
- try:
32
- if not self.ftp:
33
- ftp = FTP(self.host, timeout=self.timeout)
34
- ftp.login(self.username, self.password)
35
- ftp.set_pasv(True)
36
- self.ftp = ftp
37
- try:
38
- self.ftp.cwd(ftp_directory)
39
- except error_perm:
40
- print(f"FTP 目录不存在:{ftp_directory}")
41
- self.ftp.mkd(ftp_directory)
42
- print(f"FTP 目录创建成功:{ftp_directory}, 正在切换到目录:{ftp_directory}")
43
- self.ftp.cwd(ftp_directory)
44
- print(f"正在上传文件:{file_name}")
45
- self.ftp.storbinary(f"STOR {file_name}", file)
46
- self.ftp.quit()
47
- print(f"文件成功上传到 FTP: {file_name}")
48
- return
49
- except (error_perm, error_temp) as e:
50
- try:
51
- self.ftp.quit()
52
- except Exception:
53
- pass
54
- self.ftp = None
55
- print(f"FTP 错误:{e}")
56
- if attempt < self.max_retries - 1:
57
- print(f"正在尝试重连... 第 {attempt + 1} 次重试...")
58
- time.sleep(self.retry_delay)
59
- else:
60
- print("重试次数已用尽,上传失败。")
61
- raise
62
- except Exception as e:
63
- try:
64
- self.ftp.quit()
65
- except Exception:
66
- pass
67
- self.ftp = None
68
- print(f"连接或上传出现异常:{e}")
69
- if attempt < self.max_retries - 1:
70
- print(f"正在尝试重连... 第 {attempt + 1} 次重试...")
71
- time.sleep(self.retry_delay)
72
- else:
73
- print("重试次数已用尽,上传失败。")
74
- raise
ctools/cjson.py DELETED
@@ -1,54 +0,0 @@
1
- import jsonpickle
2
-
3
- # 需要转换成str的属性
4
- str_value_keys = []
5
- jsonpickle.set_preferred_backend('json')
6
- jsonpickle.set_encoder_options('json', ensure_ascii=False)
7
- jsonpickle.set_decoder_options('json')
8
-
9
- def dumps(obj, **kwargs) -> str:
10
- """
11
- 将对象转换为json字符串
12
- :param obj: 对象
13
- :return: json 字符串
14
- """
15
- # indent = 2 可以美化输出
16
- if obj is None: return None
17
- if type(obj) == str: return obj
18
- return f'{jsonpickle.encode(obj, unpicklable=False, make_refs=False, **kwargs)}'
19
-
20
- def loads(json_str: str, **kwargs) -> dict:
21
- """
22
- 将json字符串转换为对象
23
- :param json_str: json 字符串
24
- :return: 对象
25
- """
26
- return jsonpickle.decode(json_str, **kwargs)
27
-
28
- def unify_to_str(json_str: str) -> str:
29
- if not str_value_keys and len(str_value_keys) == 0: return json_str
30
- obj = loads(json_str)
31
- if isinstance(obj, list):
32
- _handle_list(obj)
33
- elif isinstance(obj, dict):
34
- _handle_dict(obj)
35
- return dumps(obj)
36
-
37
- def _handle_list(data):
38
- for o in data:
39
- if isinstance(o, list):
40
- _handle_list(o)
41
- elif isinstance(o, dict):
42
- _handle_dict(o)
43
-
44
- def _handle_dict(data):
45
- for k, v in data.items():
46
- if isinstance(v, list):
47
- _handle_list(v)
48
- elif isinstance(v, dict):
49
- _handle_dict(v)
50
- elif k in str_value_keys:
51
- try:
52
- data[k] = str(v)
53
- except Exception:
54
- pass
ctools/ckafka.py DELETED
@@ -1,159 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: UTF-8 -*-
3
- __author__ = 'haoyang'
4
- __date__ = '2024/9/5 10:39'
5
-
6
- import time
7
- from threading import Thread, Lock
8
-
9
- from kafka import KafkaProducer, errors, KafkaConsumer
10
- from kafka.producer.future import FutureRecordMetadata
11
-
12
- from ctools import thread_pool
13
- from ctools.cjson import dumps
14
-
15
- """
16
- import time
17
- from datetime import datetime
18
-
19
- from ctools import thread_pool, string_tools
20
- from ctools.ckafka import CKafka
21
-
22
- c = CKafka(kafka_url='192.168.3.160:9094', secure=True)
23
-
24
- producer = c.init_producer()
25
- consumer = c.init_consumer(enable_auto_commit=False)
26
-
27
- def send_msg():
28
- while True:
29
- command = input('发送消息: Y/n \n')
30
- if command.strip() not in ['N', 'n']:
31
- producer.send_msg('jqxx', '{{"jqid": "{}", "xxxx": "{}"}}'.format(string_tools.get_snowflake_id(), datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')))
32
- else:
33
- break
34
-
35
- thread_pool.submit(send_msg)
36
-
37
- def consumer_callback(msg):
38
- print(msg)
39
- return True
40
-
41
- consumer.receive_msg('jqxx', callBack=consumer_callback)
42
-
43
- while True: time.sleep(1)
44
- """
45
- class KafkaInstance:
46
- def __init__(self, producer: KafkaProducer, consumer: KafkaConsumer):
47
- self.start_consumer = False
48
- self.quited = False
49
- self.producer = producer
50
- self.consumer = consumer
51
- self.consumer_callback = {"topic_key": []}
52
-
53
- # FutureRecordMetadata 可以添加回调, 来监听是否发送成功
54
- # r.add_callback(lambda x: print(x))
55
- # r.get() 可以同步获取结果
56
- def send_msg(self, topic, msg, key: str=None, partition:int=None) -> FutureRecordMetadata:
57
- if self.producer is None: raise RuntimeError("Producer is not initialized")
58
- if self.quited: return
59
- return self.producer.send(topic=topic, value=msg, key=None if key is None else key.encode('utf-8'), partition=partition)
60
-
61
- def receive_msg(self, topics: str, callBack=print):
62
- if self.consumer is None: raise RuntimeError("Consumer is not initialized")
63
- for topic in topics.split(','):
64
- if topic not in self.consumer_callback.keys():
65
- self.consumer_callback[topic] = []
66
- self.consumer.subscribe(self.consumer_callback.keys())
67
- self.consumer_callback[topic].append(callBack)
68
- if not self.start_consumer:
69
- t = Thread(target=self._start_consumer_poll, daemon=True)
70
- t.start()
71
-
72
- def _start_consumer_poll(self):
73
- self.start_consumer = True
74
- for msg in self.consumer:
75
- if self.quited: break
76
- funcList = []
77
- begin_time = time.time()
78
- for func in self.consumer_callback[msg.topic]:
79
- if self.quited: break
80
- res = func(msg)
81
- if not self.consumer.config['enable_auto_commit'] and res: self.consumer.commit()
82
- funcList.append(func.__name__)
83
- end_time = time.time()
84
- if end_time - begin_time > 1: print(f"kafka consume too slow!!! {funcList} time cost: ", f'{round(end_time - begin_time, 2)}s')
85
- funcList.clear()
86
-
87
- def shutdown(self):
88
- self.quited = True
89
- try: self.consumer.close()
90
- except Exception: pass
91
- try: self.producer.close()
92
- except Exception: pass
93
-
94
-
95
- class CKafka:
96
-
97
- def __init__(self, kafka_url: str = '127.0.0.1:9092', secure: bool = False, username: str = 'client', password: str = 'hylink_user_password'):
98
- self.kafka_url = kafka_url
99
- self.secure = secure
100
- self.username = username
101
- self.password = password
102
-
103
- def init_producer(self, acks=1) -> KafkaInstance:
104
- print("[ Producer ] Connecting to Kafka [{}]".format(self.kafka_url))
105
- for i in range(0, 6):
106
- try:
107
- if self.secure:
108
- producer = KafkaProducer(
109
- acks=acks,
110
- bootstrap_servers=self.kafka_url,
111
- value_serializer=lambda x: dumps(x).encode('utf-8'),
112
- sasl_plain_username=self.username,
113
- sasl_plain_password=self.password,
114
- security_protocol='SASL_PLAINTEXT',
115
- sasl_mechanism='PLAIN'
116
- )
117
- else:
118
- producer = KafkaProducer(
119
- acks=acks,
120
- bootstrap_servers=self.kafka_url,
121
- value_serializer=lambda x: dumps(x).encode('utf-8')
122
- )
123
- print("[ Producer ] Success Connected to Kafka [{}]".format(self.kafka_url))
124
- return KafkaInstance(producer=producer, consumer=None)
125
- except errors.NoBrokersAvailable:
126
- print("[ Producer ] Waiting for Kafka [{}] to become available...".format(self.kafka_url))
127
- time.sleep(3)
128
- raise RuntimeError("[ Producer ] Failed to connect to Kafka [{}] within 60 seconds".format(self.kafka_url))
129
-
130
- def init_consumer(self, client_id: str = 'ck-py-kafka-consumer', consumer_group: str = 'ck-py-kafka-consumer', enable_auto_commit: bool = True) -> KafkaInstance:
131
- print("[ Consumer ] Connecting to Kafka [{}]".format(self.kafka_url))
132
- for i in range(0, 6):
133
- try:
134
- if self.secure:
135
- consumer = KafkaConsumer(
136
- client_id=client_id,
137
- group_id=consumer_group,
138
- enable_auto_commit=enable_auto_commit,
139
- bootstrap_servers=self.kafka_url,
140
- value_deserializer=lambda x: x.decode('utf-8'),
141
- sasl_plain_username=self.username,
142
- sasl_plain_password=self.password,
143
- security_protocol='SASL_PLAINTEXT',
144
- sasl_mechanism='PLAIN'
145
- )
146
- else:
147
- consumer = KafkaProducer(
148
- client_id=client_id,
149
- group_id=consumer_group,
150
- enable_auto_commit=enable_auto_commit,
151
- bootstrap_servers=self.kafka_url,
152
- value_deserializer=lambda x: x.decode('utf-8')
153
- )
154
- print("[ Consumer ] Success Connected to Kafka [{}]".format(self.kafka_url))
155
- return KafkaInstance(producer=None, consumer=consumer)
156
- except errors.NoBrokersAvailable:
157
- print("[ Consumer ] Waiting for Kafka [{}] to become available...".format(self.kafka_url))
158
- time.sleep(3)
159
- raise RuntimeError("[ Consumer ] Failed to connect to Kafka [{}] within 60 seconds".format(self.kafka_url))
ctools/compile_tools.py DELETED
@@ -1,18 +0,0 @@
1
- import importlib
2
- import os
3
- import time
4
-
5
-
6
- def code_to_pyc(code: str, out_file_path: str):
7
- file_name = os.path.split(out_file_path)[-1]
8
- compiled_code = compile(code, file_name, 'exec')
9
- bytecode = importlib._bootstrap_external._code_to_timestamp_pyc(compiled_code, time.time(), len(code))
10
- with open(out_file_path, 'wb') as f:
11
- f.write(bytecode)
12
-
13
-
14
- def file_to_pyc(file_path: str, out_file_path: str):
15
- with open(file_path, 'r') as f:
16
- code = f.read()
17
- if code:
18
- code_to_pyc(code, out_file_path)
ctools/console.py DELETED
@@ -1,55 +0,0 @@
1
- import logging
2
- import sys
3
- import tkinter as tk
4
-
5
-
6
- class Console:
7
-
8
- def __init__(self, master):
9
- self.master = master
10
-
11
- # 创建文本框和滚动条
12
- self.textbox = tk.Text(self.master, wrap=tk.NONE)
13
-
14
- self.vertical_scrollbar = tk.Scrollbar(self.textbox, command=self.textbox.yview)
15
- self.horizontal_scrollbar = tk.Scrollbar(self.textbox, command=self.textbox.xview, orient=tk.HORIZONTAL)
16
-
17
- self.textbox.configure(yscrollcommand=self.vertical_scrollbar.set, xscrollcommand=self.horizontal_scrollbar.set)
18
- self.textbox.pack(side=tk.LEFT, pady=10, padx=10, ipadx=10, ipady=10, fill=tk.BOTH, expand=True)
19
-
20
- self.vertical_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
21
- self.horizontal_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
22
-
23
- # 将标准输出和标准错误输出重定向到文本框中
24
- sys.stdout = self
25
- sys.stderr = self
26
-
27
- # # 创建输入框和按钮
28
- # self.entry = tk.Entry(self.master)
29
- # self.entry.pack(side=tk.BOTTOM, fill=tk.X, expand=True)
30
- # self.button = tk.Button(self.master, text="Send", command=self.send)
31
- # self.button.pack(side=tk.BOTTOM)
32
-
33
- # 将日志输出到文本框中
34
- self.log_handler = logging.StreamHandler(self)
35
- self.log_handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
36
- logging.getLogger().addHandler(self.log_handler)
37
- # logging.getLogger().setLevel(logging.INFO)
38
-
39
- def write(self, message):
40
- # 在文本框中输出消息
41
- self.textbox.insert(tk.END, message + '\n')
42
- self.textbox.see(tk.END)
43
-
44
- def flush(self):
45
- pass
46
-
47
- def send(self):
48
- # 获取输入框中的文本并打印到控制台
49
- text = self.entry.get()
50
- print(text)
51
- self.entry.delete(0, tk.END)
52
-
53
- def __del__(self):
54
- # 关闭日志处理器
55
- logging.getLogger().removeHandler(self.log_handler)
ctools/coord_trans.py DELETED
@@ -1,127 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- import math
3
-
4
- x_pi = 3.14159265358979324 * 3000.0 / 180.0
5
- pi = 3.1415926535897932384626 # π
6
- a = 6378245.0 # 长半轴
7
- ee = 0.00669342162296594323 # 偏心率平方
8
-
9
- def gcj02_to_bd09(lng, lat):
10
- """
11
- 火星坐标系(GCJ-02)转百度坐标系(BD-09)
12
- 谷歌、高德——>百度
13
- :param lng:火星坐标经度
14
- :param lat:火星坐标纬度
15
- :return:
16
- """
17
- z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_pi)
18
- theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_pi)
19
- bd_lng = z * math.cos(theta) + 0.0065
20
- bd_lat = z * math.sin(theta) + 0.006
21
- return [bd_lng, bd_lat]
22
-
23
-
24
- def bd09_to_gcj02(bd_lon, bd_lat):
25
- """
26
- 百度坐标系(BD-09)转火星坐标系(GCJ-02)
27
- 百度——>谷歌、高德
28
- :param bd_lat:百度坐标纬度
29
- :param bd_lon:百度坐标经度
30
- :return:转换后的坐标列表形式
31
- """
32
- x = bd_lon - 0.0065
33
- y = bd_lat - 0.006
34
- z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
35
- theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
36
- gg_lng = z * math.cos(theta)
37
- gg_lat = z * math.sin(theta)
38
- return [gg_lng, gg_lat]
39
-
40
-
41
- def wgs84_to_gcj02(lng, lat):
42
- """
43
- WGS84转GCJ02(火星坐标系)
44
- :param lng:WGS84坐标系的经度
45
- :param lat:WGS84坐标系的纬度
46
- :return:
47
- """
48
- if out_of_china(lng, lat): # 判断是否在国内
49
- return [lng, lat]
50
- dlat = _transformlat(lng - 105.0, lat - 35.0)
51
- dlng = _transformlng(lng - 105.0, lat - 35.0)
52
- radlat = lat / 180.0 * pi
53
- magic = math.sin(radlat)
54
- magic = 1 - ee * magic * magic
55
- sqrtmagic = math.sqrt(magic)
56
- dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
57
- dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
58
- mglat = lat + dlat
59
- mglng = lng + dlng
60
- return [mglng, mglat]
61
-
62
-
63
- def gcj02_to_wgs84(lng, lat):
64
- """
65
- GCJ02(火星坐标系)转GPS84
66
- :param lng:火星坐标系的经度
67
- :param lat:火星坐标系纬度
68
- :return:
69
- """
70
- if out_of_china(lng, lat):
71
- return [lng, lat]
72
- dlat = _transformlat(lng - 105.0, lat - 35.0)
73
- dlng = _transformlng(lng - 105.0, lat - 35.0)
74
- radlat = lat / 180.0 * pi
75
- magic = math.sin(radlat)
76
- magic = 1 - ee * magic * magic
77
- sqrtmagic = math.sqrt(magic)
78
- dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
79
- dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
80
- mglat = lat + dlat
81
- mglng = lng + dlng
82
- return [lng * 2 - mglng, lat * 2 - mglat]
83
-
84
-
85
- def bd09_to_wgs84(bd_lon, bd_lat):
86
- lon, lat = bd09_to_gcj02(bd_lon, bd_lat)
87
- return gcj02_to_wgs84(lon, lat)
88
-
89
-
90
- def wgs84_to_bd09(lon, lat):
91
- lon, lat = wgs84_to_gcj02(lon, lat)
92
- return gcj02_to_bd09(lon, lat)
93
-
94
-
95
- def _transformlat(lng, lat):
96
- ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
97
- 0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
98
- ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
99
- math.sin(2.0 * lng * pi)) * 2.0 / 3.0
100
- ret += (20.0 * math.sin(lat * pi) + 40.0 *
101
- math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
102
- ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
103
- math.sin(lat * pi / 30.0)) * 2.0 / 3.0
104
- return ret
105
-
106
-
107
- def _transformlng(lng, lat):
108
- ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
109
- 0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
110
- ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
111
- math.sin(2.0 * lng * pi)) * 2.0 / 3.0
112
- ret += (20.0 * math.sin(lng * pi) + 40.0 *
113
- math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
114
- ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
115
- math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
116
- return ret
117
-
118
-
119
- def out_of_china(lng, lat):
120
- """
121
- 判断是否在国内,不在国内不做偏移
122
- :param lng:
123
- :param lat:
124
- :return:
125
- """
126
- return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)
127
-
ctools/credis.py DELETED
@@ -1,111 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: UTF-8 -*-
3
- __author__ = 'haoyang'
4
- __date__ = '2025/2/14 11:09'
5
-
6
- import redis
7
- from redis import Redis
8
-
9
- from ctools import date_utils, thread_pool, string_tools
10
-
11
- def init_pool(host: str = 'localhost', port: int = 6379, db: int = 0, password: str = None,
12
- username: str = None, decode_responses: bool = True, max_connections: int = 75,
13
- health_check_interval: int = 30, retry_count: int = 3) -> Redis:
14
- for attempt in range(retry_count):
15
- try:
16
- r: Redis = redis.StrictRedis(
17
- host=host, port=port, db=db,
18
- username=username, password=password,
19
- retry_on_timeout=True,
20
- max_connections=max_connections,
21
- decode_responses=decode_responses,
22
- health_check_interval=health_check_interval,
23
- socket_connect_timeout=5,
24
- socket_timeout=5
25
- )
26
- if r.ping():
27
- print('CRedis connect {} {} success!'.format(host, port))
28
- return r
29
- except redis.ConnectionError as e:
30
- if attempt == retry_count - 1:
31
- raise Exception(f"Failed to connect to Redis after {retry_count} attempts: {str(e)}")
32
- print(f"Connection attempt {attempt + 1} failed, retrying...")
33
-
34
- def add_lock(r: Redis, key: str, timeout: int = 30):
35
- if r.exists(key):
36
- expire_time = r.get(key)
37
- if date_utils.time_diff_in_seconds(expire_time, date_utils.get_date_time()) > 0:
38
- return True
39
- else:
40
- r.delete(key)
41
- return r.set(key, date_utils.opt_time(seconds=timeout), nx=True, ex=timeout) is not None
42
-
43
- def remove_lock(r: Redis, key: str):
44
- r.delete(key)
45
-
46
- def subscribe(r: Redis, channel_name, callback):
47
- def thread_func():
48
- pubsub = r.pubsub()
49
- pubsub.subscribe(channel_name)
50
- for message in pubsub.listen():
51
- callback(message)
52
- thread_pool.submit(thread_func)
53
-
54
- def _process_pending_messages(r: Redis, stream_name: str, group_name: str, consumer_name: str, callback):
55
- """
56
- 处理未确认的消息
57
- :param r: Redis 连接
58
- :param stream_name: 流名称
59
- :param group_name: 消费者组名称
60
- :param consumer_name: 消费者名称
61
- :param callback: 消息处理回调函数
62
- """
63
- # 检查未确认的消息
64
- pending_messages = r.xpending(stream_name, group_name)
65
- if pending_messages['pending'] > 0:
66
- print(f"Found {pending_messages['pending']} pending messages.")
67
- # 获取未确认的消息列表
68
- pending_list = r.xpending_range(stream_name, group_name, min='-', max='+', count=pending_messages['pending'])
69
- for message in pending_list:
70
- message_id = message['message_id']
71
- claimed_messages = r.xclaim(stream_name, group_name, consumer_name, min_idle_time=0, message_ids=[message_id])
72
- if claimed_messages:
73
- # 处理消息
74
- for claimed_message in claimed_messages:
75
- message_id, data = claimed_message
76
- print(f"Processing pending message: {message_id}, data: {data}")
77
- try:
78
- if callback(message_id, data):
79
- r.xack(stream_name, group_name, message_id)
80
- except Exception as e:
81
- print(f"Error processing message {message_id}: {e}")
82
- else:
83
- print("No pending messages found.")
84
-
85
- def stream_subscribe(r: Redis, stream_name, group_name, callback, from_id: str='$', noack: bool = False):
86
- def thread_func():
87
- try:
88
- # $表示从最后面消费, 0表示从开始消费
89
- r.xgroup_create(name=stream_name, groupname=group_name, id=from_id, mkstream=True)
90
- print(f"Consumer group '{group_name}' created successfully.")
91
- except Exception as e:
92
- if "already exists" in str(e):
93
- print(f"Consumer group '{group_name}' already exists.")
94
- else:
95
- print(f"Error creating consumer group '{group_name}': {e}")
96
- consumer_name = 'consumer-{}'.format(string_tools.get_uuid())
97
- # 处理未确认的消息
98
- _process_pending_messages(r, stream_name, group_name, consumer_name, callback)
99
- while True:
100
- messages = r.xreadgroup(group_name, consumer_name, {stream_name: '>'}, block=1000, noack=noack)
101
- for message in messages:
102
- try:
103
- message_id, data = message[1][0]
104
- res = callback(message_id, data)
105
- if res: r.xack(stream_name, group_name, message_id)
106
- except Exception as e:
107
- print('stream_subscribe error: ', e)
108
- thread_pool.submit(thread_func)
109
-
110
- def stream_publish(r: Redis, stream_name, message):
111
- r.xadd(stream_name, message)