ryry-cli 1.0__tar.gz

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_cli-1.0/LICENSE ADDED
@@ -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.
ryry_cli-1.0/PKG-INFO ADDED
@@ -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
ryry_cli-1.0/README.md ADDED
@@ -0,0 +1,42 @@
1
+ ryry Python Tool
2
+ ===============================================
3
+ 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
4
+
5
+ Installation
6
+ ------------
7
+
8
+ The ryry requires [Python](http://www.python.org/download) 3.10.6 or later.
9
+
10
+ ##### Installing
11
+ pip install ryry-cli
12
+
13
+ ##### Uninstalling
14
+ pip uninstall ryry-cli
15
+
16
+ Use
17
+ ------------
18
+ ##### 1. Running
19
+ $ ryry service start
20
+ start a process to wait for the server to issue tasks. **Please do not close it**
21
+
22
+ Module Developer
23
+ ------------
24
+ $ ryry widget init
25
+
26
+ in empty folder, use above command craete a ryry module, structure is like
27
+
28
+ [widget folder]
29
+ |-- config.json //*required, do not change*
30
+ |-- main.py //*required, do not change*
31
+ |-- run.py
32
+
33
+ if other person share widget code to you , you can add widget path in your computer to ryry environment
34
+
35
+ $ ryry widget add [path_with_widget_code]
36
+
37
+ you can modify script and h5 file yourself, then publish to ryry sever
38
+
39
+ $ ryry widget publish
40
+
41
+ get ryry status
42
+ $ ryry services status
File without changes
@@ -0,0 +1,5 @@
1
+ #!!!!! do not change this file !!!!!
2
+ app_version="1.0"
3
+ app_bulld_number=10
4
+ app_bulld_anchor="Noh_2024-05-21 19:10:52.776464"
5
+ app_name="ryry-cli"
@@ -0,0 +1,300 @@
1
+ import sys, os, urllib3, time, platform, json
2
+
3
+ from ryry import utils
4
+ from ryry import ryry_service
5
+ from ryry import ryry_widget
6
+ from ryry import store
7
+ from ryry import utils
8
+ from ryry import taskUtils
9
+
10
+ ll = 25
11
+ def scr_str(s):
12
+ return "| " + s + " |"
13
+ def scr_str1(s):
14
+ return "| " + s
15
+ def scr_line(s):
16
+ return "|" + s + "|"
17
+
18
+ def service_status(stdscr, idx):
19
+ def real_stdsrc(*args):
20
+ if platform.system() == 'Windows':
21
+ print(args[2])
22
+ else:
23
+ stdscr.addstr(*args)
24
+ if platform.system() != 'Windows':
25
+ real_stdsrc(idx, 0, scr_str("test".ljust(ll)))
26
+ real_stdsrc(idx, ll*1-1, scr_str("us".ljust(ll)))
27
+ real_stdsrc(idx, ll*2-2, scr_str("sg".ljust(ll)))
28
+ idx+=1
29
+ def running_task_uuids():
30
+ lst = []
31
+ if os.path.exists(taskUtils.task_config_file):
32
+ with open(taskUtils.task_config_file, 'r') as f:
33
+ data = json.load(f)
34
+ infos = ""
35
+ for it in data:
36
+ if it not in ["last_task_pts"]:
37
+ lst.append(it)
38
+ return lst
39
+ lst = running_task_uuids()
40
+ for d in range(0, max([len(lst)])):
41
+ def widget_stdscr(this_d, this_lst, row_idx, col_idx, append_str):
42
+ if this_d < len(this_lst):
43
+ real_s = this_lst[this_d]
44
+ if len(append_str) > 0:
45
+ real_s += f" [{append_str}]"
46
+ real_stdsrc(row_idx, col_idx, scr_str(" " + real_s.ljust(ll-1)))
47
+ else:
48
+ real_stdsrc(row_idx, col_idx, scr_str(" " + " ".ljust(ll-1)))
49
+ widget_stdscr(d, lst, idx, 0, "task" if platform.system() == 'Windows' else "")
50
+ idx+=1
51
+ return idx
52
+
53
+ def device_status(stdscr, idx):
54
+ def real_stdsrc(*args):
55
+ if platform.system() == 'Windows':
56
+ print(args[2])
57
+ else:
58
+ stdscr.addstr(*args)
59
+ import psutil
60
+ import GPUtil
61
+ cpu_load = psutil.cpu_percent(interval=1)
62
+ mem = psutil.virtual_memory()
63
+ mem_load = mem.percent
64
+ gpu_list = GPUtil.getGPUs()
65
+ if len(gpu_list) > 0:
66
+ gpu_load = gpu_list[0].load * 100 # 只考虑第一块显卡
67
+ else:
68
+ gpu_load = 0
69
+ real_stdsrc(idx, 0, scr_str(f"Device Usage | CPU : {cpu_load}% | Memory : {mem_load}% | GPU : {gpu_load}%".ljust(ll*3-2)))
70
+ idx+=1
71
+ return idx
72
+
73
+ def widget_status(stdscr, idx):
74
+ def real_stdsrc(*args):
75
+ if platform.system() == 'Windows':
76
+ print(args[2])
77
+ else:
78
+ stdscr.addstr(*args)
79
+ real_stdsrc(idx, 0, scr_str("Widget List".ljust(ll*3-2)))
80
+ idx+=1
81
+ widget_map = store.widgetMap()
82
+ if len(widget_map) == 0:
83
+ real_stdsrc(idx, 0, scr_str("empty".ljust(ll*3-2)))
84
+ idx+=1
85
+ return idx
86
+ maxJust = 10
87
+ for it in widget_map:
88
+ if len(it) > maxJust:
89
+ maxJust = len(it)
90
+ maxJust += 5
91
+ for it in widget_map:
92
+ path = ""
93
+ is_block = False
94
+ if isinstance(widget_map[it], (dict)):
95
+ path = widget_map[it]["path"]
96
+ is_block = widget_map[it]["isBlock"]
97
+ else:
98
+ path = map[it]
99
+ end_args = ""
100
+ if is_block:
101
+ end_args = " [X]"
102
+ real_stdsrc(idx, 0, scr_str(f'{f"{it}{end_args}".ljust(maxJust)} {path}'.ljust(ll*3-2)))
103
+ idx+=1
104
+ return idx
105
+
106
+ def status():
107
+ from pkg_resources import parse_version, get_distribution
108
+ ver = get_distribution("ryry-cli").version
109
+ deviceid = utils.generate_unique_id()
110
+ import socket
111
+ machine_name = socket.gethostname()
112
+ service = ryry_service.ryryService()
113
+ thread_num = store.get_multithread()
114
+
115
+ if platform.system() == 'Windows':
116
+ service_is_running = service.is_running()
117
+ print(scr_line("-" * ll*3))
118
+ print(scr_str(f"ryry".ljust(ll*3-2)))
119
+ print(scr_str(f"版本: {ver}".ljust(ll*3-4)))
120
+ print(scr_str(f"设备号: {deviceid}".ljust(ll*3-5)))
121
+ print(scr_str(f"容器HostName: {machine_name}".ljust(ll*3-4)))
122
+ print(scr_line("-" * ll*3))
123
+ if service_is_running:
124
+ print(scr_str1(f"运行中 ({thread_num} 线程)".ljust(ll*3-2)))
125
+ else:
126
+ print(scr_str1("未运行".ljust(ll*3-2)))
127
+ print(scr_line("-" * ll*3))
128
+ service_status(None, 0)
129
+ print(scr_line("-" * ll*3))
130
+ device_status(None, 0)
131
+ print(scr_line("-" * ll*3))
132
+ widget_status(None, 0)
133
+ print(scr_line("-" * ll*3))
134
+ else:
135
+ import curses
136
+ stdscr = curses.initscr()
137
+ curses.noecho()
138
+ curses.cbreak()
139
+ curses.start_color()
140
+ curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
141
+ curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
142
+ stdscr.keypad(True)
143
+ try:
144
+ tiktak = 0
145
+ while True:
146
+ stdscr.clear()
147
+ height, width = stdscr.getmaxyx()
148
+ service_is_running = service.is_running()
149
+ idx=0
150
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
151
+ idx+=1
152
+ stdscr.addstr(idx, 0, scr_str(f"ryry".ljust(ll*3-2)))
153
+ idx+=1
154
+ stdscr.addstr(idx, 0, scr_str(f"版本: {ver}".ljust(ll*3-4)))
155
+ idx+=1
156
+ stdscr.addstr(idx, 0, scr_str(f"设备号: {deviceid}".ljust(ll*3-5)))
157
+ idx+=1
158
+ stdscr.addstr(idx, 0, scr_str(f"容器HostName: {machine_name}".ljust(ll*3-4)))
159
+ idx+=1
160
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
161
+ idx+=1
162
+ if service_is_running:
163
+ if tiktak > 3:
164
+ tiktak = 0
165
+ stdscr.addstr(idx, 0, scr_str1("运行中"+"."*tiktak+f" ({thread_num} 线程)".ljust(ll*3-2)), curses.color_pair(1))
166
+ tiktak+=1
167
+ else:
168
+ stdscr.addstr(idx, 0, scr_str1("未运行".ljust(ll*3-2)), curses.color_pair(2))
169
+ idx+=1
170
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
171
+ idx+=1
172
+ idx = service_status(stdscr, idx)
173
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
174
+ idx+=1
175
+ idx = device_status(stdscr, idx)
176
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
177
+ idx+=1
178
+ idx = widget_status(stdscr, idx)
179
+ stdscr.addstr(idx, 0, scr_line("-" * ll*3))
180
+ stdscr.refresh()
181
+ time.sleep(1)
182
+ except:
183
+ pass
184
+ curses.nocbreak()
185
+ stdscr.keypad(False)
186
+ curses.echo()
187
+ curses.endwin()
188
+
189
+ def service():
190
+ if len(sys.argv) <= 2:
191
+ print('please set command!')
192
+ return
193
+
194
+ command = sys.argv[2]
195
+ service = ryry_service.ryryService()
196
+ if command == 'start':
197
+ if service.is_running():
198
+ print('Service is already running.')
199
+ else:
200
+ print(f'Starting service...[args = {" ".join(sys.argv)}]')
201
+ threadNum = 1
202
+ idx = 2
203
+ while idx < len(sys.argv):
204
+ if sys.argv[idx] == "-thread":
205
+ threadNum = int(sys.argv[idx+1])
206
+ if threadNum < 1 or threadNum > 500:
207
+ print('multi thread number must be 1~500')
208
+ return
209
+ idx+=1
210
+ service.start(threadNum)
211
+ elif command == 'stop':
212
+ if not service.is_running():
213
+ print('Service is not running.')
214
+ else:
215
+ print('Stopping service...')
216
+ service.stop()
217
+ elif command == 'status':
218
+ status()
219
+ else:
220
+ print("Unknown command:", command)
221
+
222
+ def widget():
223
+ if len(sys.argv) <= 2:
224
+ print('please set command! Usage: ryry widget [init|publish]')
225
+ return
226
+
227
+ command = sys.argv[2]
228
+ work_path = os.getcwd()
229
+ if len(sys.argv) > 3:
230
+ work_path = sys.argv[3]
231
+ if command == 'init':
232
+ ryry_widget.createWidget(work_path)
233
+ elif command == 'publish':
234
+ ryry_widget.publishWidget(work_path)
235
+ elif command == 'list':
236
+ map = store.widgetMap()
237
+ if len(map) == 0:
238
+ print("local widget is empty")
239
+ maxJust = 20
240
+ for it in map:
241
+ if len(it) > maxJust:
242
+ maxJust = len(it)
243
+ maxJust += 10
244
+ showStatus = ""
245
+ if len(sys.argv) > 3:
246
+ showStatus = sys.argv[3]
247
+ for it in map:
248
+ path = ""
249
+ is_block = False
250
+ if isinstance(map[it], (dict)):
251
+ path = map[it]["path"]
252
+ is_block = map[it]["isBlock"]
253
+ else:
254
+ path = map[it]
255
+ end_args = ""
256
+ if is_block:
257
+ end_args = " [X]"
258
+ ss = f"{it}{end_args}"
259
+ if showStatus in ["disable", "enable"]:
260
+ if is_block and showStatus == "disable":
261
+ print(f'{ss.ljust(maxJust + 4)} {path}')
262
+ elif is_block == False and showStatus == "enable":
263
+ print(f'{ss.ljust(maxJust + 4)} {path}')
264
+ else:
265
+ print(f'{ss.ljust(maxJust + 4)} {path}')
266
+ elif command == 'add':
267
+ ryry_widget.addWidgetToEnv(work_path)
268
+ elif command == 'remove':
269
+ ryry_widget.remove(work_path)
270
+ elif command == 'enable':
271
+ ryry_widget.enable(work_path)
272
+ elif command == 'disable':
273
+ ryry_widget.disable(work_path)
274
+ elif command == 'pending_task':
275
+ ryry_widget.getTaskCount(work_path)
276
+ else:
277
+ print("Unknown command:", command)
278
+
279
+ def main():
280
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
281
+
282
+ if len(sys.argv) >= 2:
283
+ module = sys.argv[1]
284
+ if module == "widget":
285
+ widget()
286
+ elif module == "service":
287
+ service()
288
+ elif module == "status":
289
+ status()
290
+ elif module == "report":
291
+ utils.reportLog()
292
+ print(f"report success")
293
+ else:
294
+ print(f"Unknown command:{module}")
295
+ sys.exit(0)
296
+ else:
297
+ status()
298
+
299
+ if __name__ == '__main__':
300
+ main()
@@ -0,0 +1,180 @@
1
+ import os, time, json
2
+ from urllib.parse import *
3
+ import threading
4
+ from datetime import datetime, timedelta
5
+ import calendar
6
+ from threading import Thread, current_thread, Lock
7
+ import websocket
8
+ import uuid
9
+ import queue
10
+ import subprocess, platform
11
+
12
+ from ryry import store
13
+ from ryry import ryry_webapi
14
+ from ryry import task
15
+ from ryry import constant
16
+ from ryry import utils
17
+ from ryry import taskUtils
18
+
19
+ thisFileDir = os.path.dirname(os.path.abspath(__file__))
20
+
21
+ class ryryTaskExecutorThread(Thread):
22
+ THEADING_LIST = []
23
+ max_counter = 1
24
+ cur_counter = 0
25
+ is_running = False
26
+ task_queue = None
27
+ ttt = 0
28
+
29
+ def appendTask(self, data, timeout, callback):
30
+ self.cur_counter+=1
31
+ self.task_queue.put([data, timeout, callback])
32
+ try:
33
+ taskUUID = data["taskUUID"]
34
+ taskUtils.taskPrint(taskUUID, f"{current_thread().name} === addQueue task : {taskUUID}")
35
+ except:
36
+ pass
37
+
38
+ def idlePower(self):
39
+ return self.max_counter - self.cur_counter
40
+
41
+ def isWorking(self):
42
+ return self.cur_counter > 0
43
+
44
+ def __init__(self):
45
+ threading.Thread.__init__(self)
46
+ self.name = f"ryryTaskExecutorThread"
47
+ self.task_queue = queue.Queue()
48
+ self.max_counter = store.get_multithread()
49
+ self.is_running = True
50
+ self.THEADING_LIST = []
51
+ self.start()
52
+
53
+ def taskRunning(self):
54
+ while self.is_running:
55
+ try:
56
+ data, timeout, callback = self.task_queue.get()
57
+ if data is None:
58
+ break
59
+ try:
60
+ taskUUID = data["taskUUID"]
61
+ taskUtils.taskPrint(taskUUID, f"{current_thread().name} === receive task : {taskUUID}")
62
+ _appendTask(taskUUID)
63
+ is_ok, msg, result = task.runTask(data, timeout)
64
+ if is_ok == False:
65
+ taskUtils.notifyTaskFail(taskUUID, msg)
66
+ self.cur_counter-=1
67
+ callback(taskUUID, is_ok, msg, result)
68
+ _removeTask(taskUUID)
69
+ except Exception as e:
70
+ taskUtils.taskPrint(taskUUID, f"{current_thread().name} === task exception : {e}")
71
+ taskUtils.notifyScriptError(taskUUID)
72
+ finally:
73
+ taskUtils.taskPrint(taskUUID, None)
74
+ self.task_queue.task_done()
75
+ except Exception as ex:
76
+ taskUtils.taskPrint(None, f"{current_thread().name} === exception : {ex}")
77
+ pass
78
+ print(f" {current_thread().name} taskRunning stop")
79
+
80
+ def run(self):
81
+ idx = 1
82
+ for _ in range(0, self.max_counter):
83
+ self.THEADING_LIST.append(Thread(name=f"exector-{idx}",target=self.taskRunning))
84
+ idx+=1
85
+ for t in self.THEADING_LIST:
86
+ t.start()
87
+ while self.is_running:
88
+ time.sleep(5)
89
+ for t in self.THEADING_LIST:
90
+ t.join()
91
+ print(f" {self.name} stop!")
92
+
93
+ def markStop(self):
94
+ self.is_running = False
95
+ print(f" {self.name} waiting stop")
96
+ for _ in range(self.max_counter*2):
97
+ self.task_queue.put([None, -1, None])
98
+ print(f" {self.name} stop")
99
+
100
+ lock = Lock()
101
+ task_config_file = os.path.join(thisFileDir, f"task_config.txt")
102
+ def _readTaskConfig():
103
+ if os.path.exists(task_config_file) == False:
104
+ with open(task_config_file, 'w') as f:
105
+ json.dump({
106
+ "last_task_pts": 0
107
+ }, f)
108
+ with open(task_config_file, 'r') as f:
109
+ data = json.load(f)
110
+ return data
111
+ def _saveTaskConfig(data):
112
+ with open(task_config_file, 'w') as f:
113
+ json.dump(data, f)
114
+ def _appendTask(taskUUID):
115
+ lock.acquire()
116
+ task_config = _readTaskConfig()
117
+ task_config[taskUUID] = {
118
+ "pts": calendar.timegm(time.gmtime())
119
+ }
120
+ task_config["last_task_pts"] = task_config[taskUUID]["pts"]
121
+ _saveTaskConfig(task_config)
122
+ lock.release()
123
+ def _clearTask():
124
+ lock.acquire()
125
+ task_config = {
126
+ "last_task_pts": 0
127
+ }
128
+ _saveTaskConfig(task_config)
129
+ lock.release()
130
+ def _removeTask(taskUUID):
131
+ lock.acquire()
132
+ task_config = _readTaskConfig()
133
+ if taskUUID in task_config:
134
+ del task_config[taskUUID]
135
+ _saveTaskConfig(task_config)
136
+ lock.release()
137
+ def _taskCreateTime(taskUUID):
138
+ pts = 0
139
+ lock.acquire()
140
+ task_config = _readTaskConfig()
141
+ if taskUUID in task_config:
142
+ pts = task_config[taskUUID]["pts"]
143
+ lock.release()
144
+ return pts
145
+ def _getTaskConfig():
146
+ lock.acquire()
147
+ task_config = _readTaskConfig()
148
+ lock.release()
149
+ return task_config
150
+
151
+ class ryryShortConnectThread(Thread):
152
+ is_running = False
153
+ executor: ryryTaskExecutorThread = None
154
+
155
+ def __init__(self, executor):
156
+ super().__init__()
157
+ self.name = f"ryryShortConnectThread"
158
+ self.is_running = True
159
+ self.executor = executor
160
+ self.start()
161
+
162
+ def taskCallback(self, taskUUID, is_ok, msg, result):
163
+ ryry_webapi.TaskNotify(taskUUID, is_ok, msg, result)
164
+
165
+ def run(self):
166
+ print(f" {self.name} start")
167
+ what_time = 10
168
+ while (self.is_running):
169
+ try:
170
+ datas, timeout = ryry_webapi.GetTask()
171
+ for it in datas:
172
+ self.executor.appendTask(it, timeout, self.taskCallback)
173
+ except Exception as ex:
174
+ taskUtils.taskPrint(None, f"{self.name} === exception : {ex}")
175
+ time.sleep(what_time)
176
+ print(f" {self.name} stop")
177
+
178
+ def markStop(self):
179
+ print(f" {self.name} waiting stop")
180
+ self.is_running = False