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/ryry_service.py ADDED
@@ -0,0 +1,220 @@
1
+ import sys, os, time, signal, subprocess, logging, json, platform, socket, calendar
2
+ from logging.handlers import RotatingFileHandler
3
+ from urllib.parse import *
4
+ from datetime import datetime, timedelta
5
+ from threading import Thread
6
+ from pkg_resources import get_distribution
7
+
8
+ from ryry import store
9
+ from ryry import ryry_webapi
10
+ from ryry import utils
11
+ from ryry import taskUtils
12
+ from ryry import ryry_widget
13
+ from ryry import ryry_server_socket as TaskConnector
14
+
15
+ thisFileDir = os.path.dirname(os.path.abspath(__file__))
16
+ pid_file = os.path.join(thisFileDir, "ryryService.pid")
17
+ stop_file = os.path.join(thisFileDir, "stop.now")
18
+ stop_thread_file = os.path.join(thisFileDir, "stop.thread")
19
+ all_thread_stoped = os.path.join(thisFileDir, "all_stoped.now")
20
+ def notify_other_stoped():
21
+ with open(all_thread_stoped, 'w') as f:
22
+ f.write("")
23
+
24
+ class LogStdout(object):
25
+ def __init__(self):
26
+ self.stdout = sys.stdout
27
+ self.logger = logging.getLogger(__name__)
28
+ self.logger.setLevel(logging.INFO)
29
+
30
+ logFilePath = f"{os.path.dirname(os.path.abspath(__file__))}/log.log"
31
+ file_handler = RotatingFileHandler(logFilePath, maxBytes=1024*1024*20, backupCount=30)
32
+ file_handler.setLevel(logging.INFO)
33
+ formatter = logging.Formatter(fmt='%(asctime)s - %(message)s',
34
+ datefmt='%Y-%m-%d %H:%M:%S')
35
+ file_handler.setFormatter(formatter)
36
+ self.logger.addHandler(file_handler)
37
+
38
+ def write(self, message):
39
+ if message != '\n':
40
+ self.logger.info(message)
41
+ self.stdout.write(message)
42
+
43
+ def flush(self):
44
+ self.stdout.flush()
45
+
46
+ def __del__(self):
47
+ self.close()
48
+
49
+ def close(self):
50
+ sys.stdout = self.stdout
51
+
52
+ class ryryService:
53
+ def __init__(self):
54
+ self.THEADING_LIST = []
55
+
56
+ def start(self, threadNum=1):
57
+ if os.path.exists(pid_file):
58
+ #check pre process is finish successed!
59
+ with open(pid_file, 'r') as f:
60
+ pre_pid = str(f.read())
61
+ if len(pre_pid) > 0:
62
+ if utils.process_is_zombie_but_cannot_kill(int(pre_pid)):
63
+ print(f'start service fail! pre process {pre_pid} is uninterruptible sleep')
64
+ taskUtils.notifyWechatRobot({
65
+ "msgtype": "text",
66
+ "text": {
67
+ "content": f"机器<{socket.gethostname()}>无法启动服务 进程<{pre_pid}>为 uninterruptible sleep"
68
+ }
69
+ })
70
+ return False
71
+ #1: service init
72
+ sys.stdout = LogStdout()
73
+ with open(pid_file, 'w') as f:
74
+ f.write(str(os.getpid()))
75
+ signal.signal(signal.SIGTERM, self.stop)
76
+ store.save_multithread(threadNum)
77
+ store.writeDeviceInfo(utils.deviceInfo())
78
+ TaskConnector._clearTask()
79
+ #2: service step
80
+ executor = TaskConnector.ryryTaskExecutorThread()
81
+ self.THEADING_LIST.append(executor)
82
+ for _ in range(0, threadNum):
83
+ self.THEADING_LIST.append(TaskConnector.ryryShortConnectThread(executor))
84
+ self.THEADING_LIST.append(ryryStateThread())
85
+ self.THEADING_LIST.append(ryryPackageThread())
86
+ #3: service step
87
+ while (os.path.exists(stop_file) == False):
88
+ time.sleep(10)
89
+ print("prepare stop")
90
+ with open(stop_thread_file, 'w') as f:
91
+ f.write("")
92
+ for t in self.THEADING_LIST:
93
+ t.markStop()
94
+ for t in self.THEADING_LIST:
95
+ t.join()
96
+ if pid_file and os.path.exists(pid_file):
97
+ os.remove(pid_file)
98
+ #4: clean
99
+ if os.path.exists(stop_thread_file):
100
+ os.remove(stop_thread_file)
101
+ if os.path.exists(stop_file):
102
+ os.remove(stop_file)
103
+ taskUtils.offlineNotify()
104
+ print("ryryService has ended!")
105
+ utils.check_restart()
106
+ sys.stdout.close()
107
+
108
+ def is_running(self):
109
+ if pid_file and os.path.exists(pid_file):
110
+ with open(pid_file, 'r', encoding='UTF-8') as f:
111
+ pid = int(f.read())
112
+ try:
113
+ if utils.process_is_alive(pid):
114
+ return True
115
+ else:
116
+ return False
117
+ except OSError:
118
+ return False
119
+ else:
120
+ return False
121
+
122
+ def stop(self, signum=None, frame=None):
123
+ with open(stop_file, 'w') as f:
124
+ f.write("")
125
+ print("ryryService waiting stop...")
126
+ taskUtils.restartNotify("手动")
127
+ while os.path.exists(stop_file):
128
+ time.sleep(1)
129
+ print("ryryService has ended!")
130
+
131
+ class ryryPackageThread(Thread):
132
+ def __init__(self):
133
+ super().__init__()
134
+ self.name = f"ryryPackageThread"
135
+ if platform.system() == 'Windows':
136
+ self.time_task_file = os.path.join(thisFileDir, "update_ryry.bat")
137
+ elif platform.system() == 'Linux' or platform.system() == 'Darwin':
138
+ self.time_task_file = os.path.join(thisFileDir, "update_ryry.sh")
139
+ if os.path.exists(self.time_task_file):
140
+ os.remove(self.time_task_file)
141
+ self.last_check_time = calendar.timegm(time.gmtime())
142
+ self.start()
143
+ def getCommandResult(self, cmd):
144
+ try:
145
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
146
+ if result.returncode == 0:
147
+ return result.stdout.decode(encoding="utf8", errors="ignore").replace("\n","").strip()
148
+ except subprocess.CalledProcessError as e:
149
+ print(f"getCommandResult fail {e}")
150
+ return ""
151
+ def run(self):
152
+ while (os.path.exists(stop_thread_file) == False):
153
+ time.sleep(10)
154
+ if calendar.timegm(time.gmtime()) - self.last_check_time > 300:
155
+ self.last_check_time = calendar.timegm(time.gmtime())
156
+ try:
157
+ #update widget
158
+ ryry_widget.UpdateWidgetFromPypi()
159
+ except Exception as ex:
160
+ print(f'update widget fail, {ex}')
161
+
162
+ try:
163
+ #update cli
164
+ remote_version = ryry_widget._remote_package_version("ryry-cli")
165
+ simple = "https://pypi.python.org/simple/"
166
+ local_version = ryry_widget._local_package_version("ryry-cli")
167
+ if ryry_widget.compare_versions(remote_version, local_version) > 0:
168
+ print("start update progress...")
169
+ utils.begin_restart("auto upgrade ryry-cli", True, simple)
170
+ device_id = utils.generate_unique_id()
171
+ machine_name = socket.gethostname()
172
+ ver = get_distribution("ryry-cli").version
173
+ taskUtils.notifyWechatRobot({
174
+ "msgtype": "text",
175
+ "text": {
176
+ "content": f"机器<{machine_name}[{device_id}]>[{ver}] ryry-cli开始升级[{local_version}]->[{remote_version}]"
177
+ }
178
+ })
179
+ break
180
+ except Exception as ex:
181
+ print(f'update ryry-cli fail, {ex}')
182
+ time.sleep(10)
183
+ print(f" PackageChecker stop")
184
+ notify_other_stoped() #because other thread is waiting some signal to close
185
+ def markStop(self):
186
+ print(f" PackageChecker waiting stop")
187
+
188
+ class ryryStateThread(Thread):
189
+ def __init__(self):
190
+ super().__init__()
191
+ self.name = f"ryryStateThread"
192
+ self.daemon = True
193
+ self.tik_time = 30.0
194
+ self.start()
195
+ def run(self):
196
+ taskUtils.onlineNotify()
197
+ while (os.path.exists(stop_thread_file) == False):
198
+ time.sleep(self.tik_time)
199
+ try:
200
+ task_config = TaskConnector._getTaskConfig()
201
+ if task_config["last_task_pts"] > 0:
202
+ cnt = (calendar.timegm(time.gmtime()) - task_config["last_task_pts"]) #second
203
+ if cnt >= (60*60) and cnt/(60*60)%1 <= self.tik_time/3600:
204
+ taskUtils.idlingNotify(cnt)
205
+ #clear trush
206
+ for root,dirs,files in os.walk(thisFileDir):
207
+ for file in files:
208
+ if file.find(".") <= 0:
209
+ continue
210
+ ext = file[file.rindex("."):]
211
+ if ext in [ ".in", ".out" ]:
212
+ os.remove(os.path.join(thisFileDir, file))
213
+ if root != files:
214
+ break
215
+ except:
216
+ time.sleep(60)
217
+ print(f" StateChecker stop")
218
+ def markStop(self):
219
+ print(f" StateChecker waiting stop")
220
+
ryry/ryry_webapi.py ADDED
@@ -0,0 +1,251 @@
1
+ import json, os
2
+ import datetime
3
+ import uuid, requests
4
+ import calendar, time
5
+
6
+ from ryry import store
7
+ from ryry import utils
8
+ from ryry import taskUtils
9
+ from ryry import constant
10
+
11
+ def _aigc_post(func, params, files={}, timeout=10):
12
+ s = requests.session()
13
+ try:
14
+ requests.adapters.DEFAULT_RETRIES = 2
15
+ s.keep_alive = False
16
+ s.headers.update({'Connection':'close'})
17
+ s.headers.update({'Usertoken':"0cce7cfe3629e16ee9b3ea8563305d3a15c524804da1861db07c2c867d79da63"})
18
+ if len(files) <= 0:
19
+ s.headers.update({'Content-Type':'application/json'})
20
+ res = s.post(url=f"https://api.dalipen.com/{func}", json=params, files=files, timeout=timeout, verify=False)
21
+ if res.status_code == 200:
22
+ result_data = json.loads(res.content)
23
+ res.close()
24
+ if result_data["code"] == 0:
25
+ return 0, "", result_data["data"]
26
+ else:
27
+ return result_data["code"], result_data["msg"], ""
28
+ else:
29
+ raise Exception(f'''request {func} status_code={res.status_code}''')
30
+ except Exception as e:
31
+ taskUtils.taskPrint(None, f'''=============== ryry {func} server error {datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')} ===============
32
+ url={func}
33
+
34
+ req=
35
+ {params}
36
+ exception={e}
37
+ ===============
38
+ ''')
39
+ return -1, str(e), ""
40
+ finally:
41
+ s.close()
42
+ return -1, "", ""
43
+
44
+ #======================================== Task Function ==============================
45
+ def _extend():
46
+ extInfo = store.readDeviceInfo()
47
+ extInfo["app_version"] = constant.app_version
48
+ extInfo["app_bulld_number"] = constant.app_bulld_number
49
+ extInfo["app_name"] = constant.app_name
50
+ extInfo["dts"] = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S_%f')
51
+ extInfo["trace_id"] = ''.join(str(uuid.uuid4()).split('-'))
52
+ extInfo["host_name"] = utils.get_hostname()
53
+ return json.dumps(extInfo)
54
+
55
+ def GetTask():
56
+ widget_map = ["TESTTEST"]
57
+ map = store.widgetMap()
58
+ for it in map:
59
+ if isinstance(map[it], (dict)):
60
+ if map[it]["isBlock"] == False:
61
+ widget_map.append(it)
62
+ else:
63
+ widget_map.append(it)
64
+ req = {
65
+ "widget_map": json.dumps(widget_map),
66
+ "limit": 1,
67
+ }
68
+ r1, r2, r3 = _aigc_post("aigc/task/getTask", req)
69
+ if r1 != 0:
70
+ return [], 10
71
+ datas = []
72
+ for it in r3:
73
+ datas.append({
74
+ "taskUUID": it["task_uuid"],
75
+ "config": it["config"],
76
+ "data": it["data"],
77
+ })
78
+ #Previous tasks may have failed due to network problems, so collect and resend
79
+ retryLastTaskNotify()
80
+ return datas, 600
81
+
82
+ TASK_NOTIFY_DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), f"task_notify_data.json")
83
+ def saveTaskNotifyData(taskUUID, status, msg, dataStr):
84
+ taskUtils.taskPrint(taskUUID, f"save {taskUUID} to next notify")
85
+ data = []
86
+ try:
87
+ if not os.path.exists(TASK_NOTIFY_DATA):
88
+ with open(TASK_NOTIFY_DATA, 'w') as f:
89
+ json.dump([], f)
90
+ with open(TASK_NOTIFY_DATA, 'r') as f:
91
+ data = json.load(f)
92
+ except:
93
+ pass
94
+ try:
95
+ data.append({
96
+ "taskUUID":taskUUID,
97
+ "status":status,
98
+ "msg":msg,
99
+ "dataStr":dataStr,
100
+ "pts": calendar.timegm(time.gmtime())
101
+ })
102
+ with open(TASK_NOTIFY_DATA, 'w') as f:
103
+ json.dump(data, f)
104
+ except:
105
+ pass
106
+ def resetLastTaskNotify(taskUUID):
107
+ data = []
108
+ try:
109
+ if os.path.exists(TASK_NOTIFY_DATA):
110
+ with open(TASK_NOTIFY_DATA, 'r') as f:
111
+ data = json.load(f)
112
+ except:
113
+ pass
114
+ try:
115
+ newData = []
116
+ for it in data:
117
+ if it["taskUUID"] != taskUUID:
118
+ newData.append(it)
119
+ with open(TASK_NOTIFY_DATA, 'w') as f:
120
+ json.dump(newData, f)
121
+ except:
122
+ pass
123
+ def retryLastTaskNotify():
124
+ data = []
125
+ try:
126
+ if os.path.exists(TASK_NOTIFY_DATA):
127
+ with open(TASK_NOTIFY_DATA, 'r') as f:
128
+ data = json.load(f)
129
+ except:
130
+ pass
131
+ try:
132
+ newData = []
133
+ for it in data:
134
+ msg = it["msg"]
135
+ fail_count = 0
136
+ if "fail_count" in it:
137
+ fail_count = it["fail_count"]
138
+ else:
139
+ it["fail_count"] = 0
140
+ pts = 0
141
+ if "pts" in it:
142
+ pts = it["pts"]
143
+ if abs(calendar.timegm(time.gmtime())-pts) < 10: #notify late after 10 sec
144
+ newData.append(it)
145
+ continue
146
+ if fail_count < 10:
147
+ if TaskNotify(it["taskUUID"], it["status"], f"{msg} *", it["dataStr"], False) == False:
148
+ it["fail_count"] += 1
149
+ newData.append(it)
150
+ with open(TASK_NOTIFY_DATA, 'w') as f:
151
+ json.dump(newData, f)
152
+ except:
153
+ pass
154
+ def TaskNotify(taskUUID, status, msg, dataStr, failSaveNotify=True):
155
+ req = {
156
+ "task_uuid": taskUUID,
157
+ "status": status,
158
+ "msg": msg,
159
+ "dataStr": dataStr
160
+ }
161
+ r1, r2, r3 = _aigc_post("aigc/task/taskNotify", req)
162
+ if r1 != 0:
163
+ if failSaveNotify:
164
+ #tasks may have failed due to network problems, so collect and resend
165
+ saveTaskNotifyData(taskUUID, status, msg, dataStr)
166
+ return False
167
+ return r3
168
+
169
+ retryLastTaskNotify()
170
+ def TaskUpdateProgress(taskUUID, progress, dataStr):
171
+ # req = aigc_ext_pb2.TaskUpdateReq()
172
+ # req.taskUUID = taskUUID
173
+ # req.progress = progress
174
+ # req.data = dataStr
175
+
176
+ # rsp = aigc_ext_pb2.TaskUpdateRes()
177
+ # r1, r2, r3 = _aigc_post(req, "TaskUpdate")
178
+ # if r1 != 0:
179
+ # return False
180
+ # rsp.ParseFromString(r3)
181
+ return True
182
+
183
+ def upload(localFilePath, ext):
184
+ with open(localFilePath, "rb") as f:
185
+ files = { 'file':f }
186
+ params = { 'ext':ext }
187
+ r1, r2, r3 = _aigc_post("upload/create", params, files=files,timeout=100)
188
+ if r1 != 0:
189
+ raise Exception(f"upload fail!, reason={r2}")
190
+ return r3
191
+
192
+ def uploadWidget(widget_id, name, whl, ext, version):
193
+ with open(whl, "rb") as f:
194
+ files = { 'file':f }
195
+ params = {
196
+ 'widget_id':widget_id,
197
+ 'name':name,
198
+ 'version':version,
199
+ 'ext':ext
200
+ }
201
+ r1, r2, r3 = _aigc_post("aigc/task/publishWidget", params, files=files, timeout=100)
202
+ if r1 != 0:
203
+ raise Exception(f"upload fail!, reason={r2}")
204
+ return r3
205
+
206
+ def CreateWidgetUUID():
207
+ req = {}
208
+ r1, r2, r3 = _aigc_post("aigc/task/createWidget", req)
209
+ if r1 != 0:
210
+ raise Exception(f"CreateWidgetUUID fail!, reason={r2}")
211
+ return r3
212
+
213
+ #======================================== Task Function ==============================
214
+ def createTask(widget_id, params):
215
+ req = {
216
+ "widget_id": widget_id,
217
+ "widget_data": json.dumps(params),
218
+ "extend": _extend()
219
+ }
220
+ r1, r2, r3 = _aigc_post("aigc/task/createTask", req)
221
+ if r1 != 0:
222
+ raise Exception(f"create task fail!, reason={r2}")
223
+ return r3
224
+
225
+ def findWidget(name):
226
+ req = {
227
+ "name": name
228
+ }
229
+ r1, r2, r3 = _aigc_post("aigc/task/findWidget", req)
230
+ if r1 != 0:
231
+ return 0
232
+ for it in r3:
233
+ widget_id = it["widget_id"]
234
+ widget_name = it["name"]
235
+ if widget_name.strip().lower() == name.strip().lower():
236
+ return widget_id
237
+ return 0
238
+
239
+ def checkTask(checkUUID):
240
+ req = {
241
+ "task_uuid": checkUUID
242
+ }
243
+ r1, r2, r3 = _aigc_post("aigc/task/checkTask", req)
244
+ if r1 != 0:
245
+ return False, False, "server fail"
246
+ if r3["status"] < 3:
247
+ return False, False, ""
248
+ elif r3["status"] == 3:
249
+ return True, True, json.loads(r3["task_result"])
250
+ elif r3["status"] == 4:
251
+ return True, False, r3["fail_reason"]