cloudpss 4.1.1b8__py3-none-any.whl → 4.5.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.
- cloudpss/__init__.py +2 -3
- cloudpss/asyncio/__init__.py +8 -0
- cloudpss/asyncio/job/__init__.py +5 -0
- cloudpss/asyncio/job/job.py +116 -0
- cloudpss/asyncio/job/messageStreamReceiver.py +121 -0
- cloudpss/asyncio/job/messageStreamSender.py +45 -0
- cloudpss/asyncio/model/__init__.py +5 -0
- cloudpss/asyncio/model/model.py +257 -0
- cloudpss/asyncio/model/revision.py +41 -0
- cloudpss/asyncio/model/topology.py +34 -0
- cloudpss/asyncio/utils/__init__.py +6 -0
- cloudpss/{utils → asyncio/utils}/httpAsyncRequest.py +2 -2
- cloudpss/function/functionExecution.py +36 -3
- cloudpss/ieslab/DataManageModel.py +131 -9
- cloudpss/ieslab/EvaluationModel.py +80 -9
- cloudpss/ieslab/IESLabOpt.py +235 -0
- cloudpss/ieslab/IESLabPlan.py +82 -4
- cloudpss/ieslab/IESLabSimulation.py +59 -32
- cloudpss/ieslab/PlanModel.py +276 -33
- cloudpss/ieslab/__init__.py +2 -1
- cloudpss/job/job.py +136 -141
- cloudpss/job/jobReceiver.py +8 -2
- cloudpss/job/messageStreamReceiver.py +42 -99
- cloudpss/job/messageStreamSender.py +5 -42
- cloudpss/job/{view/EMTView.py → result/EMTResult.py} +11 -13
- cloudpss/job/result/IESLabSimulationResult.py +5 -0
- cloudpss/job/result/IESLabTypicalDayResult.py +136 -0
- cloudpss/job/{view/IESView.py → result/IESResult.py} +2 -2
- cloudpss/job/{view/PowerFlowView.py → result/PowerFlowResult.py} +2 -2
- cloudpss/job/result/__init__.py +39 -0
- cloudpss/job/{view/view.py → result/result.py} +37 -8
- cloudpss/model/implements/diagram.py +113 -0
- cloudpss/model/jobDefinitions.py +6 -6
- cloudpss/model/model.py +232 -209
- cloudpss/model/revision.py +30 -35
- cloudpss/model/topology.py +13 -15
- cloudpss/runner/IESLabEvaluationResult.py +14 -6
- cloudpss/runner/IESLabPlanResult.py +91 -35
- cloudpss/runner/IESLabTypicalDayResult.py +62 -50
- cloudpss/runner/MessageStreamReceiver.py +5 -100
- cloudpss/runner/result.py +6 -1
- cloudpss/runner/runner.py +77 -48
- cloudpss/utils/IO.py +1 -1
- cloudpss/utils/graphqlUtil.py +3 -2
- cloudpss/utils/httprequests.py +16 -8
- cloudpss/version.py +1 -1
- {cloudpss-4.1.1b8.dist-info → cloudpss-4.5.0.dist-info}/METADATA +2 -2
- cloudpss-4.5.0.dist-info/RECORD +70 -0
- cloudpss/dslab/__init__.py +0 -2
- cloudpss/dslab/dataManageModel.py +0 -275
- cloudpss/dslab/dslab.py +0 -210
- cloudpss/dslab/files/__init__.py +0 -2
- cloudpss/dslab/files/curveData.py +0 -140229
- cloudpss/dslab/files/files.py +0 -27
- cloudpss/dslab/financialAnalysisModel.py +0 -137
- cloudpss/job/jobMachine.py +0 -11
- cloudpss/job/jobPolicy.py +0 -129
- cloudpss/job/jobQueue.py +0 -14
- cloudpss/job/jobTres.py +0 -6
- cloudpss/job/view/IESLabSimulationView.py +0 -5
- cloudpss/job/view/IESLabTypicalDayView.py +0 -27
- cloudpss/job/view/__init__.py +0 -42
- cloudpss/runner/DSLabResult.py +0 -92
- cloudpss-4.1.1b8.dist-info/RECORD +0 -71
- /cloudpss/{utils → asyncio/utils}/AsyncIterable.py +0 -0
- {cloudpss-4.1.1b8.dist-info → cloudpss-4.5.0.dist-info}/WHEEL +0 -0
- {cloudpss-4.1.1b8.dist-info → cloudpss-4.5.0.dist-info}/top_level.txt +0 -0
cloudpss/job/job.py
CHANGED
@@ -2,23 +2,53 @@ import asyncio
|
|
2
2
|
import random
|
3
3
|
import re
|
4
4
|
import time
|
5
|
-
from cloudpss.utils.AsyncIterable import CustomAsyncIterable
|
6
5
|
|
7
|
-
from cloudpss.
|
8
|
-
from .
|
6
|
+
from cloudpss.job.result.result import Result
|
7
|
+
from .result import getResultClass
|
9
8
|
|
10
9
|
from cloudpss.utils.IO import IO
|
11
10
|
from .messageStreamReceiver import MessageStreamReceiver
|
12
11
|
|
13
12
|
from cloudpss.utils.graphqlUtil import graphql_request
|
14
|
-
from .jobPolicy import JobPolicy
|
15
|
-
from .jobMachine import JobMachine
|
16
13
|
from .messageStreamSender import MessageStreamSender
|
17
|
-
from typing import Any, Callable, TypeVar
|
14
|
+
from typing import Any, Callable, Generic, TypeVar
|
18
15
|
F = TypeVar('F', bound=Callable[..., Any])
|
19
|
-
|
16
|
+
T = TypeVar('T', bound=Callable[..., Result])
|
17
|
+
class Job(Generic[T]):
|
20
18
|
"""docstring for Job"""
|
21
|
-
|
19
|
+
__jobQuery = """query($_a:JobInput!){
|
20
|
+
job(input:$_a){
|
21
|
+
id
|
22
|
+
args
|
23
|
+
createTime
|
24
|
+
startTime
|
25
|
+
endTime
|
26
|
+
status
|
27
|
+
context
|
28
|
+
user
|
29
|
+
priority
|
30
|
+
policy {
|
31
|
+
name
|
32
|
+
queue
|
33
|
+
tres {
|
34
|
+
cpu
|
35
|
+
ecpu
|
36
|
+
mem
|
37
|
+
}
|
38
|
+
priority
|
39
|
+
maxDuration
|
40
|
+
}
|
41
|
+
machine {
|
42
|
+
id
|
43
|
+
name
|
44
|
+
}
|
45
|
+
input
|
46
|
+
output
|
47
|
+
position
|
48
|
+
}
|
49
|
+
}"""
|
50
|
+
|
51
|
+
__createJobQuery = """mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}"""
|
22
52
|
def __init__(
|
23
53
|
self,
|
24
54
|
id,
|
@@ -47,7 +77,7 @@ class Job(object):
|
|
47
77
|
self.user = user
|
48
78
|
self.priority = priority
|
49
79
|
self.policy = policy # type: ignore
|
50
|
-
self.machine =
|
80
|
+
self.machine = machine # type: ignore
|
51
81
|
self.input = input
|
52
82
|
self.output = output
|
53
83
|
self.position = position
|
@@ -57,82 +87,32 @@ class Job(object):
|
|
57
87
|
|
58
88
|
@staticmethod
|
59
89
|
def fetch(id):
|
60
|
-
return asyncio.run(Job.fetchAsync(id))
|
61
|
-
@staticmethod
|
62
|
-
async def fetchAsync(id):
|
63
90
|
"""
|
64
91
|
获取job信息
|
65
92
|
"""
|
66
93
|
if id is None:
|
67
94
|
raise Exception("id is None")
|
68
|
-
|
69
|
-
job(input:$_a){
|
70
|
-
id
|
71
|
-
args
|
72
|
-
createTime
|
73
|
-
startTime
|
74
|
-
endTime
|
75
|
-
status
|
76
|
-
context
|
77
|
-
user
|
78
|
-
priority
|
79
|
-
policy {
|
80
|
-
name
|
81
|
-
queue
|
82
|
-
tres {
|
83
|
-
cpu
|
84
|
-
ecpu
|
85
|
-
mem
|
86
|
-
}
|
87
|
-
priority
|
88
|
-
maxDuration
|
89
|
-
}
|
90
|
-
machine {
|
91
|
-
id
|
92
|
-
name
|
93
|
-
tres {
|
94
|
-
cpu
|
95
|
-
ecpu
|
96
|
-
mem
|
97
|
-
}
|
98
|
-
}
|
99
|
-
input
|
100
|
-
output
|
101
|
-
position
|
102
|
-
}
|
103
|
-
}"""
|
95
|
+
|
104
96
|
variables = {"_a": {"id": id}}
|
105
97
|
|
106
|
-
r =
|
98
|
+
r = graphql_request(Job.__jobQuery, variables)
|
107
99
|
if "errors" in r:
|
108
100
|
raise Exception(r["errors"])
|
109
101
|
return Job(**r["data"]["job"])
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
102
|
+
|
103
|
+
|
104
|
+
# @staticmethod
|
105
|
+
# def fetchMany(*args):
|
106
|
+
# """
|
107
|
+
# 批量获取任务信息
|
108
|
+
# """
|
109
|
+
# # jobs = CustomAsyncIterable(Job.fetch,*args)
|
110
|
+
# # return jobs
|
118
111
|
|
119
112
|
|
113
|
+
|
120
114
|
@staticmethod
|
121
|
-
|
122
|
-
"""
|
123
|
-
创建一个运行任务
|
124
|
-
|
125
|
-
:params: revision 项目版本号
|
126
|
-
:params: job 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
|
127
|
-
:params: config 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
|
128
|
-
:params: name 任务名称,为空时使用项目的参数方案名称和计算方案名称
|
129
|
-
:params: rid 项目rid,可为空
|
130
|
-
|
131
|
-
:return: 返回一个运行实例
|
132
|
-
|
133
|
-
>>> runner = Runner.runRevision(revision,job,config,'')
|
134
|
-
"""
|
135
|
-
|
115
|
+
def __createJobVariables(job, config, revisionHash, rid=None, policy=None, **kwargs):
|
136
116
|
# 处理policy字段
|
137
117
|
if policy is None:
|
138
118
|
policy = {}
|
@@ -148,45 +128,62 @@ class Job(object):
|
|
148
128
|
k, v = t.split("=")
|
149
129
|
tres[k] = float(v) # type: ignore
|
150
130
|
policy["tres"] = tres
|
151
|
-
|
152
|
-
query = """mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}"""
|
153
131
|
function = job["rid"].replace("job-definition/cloudpss/", "function/CloudPSS/")
|
132
|
+
implement = kwargs.get("implement", None)
|
133
|
+
debug = job["args"].get("@debug", None )
|
134
|
+
debugargs={}
|
135
|
+
if debug is not None:
|
136
|
+
t= [ i.split('=') for i in re.split(r'\s+',debug) if i.find('=')>0]
|
137
|
+
for i in t:
|
138
|
+
debugargs[i[0]]=i[1]
|
139
|
+
context=[
|
140
|
+
function,
|
141
|
+
f"model/@sdk/{str(int(time.time() * random.random()))}",
|
142
|
+
]
|
143
|
+
if rid is not None and rid != "":
|
144
|
+
context.append(rid)
|
145
|
+
|
146
|
+
PARENT_JOB_ID =kwargs.get("PARENT_JOB_ID",None)
|
147
|
+
if PARENT_JOB_ID is not None:
|
148
|
+
context.append(f"job/parent/{PARENT_JOB_ID}")
|
149
|
+
|
154
150
|
variables = {
|
155
151
|
"input": {
|
156
152
|
"args": {
|
157
153
|
**job["args"],
|
158
154
|
"_ModelRevision": revisionHash,
|
159
155
|
"_ModelArgs": config["args"],
|
156
|
+
"implement":implement
|
160
157
|
},
|
161
|
-
"context":
|
162
|
-
function,
|
163
|
-
rid,
|
164
|
-
f"model/@sdk/{str(int(time.time() * random.random()))}",
|
165
|
-
],
|
158
|
+
"context": context,
|
166
159
|
"policy": policy,
|
160
|
+
"debug":debugargs
|
167
161
|
}
|
168
162
|
}
|
169
|
-
|
170
|
-
if "errors" in r:
|
171
|
-
raise Exception(r["errors"])
|
172
|
-
id = r["data"]["job"]["id"]
|
173
|
-
return await Job.fetchAsync(id)
|
174
|
-
|
163
|
+
return variables
|
175
164
|
@staticmethod
|
176
|
-
|
165
|
+
def create(revisionHash, job, config, name=None, rid=None, policy=None, **kwargs):
|
177
166
|
"""
|
178
|
-
|
167
|
+
创建一个运行任务
|
179
168
|
|
169
|
+
:params: revision 项目版本号
|
170
|
+
:params: job 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
|
171
|
+
:params: config 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
|
172
|
+
:params: name 任务名称,为空时使用项目的参数方案名称和计算方案名称
|
173
|
+
:params: rid 项目rid,可为空
|
174
|
+
|
175
|
+
:return: 返回一个运行实例
|
176
|
+
|
177
|
+
>>> runner = Runner.runRevision(revision,job,config,'')
|
180
178
|
"""
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
await graphql_fetch(query, variables)
|
179
|
+
variables=Job.__createJobVariables(job, config, revisionHash, rid=rid, policy=policy, **kwargs)
|
180
|
+
r = graphql_request(Job.__createJobQuery, variables)
|
181
|
+
if "errors" in r:
|
182
|
+
raise Exception(r["errors"])
|
183
|
+
id = r["data"]["job"]["id"]
|
184
|
+
return Job.fetch(id)
|
185
|
+
|
186
|
+
|
190
187
|
|
191
188
|
@staticmethod
|
192
189
|
def load(file, format="yaml"):
|
@@ -196,49 +193,30 @@ class Job(object):
|
|
196
193
|
def dump(job, file, format="yaml", compress="gzip"):
|
197
194
|
return IO.dump(job, file, format, compress)
|
198
195
|
|
199
|
-
|
200
|
-
"""
|
201
|
-
使用接收器获取当前运行实例的输出
|
202
|
-
"""
|
203
|
-
if receiver is not None:
|
204
|
-
self.__receiver = receiver
|
205
|
-
if self.__receiver is None:
|
206
|
-
self.__receiver = MessageStreamReceiver(self, dev)
|
207
|
-
await self.__receiver.connect(**kwargs)
|
208
|
-
return self.__receiver
|
196
|
+
|
209
197
|
|
210
|
-
def
|
198
|
+
def read(self, receiver=None, **kwargs):
|
211
199
|
"""
|
212
200
|
使用接收器获取当前运行实例的输出
|
213
201
|
"""
|
214
202
|
if receiver is not None:
|
215
203
|
self.__receiver = receiver
|
216
204
|
if self.__receiver is None:
|
217
|
-
self.__receiver = MessageStreamReceiver(self
|
218
|
-
self.__receiver.
|
205
|
+
self.__receiver = MessageStreamReceiver(self)
|
206
|
+
self.__receiver.connect(**kwargs)
|
219
207
|
return self.__receiver
|
220
208
|
|
221
|
-
async def write(self, sender=None, dev=False, **kwargs) -> MessageStreamSender:
|
222
|
-
"""
|
223
|
-
使用发送器为当前运行实例输入
|
224
|
-
"""
|
225
|
-
|
226
|
-
if sender is not None:
|
227
|
-
self.__sender = sender
|
228
|
-
if self.__sender is None:
|
229
|
-
self.__sender = MessageStreamSender(self, dev)
|
230
|
-
await self.__sender.connect(**kwargs)
|
231
|
-
return self.__sender
|
232
209
|
|
233
|
-
|
210
|
+
|
211
|
+
def write(self, sender=None, **kwargs) -> MessageStreamSender:
|
234
212
|
"""
|
235
|
-
|
213
|
+
使用发送器为当前运行实例输入
|
236
214
|
"""
|
237
215
|
|
238
216
|
if sender is not None:
|
239
217
|
self.__sender = sender
|
240
218
|
if self.__sender is None:
|
241
|
-
self.__sender = MessageStreamSender(self
|
219
|
+
self.__sender = MessageStreamSender(self)
|
242
220
|
self.__sender.connect_legacy(**kwargs)
|
243
221
|
return self.__sender
|
244
222
|
|
@@ -246,43 +224,60 @@ class Job(object):
|
|
246
224
|
"""
|
247
225
|
return: 0: 运行中 1: 运行完成 2: 运行失败
|
248
226
|
"""
|
249
|
-
|
227
|
+
time.sleep(0)
|
250
228
|
if self.__receiver is not None:
|
251
229
|
return self.__receiver.status
|
252
230
|
if self.__receiver is None:
|
253
|
-
self.
|
231
|
+
self.__connect()
|
232
|
+
|
254
233
|
return 0
|
255
234
|
|
256
|
-
def
|
235
|
+
def __connect(self):
|
257
236
|
"""
|
258
237
|
连接接收器和发送器
|
259
238
|
"""
|
260
|
-
|
261
|
-
|
239
|
+
resultType = getResultClass(self.context[0])
|
240
|
+
|
241
|
+
self._result = self._resultView(resultType)
|
262
242
|
|
263
243
|
@property
|
264
|
-
def result(self):
|
244
|
+
def result(self)->T:
|
265
245
|
"""
|
266
246
|
获取当前运行实例的输出
|
267
247
|
"""
|
268
248
|
if self._result is None:
|
269
|
-
self.
|
249
|
+
self.__connect()
|
270
250
|
return self._result
|
271
251
|
|
272
|
-
|
273
|
-
|
252
|
+
|
253
|
+
|
254
|
+
def _resultView(self, resultType=None):
|
274
255
|
"""
|
275
256
|
获取当前运行实例的输出
|
276
257
|
"""
|
277
|
-
receiver = self.
|
278
|
-
sender = self.
|
279
|
-
|
258
|
+
receiver = self.read()
|
259
|
+
sender = self.write()
|
260
|
+
if resultType is None:
|
261
|
+
resultType = getResultClass(self.context[0])
|
262
|
+
return resultType(receiver, sender)
|
263
|
+
|
264
|
+
|
280
265
|
|
281
|
-
|
266
|
+
def abort(self,timeout=3):
|
282
267
|
"""
|
283
|
-
|
268
|
+
中断当前运行实例
|
284
269
|
"""
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
270
|
+
query = '''mutation ($input: AbortJobInput!) {
|
271
|
+
job: abortJob(input: $input) {
|
272
|
+
id
|
273
|
+
status
|
274
|
+
}
|
275
|
+
}
|
276
|
+
'''
|
277
|
+
variables = {
|
278
|
+
'input': {
|
279
|
+
'id': self.taskId,
|
280
|
+
'timeout': timeout
|
281
|
+
}
|
282
|
+
}
|
283
|
+
graphql_request(query, variables)
|
cloudpss/job/jobReceiver.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from deprecated import deprecated
|
1
2
|
class JobReceiver(object):
|
2
3
|
messages = []
|
3
4
|
index = 0
|
@@ -20,7 +21,7 @@ class JobReceiver(object):
|
|
20
21
|
return message
|
21
22
|
raise StopIteration()
|
22
23
|
|
23
|
-
def
|
24
|
+
def result(self, resultType):
|
24
25
|
"""
|
25
26
|
获取指定类型的视图数据
|
26
27
|
|
@@ -30,4 +31,9 @@ class JobReceiver(object):
|
|
30
31
|
|
31
32
|
>>> view= receiver.view(EMTView)
|
32
33
|
"""
|
33
|
-
return
|
34
|
+
return resultType(self)
|
35
|
+
|
36
|
+
@property
|
37
|
+
@deprecated(version='3.0', reason="该方法将在 5.0 版本移除")
|
38
|
+
def message(self):
|
39
|
+
return self.messages
|
@@ -1,9 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import aiohttp
|
4
|
-
from aiohttp import WSMsgType
|
5
|
-
|
6
|
-
from cloudpss.utils.httpAsyncRequest import websocket_connect
|
2
|
+
import sys
|
7
3
|
from .jobReceiver import JobReceiver
|
8
4
|
import os
|
9
5
|
from urllib.parse import urlparse
|
@@ -24,91 +20,36 @@ class Message(object):
|
|
24
20
|
|
25
21
|
|
26
22
|
class MessageStreamReceiver(JobReceiver):
|
27
|
-
def __init__(self, job
|
23
|
+
def __init__(self, job):
|
28
24
|
super().__init__()
|
29
25
|
self.job = job
|
30
|
-
self.
|
26
|
+
self.id =self.job.output
|
31
27
|
self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
|
32
28
|
self.__hasOpen = False
|
33
29
|
|
34
|
-
def
|
35
|
-
|
36
|
-
同步方法读取消息流中的数据
|
37
|
-
id: 消息流id
|
38
|
-
fr0m: 从哪个位置开始读取,如果为0则从头开始读取
|
39
|
-
on_open: 连接建立时的回调函数
|
40
|
-
on_message: 收到消息时的回调函数
|
41
|
-
on_error: 发生错误时的回调函数
|
42
|
-
on_close: 连接关闭时的回调函数
|
43
|
-
"""
|
44
|
-
if id is None:
|
45
|
-
raise Exception("id is None")
|
46
|
-
u = list(urlparse(self.origin))
|
47
|
-
head = "wss" if u[0] == "https" else "ws"
|
48
|
-
|
49
|
-
path = head + "://" + str(u[1]) + "/api/streams/id/" + id
|
50
|
-
if fr0m is not None:
|
51
|
-
path = path + "&from=" + str(fr0m)
|
52
|
-
logging.info(f"receive data from websocket: {path}")
|
53
|
-
ws = websocket.WebSocketApp(
|
54
|
-
path,
|
55
|
-
on_open=self.__on_open,
|
56
|
-
on_message=self.__on_message_legacy,
|
57
|
-
on_error=self.__on_error,
|
58
|
-
on_close=self.__on_close,
|
59
|
-
)
|
60
|
-
|
61
|
-
return ws
|
62
|
-
|
63
|
-
async def __receive(self, id, fr0m):
|
64
|
-
"""
|
65
|
-
读取消息流中的数据
|
66
|
-
id: 消息流id
|
67
|
-
fr0m: 从哪个位置开始读取,如果为0则从头开始读取
|
68
|
-
on_open: 连接建立时的回调函数
|
69
|
-
on_message: 收到消息时的回调函数
|
70
|
-
on_error: 发生错误时的回调函数
|
71
|
-
on_close: 连接关闭时的回调函数
|
72
|
-
"""
|
73
|
-
if id is None:
|
30
|
+
def __path(self, from_=None):
|
31
|
+
if self.id is None:
|
74
32
|
raise Exception("id is None")
|
75
33
|
u = list(urlparse(self.origin))
|
76
34
|
head = "wss" if u[0] == "https" else "ws"
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
async for msg in websocket_connect(
|
83
|
-
path,
|
84
|
-
open_func=self.__on_open,
|
85
|
-
):
|
86
|
-
if msg.type == WSMsgType.BINARY:
|
87
|
-
decode = self.__on_message(msg.data)
|
88
|
-
yield decode
|
89
|
-
elif msg.type == WSMsgType.TEXT:
|
90
|
-
decode = self.__on_message(msg.data)
|
91
|
-
yield decode
|
92
|
-
elif msg.type == WSMsgType.CLOSED:
|
93
|
-
logging.debug("WebSocket连接已关闭")
|
94
|
-
self.__on_close()
|
95
|
-
|
96
|
-
break
|
97
|
-
elif msg.type == WSMsgType.ERROR:
|
98
|
-
logging.debug(f"WebSocket连接发生错误:{msg.data}")
|
99
|
-
self.__on_error(msg.data)
|
100
|
-
break
|
101
|
-
self._status=1
|
35
|
+
path = head + "://" + str(u[1]) + "/api/streams/id/" + self.id
|
36
|
+
if from_ is not None:
|
37
|
+
path = path + "?from=" + str(from_)
|
38
|
+
return path
|
39
|
+
|
102
40
|
###下面是兼容Receiver部分功能实现
|
103
41
|
def __on_message_legacy(self, *args, **kwargs):
|
104
|
-
|
42
|
+
|
43
|
+
if type(args[0]) != websocket.WebSocketApp:
|
105
44
|
message = args[0]
|
106
45
|
else:
|
107
46
|
message = args[1]
|
108
47
|
return self.__on_message(message)
|
109
48
|
|
110
49
|
def __on_message(self, message):
|
50
|
+
|
111
51
|
data = IO.deserialize(message, "ubjson")
|
52
|
+
self.ws.url = self.__path(data["id"])
|
112
53
|
msg = IO.deserialize(data["data"], "ubjson")
|
113
54
|
self.messages.append(msg)
|
114
55
|
if(msg['type']=='terminate'):
|
@@ -130,9 +71,10 @@ class MessageStreamReceiver(JobReceiver):
|
|
130
71
|
self.messages.append(msg)
|
131
72
|
|
132
73
|
def __on_close(self, *args, **kwargs):
|
133
|
-
if len(args)>
|
74
|
+
if len(args)>1:
|
134
75
|
msg =args[2]
|
135
|
-
|
76
|
+
|
77
|
+
if msg is not None and msg.startswith("CMS_NO_STREAM_ID:"):
|
136
78
|
self._status = 1
|
137
79
|
msg = {
|
138
80
|
"type": "log",
|
@@ -145,7 +87,6 @@ class MessageStreamReceiver(JobReceiver):
|
|
145
87
|
self.messages.append(msg)
|
146
88
|
return
|
147
89
|
logging.debug("MessageStreamReceiver close")
|
148
|
-
self._status = 1
|
149
90
|
msg = {
|
150
91
|
"type": "log",
|
151
92
|
"verb": "create",
|
@@ -156,7 +97,7 @@ class MessageStreamReceiver(JobReceiver):
|
|
156
97
|
},
|
157
98
|
}
|
158
99
|
self.messages.append(msg)
|
159
|
-
|
100
|
+
self._status = 1
|
160
101
|
|
161
102
|
def __on_open(self,ws, *args, **kwargs):
|
162
103
|
self.ws = ws
|
@@ -173,31 +114,33 @@ class MessageStreamReceiver(JobReceiver):
|
|
173
114
|
def status(self):
|
174
115
|
return self._status
|
175
116
|
|
176
|
-
|
177
|
-
|
178
|
-
|
117
|
+
def waitFor(self,timeOut=sys.maxsize):
|
118
|
+
"""
|
119
|
+
阻塞方法,直到任务完成
|
179
120
|
|
180
|
-
|
121
|
+
:params timeOut: 超时时间
|
122
|
+
"""
|
123
|
+
start = time.time()
|
124
|
+
while self.status == 0:
|
125
|
+
time.sleep(0)
|
126
|
+
if time.time()-start>timeOut:
|
127
|
+
raise Exception("time out")
|
128
|
+
|
129
|
+
|
130
|
+
def connect(self):
|
181
131
|
self._status = 1
|
182
|
-
|
183
|
-
|
184
|
-
|
132
|
+
path = self.__path()
|
133
|
+
logging.info(f"receive data from websocket: {path}")
|
134
|
+
self.ws = websocket.WebSocketApp(
|
135
|
+
path,
|
136
|
+
on_open=self.__on_open,
|
137
|
+
on_message=self.__on_message_legacy,
|
138
|
+
on_error=self.__on_error,
|
139
|
+
on_close=self.__on_close,
|
185
140
|
)
|
186
|
-
thread = threading.Thread(target=self.ws.run_forever,
|
141
|
+
thread = threading.Thread(target=self.ws.run_forever, kwargs={'ping_interval':60,'ping_timeout':5,'reconnect':True})
|
187
142
|
thread.setDaemon(True)
|
188
143
|
thread.start()
|
189
144
|
while not self.__hasOpen:
|
190
|
-
time.sleep(0
|
191
|
-
|
192
|
-
async def connect(self):
|
193
|
-
self._status = 0
|
194
|
-
self.receiver= self.__receive(
|
195
|
-
self.job.output,
|
196
|
-
None,
|
197
|
-
)
|
198
|
-
# asyncio.create_task(
|
199
|
-
# self.__receive(
|
200
|
-
# self.job.output,
|
201
|
-
# None
|
202
|
-
# )
|
203
|
-
# )
|
145
|
+
time.sleep(0)
|
146
|
+
|
@@ -2,10 +2,6 @@ import asyncio
|
|
2
2
|
import sys, os
|
3
3
|
import threading
|
4
4
|
from urllib.parse import urlparse
|
5
|
-
|
6
|
-
import aiohttp
|
7
|
-
|
8
|
-
|
9
5
|
sys.path.append(os.path.join(os.path.dirname(__file__), "../"))
|
10
6
|
|
11
7
|
import websocket
|
@@ -16,10 +12,9 @@ import logging
|
|
16
12
|
|
17
13
|
|
18
14
|
class MessageStreamSender:
|
19
|
-
def __init__(self, job
|
15
|
+
def __init__(self, job):
|
20
16
|
super().__init__()
|
21
17
|
self.job = job
|
22
|
-
self.dev = dev
|
23
18
|
self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
|
24
19
|
self.__hasOpen = False
|
25
20
|
|
@@ -56,19 +51,9 @@ class MessageStreamSender:
|
|
56
51
|
def status(self):
|
57
52
|
return self._status
|
58
53
|
|
59
|
-
async def write_async(self, message):
|
60
|
-
if self.websocket:
|
61
|
-
data = IO.serialize(message, "ubjson", None)
|
62
|
-
await self.websocket.send_bytes(data)
|
63
|
-
else:
|
64
|
-
logging.info("websocket is None")
|
65
|
-
|
66
54
|
def write(self, message):
|
67
|
-
|
68
|
-
|
69
|
-
self.ws.send(data,websocket.ABNF.OPCODE_BINARY)
|
70
|
-
else:
|
71
|
-
asyncio.run(self.write_async(message))
|
55
|
+
data = IO.serialize(message, "ubjson", None)
|
56
|
+
self.ws.send(data,websocket.ABNF.OPCODE_BINARY)
|
72
57
|
|
73
58
|
def connect_legacy(self):
|
74
59
|
"""
|
@@ -99,28 +84,6 @@ class MessageStreamSender:
|
|
99
84
|
time.sleep(0.2)
|
100
85
|
return self.ws
|
101
86
|
|
102
|
-
|
103
|
-
if self.websocket:
|
104
|
-
data = await self.websocket.receive()
|
105
|
-
if data.type == aiohttp.WSMsgType.TEXT:
|
106
|
-
self.__on_message(data.data)
|
107
|
-
elif data.type == aiohttp.WSMsgType.CLOSED:
|
108
|
-
self.__on_close()
|
109
|
-
elif data.type == aiohttp.WSMsgType.ERROR:
|
110
|
-
self.__on_error(data.data)
|
111
|
-
else:
|
112
|
-
logging.info("WebSocket connection not established")
|
113
|
-
|
114
|
-
async def connect(self):
|
115
|
-
self._status = 0
|
116
|
-
if self.job.input is None:
|
117
|
-
raise Exception("id is None")
|
118
|
-
if self.job.input == "00000000-0000-0000-0000-000000000000":
|
119
|
-
return
|
120
|
-
u = list(urlparse(self.origin))
|
121
|
-
head = "wss" if u[0] == "https" else "ws"
|
87
|
+
|
122
88
|
|
123
|
-
|
124
|
-
logging.info(f"MessageStreamSender data from websocket: {path}")
|
125
|
-
async with aiohttp.ClientSession() as session:
|
126
|
-
self.websocket = await session.ws_connect(path)
|
89
|
+
|