gomyck-tools 1.3.1__py3-none-any.whl → 1.3.2__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 (64) hide show
  1. ctools/__init__.py +0 -0
  2. ctools/aes_tools.py +35 -0
  3. ctools/api_result.py +55 -0
  4. ctools/application.py +386 -0
  5. ctools/b64.py +7 -0
  6. ctools/bashPath.py +13 -0
  7. ctools/bottle_web_base.py +169 -0
  8. ctools/bottle_webserver.py +143 -0
  9. ctools/bottle_websocket.py +75 -0
  10. ctools/browser_element_tools.py +314 -0
  11. ctools/call.py +71 -0
  12. ctools/cftp.py +74 -0
  13. ctools/cjson.py +54 -0
  14. ctools/ckafka.py +159 -0
  15. ctools/compile_tools.py +18 -0
  16. ctools/console.py +55 -0
  17. ctools/coord_trans.py +127 -0
  18. ctools/credis.py +111 -0
  19. ctools/cron_lite.py +252 -0
  20. ctools/ctoken.py +34 -0
  21. ctools/cword.py +30 -0
  22. ctools/czip.py +130 -0
  23. ctools/database.py +185 -0
  24. ctools/date_utils.py +43 -0
  25. ctools/dict_wrapper.py +20 -0
  26. ctools/douglas_rarefy.py +136 -0
  27. ctools/download_tools.py +57 -0
  28. ctools/enums.py +4 -0
  29. ctools/ex.py +31 -0
  30. ctools/excelOpt.py +36 -0
  31. ctools/html_soup.py +35 -0
  32. ctools/http_utils.py +24 -0
  33. ctools/images_tools.py +27 -0
  34. ctools/imgDialog.py +44 -0
  35. ctools/metrics.py +131 -0
  36. ctools/mqtt_utils.py +289 -0
  37. ctools/obj.py +20 -0
  38. ctools/pacth.py +74 -0
  39. ctools/plan_area_tools.py +97 -0
  40. ctools/process_pool.py +36 -0
  41. ctools/pty_tools.py +72 -0
  42. ctools/resource_bundle_tools.py +121 -0
  43. ctools/rsa.py +70 -0
  44. ctools/screenshot_tools.py +127 -0
  45. ctools/sign.py +20 -0
  46. ctools/sm_tools.py +49 -0
  47. ctools/snow_id.py +76 -0
  48. ctools/str_diff.py +20 -0
  49. ctools/string_tools.py +85 -0
  50. ctools/sys_info.py +157 -0
  51. ctools/sys_log.py +89 -0
  52. ctools/thread_pool.py +35 -0
  53. ctools/upload_tools.py +40 -0
  54. ctools/win_canvas.py +83 -0
  55. ctools/win_control.py +106 -0
  56. ctools/word_fill.py +562 -0
  57. ctools/word_fill_entity.py +46 -0
  58. ctools/work_path.py +69 -0
  59. {gomyck_tools-1.3.1.dist-info → gomyck_tools-1.3.2.dist-info}/METADATA +1 -1
  60. gomyck_tools-1.3.2.dist-info/RECORD +62 -0
  61. gomyck_tools-1.3.2.dist-info/top_level.txt +1 -0
  62. gomyck_tools-1.3.1.dist-info/RECORD +0 -4
  63. gomyck_tools-1.3.1.dist-info/top_level.txt +0 -1
  64. {gomyck_tools-1.3.1.dist-info → gomyck_tools-1.3.2.dist-info}/WHEEL +0 -0
