ryry-cli 1.0__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.
ryry/utils.py ADDED
@@ -0,0 +1,358 @@
1
+ import uuid
2
+ import platform
3
+ import subprocess
4
+ import os
5
+ import sys
6
+ import requests
7
+ from io import BytesIO
8
+ import psutil
9
+ import pynvml
10
+ from datetime import datetime, timedelta
11
+ import http
12
+ import json
13
+ from pathlib import Path
14
+ import zipfile
15
+ import socket
16
+ from PIL import Image
17
+
18
+ def get_mac_from_nettools():
19
+ try:
20
+ cmd = "ifconfig"
21
+ output = subprocess.check_output(cmd, shell=True)
22
+ output_str = output.decode(encoding='UTF-8')
23
+ mac = output_str[output_str.index('ether') + 6:output_str.index('ether') + 23].replace(':', '')
24
+ return True, mac
25
+ except Exception as e:
26
+ return False, None
27
+
28
+ def get_mac_from_system():
29
+ try:
30
+ root_path = '/sys/class/net/'
31
+ dbtype_list = os.listdir(root_path)
32
+ for dbtype in dbtype_list:
33
+ if os.path.isfile(os.path.join(root_path, dbtype)):
34
+ dbtype_list.remove(dbtype)
35
+
36
+ if len(dbtype_list) == 0:
37
+ return False, None
38
+ mac = ''
39
+ for dbtype in dbtype_list:
40
+ cmd = f"cat {root_path}{dbtype}/address"
41
+ output = subprocess.check_output(cmd, shell=True)
42
+ mac += output.decode(encoding='UTF-8')
43
+ return True, mac
44
+ except Exception as e:
45
+ return False, None
46
+
47
+ mac_value = ""
48
+ def get_mac_address():
49
+ global mac_value
50
+ if mac_value and len(mac_value) > 0:
51
+ return mac_value
52
+
53
+ if platform.system() == 'Windows':
54
+ cmd = "ipconfig /all"
55
+ output = subprocess.check_output(cmd, shell=True)
56
+ output_str = output.decode('gbk')
57
+ pos = output_str.find('Physical Address')
58
+ if pos == -1:
59
+ pos = output_str.find('物理地址')
60
+ mac_value = (output_str[pos:pos+100].split(':')[1]).strip().replace('-', '')
61
+ elif platform.system() == 'Linux' or platform.system() == 'Darwin':
62
+ ok, mac_value = get_mac_from_nettools()
63
+ if ok:
64
+ return mac_value
65
+ ok, mac_value = get_mac_from_system()
66
+ if ok:
67
+ return mac_value
68
+ return None
69
+ else:
70
+ mac_value = None
71
+ return mac_value
72
+
73
+ cpu_serial = ""
74
+ def get_cpu_serial():
75
+ global cpu_serial
76
+ if cpu_serial and len(cpu_serial) > 0:
77
+ return cpu_serial
78
+
79
+ if platform.system() == 'Windows':
80
+ cmd = "wmic cpu get ProcessorId"
81
+ output = subprocess.check_output(cmd, shell=True)
82
+ output_str = output.decode('gbk')
83
+ pos = output_str.index("\n")
84
+ cpu_serial = output_str[pos:].strip()
85
+ elif platform.system() == 'Linux':
86
+ with open('/proc/cpuinfo') as f:
87
+
88
+ for line in f:
89
+ if line[0:6] == 'Serial':
90
+ return "1"
91
+ if line.strip().startswith('serial'):
92
+ cpu_serial = line.split(":")[1].strip()
93
+ break
94
+ if not cpu_serial:
95
+ cpu_serial = None
96
+ elif platform.system() == 'Darwin':
97
+ cmd = "/usr/sbin/system_profiler SPHardwareDataType"
98
+ output = subprocess.check_output(cmd, shell=True)
99
+ output_str = output.decode(encoding='UTF-8')
100
+ cpu_serial = output_str[output_str.index('Hardware UUID:') + 14:output_str.index('Hardware UUID:') + 51].replace('-', '')
101
+ else:
102
+ cpu_serial = None
103
+ return cpu_serial
104
+
105
+ def get_hostname():
106
+ return socket.gethostname()
107
+
108
+ def generate_unique_id():
109
+ mac = get_mac_address()
110
+ cpu_serial = get_cpu_serial()
111
+ hostname = get_hostname()
112
+ if mac and cpu_serial:
113
+ unique_id = uuid.uuid5(uuid.NAMESPACE_DNS, mac + cpu_serial + hostname)
114
+ return str(unique_id).replace('-', '')
115
+ if mac :
116
+ unique_id = uuid.uuid5(uuid.NAMESPACE_DNS, mac + hostname)
117
+ return str(unique_id).replace('-', '')
118
+
119
+ def getOssImageSize(p):
120
+ try:
121
+ s = requests.session()
122
+ s.keep_alive = False
123
+ res = s.get(p, timeout=60)
124
+ image = Image.open(BytesIO(res.content), "r")
125
+ s.close()
126
+ return image.size
127
+ except:
128
+ return 0, 0
129
+
130
+ def deviceInfo():
131
+ mac = get_mac_address()
132
+ mac = "" if mac == None else mac
133
+ cpu_serial = get_cpu_serial()
134
+ cpu_serial = "" if cpu_serial == None else cpu_serial
135
+ hostname = get_hostname()
136
+ M=1024*1024
137
+ data = {
138
+ "cpu": {
139
+ "logical_count" : psutil.cpu_count(),
140
+ "count" : psutil.cpu_count(logical=False),
141
+ "max_freq" : f"{psutil.cpu_freq().max / 1000} GHz",
142
+ },
143
+ "memory": {
144
+ "total" : f"{psutil.virtual_memory().total/M} M",
145
+ "free" : f"{psutil.virtual_memory().free/M} M"
146
+ },
147
+ "gpu": {
148
+ "count" : 0,
149
+ "list" : [],
150
+ "mem" : []
151
+ },
152
+ "device_id": generate_unique_id(),
153
+ "host_name": hostname
154
+ }
155
+ try:
156
+ pynvml.nvmlInit()
157
+ gpuCount = pynvml.nvmlDeviceGetCount()
158
+ data["gpu"]["count"] = gpuCount
159
+ for i in range(gpuCount):
160
+ handle = pynvml.nvmlDeviceGetHandleByIndex(i)
161
+ data["gpu"]["list"].append(f"GPU{i}: {pynvml.nvmlDeviceGetName(handle)}")
162
+ memInfo = pynvml.nvmlDeviceGetMemoryInfo(handle)
163
+ data["gpu"]["mem"].append(f"GPU{i}: total:{memInfo.total/M} M free:{memInfo.free/M} M")
164
+
165
+ pynvml.nvmlShutdown()
166
+ except Exception as e:
167
+ data["gpu"]["count"] = 1
168
+ data["gpu"]["list"].append(f"GPU0: Normal")
169
+ return data
170
+
171
+ def reportLog():
172
+ reason = ""
173
+ if len(sys.argv) >= 2:
174
+ reason = sys.argv[2].strip().replace("\n","").replace(",","").replace(" ","").replace(";","")
175
+ d = datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
176
+ uid = generate_unique_id()
177
+
178
+ thisFileDir = os.path.dirname(os.path.abspath(__file__))
179
+ dist = os.path.join(thisFileDir, f"{uid}_{reason}_{d}.zip")
180
+ zip = zipfile.ZipFile(dist, "w", zipfile.ZIP_DEFLATED)
181
+
182
+ for root,dirs,files in os.walk(thisFileDir):
183
+ for file in files:
184
+ if str(file).startswith("~$"):
185
+ continue
186
+ ext = file[file.rindex("."):]
187
+ if ext == ".log" or ext == ".json" or ".log." in file:
188
+ filepath = os.path.join(root, file)
189
+ zip.write(filepath, file)
190
+ if root != files:
191
+ break
192
+ zip.close()
193
+ ossurl = uploadOSS(dist)
194
+ os.remove(dist)
195
+ return ossurl
196
+
197
+ def uploadOSS(file):
198
+ conn = http.client.HTTPSConnection("api.ryryai.com")
199
+ payload = json.dumps({
200
+ "sign": "f0463f490eb84133c0aab3a8576ed2fc"
201
+ })
202
+ headers = {
203
+ 'Content-Type': 'application/json'
204
+ }
205
+ conn.request("POST", "/proxymsg/get_oss_config", payload, headers)
206
+ res = conn.getresponse()
207
+ data = json.loads(res.read().decode("utf-8"))
208
+ if data["code"] == 0:
209
+ AccessKeyId = data["data"]["AccessKeyId"]
210
+ AccessKeySecret = data["data"]["AccessKeySecret"]
211
+ SecurityToken = data["data"]["SecurityToken"]
212
+ BucketName = data["data"]["BucketName"]
213
+ Expiration = data["data"]["Expiration"]
214
+ Endpoint = data["data"]["Endpoint"]
215
+ CallbackUrl = data["data"]["CallbackUrl"]
216
+ cdn = data["data"]["cdn"]
217
+
218
+ if len(AccessKeyId) > 0:
219
+ import oss2
220
+ auth = oss2.StsAuth(AccessKeyId, AccessKeySecret, SecurityToken)
221
+ bucket = oss2.Bucket(auth, Endpoint, BucketName, connect_timeout=600)
222
+ with open(file, "rb") as f:
223
+ byte_data = f.read()
224
+ file_name = Path(file).name
225
+ publish_name = f"ryry/report/{file_name}"
226
+ bucket.put_object(publish_name, byte_data)
227
+ return f"{cdn}{publish_name}"
228
+ else:
229
+ print(f"get_oss_config fail: response={data}")
230
+
231
+ def process_is_alive(pid: int) -> bool:
232
+ try:
233
+ process = psutil.Process(pid)
234
+ pstatus = process.status()
235
+ if pstatus == psutil.STATUS_RUNNING or pstatus == psutil.STATUS_SLEEPING:
236
+ return True
237
+ else:
238
+ return False
239
+ except (FileNotFoundError, psutil.NoSuchProcess):
240
+ return False
241
+ except Exception as e:
242
+ return False
243
+
244
+ def process_is_zombie_but_cannot_kill(pid: int) -> bool:
245
+ try:
246
+ process = psutil.Process(pid)
247
+ pstatus = process.status()
248
+ if pstatus == psutil.STATUS_DISK_SLEEP:
249
+ return True
250
+ except Exception as e:
251
+ return False
252
+ return False
253
+
254
+ def firstExitWithDir(root, suffix):
255
+ for root,dirs,files in os.walk(root):
256
+ for file in files:
257
+ if file.find(".") <= 0:
258
+ continue
259
+ ext = file[file.rindex("."):]
260
+ if ext == f".{suffix}":
261
+ return os.path.join(root, file)
262
+ if root != files:
263
+ break
264
+ return None
265
+
266
+ def begin_restart(reason, update_cli=False, simple="https://pypi.python.org/simple/"):
267
+ thisFileDir = os.path.dirname(os.path.abspath(__file__))
268
+ restart_file = os.path.join(thisFileDir, "restart")
269
+ if os.path.exists(restart_file):
270
+ os.remove(restart_file)
271
+ stop_file = os.path.join(thisFileDir, "stop.now")
272
+ with open(stop_file, 'w') as f:
273
+ f.write("")
274
+ with open(restart_file, 'w') as f:
275
+ json.dump({
276
+ "reason": reason,
277
+ "update_cli": update_cli,
278
+ "simple": simple
279
+ },f)
280
+
281
+ def check_restart():
282
+ thisFileDir = os.path.dirname(os.path.abspath(__file__))
283
+ restart_file = os.path.join(thisFileDir, "restart")
284
+ if os.path.exists(restart_file) == False:
285
+ return
286
+ from ryry import taskUtils
287
+ from ryry import store
288
+ import time, calendar, platform, subprocess
289
+ reason = "unknow"
290
+ update_cli = False
291
+ simple = "https://pypi.python.org/simple/"
292
+ try:
293
+ with open(restart_file, 'r') as f:
294
+ config = json.load(f)
295
+ reason = config["reason"]
296
+ update_cli = config["update_cli"]
297
+ simple = config["simple"]
298
+ except:
299
+ pass
300
+
301
+ if platform.system() == 'Windows':
302
+ time_task_file = os.path.join(thisFileDir, "update_ryry.bat")
303
+ elif platform.system() == 'Linux' or platform.system() == 'Darwin':
304
+ time_task_file = os.path.join(thisFileDir, "update_ryry.sh")
305
+ else:
306
+ time_task_file = os.path.join(thisFileDir, "update_ryry.txt")
307
+ if os.path.exists(time_task_file):
308
+ os.remove(time_task_file)
309
+
310
+ def getCommandResult(cmd):
311
+ try:
312
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
313
+ if result.returncode == 0:
314
+ return result.stdout.decode(encoding="utf8", errors="ignore").replace("\n","").strip()
315
+ except subprocess.CalledProcessError as e:
316
+ print(f"getCommandResult fail {e}")
317
+ return ""
318
+ print(" restart_ryry_cli begin...")
319
+ taskUtils.restartNotify(reason)
320
+ restart_command = "ryry service start"
321
+ threadNum = store.get_multithread()
322
+ if threadNum > 1:
323
+ restart_command = f"{restart_command} -thread {threadNum}"
324
+ restart_command = f"{restart_command}"
325
+ if platform.system() == 'Windows':
326
+ new_time = datetime.now() + timedelta(minutes=1)
327
+ win_time = new_time.strftime("%H:%M")
328
+ with open(time_task_file, 'w') as f:
329
+ if update_cli:
330
+ f.write(f'''pip uninstall ryry-cli -y
331
+ pip install -U ryry-cli -i {simple} --extra-index-url https://pypi.python.org/simple/
332
+ start /B {restart_command}''')
333
+ else:
334
+ f.write(f'''start /B {restart_command}''')
335
+ result = subprocess.Popen(['schtasks', '/create', '/sc', 'ONCE', '/st', f'{win_time}', '/tn', f'ryryUpdate-{calendar.timegm(time.gmtime())}', '/tr', f"\"{time_task_file}\""], shell=True)
336
+ print(f"{result.stdout}\n{result.stderr}")
337
+ elif platform.system() == 'Linux' or platform.system() == 'Darwin':
338
+ def run_subprocess(s):
339
+ r = subprocess.run(s, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
340
+ print(f"{r.stdout}\n{r.stderr}")
341
+ if len(getCommandResult("which at")) <= 0:
342
+ run_subprocess(f"apt-get update")
343
+ run_subprocess(f"apt-get install -y at libopencv-features2d-dev=4.5.4+dfsg-9ubuntu4 systemctl")
344
+ run_subprocess(f"systemctl start atd")
345
+ with open(time_task_file, 'w') as f:
346
+ if update_cli:
347
+ f.write(f'''#!/bin/bash
348
+ pip uninstall ryry-cli -y
349
+ pip install -U ryry-cli -i {simple} --extra-index-url https://pypi.python.org/simple/
350
+ nohup {restart_command} &''')
351
+ else:
352
+ f.write(f'''#!/bin/bash
353
+ nohup {restart_command} &''')
354
+ ot = os.path.join(thisFileDir, "update_ryry.out")
355
+ result = subprocess.run(f"at now + 1 minutes -f {time_task_file} > {ot}", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
356
+ print(f"{result.stdout}\n{result.stderr}")
357
+ os.remove(restart_file)
358
+ print("one minute later must be start!")
@@ -0,0 +1,7 @@
1
+ Copyright 2023 https://www.dalipen.com/
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.1
2
+ Name: ryry-cli
3
+ Version: 1.0
4
+ Summary: ryry tools
5
+ Home-page: https://github.com/dalipenMedia
6
+ Author: dalipen
7
+ Author-email: dalipen01@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.4
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: requests
15
+ Requires-Dist: uuid
16
+ Requires-Dist: Image
17
+ Requires-Dist: pillow
18
+ Requires-Dist: protobuf
19
+ Requires-Dist: psutil
20
+ Requires-Dist: pynvml
21
+ Requires-Dist: requests-toolbelt
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: ping3
24
+ Requires-Dist: piexif
25
+ Requires-Dist: gputil
26
+ Requires-Dist: urlparser
27
+ Requires-Dist: setuptools
28
+ Requires-Dist: twine
29
+ Requires-Dist: python-crontab
30
+
31
+ ryry Python Tool
32
+ ===============================================
33
+ The ryry Python Tool is a official tool, you can use it to **Register** device to ryry server, other person can use **ryry Application** assign tasks to you for implementation
34
+
35
+ Installation
36
+ ------------
37
+
38
+ The ryry requires [Python](http://www.python.org/download) 3.10.6 or later.
39
+
40
+ ##### Installing
41
+ pip install ryry-cli
42
+
43
+ ##### Uninstalling
44
+ pip uninstall ryry-cli
45
+
46
+ Use
47
+ ------------
48
+ ##### 1. Running
49
+ $ ryry service start
50
+ start a process to wait for the server to issue tasks. **Please do not close it**
51
+
52
+ Module Developer
53
+ ------------
54
+ $ ryry widget init
55
+
56
+ in empty folder, use above command craete a ryry module, structure is like
57
+
58
+ [widget folder]
59
+ |-- config.json //*required, do not change*
60
+ |-- main.py //*required, do not change*
61
+ |-- run.py
62
+
63
+ if other person share widget code to you , you can add widget path in your computer to ryry environment
64
+
65
+ $ ryry widget add [path_with_widget_code]
66
+
67
+ you can modify script and h5 file yourself, then publish to ryry sever
68
+
69
+ $ ryry widget publish
70
+
71
+ get ryry status
72
+ $ ryry services status
@@ -0,0 +1,22 @@
1
+ ryry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ ryry/constant.py,sha256=l7BxTcRrq4VngqIsy1UZkIjM2TckIWUkvhhAlmZX2nk,150
3
+ ryry/main.py,sha256=wQXEkj3YZMYkYjtXsmT03sCbHfzJJ136fefx1Tguwck,10438
4
+ ryry/ryry_server_socket.py,sha256=bZsN1UwNkM6SAmTFmRK7o_cU_-4bL_ME5iqJ59l_5-Q,5895
5
+ ryry/ryry_service.py,sha256=gyB-d0o-ROL4Bo_k6ClMKH7akaPwIt0fDgYHyDxEanw,9198
6
+ ryry/ryry_webapi.py,sha256=NLuJ7N1n_dZftInWkkaG7ZVZdYrBOnwE0h33LGUPRRg,8105
7
+ ryry/ryry_widget.py,sha256=73-J7M10CU_G4KvtpzAPbP0vHBs16Bim2DidnTvhwx4,14641
8
+ ryry/server_func.py,sha256=1c1PW_Gr568XlAwfHwNFEGPXUqeqJJMBaVqhdSb4iOI,2447
9
+ ryry/store.py,sha256=_xeCH8Q68pEEPe7aYr9Vfc8UVuLO3juSMAGbDuuuj_4,4375
10
+ ryry/task.py,sha256=LGqhk_-RpyH9yFPudqif53WSj-vnlHq2tryvo_Zn86E,8723
11
+ ryry/taskUtils.py,sha256=asnr5opQDesMK1TkG79wQC6RZj99xuDcBdLe0J3xkDg,10277
12
+ ryry/upload.py,sha256=TUldEew7iwve4TRojNsIt706vA6izh9CaA6clLfCuZ4,5279
13
+ ryry/utils.py,sha256=7QR67JAOPYveCwhjntj3ctnSh1sDn1vHvFx0O18d-UE,13198
14
+ ryry/script_template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ ryry/script_template/main.py,sha256=2ywgwhL0XA1fO-ufxR0AubT7q1KdDI6waSfEMVrBPK0,893
16
+ ryry/script_template/run.py,sha256=iLHbjGoHL0_A26R2EbRogsyXLWkWfWH3jrYqw9wkTrY,495
17
+ ryry_cli-1.0.dist-info/LICENSE,sha256=MeYPss-bnfrn3Fu_fVxdNBhLFiCAHywtGVLQzQWw2Oc,1077
18
+ ryry_cli-1.0.dist-info/METADATA,sha256=FlMpqWqAoiGf4kTsOMELy-_iLZ3WMjAkk9Z8KHMZAbs,2013
19
+ ryry_cli-1.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
20
+ ryry_cli-1.0.dist-info/entry_points.txt,sha256=0Hf0kMFkZhv1zASQaBZkpDyVBxwPLPV6_P59O5AuFlQ,40
21
+ ryry_cli-1.0.dist-info/top_level.txt,sha256=blmPfw7PDn2CArFtSzCw8i_AaGsxh77Ta3Kvo46j4dI,26
22
+ ryry_cli-1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.38.4)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ryry = ryry.main:main
@@ -0,0 +1,3 @@
1
+ public_tools
2
+ ryry
3
+ windows