ryry-cli 4.12__tar.gz → 4.14__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-4.12/ryry_cli.egg-info → ryry_cli-4.14}/PKG-INFO +1 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/constant.py +2 -2
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/daemon_base.py +33 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/daemon_manager.py +52 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/main.py +10 -7
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/ryry_service.py +3 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/store.py +3 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/upload.py +7 -7
- {ryry_cli-4.12 → ryry_cli-4.14/ryry_cli.egg-info}/PKG-INFO +1 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/setup.py +1 -1
- {ryry_cli-4.12 → ryry_cli-4.14}/LICENSE +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/README.md +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/__init__.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/ryry_server_socket.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/ryry_webapi.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/ryry_widget.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/script_template/__init__.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/script_template/daemon.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/script_template/main.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/script_template/run.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/server_func.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/shared_memory.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/task.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/taskUtils.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry/utils.py +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry_cli.egg-info/SOURCES.txt +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry_cli.egg-info/dependency_links.txt +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry_cli.egg-info/entry_points.txt +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry_cli.egg-info/requires.txt +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/ryry_cli.egg-info/top_level.txt +0 -0
- {ryry_cli-4.12 → ryry_cli-4.14}/setup.cfg +0 -0
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
import json
|
|
4
4
|
import time
|
|
5
5
|
import signal
|
|
6
|
+
import threading
|
|
6
7
|
from typing import Optional, Dict, Any
|
|
7
8
|
|
|
8
9
|
class SimpleDaemonBase:
|
|
@@ -83,6 +84,13 @@ class SimpleDaemonBase:
|
|
|
83
84
|
"""
|
|
84
85
|
pass
|
|
85
86
|
|
|
87
|
+
def wait_for_tasks_completion(self, timeout: int = 30) -> bool:
|
|
88
|
+
"""
|
|
89
|
+
等待任务完成的方法 - 子类可选实现
|
|
90
|
+
返回True表示所有任务已完成,False表示超时
|
|
91
|
+
"""
|
|
92
|
+
return True
|
|
93
|
+
|
|
86
94
|
# ==================== 通信方法 ====================
|
|
87
95
|
|
|
88
96
|
def send_ready_signal(self):
|
|
@@ -94,6 +102,19 @@ class SimpleDaemonBase:
|
|
|
94
102
|
except Exception as e:
|
|
95
103
|
print(f"发送就绪信号失败: {e}", file=sys.stderr)
|
|
96
104
|
|
|
105
|
+
def send_stop_signal(self):
|
|
106
|
+
"""发送停止信号"""
|
|
107
|
+
try:
|
|
108
|
+
stop_file = os.path.join(self.base_path, f"daemon_stopped_{self.widget_id}.json")
|
|
109
|
+
with open(stop_file, 'w', encoding='utf-8') as f:
|
|
110
|
+
json.dump({
|
|
111
|
+
"widget_id": self.widget_id,
|
|
112
|
+
"stopped_at": time.time(),
|
|
113
|
+
"pid": os.getpid()
|
|
114
|
+
}, f)
|
|
115
|
+
except Exception as e:
|
|
116
|
+
print(f"发送停止信号失败: {e}", file=sys.stderr)
|
|
117
|
+
|
|
97
118
|
def process_command(self):
|
|
98
119
|
"""处理命令文件"""
|
|
99
120
|
cmd_file = os.path.join(self.base_path, f"daemon_cmd_{self.widget_id}.json")
|
|
@@ -182,7 +203,7 @@ class SimpleDaemonBase:
|
|
|
182
203
|
"""
|
|
183
204
|
return {
|
|
184
205
|
"healthy": True,
|
|
185
|
-
"state": "running",
|
|
206
|
+
"state": "running" if self.running else "stopped",
|
|
186
207
|
"accept_tasks": False,
|
|
187
208
|
"timestamp": time.time()
|
|
188
209
|
}
|
|
@@ -206,8 +227,10 @@ class SimpleDaemonBase:
|
|
|
206
227
|
try:
|
|
207
228
|
# 处理命令
|
|
208
229
|
self.process_command()
|
|
230
|
+
|
|
209
231
|
# 执行循环函数
|
|
210
232
|
self.loop_function()
|
|
233
|
+
|
|
211
234
|
time.sleep(1)
|
|
212
235
|
except KeyboardInterrupt:
|
|
213
236
|
print(f"【{self.widget_name}】收到KeyboardInterrupt", file=sys.stderr)
|
|
@@ -215,10 +238,19 @@ class SimpleDaemonBase:
|
|
|
215
238
|
except Exception as e:
|
|
216
239
|
print(f"主循环异常: {e}", file=sys.stderr)
|
|
217
240
|
time.sleep(5) # 异常后等待5秒再继续
|
|
241
|
+
|
|
242
|
+
# 等待任务完成
|
|
243
|
+
print(f"【{self.widget_name}】等待任务完成...", file=sys.stderr)
|
|
244
|
+
tasks_completed = self.wait_for_tasks_completion(timeout=60)
|
|
245
|
+
if not tasks_completed:
|
|
246
|
+
print(f"【{self.widget_name}】任务等待超时,强制停止", file=sys.stderr)
|
|
247
|
+
|
|
218
248
|
# 清理
|
|
219
249
|
self.on_stop()
|
|
220
250
|
|
|
221
251
|
except Exception as e:
|
|
222
252
|
print(f"运行异常: {e}", file=sys.stderr)
|
|
223
253
|
finally:
|
|
254
|
+
# 发送停止信号
|
|
255
|
+
self.send_stop_signal()
|
|
224
256
|
print(f"【{self.widget_name}】进程终止", file=sys.stderr)
|
|
@@ -316,7 +316,22 @@ class DaemonManager:
|
|
|
316
316
|
if not daemon_info:
|
|
317
317
|
return {"running": False, "ready": False, "accept_tasks": False}
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
pid = daemon_info.get("pid", 0)
|
|
320
|
+
running = daemon_info.get("running", False) and self._is_process_alive(pid)
|
|
321
|
+
|
|
322
|
+
# 如果进程还活着,检查是否有停止信号文件
|
|
323
|
+
if running:
|
|
324
|
+
stop_file = os.path.join(constant.base_path, f"daemon_stopped_{widget_id}.json")
|
|
325
|
+
if os.path.exists(stop_file):
|
|
326
|
+
try:
|
|
327
|
+
with open(stop_file, 'r', encoding='utf-8') as f:
|
|
328
|
+
stop_info = json.load(f)
|
|
329
|
+
os.remove(stop_file)
|
|
330
|
+
# 验证PID是否匹配
|
|
331
|
+
if stop_info.get("pid") == pid:
|
|
332
|
+
running = False
|
|
333
|
+
except:
|
|
334
|
+
pass
|
|
320
335
|
|
|
321
336
|
if not running and daemon_info.get("running", False):
|
|
322
337
|
# 清理无效进程
|
|
@@ -336,6 +351,9 @@ class DaemonManager:
|
|
|
336
351
|
|
|
337
352
|
def stop_all_daemons(self) -> bool:
|
|
338
353
|
"""停止所有常驻进程"""
|
|
354
|
+
# 首先清理已死亡的进程
|
|
355
|
+
self.sync_daemons_with_widget_map()
|
|
356
|
+
|
|
339
357
|
config = self._read_daemon_config()
|
|
340
358
|
widget_ids = list(config.keys())
|
|
341
359
|
|
|
@@ -350,6 +368,38 @@ class DaemonManager:
|
|
|
350
368
|
"""同步daemon状态与widgetMap,自动关闭不需要的daemon,启动需要的新daemon"""
|
|
351
369
|
config = self._read_daemon_config()
|
|
352
370
|
widget_map = store.widgetMap()
|
|
371
|
+
|
|
372
|
+
# 0. 首先检查所有已死亡的daemon进程并清理
|
|
373
|
+
dead_daemons = []
|
|
374
|
+
for widget_id, daemon_info in config.items():
|
|
375
|
+
if daemon_info.get("running", False):
|
|
376
|
+
pid = daemon_info.get("pid", 0)
|
|
377
|
+
# 检查进程是否还活着
|
|
378
|
+
if not self._is_process_alive(pid):
|
|
379
|
+
dead_daemons.append(widget_id)
|
|
380
|
+
else:
|
|
381
|
+
# 检查是否有停止信号文件
|
|
382
|
+
stop_file = os.path.join(constant.base_path, f"daemon_stopped_{widget_id}.json")
|
|
383
|
+
if os.path.exists(stop_file):
|
|
384
|
+
try:
|
|
385
|
+
with open(stop_file, 'r', encoding='utf-8') as f:
|
|
386
|
+
stop_info = json.load(f)
|
|
387
|
+
os.remove(stop_file)
|
|
388
|
+
# 验证PID是否匹配
|
|
389
|
+
if stop_info.get("pid") == pid:
|
|
390
|
+
dead_daemons.append(widget_id)
|
|
391
|
+
except:
|
|
392
|
+
pass
|
|
393
|
+
|
|
394
|
+
if dead_daemons:
|
|
395
|
+
with self.lock:
|
|
396
|
+
config = self._read_daemon_config()
|
|
397
|
+
for widget_id in dead_daemons:
|
|
398
|
+
if widget_id in config:
|
|
399
|
+
del config[widget_id]
|
|
400
|
+
taskUtils.taskPrint(None, f"清理已停止的daemon进程: {widget_id}")
|
|
401
|
+
self._write_daemon_config(config)
|
|
402
|
+
|
|
353
403
|
# 1. 关闭不需要的daemon(被移除、被屏蔽、版本不一致)
|
|
354
404
|
for widget_id in list(config.keys()):
|
|
355
405
|
daemon_info = config[widget_id]
|
|
@@ -370,6 +420,7 @@ class DaemonManager:
|
|
|
370
420
|
need_stop = True
|
|
371
421
|
if need_stop:
|
|
372
422
|
self.stop_daemon(widget_id)
|
|
423
|
+
|
|
373
424
|
# 2. 启动需要的daemon(未运行、或因上述原因被重启)
|
|
374
425
|
for widget_id, widget_info in widget_map.items():
|
|
375
426
|
is_block = widget_info.get("isBlock", False)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import sys, os, urllib3, time, platform, json
|
|
1
|
+
import sys, os, urllib3, time, platform, json, curses
|
|
2
2
|
|
|
3
3
|
from ryry import utils
|
|
4
4
|
from ryry import ryry_service
|
|
@@ -108,19 +108,23 @@ def widget_status(stdscr, idx):
|
|
|
108
108
|
end_args = "[X]"
|
|
109
109
|
|
|
110
110
|
# 检查daemon状态
|
|
111
|
+
color_pair = 0
|
|
111
112
|
daemon_status = daemon_statuses.get(it, {})
|
|
112
113
|
if daemon_status.get("running", False):
|
|
113
114
|
if daemon_status.get("accept_tasks", False):
|
|
114
|
-
|
|
115
|
+
color_pair = 1
|
|
116
|
+
end_args += "[后台运行中+接受任务]" # 运行中且接受任务
|
|
115
117
|
else:
|
|
116
|
-
|
|
118
|
+
color_pair = 1
|
|
119
|
+
end_args += "[后台运行中]" # 运行中但不接受任务
|
|
117
120
|
elif daemon_manager and daemon_manager.should_start_daemon(it):
|
|
118
|
-
|
|
121
|
+
color_pair = 2
|
|
122
|
+
end_args += "[后台未运行]" # 应该启动但未运行
|
|
119
123
|
|
|
120
124
|
max_task_number_str = ""
|
|
121
125
|
if max_task_number > 0:
|
|
122
126
|
max_task_number_str = f"*{max_task_number}"
|
|
123
|
-
real_stdsrc(idx, 0, scr_str(f'{f"[{name}{max_task_number_str} v{version}] {it}{end_args} OOT:{timeout}s".ljust(maxJust)}'.ljust(ll*3-2)))
|
|
127
|
+
real_stdsrc(idx, 0, scr_str(f'{f"[{name}{max_task_number_str} v{version}] {it}{end_args} OOT:{timeout}s".ljust(maxJust)}'.ljust(ll*3-2)), curses.color_pair(color_pair))
|
|
124
128
|
idx+=1
|
|
125
129
|
real_stdsrc(idx, 0, scr_str(f' PATH:{path}'.ljust(ll*3-2)))
|
|
126
130
|
idx+=1
|
|
@@ -179,7 +183,6 @@ def status():
|
|
|
179
183
|
widget_status(None, 0)
|
|
180
184
|
print(scr_line("-" * ll*3))
|
|
181
185
|
else:
|
|
182
|
-
import curses
|
|
183
186
|
stdscr = curses.initscr()
|
|
184
187
|
curses.noecho()
|
|
185
188
|
curses.cbreak()
|
|
@@ -323,7 +326,7 @@ def widget():
|
|
|
323
326
|
if is_block:
|
|
324
327
|
end_args = " [X]"
|
|
325
328
|
if daemon_enabled:
|
|
326
|
-
end_args += " [
|
|
329
|
+
end_args += " [支持后台运行]"
|
|
327
330
|
ss = f"{it}{end_args}"
|
|
328
331
|
if showStatus in ["disable", "enable"]:
|
|
329
332
|
if is_block and showStatus == "disable":
|
|
@@ -67,6 +67,7 @@ class ryryService:
|
|
|
67
67
|
with open(pid_file, 'w', encoding='utf-8') as f:
|
|
68
68
|
f.write(str(os.getpid()))
|
|
69
69
|
signal.signal(signal.SIGTERM, self.stop)
|
|
70
|
+
# signal.signal(signal.SIGINT, self.stop)
|
|
70
71
|
store.save_multithread(threadNum)
|
|
71
72
|
store.writeDeviceInfo(utils.deviceInfo())
|
|
72
73
|
TaskConnector._clearTask()
|
|
@@ -80,6 +81,7 @@ class ryryService:
|
|
|
80
81
|
|
|
81
82
|
#3: service step
|
|
82
83
|
while (os.path.exists(stop_file) == False):
|
|
84
|
+
print("~~~~~~~~")
|
|
83
85
|
time.sleep(5)
|
|
84
86
|
print("Prepare stop")
|
|
85
87
|
|
|
@@ -133,6 +135,7 @@ class ryryDaemonThread(Thread):
|
|
|
133
135
|
self.start()
|
|
134
136
|
|
|
135
137
|
def run(self):
|
|
138
|
+
#延迟启动
|
|
136
139
|
print(f" {self.name} start")
|
|
137
140
|
daemon_manager.start_all_daemons()
|
|
138
141
|
|
|
@@ -142,7 +145,6 @@ class ryryDaemonThread(Thread):
|
|
|
142
145
|
daemon_manager.sync_daemons_with_widget_map()
|
|
143
146
|
except:
|
|
144
147
|
time.sleep(60)
|
|
145
|
-
|
|
146
148
|
try:
|
|
147
149
|
print("Stopping daemon processes...")
|
|
148
150
|
if daemon_manager.stop_all_daemons():
|
|
@@ -155,11 +155,14 @@ def extend():
|
|
|
155
155
|
_genExtend()
|
|
156
156
|
elif read_data["extend"].get("device_id", "") != read_data.get("deviceInfo", {}).get("device_id", ""):
|
|
157
157
|
_genExtend()
|
|
158
|
+
elif read_data["extend"].get("app", "") == "ryry-cli 4.14":
|
|
159
|
+
_genExtend()
|
|
158
160
|
else:
|
|
159
161
|
_genExtend()
|
|
160
162
|
return GLOBAL_EXT_JSON
|
|
161
163
|
|
|
162
164
|
def _genExtend():
|
|
165
|
+
print("asdasdas _genExtend ")
|
|
163
166
|
sp = Store()
|
|
164
167
|
read_data = sp.read()
|
|
165
168
|
if "deviceInfo" in read_data:
|
|
@@ -191,7 +191,7 @@ def deepFtpUpload(file, new_file_name, ftp, writepath, readpath):
|
|
|
191
191
|
|
|
192
192
|
with open(file, 'rb') as f:
|
|
193
193
|
ftp.storbinary(f'STOR {new_file_name}', f)
|
|
194
|
-
return f"{readpath}/{new_file_name}"
|
|
194
|
+
return f"{readpath}/{writepath}/{new_file_name}"
|
|
195
195
|
|
|
196
196
|
def ftpUpload(file, new_file_name, subdomain, upload_path=""):
|
|
197
197
|
ip = subdomain["host"]
|
|
@@ -214,7 +214,7 @@ def ftpUpload(file, new_file_name, subdomain, upload_path=""):
|
|
|
214
214
|
if upload_path:
|
|
215
215
|
if upload_path[0:1] == "/":
|
|
216
216
|
upload_path = upload_path[1:]
|
|
217
|
-
s = deepFtpUpload(file, new_file_name, ftp, upload_path, f'ftp://{ip}/
|
|
217
|
+
s = deepFtpUpload(file, new_file_name, ftp, upload_path, f'ftp://{ip}/mnt/NAS/mcn')
|
|
218
218
|
else:
|
|
219
219
|
s = deepFtpUpload(file, new_file_name, ftp, writepath, readpath)
|
|
220
220
|
|
|
@@ -228,7 +228,7 @@ def ftpUpload(file, new_file_name, subdomain, upload_path=""):
|
|
|
228
228
|
if upload_path:
|
|
229
229
|
if upload_path[0:1] == "/":
|
|
230
230
|
upload_path = upload_path[1:]
|
|
231
|
-
s = deepFtpUpload(file, new_file_name, ftp, upload_path, f'ftp://{ip}/
|
|
231
|
+
s = deepFtpUpload(file, new_file_name, ftp, upload_path, f'ftp://{ip}/mnt/NAS/mcn')
|
|
232
232
|
else:
|
|
233
233
|
s = deepFtpUpload(file, new_file_name, ftp, writepath, readpath)
|
|
234
234
|
|
|
@@ -263,16 +263,16 @@ ftp_192_168_50_12={
|
|
|
263
263
|
"port": 21,
|
|
264
264
|
"username" : "mcn",
|
|
265
265
|
"password" : "meco@2024+",
|
|
266
|
-
"writepath" : "
|
|
267
|
-
"readpath" : "ftp://192.168.50.12/mnt/NAS/mcn
|
|
266
|
+
"writepath" : "cache",
|
|
267
|
+
"readpath" : "ftp://192.168.50.12/mnt/NAS/mcn"
|
|
268
268
|
}
|
|
269
269
|
ftp_183_6_90_205={
|
|
270
270
|
"host" : "183.6.90.205",
|
|
271
271
|
"port": 2221,
|
|
272
272
|
"username" : "mcn",
|
|
273
273
|
"password" : "meco@2024+",
|
|
274
|
-
"writepath" : "
|
|
275
|
-
"readpath" : "ftp://183.6.90.205/mnt/NAS/mcn
|
|
274
|
+
"writepath" : "cache",
|
|
275
|
+
"readpath" : "ftp://183.6.90.205/mnt/NAS/mcn"
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
from ryry import utils
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|