ctools/__init__.py ADDED
File without changes
ctools/aes_tools.py ADDED
@@ -0,0 +1,35 @@
1
+ from cryptography.fernet import Fernet
2
+
3
+ def generate_key():
4
+ """
5
+ 生成 AES key
6
+ Returns 32 bytes key
7
+ -------
8
+ """
9
+ key = Fernet.generate_key()
10
+ return key.decode()
11
+
12
+ def aes_encrypt(sec_key, plaintext):
13
+ """
14
+ aes加密
15
+ :param sec_key: 加密 key
16
+ :param plaintext: 明文信息
17
+ :return: 加密后的信息
18
+ """
19
+ cipher = Fernet(sec_key)
20
+ ciphertext = cipher.encrypt(plaintext.encode())
21
+ return ciphertext.decode()
22
+
23
+
24
+ def aes_decrypt(sec_key, ciphertext):
25
+ """
26
+ aes解密
27
+ :param sec_key: 加密 key
28
+ :param ciphertext: 密文
29
+ :return: 解密后的明文信息
30
+ """
31
+ cipher = Fernet(sec_key)
32
+ decrypted_data = cipher.decrypt(ciphertext)
33
+ return decrypted_data.decode()
34
+
35
+
ctools/api_result.py ADDED
@@ -0,0 +1,55 @@
1
+ from ctools import cjson
2
+
3
+ cjson.str_value_keys = [
4
+ "obj_id",
5
+ ]
6
+
7
+
8
+ class _ResEnum(object):
9
+ def __init__(self, code: int, message: str):
10
+ self.code = code
11
+ self.message = message
12
+
13
+ def __eq__(self, o: object) -> bool:
14
+ return self.code == o
15
+
16
+ class R(object):
17
+ class Code:
18
+
19
+ @staticmethod
20
+ def cus_code(code, msg):
21
+ return _ResEnum(code, msg)
22
+
23
+ SUCCESS = _ResEnum(200, "成功")
24
+ FAIL = _ResEnum(400, "失败")
25
+ ERROR = _ResEnum(500, "异常")
26
+
27
+ def __init__(self, code: int, message: str, data=""):
28
+ self.code = code
29
+ self.message = message
30
+ self.data = data
31
+
32
+ def _to_json_str(self):
33
+ return cjson.unify_to_str(cjson.dumps(self))
34
+
35
+ @staticmethod
36
+ def parser(r_json: str):
37
+ return R(**cjson.loads(r_json))
38
+
39
+ @staticmethod
40
+ def ok(data=None, resp=Code.SUCCESS, msg=None, to_json_str=True):
41
+ if not to_json_str:
42
+ return R(resp.code, msg if msg is not None else resp.message, data)
43
+ return R(resp.code, msg if msg is not None else resp.message, data)._to_json_str()
44
+
45
+ @staticmethod
46
+ def fail(msg=None, resp=Code.FAIL, data=None, to_json_str=True):
47
+ if not to_json_str:
48
+ return R(resp.code, msg if msg is not None else resp.message, data)
49
+ return R(resp.code, msg if msg is not None else resp.message, data)._to_json_str()
50
+
51
+ @staticmethod
52
+ def error(msg=None, resp=Code.ERROR, data=None, to_json_str=True):
53
+ if not to_json_str:
54
+ return R(resp.code, msg if msg is not None else resp.message, data)
55
+ return R(resp.code, msg if msg is not None else resp.message, data)._to_json_str()
ctools/application.py ADDED
@@ -0,0 +1,386 @@
1
+ import os
2
+ import shutil
3
+ import socket
4
+ import subprocess
5
+ import time
6
+ import zipfile
7
+ from configparser import ConfigParser
8
+
9
+ from PIL import Image
10
+
11
+ from ctools import work_path, call, sign, thread_pool
12
+ from ctools.sys_info import get_os_architecture, get_os_architecture4x
13
+
14
+ """
15
+ 本模块引用的依赖, 不允许引用sys_log模块, 否则将报错: 循环引用
16
+ 打印使用print即可, 程序启动后, 会自动接管为log
17
+ """
18
+
19
+
20
+ class Server:
21
+ version = '' # 版本信息
22
+ port = 8010 # 服务端口
23
+ metricsPort = 8011 # 获取指标信息端口
24
+ wsPort = 8012 # websocket服务端口
25
+ startTime = time.time() # 系统启动时间
26
+ baseWorkPath = work_path.get_user_work_path('rpa') # 基础的工作目录
27
+ sysLogPath = os.path.join(baseWorkPath, ".logs") # 系统日志存储目录
28
+ pythonHome = os.path.join(work_path.get_Users_path(), 'Public/python-3.8.9') # python根目录
29
+ indicatorsPath = os.path.join(baseWorkPath, "indicators") # 指标信息存储目录
30
+ screenshotPath = os.path.join(baseWorkPath, "screenshot") # 截图存储目录
31
+ controlServerAddr = None
32
+
33
+
34
+ class Authorization:
35
+ enabled = True # 访问权限验证开关
36
+ whitelist = []
37
+
38
+
39
+ class Database:
40
+ url_biz = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core", 'systemRDB') # 数据库文件地址
41
+ url_func = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core", 'explorerSearch') # 函数库地址
42
+ url_auth = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core", 'tmp') # 授权库地址
43
+ pool_size = 5
44
+ max_overflow = 25
45
+
46
+
47
+ class Upload:
48
+ upload_path = os.path.join(Server.baseWorkPath, 'uploads') # 上传文件存储目录
49
+ driver_path = os.path.join(Server.baseWorkPath, 'uploadDriver') # 上传驱动存储目录
50
+ source_pkg_path = os.path.join(Server.baseWorkPath, 'source_pkg') # 资源中心位置
51
+ module_path = os.path.join(Server.baseWorkPath, 'module_path') # 上传组件存储目录
52
+
53
+
54
+ class Schedule:
55
+ rpa_script_path = os.path.join(work_path.get_user_work_path(), ".cache/.tmp") # 执行流程存储目录
56
+ template_output_path = os.path.join(Server.baseWorkPath, 'document') # 使用模板生成的文档存储目录
57
+ play_wright_slow_mo = 0 # play wright每一步执行延时时间, 单位毫秒
58
+
59
+
60
+ @call.once
61
+ def sync_config():
62
+ path = os.path.join(work_path.get_app_path(), "application.ini")
63
+ conf = ConfigParser()
64
+ if os.path.exists(path):
65
+ conf.read(path)
66
+ sections = conf.sections()
67
+ ######### Server 必须放在第一个初始化的位置 ########
68
+ if "Server" in sections:
69
+ server_conf = conf['Server']
70
+ Server.version = server_conf['version']
71
+ Server.port = int(server_conf['port'])
72
+ Server.baseWorkPath = work_path.get_user_work_path(server_conf['baseWorkPath'])
73
+ Server.sysLogPath = os.path.join(Server.baseWorkPath, ".logs")
74
+ ######### Server 必须放在第一个初始化的位置 ########
75
+ if "Database" in sections:
76
+ database = conf['Database']
77
+ Database.url_biz = database['url_biz'] if database['url_biz'] else Database.url_biz
78
+ Database.url_func = database['url_func'] if database['url_func'] else Database.url_func
79
+ Database.url_auth = database['url_auth'] if database['url_auth'] else Database.url_auth
80
+ Database.pool_size = int(database['poolSize'])
81
+ Database.max_overflow = int(database['maxOverflow'])
82
+ if "Upload" in sections:
83
+ upload_path_section = conf['Upload']
84
+ Upload.upload_path = os.path.join(Server.baseWorkPath, upload_path_section['path'])
85
+ Upload.driver_path = os.path.join(Server.baseWorkPath, upload_path_section['driver_path'])
86
+ Upload.source_pkg_path = os.path.join(Server.baseWorkPath, upload_path_section['source_pkg_path'])
87
+ if "Schedule" in sections:
88
+ schedule = conf['Schedule']
89
+ Schedule.template_output_path = os.path.join(Server.baseWorkPath, schedule['templateOutputPath'])
90
+ Schedule.play_wright_slow_mo = schedule['playWrightSlowMo']
91
+ if "Authorization" in sections:
92
+ auth = conf['Authorization']
93
+ Authorization.enabled = bool(int(auth['enabled']))
94
+ whitelist_paths = [w.strip() for w in auth['whitelist'].split(',')]
95
+ Authorization.whitelist.extend(whitelist_paths)
96
+
97
+ os.makedirs(Server.baseWorkPath, exist_ok=True)
98
+ os.makedirs(Server.indicatorsPath, exist_ok=True)
99
+ os.makedirs(Server.screenshotPath, exist_ok=True)
100
+ os.makedirs(Upload.source_pkg_path, exist_ok=True)
101
+ os.makedirs(Schedule.template_output_path, exist_ok=True)
102
+ os.makedirs(Upload.module_path, exist_ok=True)
103
+ else:
104
+ print('配置文件不存在!')
105
+ raise Exception('配置文件不存在!')
106
+
107
+
108
+ def check_database():
109
+ db_file = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core", 'systemRDB')
110
+ if os.path.exists(db_file):
111
+ db_size = os.path.getsize(db_file)
112
+ if db_size < 2000 * 1024: os.remove(db_file)
113
+ db_file = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core", 'tmp')
114
+ if os.path.exists(db_file):
115
+ db_size = os.path.getsize(db_file)
116
+ if db_size < 2000 * 1024: os.remove(db_file)
117
+
118
+ def validate_sign():
119
+ sign_app_val = sign.generate_signature(work_path.get_install_path('rpa-server.exe'))
120
+ with open(work_path.get_install_path('rpa-server.sign')) as sign_file:
121
+ sign_file_val = sign_file.readline()
122
+ if 'rpa-dev-sign' == sign_file_val.strip(): return
123
+ if sign_app_val != sign_file_val: raise Exception('程序签名验证失败!!!')
124
+
125
+
126
+ def path_config():
127
+ print('start config path')
128
+ driverPath = Upload.driver_path
129
+ pythonPath = os.path.join(work_path.get_Users_path(), 'Public/python-3.8.9')
130
+ hplPath = os.path.join(work_path.get_user_work_path(), 'AppData/Local/ms-playwright')
131
+ taguiPath = os.path.join(work_path.get_user_work_path(), 'AppData/Roaming/tagui')
132
+ os.environ['PATH'] = os.pathsep.join([pythonPath, os.path.join(pythonPath, 'Scripts'), driverPath, os.path.join(hplPath, 'chromium-920619\chrome-win'), taguiPath, os.environ['PATH']])
133
+ print('end config path')
134
+
135
+
136
+ def sync_version(callFunc):
137
+ destFilePath = os.path.join(Server.baseWorkPath, "version")
138
+ driverPath = Upload.driver_path
139
+ pythonPath = os.path.join(work_path.get_Users_path(), 'Public/python-3.8.9')
140
+ msPlayPath = os.path.join(work_path.get_user_work_path(), 'AppData/Local/ms-playwright')
141
+ taguiPath = os.path.join(work_path.get_user_work_path(), 'AppData/Roaming/tagui')
142
+ if not os.path.exists(destFilePath):
143
+ try:
144
+ shutil.rmtree(pythonPath)
145
+ except Exception:
146
+ pass
147
+ try:
148
+ shutil.rmtree(msPlayPath)
149
+ except Exception:
150
+ pass
151
+ try:
152
+ shutil.rmtree(driverPath)
153
+ except Exception:
154
+ pass
155
+ try:
156
+ shutil.rmtree(taguiPath)
157
+ except Exception:
158
+ pass
159
+ from ctools.pacth import Patch
160
+ patch = Patch(oldVersion='V1.0.0', newVersion=Server.version, pythonPath=pythonPath, playwrightPath=msPlayPath, driverPath=driverPath)
161
+ patch.apply_patch()
162
+ if callFunc: callFunc()
163
+ with open(destFilePath, 'w') as newVersion:
164
+ newVersion.write(Server.version)
165
+ print('初始化安装, 版本信息为: {}'.format(Server.version))
166
+ newVersion.flush()
167
+ else:
168
+ with open(destFilePath, 'r') as oldVersion:
169
+ oldV = oldVersion.readline()
170
+ print('本地版本信息为: {}, 程序版本信息为: {}'.format(oldV, Server.version))
171
+ oldVersion.close()
172
+ if oldV == Server.version and '-snapshot' not in oldV: return
173
+ print('开始升级本地程序..')
174
+ from ctools.pacth import Patch
175
+ patch = Patch(oldVersion=oldV, newVersion=Server.version, pythonPath=pythonPath, playwrightPath=msPlayPath, driverPath=driverPath)
176
+ patch.apply_patch()
177
+ if callFunc: callFunc()
178
+ with open(destFilePath, 'w') as newVersion:
179
+ newVersion.write(Server.version)
180
+ print('程序升级成功, 更新版本信息为: {}'.format(Server.version))
181
+ newVersion.flush()
182
+
183
+
184
+ def sync_database():
185
+ for db in [['simpleYWI', 'systemRDB', False], ['simpleHSI', 'explorerSearch', True], ['simpleSQI', 'tmp', False]]:
186
+ dbPath = os.path.join(work_path.get_app_path(), "extension", db[0])
187
+ destDBPath = os.path.join(work_path.get_user_work_path(), "AppData/Local/SystemWin32Core")
188
+ os.makedirs(destDBPath, exist_ok=True)
189
+ destFilePath = os.path.join(destDBPath, db[1])
190
+ try:
191
+ if db[2] and os.path.exists(destFilePath): os.remove(destFilePath)
192
+ except Exception:
193
+ pass
194
+ if not os.path.exists(destFilePath):
195
+ shutil.copy(dbPath, destFilePath)
196
+ else:
197
+ pass
198
+
199
+
200
+ def sync_python_env():
201
+ print('SDK 开始安装...')
202
+ sourcePath = os.path.join(work_path.get_install_path(), "sources", 'python-3.8.9-{}.zip'.format(get_os_architecture()))
203
+ destPLPath = os.path.join(work_path.get_Users_path(), 'Public/python-3.8.9')
204
+ unzipPLPath = os.path.join(work_path.get_Users_path(), 'Public')
205
+ if not os.path.exists(destPLPath):
206
+ with zipfile.ZipFile(sourcePath, 'r') as zip_ref:
207
+ zip_ref.extractall(unzipPLPath)
208
+ print('SDK 安装成功(0)')
209
+ else:
210
+ print('SDK 安装成功(1)')
211
+ print('SDK 环境变量配置成功')
212
+
213
+
214
+ def sync_python_module():
215
+ print('SDK 安装模块开始')
216
+ module_list = []
217
+
218
+ if os.path.exists(Upload.module_path):
219
+ for file_name in os.listdir(Upload.module_path):
220
+ m_path = os.path.join(Upload.module_path, file_name)
221
+ module_list.append(m_path)
222
+
223
+ upgrade_module_path = os.path.join(work_path.get_install_path(), "sources/UpgradeModule")
224
+ init_flag = os.path.join(upgrade_module_path, "init")
225
+ upgrade_module_path = os.path.join(upgrade_module_path, get_os_architecture4x())
226
+ if not os.path.exists(init_flag) and os.path.exists(upgrade_module_path):
227
+ for file_name in os.listdir(upgrade_module_path):
228
+ m_path = os.path.join(upgrade_module_path, file_name)
229
+ module_list.append(m_path)
230
+
231
+ if module_list:
232
+
233
+ freeze_msg = ""
234
+ pip_path = os.path.join(Server.pythonHome, 'Scripts/pip.exe')
235
+ cmd = [pip_path, "freeze"]
236
+ proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
237
+ stderr=subprocess.PIPE, close_fds=True)
238
+ if proc:
239
+ stdout, stderr = proc.communicate()
240
+ freeze_msg = str(stdout)
241
+
242
+ for m_path in module_list:
243
+ if os.path.isfile(m_path):
244
+ installed = False
245
+ m = os.path.basename(m_path)
246
+ m_name = m.split("-")
247
+ if len(m_name) >= 2:
248
+ installed = "%s-%s" % (m_name[0], m_name[1]) in freeze_msg or "%s==%s" % (m_name[0], m_name[1]) in freeze_msg
249
+
250
+ if not installed:
251
+ cmd = [pip_path, "install", "--no-dependencies", m_path]
252
+ proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
253
+ stderr=subprocess.PIPE, close_fds=True)
254
+ if proc:
255
+ stdout, stderr = proc.communicate()
256
+ if stdout:
257
+ if "Successfully installed" in str(stdout) or "already installed" in str(stdout):
258
+ print("SDK 安装本地模块%s成功" % m)
259
+ else:
260
+ print("SDK 安装本地模块%s失败" % m)
261
+
262
+ if not os.path.exists(init_flag):
263
+ with open(init_flag, "w") as f:
264
+ f.write("success")
265
+ f.flush()
266
+ print('SDK 安装本地模块完成')
267
+
268
+
269
+ def sync_python_interpreter():
270
+ destPLPath = os.path.join(work_path.get_Users_path(), 'Public/python-3.8.9')
271
+ enhancePath = os.path.join(work_path.get_Users_path(), "Public/enhance", 'enhance-{}.zip'.format(get_os_architecture()))
272
+ originPath = os.path.join(work_path.get_Users_path(), "Public/enhance", 'origin-{}.zip'.format(get_os_architecture()))
273
+ initFlag = os.path.join(work_path.get_Users_path(), "Public/enhance", 'init')
274
+ flagValue = 'can not find dest dir'
275
+ os.makedirs(os.path.join(work_path.get_Users_path(), "Public/enhance"), exist_ok=True)
276
+ if not os.path.exists(initFlag):
277
+ try:
278
+ if os.path.exists(enhancePath):
279
+ with zipfile.ZipFile(enhancePath, 'r') as zip_ref:
280
+ zip_ref.extractall(destPLPath)
281
+ flagValue = 'enhance'
282
+ print('enhance enabled..')
283
+ elif os.path.exists(originPath):
284
+ with zipfile.ZipFile(originPath, 'r') as zip_ref:
285
+ zip_ref.extractall(destPLPath)
286
+ flagValue = 'origin'
287
+ print('origin enabled..')
288
+ with open(initFlag, 'w') as flag:
289
+ flag.write(flagValue)
290
+ print('interpreter init success: {}'.format(flagValue))
291
+ flag.flush()
292
+ except Exception as e:
293
+ print('interpreter init error: {}'.format(e))
294
+ else:
295
+ with open(initFlag, 'r') as flag:
296
+ flagValue = flag.readline()
297
+ print('interpreter flag: {}'.format(flagValue))
298
+ flag.close()
299
+
300
+
301
+ def sync_driver():
302
+ print('DRIVER 开始安装...')
303
+ sourcePath = os.path.join(work_path.get_install_path(), "sources", 'uploadDriver.zip')
304
+ destPLPath = Upload.driver_path
305
+ unzipPLPath = Upload.driver_path
306
+ if not os.path.exists(os.path.join(destPLPath)):
307
+ with zipfile.ZipFile(sourcePath, 'r') as zip_ref:
308
+ zip_ref.extractall(unzipPLPath)
309
+ print('DRIVER 安装成功(0)')
310
+ else:
311
+ print('DRIVER 安装成功(1)')
312
+
313
+ print('DRIVER 配置成功')
314
+
315
+
316
+ def sync_tagui():
317
+ print('HTG ENGINE 开始安装...')
318
+ plPath = os.path.join(work_path.get_install_path(), "sources", 'htg-source.zip')
319
+ destPLPath = os.path.join(work_path.get_user_work_path(), 'AppData/Roaming/tagui')
320
+ unzipPLPath = os.path.join(work_path.get_user_work_path(), 'AppData/Roaming/')
321
+ if not os.path.exists(os.path.join(destPLPath)):
322
+ with zipfile.ZipFile(plPath, 'r') as zip_ref:
323
+ zip_ref.extractall(unzipPLPath)
324
+ print('HTG ENGINE 依赖安装成功(0)')
325
+ else:
326
+ print('HTG ENGINE 依赖安装成功(1)')
327
+
328
+
329
+ def sync_playwright():
330
+ print('HPL ENGINE 开始安装...')
331
+ plPath = os.path.join(work_path.get_install_path(), "sources", 'ms-playwright.zip')
332
+ destPLPath = os.path.join(work_path.get_user_work_path(), 'AppData/Local/ms-playwright')
333
+ unzipPLPath = os.path.join(work_path.get_user_work_path(), 'AppData/Local/')
334
+ if not os.path.exists(os.path.join(destPLPath)):
335
+ with zipfile.ZipFile(plPath, 'r') as zip_ref:
336
+ zip_ref.extractall(unzipPLPath)
337
+ print('HPL ENGINE 依赖安装成功(0)')
338
+ else:
339
+ print('HPL ENGINE 依赖安装成功(1)')
340
+
341
+ def sync_paddleocr_model():
342
+ model_path = os.path.join(work_path.get_install_path(), "sources", 'paddleocr-model.zip')
343
+ paddleocr_path = work_path.get_user_work_path(".paddleocr")
344
+ if not os.path.exists(paddleocr_path) and os.path.exists(model_path) and get_os_architecture() == "64":
345
+ print('安装paddleocr模型文件开始')
346
+ with zipfile.ZipFile(model_path, 'r') as zip_ref:
347
+ zip_ref.extractall(paddleocr_path)
348
+ print('安装paddleocr模型文件结束')
349
+
350
+
351
+ def clean_temp_dir(target_file='rpa_ident'):
352
+ root_folder = work_path.get_user_temp_path()
353
+ print("Start clear cache...")
354
+ for folder_name in os.listdir(root_folder):
355
+ folder_path = os.path.join(root_folder, folder_name)
356
+ if os.path.isdir(folder_path):
357
+ file_path = os.path.join(folder_path, target_file)
358
+ if os.path.exists(file_path) and os.path.normpath(folder_path) != os.path.normpath(work_path.get_app_path()):
359
+ try:
360
+ shutil.rmtree(folder_path)
361
+ except Exception:
362
+ pass
363
+ print("End clear cache...")
364
+ shutil.rmtree(Schedule.rpa_script_path, ignore_errors=True)
365
+
366
+
367
+ def is_port_in_use(port):
368
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
369
+ return s.connect_ex(('localhost', port)) == 0
370
+
371
+
372
+ def system_tray(app_server):
373
+ pystray = __import__('pystray')
374
+ try:
375
+ def on_quit_clicked(app_icon):
376
+ thread_pool.submit(app_server.stop)
377
+ app_icon.stop()
378
+
379
+ image = Image.open(os.path.join(work_path.get_app_path(), "images/ico.png"))
380
+ menu = (
381
+ pystray.MenuItem(text='退出', action=on_quit_clicked),
382
+ )
383
+ icon = pystray.Icon("name", image, "RPA客户端", menu)
384
+ icon.run()
385
+ except Exception:
386
+ pass
ctools/b64.py ADDED
@@ -0,0 +1,7 @@
1
+ import base64
2
+
3
+ def encode(param: str):
4
+ return base64.b64encode(param.encode('UTF-8')).decode('UTF-8')
5
+
6
+ def decode(param: str):
7
+ return base64.b64decode(param.encode('UTF-8')).decode('UTF-8')
ctools/bashPath.py ADDED
@@ -0,0 +1,13 @@
1
+ import inspect
2
+ import os
3
+ import sys
4
+
5
+
6
+ def path(subPath: str = '') -> str:
7
+ if getattr(sys, 'frozen', False):
8
+ base_path = sys._MEIPASS
9
+ else:
10
+ caller_frame = inspect.currentframe().f_back
11
+ caller_path = caller_frame.f_globals["__file__"]
12
+ base_path = os.path.dirname(caller_path)
13
+ return base_path + os.path.sep + subPath
@@ -0,0 +1,169 @@
1
+ import inspect
2
+ import threading
3
+ from functools import wraps
4
+
5
+ import bottle
6
+ from bottle import response, Bottle, request
7
+
8
+ from ctools import ctoken
9
+ from ctools.dict_wrapper import DictWrapper
10
+ from ctools.api_result import R
11
+ from ctools.sys_log import flog as log
12
+
13
+ bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 50
14
+ func_has_params = {}
15
+
16
+ class GlobalState:
17
+ lock = threading.Lock()
18
+ withOutLoginURI = [
19
+ '/',
20
+ '/index',
21
+ '/login'
22
+ ]
23
+ allowRemoteCallURI = [
24
+
25
+ ]
26
+ token = {}
27
+ interceptors = []
28
+
29
+ def init_app(context_path=None):
30
+ app = Bottle()
31
+ app.context_path = context_path
32
+
33
+ @app.hook('before_request')
34
+ def before_request():
35
+ for interceptor in GlobalState.interceptors:
36
+ res: R = interceptor['func']()
37
+ if res.code != 200: bottle.abort(res.code, res.message)
38
+
39
+ @app.error(401)
40
+ def unauthorized(error):
41
+ response.status = 401
42
+ log.error("系统未授权: {} {} {}".format(error.body, request.method, request.fullpath))
43
+ return R.error(resp=R.Code.cus_code(401, "系统未授权! {}".format(error.body)))
44
+
45
+ @app.error(403)
46
+ def unauthorized(error):
47
+ response.status = 403
48
+ log.error("访问受限: {} {} {}".format(error.body, request.method, request.fullpath))
49
+ return R.error(resp=R.Code.cus_code(403, "访问受限: {}".format(error.body)))
50
+
51
+ @app.error(404)
52
+ def not_found(error):
53
+ response.status = 404
54
+ log.error("404 not found : {} {} {}".format(error.body, request.method, request.fullpath))
55
+ return R.error(resp=R.Code.cus_code(404, "资源未找到: {}".format(error.body)))
56
+
57
+ @app.error(405)
58
+ def method_not_allow(error):
59
+ response.status = 405
60
+ log.error("请求方法错误: {} {} {}".format(error.status_line, request.method, request.fullpath))
61
+ return R.error(resp=R.Code.cus_code(405, '请求方法错误: {}'.format(error.status_line)))
62
+
63
+ @app.error(500)
64
+ def internal_error(error):
65
+ response.status = 500
66
+ log.error("系统发生错误: {} {} {}".format(error.body, request.method, request.fullpath))
67
+ return R.error(msg='系统发生错误: {}'.format(error.exception))
68
+
69
+ @app.hook('after_request')
70
+ def after_request():
71
+ enable_cors()
72
+
73
+ app.install(params_resolve)
74
+ return app
75
+
76
+ def enable_cors():
77
+ response.headers['Access-Control-Allow-Origin'] = '*'
78
+ response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
79
+ request_headers = request.headers.get('Access-Control-Request-Headers')
80
+ response.headers['Access-Control-Allow-Headers'] = request_headers if request_headers else ''
81
+ response.headers['Access-Control-Expose-Headers'] = '*'
82
+
83
+ # annotation
84
+ def before_intercept(order=0):
85
+ def decorator(func):
86
+ log.info("add before interceptor: {}".format(func.__name__))
87
+ GlobalState.interceptors.append({'order': order, 'func': func})
88
+ GlobalState.interceptors = sorted(GlobalState.interceptors, key=lambda x: x['order'])
89
+ return decorator
90
+
91
+ # annotation
92
+ def rule(key):
93
+ def return_func(func):
94
+ @wraps(func)
95
+ def decorated(*args, **kwargs):
96
+ # if GlobalState.licenseInfo is not None and key not in GlobalState.licenseInfo.access_module:
97
+ # log.error("系统未授权! {} {}".format(request.fullpath, '当前请求的模块未授权!请联系管理员!'))
98
+ # return R.error(resp=R.Code.cus_code(9999, "系统未授权! {}".format('当前请求的模块未授权!请联系管理员!')))
99
+ return func(*args, **kwargs)
100
+ return decorated
101
+ return return_func
102
+
103
+ # annotation or plugins, has auto install, don't need to call
104
+ def params_resolve(func):
105
+ @wraps(func)
106
+ def decorated(*args, **kwargs):
107
+ if func_has_params.get(request.fullpath) is not None and not func_has_params.get(request.fullpath):
108
+ return func(*args, **kwargs)
109
+ if func_has_params.get(request.fullpath) is None:
110
+ sig = inspect.signature(func)
111
+ params = sig.parameters
112
+ if not params.get('params'):
113
+ func_has_params[request.fullpath] = False
114
+ return func(*args, **kwargs)
115
+ else:
116
+ func_has_params[request.fullpath] = True
117
+ if request.method == 'GET':
118
+ queryStr = request.query.decode('utf-8')
119
+ page_info = PageInfo(
120
+ page_size=10 if request.headers.get('page_size') is None else int(request.headers.get('page_size')),
121
+ page_index=1 if request.headers.get('page_index') is None else int(request.headers.get('page_index'))
122
+ )
123
+ queryStr.page_info = page_info
124
+ return func(params=queryStr, *args, **kwargs)
125
+ elif request.method == 'POST':
126
+ query_params = request.query.decode('utf-8')
127
+ content_type = request.get_header('content-type')
128
+ if content_type == 'application/json':
129
+ params = request.json or {}
130
+ dict_wrapper = DictWrapper(params)
131
+ dict_wrapper.update(query_params.dict)
132
+ return func(params=dict_wrapper, *args, **kwargs)
133
+ elif 'multipart/form-data' in content_type:
134
+ form_data = request.forms.decode()
135
+ form_files = request.files.decode()
136
+ dict_wrapper = DictWrapper(form_data)
137
+ dict_wrapper.update(query_params.dict)
138
+ dict_wrapper.files = form_files
139
+ return func(params=dict_wrapper, *args, **kwargs)
140
+ elif 'application/x-www-form-urlencoded' in content_type:
141
+ params = request.forms.decode()
142
+ dict_wrapper = DictWrapper(params.dict)
143
+ dict_wrapper.update(query_params.dict)
144
+ return func(params=dict_wrapper, *args, **kwargs)
145
+ elif 'text/plain' in content_type:
146
+ params = request.body.read().decode('utf-8')
147
+ dict_wrapper = DictWrapper({'body': params})
148
+ dict_wrapper.update(query_params.dict)
149
+ return func(params=dict_wrapper, *args, **kwargs)
150
+ else:
151
+ return func(*args, **kwargs)
152
+ return decorated
153
+
154
+ class PageInfo:
155
+ def __init__(self, page_size, page_index):
156
+ self.page_size = page_size
157
+ self.page_index = page_index
158
+
159
+ # 通用的鉴权方法
160
+ def common_auth_verify(aes_key):
161
+ if request.path.startswith('/static') or request.path in GlobalState.withOutLoginURI:
162
+ return R.ok(to_json_str=False)
163
+ auth_token = request.get_header('Authorization')
164
+ if auth_token is None:
165
+ auth_token = request.get_cookie('Authorization')
166
+ payload = ctoken.get_payload(auth_token, aes_key)
167
+ if payload:
168
+ return R.ok(to_json_str=False)
169
+ return R.error(resp=R.Code.cus_code(401, "未授权"), to_json_str=False)