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/__init__.py +0 -0
- ryry/constant.py +5 -0
- ryry/main.py +300 -0
- ryry/ryry_server_socket.py +180 -0
- ryry/ryry_service.py +220 -0
- ryry/ryry_webapi.py +251 -0
- ryry/ryry_widget.py +398 -0
- ryry/script_template/__init__.py +0 -0
- ryry/script_template/main.py +25 -0
- ryry/script_template/run.py +22 -0
- ryry/server_func.py +74 -0
- ryry/store.py +161 -0
- ryry/task.py +203 -0
- ryry/taskUtils.py +283 -0
- ryry/upload.py +139 -0
- ryry/utils.py +358 -0
- ryry_cli-1.0.dist-info/LICENSE +7 -0
- ryry_cli-1.0.dist-info/METADATA +72 -0
- ryry_cli-1.0.dist-info/RECORD +22 -0
- ryry_cli-1.0.dist-info/WHEEL +5 -0
- ryry_cli-1.0.dist-info/entry_points.txt +2 -0
- ryry_cli-1.0.dist-info/top_level.txt +3 -0
ryry/task.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import os, time, calendar
|
|
2
|
+
import json
|
|
3
|
+
from urllib.parse import *
|
|
4
|
+
import sys
|
|
5
|
+
import signal
|
|
6
|
+
import subprocess, multiprocessing
|
|
7
|
+
from threading import Thread, current_thread, Lock
|
|
8
|
+
|
|
9
|
+
from ryry import ryry_webapi
|
|
10
|
+
from ryry import store
|
|
11
|
+
from ryry import taskUtils
|
|
12
|
+
from ryry import utils
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
def runTask(it, timeout):
|
|
16
|
+
start_time = calendar.timegm(time.gmtime())
|
|
17
|
+
taskUUID = it["taskUUID"]
|
|
18
|
+
config = json.loads(it["config"])
|
|
19
|
+
params = json.loads(it["data"])
|
|
20
|
+
widget_id = config["widget_id"]
|
|
21
|
+
#cmd
|
|
22
|
+
cmd = cmdWithWidget(widget_id)
|
|
23
|
+
#params
|
|
24
|
+
params["task_id"] = taskUUID
|
|
25
|
+
#run
|
|
26
|
+
taskUtils.taskPrint(taskUUID, f"{current_thread().name}=== start execute task : {taskUUID}")
|
|
27
|
+
executeSuccess, result_obj = executeLocalPython(taskUUID, cmd, params, timeout)
|
|
28
|
+
#result
|
|
29
|
+
is_ok = executeSuccess and result_obj["status"] == 0
|
|
30
|
+
msg = ""
|
|
31
|
+
if len(result_obj["message"]) > 0:
|
|
32
|
+
msg = str(result_obj["message"])
|
|
33
|
+
if is_ok:
|
|
34
|
+
checkResult(taskUUID, result_obj)
|
|
35
|
+
taskUtils.taskPrint(taskUUID, f"{current_thread().name}=== task {taskUUID} is_ok={is_ok} ")
|
|
36
|
+
taskUtils.saveCounter(taskUUID, (calendar.timegm(time.gmtime()) - start_time), is_ok)
|
|
37
|
+
return is_ok, msg, json.dumps(result_obj["result"], separators=(',', ':'))
|
|
38
|
+
|
|
39
|
+
def cmdWithWidget(widget_id):
|
|
40
|
+
map = store.widgetMap()
|
|
41
|
+
if widget_id in map:
|
|
42
|
+
path = ""
|
|
43
|
+
is_block = False
|
|
44
|
+
if isinstance(map[widget_id], (dict)):
|
|
45
|
+
is_block = map[widget_id]["isBlock"]
|
|
46
|
+
path = map[widget_id]["path"]
|
|
47
|
+
else:
|
|
48
|
+
is_block = False
|
|
49
|
+
path = map[widget_id]
|
|
50
|
+
if len(path) > 0 and is_block == False:
|
|
51
|
+
return path
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
def executeLocalPython(taskUUID, cmd, param, timeout):
|
|
55
|
+
inputArgs = os.path.join(os.path.dirname(os.path.abspath(__file__)), f"{taskUUID}.in")
|
|
56
|
+
if os.path.exists(inputArgs):
|
|
57
|
+
os.remove(inputArgs)
|
|
58
|
+
with open(inputArgs, 'w') as f:
|
|
59
|
+
json.dump(param, f)
|
|
60
|
+
outArgs = os.path.join(os.path.dirname(os.path.abspath(__file__)), f"{taskUUID}.out")
|
|
61
|
+
if os.path.exists(outArgs):
|
|
62
|
+
os.remove(outArgs)
|
|
63
|
+
|
|
64
|
+
outData = {
|
|
65
|
+
"result" : [
|
|
66
|
+
],
|
|
67
|
+
"status" : -1,
|
|
68
|
+
"message" : "script error"
|
|
69
|
+
}
|
|
70
|
+
executeSuccess = False
|
|
71
|
+
command = [sys.executable, cmd, "--run", inputArgs, "--out", outArgs]
|
|
72
|
+
taskUtils.taskPrint(taskUUID, f"{current_thread().name}=== exec => {command}")
|
|
73
|
+
process = None
|
|
74
|
+
try:
|
|
75
|
+
if timeout == 0:
|
|
76
|
+
timeout = 60*60 #max 1 hour expire time
|
|
77
|
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
78
|
+
timeout_killprocess(process, timeout)
|
|
79
|
+
output, error = process.communicate()
|
|
80
|
+
if process.returncode == 0:
|
|
81
|
+
taskUtils.taskPrint(taskUUID, output.decode(encoding="utf8", errors="ignore"))
|
|
82
|
+
if os.path.exists(outArgs) and os.stat(outArgs).st_size > 0:
|
|
83
|
+
try:
|
|
84
|
+
with open(outArgs, 'r', encoding='UTF-8') as f:
|
|
85
|
+
outData = json.load(f)
|
|
86
|
+
executeSuccess = True
|
|
87
|
+
taskUtils.taskPrint(taskUUID, f"[{taskUUID}]exec success result => {outData}")
|
|
88
|
+
except:
|
|
89
|
+
taskUtils.taskPrint(taskUUID, f"[{taskUUID}]task result format error, please check => {outData}")
|
|
90
|
+
else:
|
|
91
|
+
taskUtils.taskPrint(taskUUID, f"[{taskUUID}]task result is empty!, please check {cmd}")
|
|
92
|
+
else:
|
|
93
|
+
taskUtils.taskPrint(taskUUID, f"====================== script error [{taskUUID}]======================")
|
|
94
|
+
o1 = output.decode(encoding="utf8", errors="ignore")
|
|
95
|
+
o2 = error.decode(encoding="utf8", errors="ignore")
|
|
96
|
+
error_msg = f"{o1}\n{o2}"
|
|
97
|
+
short_error_msg = ""
|
|
98
|
+
if len(error_msg) > 310:
|
|
99
|
+
short_error_msg = f"{error_msg[0:99]}\n...\n{error_msg[len(error_msg)-200:]}"
|
|
100
|
+
else:
|
|
101
|
+
short_error_msg = error_msg
|
|
102
|
+
outData["message"] = short_error_msg
|
|
103
|
+
taskUtils.taskPrint(taskUUID, error_msg)
|
|
104
|
+
taskUtils.taskPrint(taskUUID, "====================== end ======================")
|
|
105
|
+
taskUtils.notifyScriptError(taskUUID)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
time.sleep(1)
|
|
108
|
+
taskUtils.taskPrint(taskUUID, f"====================== process error [{taskUUID}]======================")
|
|
109
|
+
taskUtils.taskPrint(taskUUID, e)
|
|
110
|
+
taskUtils.taskPrint(taskUUID, "====================== end ======================")
|
|
111
|
+
if process:
|
|
112
|
+
os.kill(process.pid, signal.SIGTERM)
|
|
113
|
+
if process.poll() is None:
|
|
114
|
+
os.kill(process.pid, signal.SIGKILL)
|
|
115
|
+
taskUtils.notifyScriptError(taskUUID)
|
|
116
|
+
outData["message"] = str(e)
|
|
117
|
+
finally:
|
|
118
|
+
if process and process.returncode is None:
|
|
119
|
+
try:
|
|
120
|
+
print("kill -9 " + str(process.pid))
|
|
121
|
+
os.system("kill -9 " + str(process.pid))
|
|
122
|
+
except ProcessLookupError:
|
|
123
|
+
pass
|
|
124
|
+
if os.path.exists(inputArgs):
|
|
125
|
+
os.remove(inputArgs)
|
|
126
|
+
if os.path.exists(outArgs):
|
|
127
|
+
os.remove(outArgs)
|
|
128
|
+
return executeSuccess, outData
|
|
129
|
+
|
|
130
|
+
def _needChangeValue(taskUUID, data, type, key):
|
|
131
|
+
if "type" not in data:
|
|
132
|
+
taskUtils.taskPrint(taskUUID, "result is not avalid")
|
|
133
|
+
return False
|
|
134
|
+
if data["type"] != type:
|
|
135
|
+
return False
|
|
136
|
+
if "extension" not in data or key not in data["extension"] or len(data["extension"][key]) == 0:
|
|
137
|
+
return True
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
def checkResult(taskUUID, data):
|
|
141
|
+
try:
|
|
142
|
+
for it in data["result"]:
|
|
143
|
+
if "extension" not in it:
|
|
144
|
+
continue
|
|
145
|
+
if _needChangeValue(taskUUID, it, "text", "cover_url"):
|
|
146
|
+
it["extension"]["cover_url"] = ""
|
|
147
|
+
if _needChangeValue(taskUUID, it, "audio", "cover_url"):
|
|
148
|
+
it["extension"]["cover_url"] = ""
|
|
149
|
+
if _needChangeValue(taskUUID, it, "image", "cover_url"):
|
|
150
|
+
it["extension"]["cover_url"] = ""
|
|
151
|
+
if _needChangeValue(taskUUID, it, "video", "cover_url"):
|
|
152
|
+
it["extension"]["cover_url"] = ""
|
|
153
|
+
|
|
154
|
+
if "cover_url" in it["extension"] and len(it["extension"]["cover_url"]) > 0:
|
|
155
|
+
cover_url = str(it["extension"]["cover_url"]).replace('\\u0026', '&')
|
|
156
|
+
parsed_url = urlparse(cover_url)
|
|
157
|
+
params = parse_qs(parsed_url.query)
|
|
158
|
+
#add width & height if need
|
|
159
|
+
if "width" not in params and "height" not in params:
|
|
160
|
+
w, h = utils.getOssImageSize(cover_url)
|
|
161
|
+
if w > 0 and h > 0:
|
|
162
|
+
params["width"] = w
|
|
163
|
+
params["height"] = h
|
|
164
|
+
it["extension"]["width"] = w
|
|
165
|
+
it["extension"]["height"] = h
|
|
166
|
+
#remove optional parameters
|
|
167
|
+
for k in ["Expires","OSSAccessKeyId","Signature","security-token"]:
|
|
168
|
+
params.pop(k, None)
|
|
169
|
+
if "width" in it["extension"]:
|
|
170
|
+
if isinstance(it["extension"]["width"], str):
|
|
171
|
+
it["extension"]["width"] = int(it["extension"]["width"])
|
|
172
|
+
if "height" in it["extension"]:
|
|
173
|
+
if isinstance(it["extension"]["height"], str):
|
|
174
|
+
it["extension"]["height"] = int(it["extension"]["height"])
|
|
175
|
+
updated_query_string = urlencode(params, doseq=True)
|
|
176
|
+
final_url = parsed_url._replace(query=updated_query_string).geturl()
|
|
177
|
+
it["extension"]["cover_url"] = final_url
|
|
178
|
+
except Exception as ex:
|
|
179
|
+
taskUtils.taskPrint(taskUUID, f"result: {data} status is not valid, exception is {ex} ")
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
def updateProgress(data, progress=0.5, taskUUID=None):
|
|
183
|
+
realTaskUUID = taskUUID
|
|
184
|
+
if realTaskUUID == None or len(realTaskUUID) <= 0:
|
|
185
|
+
realTaskUUID = taskUtils.taskInfoWithFirstTask()
|
|
186
|
+
|
|
187
|
+
if progress < 0:
|
|
188
|
+
progress = 0
|
|
189
|
+
if progress > 1:
|
|
190
|
+
progress = progress / 100.0
|
|
191
|
+
return ryry_webapi.TaskUpdateProgress(realTaskUUID, progress, json.dumps(data["result"]))
|
|
192
|
+
|
|
193
|
+
def timeout_killprocess(proc, timeout): # """超过指定的秒数后杀死进程"""
|
|
194
|
+
import threading
|
|
195
|
+
timer = threading.Timer(timeout, lambda p: p.kill(), [proc])
|
|
196
|
+
try:
|
|
197
|
+
timer.start()
|
|
198
|
+
proc.communicate()
|
|
199
|
+
except Exception as e:
|
|
200
|
+
print(e)
|
|
201
|
+
finally:
|
|
202
|
+
timer.cancel()
|
|
203
|
+
|
ryry/taskUtils.py
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import requests
|
|
3
|
+
import datetime
|
|
4
|
+
import json
|
|
5
|
+
import socket
|
|
6
|
+
from requests_toolbelt import MultipartEncoder
|
|
7
|
+
from urllib import parse
|
|
8
|
+
import base64
|
|
9
|
+
import hashlib
|
|
10
|
+
from ryry import utils
|
|
11
|
+
from pkg_resources import get_distribution
|
|
12
|
+
|
|
13
|
+
task_config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)) , f"task_config.txt")
|
|
14
|
+
def taskInfoWithFirstTask():
|
|
15
|
+
if os.path.exists(task_config_file):
|
|
16
|
+
with open(task_config_file, 'r') as f:
|
|
17
|
+
data = json.load(f)
|
|
18
|
+
for it in data:
|
|
19
|
+
if it not in ["last_task_pts"]:
|
|
20
|
+
return it
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
WECHAT_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=f40c5fb0-2734-48b0-a2d0-0faedf7dd2e4"
|
|
24
|
+
def uploadFile2Wechat(filepath):
|
|
25
|
+
real_robot_url = WECHAT_URL
|
|
26
|
+
params = parse.parse_qs( parse.urlparse( real_robot_url ).query )
|
|
27
|
+
webHookKey=params['key'][0]
|
|
28
|
+
upload_url = f'https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={webHookKey}&type=file'
|
|
29
|
+
headers = {"Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate",
|
|
30
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36"}
|
|
31
|
+
filename = os.path.basename(filepath)
|
|
32
|
+
try:
|
|
33
|
+
multipart = MultipartEncoder(
|
|
34
|
+
fields={'filename': filename, 'filelength': '', 'name': 'media', 'media': (filename, open(filepath, 'rb'), 'application/octet-stream')},
|
|
35
|
+
boundary='-------------------------acebdf13572468')
|
|
36
|
+
headers['Content-Type'] = multipart.content_type
|
|
37
|
+
resp = requests.post(upload_url, headers=headers, data=multipart, timeout=300)
|
|
38
|
+
json_res = resp.json()
|
|
39
|
+
if json_res.get('media_id'):
|
|
40
|
+
return json_res.get('media_id')
|
|
41
|
+
except Exception as e:
|
|
42
|
+
return ""
|
|
43
|
+
def notifyWechatRobot(param):
|
|
44
|
+
real_robot_url = WECHAT_URL
|
|
45
|
+
try:
|
|
46
|
+
s = requests.session()
|
|
47
|
+
s.headers.update({'Connection':'close'})
|
|
48
|
+
headers = dict()
|
|
49
|
+
headers['Content-Type'] = "application/json"
|
|
50
|
+
res = s.post(real_robot_url, json.dumps(param), headers=headers, verify=False, timeout=30)
|
|
51
|
+
s.close()
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f"===== qyapi.weixin.qq.com fail ", True)
|
|
54
|
+
|
|
55
|
+
logs = {}
|
|
56
|
+
def taskPrint(taskUUID, msg):
|
|
57
|
+
global logs
|
|
58
|
+
if (taskUUID == None or len(taskUUID) == 0) and msg == None:
|
|
59
|
+
return
|
|
60
|
+
if taskUUID and msg == None:
|
|
61
|
+
del logs[taskUUID]
|
|
62
|
+
return
|
|
63
|
+
if taskUUID and msg:
|
|
64
|
+
if taskUUID not in logs:
|
|
65
|
+
logs[taskUUID] = []
|
|
66
|
+
logs[taskUUID].append(msg)
|
|
67
|
+
if taskUUID == None and msg:
|
|
68
|
+
for uuid in logs:
|
|
69
|
+
logs[uuid].append(msg)
|
|
70
|
+
print(msg)
|
|
71
|
+
def getTaskLog(taskUUID):
|
|
72
|
+
if taskUUID in logs:
|
|
73
|
+
return logs[taskUUID]
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
def _uploadLog(taskUUID):
|
|
77
|
+
try:
|
|
78
|
+
log_path = f"{os.path.dirname(os.path.abspath(__file__))}/log_{taskUUID}.log"
|
|
79
|
+
with open(log_path, 'w') as f:
|
|
80
|
+
f.write("\n".join(getTaskLog(taskUUID)))
|
|
81
|
+
notifyWechatRobot({
|
|
82
|
+
"msgtype": "file",
|
|
83
|
+
"file": {
|
|
84
|
+
"media_id": uploadFile2Wechat(log_path)
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
if os.path.exists(log_path):
|
|
88
|
+
os.remove(log_path)
|
|
89
|
+
except:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
def notifyTaskFail(taskUUID, reason):
|
|
93
|
+
try:
|
|
94
|
+
real_reason = ""
|
|
95
|
+
if len(reason) > 610:
|
|
96
|
+
real_reason = f"{reason[0:300]}\n...\n{reason[len(reason)-300:]}"
|
|
97
|
+
else:
|
|
98
|
+
real_reason = reason
|
|
99
|
+
notifyWechatRobot({
|
|
100
|
+
"msgtype": "markdown",
|
|
101
|
+
"markdown": {
|
|
102
|
+
"content": f"机器<<font color=\"warning\">{socket.gethostname()}</font>> 执行任务<{taskUUID}>失败\n<{real_reason}>"
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
_uploadLog(taskUUID)
|
|
106
|
+
except:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
def notifyServerError(taskUUID):
|
|
110
|
+
try:
|
|
111
|
+
notifyWechatRobot({
|
|
112
|
+
"msgtype": "markdown",
|
|
113
|
+
"markdown": {
|
|
114
|
+
"content": f"机器<<font color=\"warning\">{socket.gethostname()}</font>> 执行任务<{taskUUID}>上报失败, retry..."
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
except:
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
def notifyScriptError(taskUUID):
|
|
121
|
+
try:
|
|
122
|
+
notifyWechatRobot({
|
|
123
|
+
"msgtype": "markdown",
|
|
124
|
+
"markdown": {
|
|
125
|
+
"content": f"机器<<font color=\"warning\">{socket.gethostname()}</font>> 执行任务<{taskUUID}>异常"
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
_uploadLog(taskUUID)
|
|
129
|
+
except:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
def idlingNotify(cnt):
|
|
133
|
+
device_id = utils.generate_unique_id()
|
|
134
|
+
machine_name = socket.gethostname()
|
|
135
|
+
hour = int(float(cnt)/(60.0*60.0))
|
|
136
|
+
if hour<72:
|
|
137
|
+
if hour not in [1, 2, 3, 10, 30, 50, 70]:
|
|
138
|
+
return
|
|
139
|
+
notifyWechatRobot({
|
|
140
|
+
"msgtype": "text",
|
|
141
|
+
"text": {
|
|
142
|
+
"content": f"机器<{machine_name}[{device_id}]> 空转{hour}小时"
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
def onlineNotify():
|
|
147
|
+
device_id = utils.generate_unique_id()
|
|
148
|
+
machine_name = socket.gethostname()
|
|
149
|
+
ver = get_distribution("ryry-cli").version
|
|
150
|
+
notifyWechatRobot({
|
|
151
|
+
"msgtype": "text",
|
|
152
|
+
"text": {
|
|
153
|
+
"content": f"机器<{machine_name}[{device_id}]>[{ver}] 上线"
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
def restartNotify(msg):
|
|
158
|
+
device_id = utils.generate_unique_id()
|
|
159
|
+
machine_name = socket.gethostname()
|
|
160
|
+
notifyWechatRobot({
|
|
161
|
+
"msgtype": "text",
|
|
162
|
+
"text": {
|
|
163
|
+
"content": f"机器<{machine_name}[{device_id}]> 即将下线,原因:{msg}"
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
def offlineNotify():
|
|
168
|
+
device_id = utils.generate_unique_id()
|
|
169
|
+
machine_name = socket.gethostname()
|
|
170
|
+
ver = get_distribution("ryry-cli").version
|
|
171
|
+
notifyWechatRobot({
|
|
172
|
+
"msgtype": "text",
|
|
173
|
+
"text": {
|
|
174
|
+
"content": f"机器<{machine_name}[{device_id}]> 下线"
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
#===================================================== counter ===============================================#
|
|
179
|
+
task_counter_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "task_counter.txt")
|
|
180
|
+
def notifyCounterIfNeed():
|
|
181
|
+
if os.path.exists(task_counter_file) == False:
|
|
182
|
+
return
|
|
183
|
+
with open(task_counter_file, 'r') as f:
|
|
184
|
+
data = json.load(f)
|
|
185
|
+
now_hour = datetime.datetime.now().hour
|
|
186
|
+
if now_hour == 0 and len(data) > 2:
|
|
187
|
+
yesterday = (datetime.datetime.now() + datetime.timedelta(days=-1)).strftime('%Y-%m-%d')
|
|
188
|
+
s_cnt = 0
|
|
189
|
+
f_cnt = 0
|
|
190
|
+
all_day_usage = 0
|
|
191
|
+
t_l = []
|
|
192
|
+
s_l = []
|
|
193
|
+
f_l = []
|
|
194
|
+
for i in range(0,24):
|
|
195
|
+
tips = ""
|
|
196
|
+
if str(i) in data:
|
|
197
|
+
s_cnt += data[str(i)]["success"]
|
|
198
|
+
f_cnt += data[str(i)]["fail"]
|
|
199
|
+
s_l.append(data[str(i)]["success"])
|
|
200
|
+
f_l.append(data[str(i)]["fail"])
|
|
201
|
+
if "usage" in data[str(i)]:
|
|
202
|
+
all_day_usage += data[str(i)]["usage"]
|
|
203
|
+
usage_percentage = int((float(data[str(i)]["usage"])/float(60*60))*100)
|
|
204
|
+
tips = f"({usage_percentage}%)"
|
|
205
|
+
else:
|
|
206
|
+
s_cnt += 0
|
|
207
|
+
f_cnt += 0
|
|
208
|
+
s_l.append(0)
|
|
209
|
+
f_l.append(0)
|
|
210
|
+
t_l.append(f"{i}{tips}")
|
|
211
|
+
usage_percentage = int((float(all_day_usage)/float(24*60*60))*100)
|
|
212
|
+
notifyWechatRobot({
|
|
213
|
+
"msgtype": "markdown",
|
|
214
|
+
"markdown": {
|
|
215
|
+
"content": f"机器<<font color=\"warning\">{socket.gethostname()}</font>> {yesterday} 日报 \n\n\
|
|
216
|
+
>过去24小时执行任务<<font color=\"warning\">{s_cnt+f_cnt}</font>>个, 负载<<font color=\"warning\">{usage_percentage}%</font>> \n\
|
|
217
|
+
>成功<font color=\"warning\">{s_cnt}</font>个 \n\
|
|
218
|
+
>失败<font color=\"warning\">{f_cnt}</font>个"
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
import matplotlib.pyplot as plt
|
|
224
|
+
plt.figure(figsize=(8,3))
|
|
225
|
+
plt.rcParams.update({
|
|
226
|
+
'font.size': 7
|
|
227
|
+
})
|
|
228
|
+
plt.bar(t_l, s_l, color='g', label='success')
|
|
229
|
+
plt.bar(t_l, f_l, bottom=s_l, color='r', label='fail')
|
|
230
|
+
plt.title(f'[{socket.gethostname()}] [{yesterday}] success/fail={s_cnt}/{f_cnt}')
|
|
231
|
+
plt.xlabel('time')
|
|
232
|
+
plt.xticks(ticks=t_l,rotation=45)
|
|
233
|
+
plt.ylabel('count')
|
|
234
|
+
plt.subplots_adjust(bottom=0.25)
|
|
235
|
+
plt.legend()
|
|
236
|
+
fff = os.path.join(os.path.dirname(os.path.abspath(__file__)), "plt.png")
|
|
237
|
+
plt.savefig(fff)
|
|
238
|
+
with open(fff, "rb") as f:
|
|
239
|
+
encode_string = str(base64.b64encode(f.read()), encoding='utf-8')
|
|
240
|
+
md5 = hashlib.md5()
|
|
241
|
+
md5.update(base64.b64decode(encode_string))
|
|
242
|
+
hash = md5.hexdigest()
|
|
243
|
+
notifyWechatRobot({
|
|
244
|
+
"msgtype": "image",
|
|
245
|
+
"image": {
|
|
246
|
+
"base64": encode_string,
|
|
247
|
+
"md5": hash
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
os.remove(fff)
|
|
251
|
+
os.remove(task_counter_file)
|
|
252
|
+
except:
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
def saveCounter(taskUUID, duration, isSuccess):
|
|
256
|
+
try:
|
|
257
|
+
notifyCounterIfNeed()
|
|
258
|
+
if os.path.exists(task_counter_file) == False:
|
|
259
|
+
with open(task_counter_file, 'w') as f:
|
|
260
|
+
json.dump({}, f)
|
|
261
|
+
with open(task_counter_file, 'r') as f:
|
|
262
|
+
data = json.load(f)
|
|
263
|
+
#update
|
|
264
|
+
now_hour = str(datetime.datetime.now().hour)
|
|
265
|
+
if now_hour in data:
|
|
266
|
+
if isSuccess:
|
|
267
|
+
data[now_hour]["success"] += 1
|
|
268
|
+
else:
|
|
269
|
+
data[now_hour]["fail"] += 1
|
|
270
|
+
if "usage" not in data[now_hour]:
|
|
271
|
+
data[now_hour]["usage"] = 0
|
|
272
|
+
data[now_hour]["usage"] += duration
|
|
273
|
+
else:
|
|
274
|
+
data[now_hour] = {
|
|
275
|
+
"success" : 1 if isSuccess else 0,
|
|
276
|
+
"fail" : 0 if isSuccess else 1,
|
|
277
|
+
"usage" : 0
|
|
278
|
+
}
|
|
279
|
+
#save
|
|
280
|
+
with open(task_counter_file, 'w') as f:
|
|
281
|
+
json.dump(data, f)
|
|
282
|
+
except:
|
|
283
|
+
pass
|
ryry/upload.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from urllib.parse import *
|
|
2
|
+
|
|
3
|
+
def addtionExif(srcFile, taskUUID):
|
|
4
|
+
if taskUUID == None or len(taskUUID) == 0:
|
|
5
|
+
return
|
|
6
|
+
try:
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
file_name = Path(srcFile).name
|
|
9
|
+
ext = file_name[file_name.index("."):].lower()
|
|
10
|
+
if ext in [".jpg", ".png", ".jpeg", ".bmp", ".webp", ".gif"]:
|
|
11
|
+
from PIL import Image
|
|
12
|
+
img = Image.open(srcFile)
|
|
13
|
+
exif_dict = {
|
|
14
|
+
"0th": { },
|
|
15
|
+
"Exif": { },
|
|
16
|
+
"1st": { },
|
|
17
|
+
"thumbnail": None,
|
|
18
|
+
"GPS": { }
|
|
19
|
+
}
|
|
20
|
+
import piexif
|
|
21
|
+
if taskUUID:
|
|
22
|
+
exif_dict["0th"] = {
|
|
23
|
+
piexif.ImageIFD.Software: f'make with ryry({taskUUID})'.encode(),
|
|
24
|
+
piexif.ImageIFD.Copyright: f'dalipen'.encode(),
|
|
25
|
+
}
|
|
26
|
+
exif_dict["Exif"] = {
|
|
27
|
+
piexif.ExifIFD.UserComment: f'make with ryry({taskUUID})'.encode(),
|
|
28
|
+
}
|
|
29
|
+
exif_dat = piexif.dump(exif_dict)
|
|
30
|
+
img.save(srcFile, "webp", quality=90, exif=exif_dat)
|
|
31
|
+
# elif ext in [".mp4",".mov",".avi",".wmv",".mpg",".mpeg",".rm",".ram",".flv",".swf",".ts"]:
|
|
32
|
+
# params = {}
|
|
33
|
+
# elif ext in [".mp3",".aac",".wav",".wma",".cda",".flac",".m4a",".mid",".mka",".mp2",".mpa",".mpc",".ape",".ofr",".ogg",".ra",".wv",".tta",".ac3",".dts"]:
|
|
34
|
+
# params = {}
|
|
35
|
+
# else:
|
|
36
|
+
# params = {}
|
|
37
|
+
except:
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
def transcode(srcFile):
|
|
41
|
+
try:
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
from PIL import Image
|
|
44
|
+
file_name = Path(srcFile).name
|
|
45
|
+
ext = file_name[file_name.index("."):].lower()
|
|
46
|
+
if ext in [".jpg", ".png", ".jpeg", ".bmp"]:
|
|
47
|
+
image = Image.open(srcFile, "r")
|
|
48
|
+
format = image.format
|
|
49
|
+
if format.lower() != "webp":
|
|
50
|
+
fname = Path(srcFile).name
|
|
51
|
+
newFile = srcFile.replace(fname[fname.index("."):], ".webp")
|
|
52
|
+
image.save(newFile, "webp", quality=90)
|
|
53
|
+
image.close()
|
|
54
|
+
return True, newFile
|
|
55
|
+
except Exception as e:
|
|
56
|
+
pass
|
|
57
|
+
return False, srcFile
|
|
58
|
+
|
|
59
|
+
def additionalUrl(srcFile, ossUrl):
|
|
60
|
+
from pathlib import Path
|
|
61
|
+
from PIL import Image
|
|
62
|
+
try:
|
|
63
|
+
file_name = Path(srcFile).name
|
|
64
|
+
ext = file_name[file_name.index("."):].lower()
|
|
65
|
+
params = {}
|
|
66
|
+
if ext in [".jpg", ".png", ".jpeg", ".bmp", ".webp", ".gif"]:
|
|
67
|
+
img = Image.open(srcFile)
|
|
68
|
+
params["width"] = img.width
|
|
69
|
+
params["height"] = img.height
|
|
70
|
+
elif ext in [".mp4",".mov",".avi",".wmv",".mpg",".mpeg",".rm",".ram",".flv",".swf",".ts"]:
|
|
71
|
+
params = {}
|
|
72
|
+
elif ext in [".mp3",".aac",".wav",".wma",".cda",".flac",".m4a",".mid",".mka",".mp2",".mpa",".mpc",".ape",".ofr",".ogg",".ra",".wv",".tta",".ac3",".dts"]:
|
|
73
|
+
params = {}
|
|
74
|
+
else:
|
|
75
|
+
params = {}
|
|
76
|
+
parsed_url = urlparse(ossUrl)
|
|
77
|
+
updated_query_string = urlencode(params, doseq=True)
|
|
78
|
+
final_url = parsed_url._replace(query=updated_query_string).geturl()
|
|
79
|
+
return final_url
|
|
80
|
+
except:
|
|
81
|
+
return ossUrl
|
|
82
|
+
|
|
83
|
+
def upload(src, taskUUID, timeout=300):
|
|
84
|
+
import os
|
|
85
|
+
from ryry import store
|
|
86
|
+
from pathlib import Path
|
|
87
|
+
from ryry import taskUtils
|
|
88
|
+
from ryry import ryry_webapi
|
|
89
|
+
import requests
|
|
90
|
+
if os.path.exists(src) == False:
|
|
91
|
+
raise Exception(f"upload file not found")
|
|
92
|
+
if taskUUID==None or len(taskUUID) <= 0:
|
|
93
|
+
taskUUID = taskUtils.taskInfoWithFirstTask()
|
|
94
|
+
|
|
95
|
+
needDeleteSrc, newSrc = transcode(src)
|
|
96
|
+
addtionExif(newSrc, taskUUID)
|
|
97
|
+
file_name = Path(newSrc).name
|
|
98
|
+
ossurl, content_type = ryry_webapi.GetOssUrl(os.path.splitext(file_name)[-1][1:])
|
|
99
|
+
if len(ossurl) == 0:
|
|
100
|
+
raise Exception(f"oss server is not avalid, msg = {content_type}")
|
|
101
|
+
|
|
102
|
+
headers = dict()
|
|
103
|
+
headers['Content-Type'] = content_type
|
|
104
|
+
requests.adapters.DEFAULT_RETRIES = 3
|
|
105
|
+
s = requests.session()
|
|
106
|
+
s.keep_alive = False
|
|
107
|
+
res = s.put(ossurl, data=open(newSrc, 'rb').read(), headers=headers, timeout=timeout)
|
|
108
|
+
s.close()
|
|
109
|
+
if res.status_code == 200:
|
|
110
|
+
ossurl = additionalUrl(newSrc, ossurl)
|
|
111
|
+
if needDeleteSrc:
|
|
112
|
+
os.remove(newSrc)
|
|
113
|
+
return ossurl
|
|
114
|
+
else:
|
|
115
|
+
raise Exception(f"upload file fail! res = {res}")
|
|
116
|
+
|
|
117
|
+
def uploadWidget(src, widgetid, timeout=300):
|
|
118
|
+
from ryry import ryry_webapi
|
|
119
|
+
import requests
|
|
120
|
+
ossurl, content_type = ryry_webapi.GetWidgetOssUrl(widgetid)
|
|
121
|
+
if len(ossurl) == 0:
|
|
122
|
+
raise Exception("oss server is not avalid")
|
|
123
|
+
|
|
124
|
+
headers = dict()
|
|
125
|
+
headers['Content-Type'] = content_type
|
|
126
|
+
requests.adapters.DEFAULT_RETRIES = 3
|
|
127
|
+
s = requests.session()
|
|
128
|
+
s.keep_alive = False
|
|
129
|
+
res = s.put(ossurl, data=open(src, 'rb').read(), headers=headers, timeout=timeout)
|
|
130
|
+
s.close()
|
|
131
|
+
if res.status_code == 200:
|
|
132
|
+
ossurl = additionalUrl(src, ossurl)
|
|
133
|
+
checkid = ryry_webapi.WidgetUploadEnd(ossurl)
|
|
134
|
+
if checkid > 0:
|
|
135
|
+
return ossurl, checkid
|
|
136
|
+
else:
|
|
137
|
+
raise Exception("check fail!")
|
|
138
|
+
else:
|
|
139
|
+
raise Exception(f"upload file fail! res = {res}")
|