ryry-cli 4.12__tar.gz → 4.13__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.
Files changed (31) hide show
  1. {ryry_cli-4.12/ryry_cli.egg-info → ryry_cli-4.13}/PKG-INFO +1 -1
  2. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/constant.py +2 -2
  3. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/daemon_base.py +33 -1
  4. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/daemon_manager.py +52 -1
  5. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/main.py +10 -7
  6. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/ryry_service.py +3 -1
  7. {ryry_cli-4.12 → ryry_cli-4.13/ryry_cli.egg-info}/PKG-INFO +1 -1
  8. {ryry_cli-4.12 → ryry_cli-4.13}/setup.py +1 -1
  9. {ryry_cli-4.12 → ryry_cli-4.13}/LICENSE +0 -0
  10. {ryry_cli-4.12 → ryry_cli-4.13}/README.md +0 -0
  11. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/__init__.py +0 -0
  12. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/ryry_server_socket.py +0 -0
  13. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/ryry_webapi.py +0 -0
  14. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/ryry_widget.py +0 -0
  15. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/script_template/__init__.py +0 -0
  16. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/script_template/daemon.py +0 -0
  17. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/script_template/main.py +0 -0
  18. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/script_template/run.py +0 -0
  19. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/server_func.py +0 -0
  20. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/shared_memory.py +0 -0
  21. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/store.py +0 -0
  22. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/task.py +0 -0
  23. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/taskUtils.py +0 -0
  24. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/upload.py +0 -0
  25. {ryry_cli-4.12 → ryry_cli-4.13}/ryry/utils.py +0 -0
  26. {ryry_cli-4.12 → ryry_cli-4.13}/ryry_cli.egg-info/SOURCES.txt +0 -0
  27. {ryry_cli-4.12 → ryry_cli-4.13}/ryry_cli.egg-info/dependency_links.txt +0 -0
  28. {ryry_cli-4.12 → ryry_cli-4.13}/ryry_cli.egg-info/entry_points.txt +0 -0
  29. {ryry_cli-4.12 → ryry_cli-4.13}/ryry_cli.egg-info/requires.txt +0 -0
  30. {ryry_cli-4.12 → ryry_cli-4.13}/ryry_cli.egg-info/top_level.txt +0 -0
  31. {ryry_cli-4.12 → ryry_cli-4.13}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ryry-cli
3
- Version: 4.12
3
+ Version: 4.13
4
4
  Summary: ryry tools
5
5
  Home-page: https://github.com/dalipenMedia
6
6
  Author: dalipen
@@ -1,6 +1,6 @@
1
1
  #!!!!! do not change this file !!!!!
2
- app_version="4.12"
3
- app_bulld_anchor="Noh_2025-07-21 15:09:23.991341"
2
+ app_version="4.13"
3
+ app_bulld_anchor="Noh_2025-07-22 11:57:25.792576"
4
4
  app_name="ryry-cli"
5
5
  import sys, os
6
6
  if getattr(sys, 'frozen', False):
@@ -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
- running = daemon_info.get("running", False) and self._is_process_alive(daemon_info.get("pid", 0))
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
- end_args += "[D]" # 运行中且接受任务
115
+ color_pair = 1
116
+ end_args += "[后台运行中+接受任务]" # 运行中且接受任务
115
117
  else:
116
- end_args += "[D-]" # 运行中但不接受任务
118
+ color_pair = 1
119
+ end_args += "[后台运行中]" # 运行中但不接受任务
117
120
  elif daemon_manager and daemon_manager.should_start_daemon(it):
118
- end_args += "[d]" # 应该启动但未运行
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 += " [D]"
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():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ryry-cli
3
- Version: 4.12
3
+ Version: 4.13
4
4
  Summary: ryry tools
5
5
  Home-page: https://github.com/dalipenMedia
6
6
  Author: dalipen
@@ -3,7 +3,7 @@ import os
3
3
  import subprocess
4
4
  import datetime
5
5
 
6
- ryry_version = "4.12"
6
+ ryry_version = "4.13"
7
7
  cur_dir = os.path.dirname(os.path.abspath(__file__))
8
8
  constanspy = os.path.join(cur_dir, "ryry", "constant.py")
9
9
  try:
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