cloudpss 4.5.0__py3-none-any.whl → 4.5.1a1__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 -1
- cloudpss/dslab/__init__.py +2 -0
- cloudpss/dslab/dataManageModel.py +275 -0
- cloudpss/dslab/dslab.py +213 -0
- cloudpss/dslab/files/__init__.py +2 -0
- cloudpss/dslab/files/curveData.py +140229 -0
- cloudpss/dslab/files/files.py +27 -0
- cloudpss/dslab/financialAnalysisModel.py +137 -0
- cloudpss/job/TemplateCompiler.py +273 -0
- cloudpss/job/TemplateManager.py +36 -0
- cloudpss/job/job.py +2 -2
- cloudpss/job/messageStreamReceiver.py +24 -10
- cloudpss/job/messageStreamSender.py +5 -5
- cloudpss/job/result/result.py +0 -1
- cloudpss/runner/DSLabResult.py +92 -0
- cloudpss/runner/result.py +0 -1
- cloudpss/runner/runner.py +15 -1
- cloudpss/utils/httprequests.py +2 -2
- cloudpss/version.py +1 -1
- {cloudpss-4.5.0.dist-info → cloudpss-4.5.1a1.dist-info}/METADATA +1 -1
- {cloudpss-4.5.0.dist-info → cloudpss-4.5.1a1.dist-info}/RECORD +23 -13
- {cloudpss-4.5.0.dist-info → cloudpss-4.5.1a1.dist-info}/WHEEL +0 -0
- {cloudpss-4.5.0.dist-info → cloudpss-4.5.1a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
from .curveData import 基准出力曲线, 基准出力曲线2, 基准出力曲线3, 负荷曲线, 策略曲线, 运行策略曲线
|
2
|
+
|
3
|
+
extra_paths = {
|
4
|
+
'光伏': 基准出力曲线,
|
5
|
+
'光伏曲线': 基准出力曲线,
|
6
|
+
'风机': 基准出力曲线,
|
7
|
+
'风机曲线': 基准出力曲线,
|
8
|
+
'燃气': 基准出力曲线2,
|
9
|
+
'燃气曲线': 基准出力曲线,
|
10
|
+
'水电': 基准出力曲线2,
|
11
|
+
'水电曲线': 基准出力曲线,
|
12
|
+
'火电': 基准出力曲线2,
|
13
|
+
'火电曲线': 基准出力曲线,
|
14
|
+
'生物质发电': 基准出力曲线2,
|
15
|
+
'生物质发电曲线': 基准出力曲线,
|
16
|
+
'垃圾电厂': 基准出力曲线2,
|
17
|
+
'垃圾电厂曲线': 基准出力曲线,
|
18
|
+
'负荷分类': 负荷曲线,
|
19
|
+
'负荷用户': 负荷曲线,
|
20
|
+
'储能运行策略': 运行策略曲线,
|
21
|
+
}
|
22
|
+
|
23
|
+
def getCurveData(kind):
|
24
|
+
if kind in extra_paths:
|
25
|
+
return extra_paths[kind]
|
26
|
+
else :
|
27
|
+
return []
|
@@ -0,0 +1,137 @@
|
|
1
|
+
import time
|
2
|
+
from cloudpss.runner.runner import Runner, HttpRunner, DSLabRunner
|
3
|
+
from cloudpss.runner.DSLabResult import DSLabResult
|
4
|
+
from ..utils import request
|
5
|
+
import json
|
6
|
+
|
7
|
+
class DSLabFinancialAnalysisModel(object):
|
8
|
+
_baseUri = 'api/dslab/rest/pe/'
|
9
|
+
|
10
|
+
_kindNameMap = {
|
11
|
+
"投资组成": "investmentbanchandproportion",
|
12
|
+
"资金来源": "capitalsource",
|
13
|
+
"资产形式": "assetformation",
|
14
|
+
"生产成本": "productioncost",
|
15
|
+
"流动资金及财务费用": "workingcapitalandfinancialexpenses",
|
16
|
+
"税率及附加": "projectcalculation",
|
17
|
+
}
|
18
|
+
|
19
|
+
# 财务评价基础参数接口默认值
|
20
|
+
_financialParasDefaultValues = {
|
21
|
+
"资产形式": {
|
22
|
+
"fixedAssetsRatio": "95",
|
23
|
+
"residualRrate": "5",
|
24
|
+
"depreciationPeriod": "15",
|
25
|
+
"reimbursementPeriod": "5"
|
26
|
+
},
|
27
|
+
"生产成本": {
|
28
|
+
'annualSalary': "8",
|
29
|
+
'capacity': "4",
|
30
|
+
'insuranceRate': "0.25",
|
31
|
+
'materialsExpenses': "5.0",
|
32
|
+
'otherExpenses': "1.0",
|
33
|
+
'welfareFactor': "0"
|
34
|
+
},
|
35
|
+
"流动资金及财务费用": {
|
36
|
+
"annualAPCirculationTimes": "12",
|
37
|
+
"annualARCirculationTimes": "12",
|
38
|
+
"annualCashCirculationTimes": "12",
|
39
|
+
"annualStockCirculationTimes": "12",
|
40
|
+
"interestRateAndWorkingCapital": "4",
|
41
|
+
"workingCapitalLoanRatio": "70"
|
42
|
+
},
|
43
|
+
"税率及附加": {
|
44
|
+
"aleatoricAccumulationFundRate": "0",
|
45
|
+
"basicDiscountRate": "8",
|
46
|
+
"cityMaintenanceConstructionTaxTate": "5",
|
47
|
+
"corporateIncomeTaxRate": "25",
|
48
|
+
"educationFeePlus": "5",
|
49
|
+
"electricityVATRate": "18",
|
50
|
+
"fuelBoughtVATRate": "10",
|
51
|
+
"hotColdVATRate": "12",
|
52
|
+
"legalAccumulationFundRate": "10",
|
53
|
+
"localEducationPlus": "2",
|
54
|
+
"materialBoughtVATRate": "17",
|
55
|
+
"steamSaleVATRate": "12"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
def __init__(self, simulationId):
|
60
|
+
'''
|
61
|
+
初始化
|
62
|
+
'''
|
63
|
+
self.simulationId = simulationId
|
64
|
+
|
65
|
+
def _saveItemData(self, url, data):
|
66
|
+
'''
|
67
|
+
保存url链接对应的优化方案下财务评估模块的基础信息
|
68
|
+
:param url string类型,表示优化方案的接口链接
|
69
|
+
|
70
|
+
:return: dict 类型,代表方案对应的财务评价基础参数信息
|
71
|
+
'''
|
72
|
+
r = request('POST', url, None, data=json.dumps(data))
|
73
|
+
return json.loads(r.text)
|
74
|
+
|
75
|
+
def _fetchItemData(self, url, planID):
|
76
|
+
'''
|
77
|
+
获取planID对应的优化方案下财务评估模块的基础信息
|
78
|
+
:param planID int类型,表示优化方案的ID,数值位于0~优化方案数量之间
|
79
|
+
|
80
|
+
:return: dict 类型,为源数据的引用,代表方案对应的财务评价基础参数信息
|
81
|
+
'''
|
82
|
+
r = request('GET',
|
83
|
+
url,
|
84
|
+
params={
|
85
|
+
"planId": planID,
|
86
|
+
"simu": self.simulationId
|
87
|
+
})
|
88
|
+
return json.loads(r.text)
|
89
|
+
|
90
|
+
def run(self, planID) -> Runner[DSLabResult]:
|
91
|
+
'''
|
92
|
+
运行财务评价概览计算
|
93
|
+
|
94
|
+
:param planID int类型,表示优化方案的ID,数值位于0~优化方案数量之间
|
95
|
+
|
96
|
+
:return: Runner[DSLabResult]
|
97
|
+
'''
|
98
|
+
url = 'api/dslab/rest/saveDataToclickhouse'
|
99
|
+
try:
|
100
|
+
r = request('GET',
|
101
|
+
url,
|
102
|
+
params={
|
103
|
+
"planId": planID,
|
104
|
+
"simu": self.simulationId,
|
105
|
+
"CMD_TYPE": 'financialEvaluation'
|
106
|
+
})
|
107
|
+
data = json.loads(r.text)
|
108
|
+
return DSLabRunner({'rid': 'function/ieslab/evaluation'},
|
109
|
+
self.simulationId,
|
110
|
+
planId=planID,
|
111
|
+
cmdType='financialEvaluation')
|
112
|
+
except:
|
113
|
+
raise Exception('财务评价概览计算失败')
|
114
|
+
|
115
|
+
def GetFinancialParams(self, planID):
|
116
|
+
'''
|
117
|
+
获取planID对应的优化方案下财务评估模块的基础信息
|
118
|
+
:param planID int类型,表示优化方案的ID,数值位于0~优化方案数量之间
|
119
|
+
|
120
|
+
:return: dict 类型,为源数据的引用,代表方案对应的财务评价基础参数信息
|
121
|
+
'''
|
122
|
+
dict_result = dict()
|
123
|
+
for k, v in self._kindNameMap.items():
|
124
|
+
kind = self._kindNameMap.get(k, k)
|
125
|
+
url = f"{self._baseUri}{kind}"
|
126
|
+
list_data = self._fetchItemData(url, planID)
|
127
|
+
if not list_data :
|
128
|
+
data = {
|
129
|
+
"simu": self.simulationId,
|
130
|
+
"planId": planID,
|
131
|
+
}
|
132
|
+
if k in self._financialParasDefaultValues:
|
133
|
+
data.update(self._financialParasDefaultValues[k])
|
134
|
+
dict_result[v] = self._saveItemData(url, data)
|
135
|
+
else:
|
136
|
+
dict_result[v] = list_data
|
137
|
+
return dict_result
|
@@ -0,0 +1,273 @@
|
|
1
|
+
import json
|
2
|
+
from collections import namedtuple
|
3
|
+
from typing import Any, Dict, List, Union
|
4
|
+
|
5
|
+
PARSER_STATUS_TEXT = 0
|
6
|
+
PARSER_STATUS_EXPRESSION_SIMPLE = 1
|
7
|
+
PARSER_STATUS_EXPRESSION_COMPLEX = 2
|
8
|
+
|
9
|
+
def is_identifier_char(char):
|
10
|
+
char_code = ord(char)
|
11
|
+
return ((char_code >= 97 and char_code <= 122) or
|
12
|
+
(char_code >= 65 and char_code <= 90) or
|
13
|
+
(char_code >= 48 and char_code <= 57) or
|
14
|
+
char_code == 95)
|
15
|
+
|
16
|
+
INTERPOLATION_CHAR = '$'
|
17
|
+
INTERPOLATION_EXPRESSION_START = '{'
|
18
|
+
INTERPOLATION_EXPRESSION_END = '}'
|
19
|
+
|
20
|
+
def parse_interpolation_impl(template, start, length):
|
21
|
+
templates = []
|
22
|
+
values = []
|
23
|
+
current_template = ''
|
24
|
+
current_value = ''
|
25
|
+
expression_complex_depth = 0
|
26
|
+
status = PARSER_STATUS_TEXT
|
27
|
+
end = start + length - 1
|
28
|
+
|
29
|
+
i = start
|
30
|
+
while i <= end:
|
31
|
+
if status == PARSER_STATUS_TEXT:
|
32
|
+
next_interpolation_char = template.find(INTERPOLATION_CHAR, i)
|
33
|
+
if next_interpolation_char < 0 or next_interpolation_char >= end:
|
34
|
+
current_template += template[i:end + 1]
|
35
|
+
break
|
36
|
+
current_template += template[i:next_interpolation_char]
|
37
|
+
next_char = template[next_interpolation_char + 1]
|
38
|
+
i = next_interpolation_char
|
39
|
+
if next_char == INTERPOLATION_CHAR:
|
40
|
+
current_template += INTERPOLATION_CHAR
|
41
|
+
i += 1
|
42
|
+
continue
|
43
|
+
if next_char == INTERPOLATION_EXPRESSION_START:
|
44
|
+
templates.append(current_template)
|
45
|
+
current_template = ''
|
46
|
+
status = PARSER_STATUS_EXPRESSION_COMPLEX
|
47
|
+
expression_complex_depth = 1
|
48
|
+
i += 1
|
49
|
+
continue
|
50
|
+
if is_identifier_char(next_char):
|
51
|
+
templates.append(current_template)
|
52
|
+
current_template = ''
|
53
|
+
current_value = next_char
|
54
|
+
status = PARSER_STATUS_EXPRESSION_SIMPLE
|
55
|
+
i += 1
|
56
|
+
continue
|
57
|
+
current_template += INTERPOLATION_CHAR
|
58
|
+
continue
|
59
|
+
|
60
|
+
char = template[i]
|
61
|
+
if status == PARSER_STATUS_EXPRESSION_SIMPLE:
|
62
|
+
if is_identifier_char(char):
|
63
|
+
current_value += char
|
64
|
+
i += 1
|
65
|
+
continue
|
66
|
+
values.append(current_value)
|
67
|
+
current_value = ''
|
68
|
+
status = PARSER_STATUS_TEXT
|
69
|
+
continue
|
70
|
+
|
71
|
+
if status == PARSER_STATUS_EXPRESSION_COMPLEX:
|
72
|
+
if char == INTERPOLATION_EXPRESSION_START:
|
73
|
+
expression_complex_depth += 1
|
74
|
+
elif char == INTERPOLATION_EXPRESSION_END:
|
75
|
+
expression_complex_depth -= 1
|
76
|
+
if expression_complex_depth == 0:
|
77
|
+
values.append(current_value.strip())
|
78
|
+
current_value = ''
|
79
|
+
status = PARSER_STATUS_TEXT
|
80
|
+
i += 1
|
81
|
+
continue
|
82
|
+
current_value += char
|
83
|
+
i += 1
|
84
|
+
continue
|
85
|
+
|
86
|
+
if status == PARSER_STATUS_TEXT:
|
87
|
+
templates.append(current_template)
|
88
|
+
elif status == PARSER_STATUS_EXPRESSION_SIMPLE:
|
89
|
+
values.append(current_value)
|
90
|
+
templates.append('')
|
91
|
+
else:
|
92
|
+
raise ValueError('Unexpected end of input')
|
93
|
+
|
94
|
+
return {
|
95
|
+
'type': 'interpolation',
|
96
|
+
'templates': templates,
|
97
|
+
'values': values,
|
98
|
+
}
|
99
|
+
|
100
|
+
# 是否为 ArrayBuffer
|
101
|
+
def is_array_buffer(value: Any) -> bool:
|
102
|
+
return isinstance(value, (memoryview, bytearray))
|
103
|
+
|
104
|
+
# 是否为 Error
|
105
|
+
def is_error(value: Any) -> bool:
|
106
|
+
return isinstance(value, Exception)
|
107
|
+
|
108
|
+
|
109
|
+
def parse_template(template: str) -> Any:
|
110
|
+
if not template:
|
111
|
+
return ''
|
112
|
+
if template.startswith('='):
|
113
|
+
return {
|
114
|
+
'type': 'formula',
|
115
|
+
'value': template[1:].strip(),
|
116
|
+
}
|
117
|
+
if template.startswith('$'):
|
118
|
+
result = parse_interpolation_impl(template, 1, len(template)-1)
|
119
|
+
if len(result['templates']) == 0:
|
120
|
+
return result['templates'][0]
|
121
|
+
return result
|
122
|
+
return template
|
123
|
+
# KNOWN_ERRORS = [EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError]
|
124
|
+
|
125
|
+
# 模板序列号
|
126
|
+
seq = 0
|
127
|
+
|
128
|
+
# 创建模板
|
129
|
+
class TemplateCompiler:
|
130
|
+
def __init__(self, template: Any, options: Dict[str, Any]):
|
131
|
+
self.template = template
|
132
|
+
self.options = options
|
133
|
+
self.params = {}
|
134
|
+
self.copyable = []
|
135
|
+
|
136
|
+
# 构建求值
|
137
|
+
def build_eval(self, expression: str, type_: str) -> str:
|
138
|
+
evaluator = self.options['evaluator']
|
139
|
+
if 'evaluator' not in self.params:
|
140
|
+
self.params['evaluator'] = evaluator.get('inject',None)
|
141
|
+
return evaluator['compile'](expression, type_)
|
142
|
+
|
143
|
+
# 构建字符串
|
144
|
+
def build_string(self, str_: str) -> Union[str, bool]:
|
145
|
+
parsed = parse_template(str_)
|
146
|
+
if isinstance(parsed, str):
|
147
|
+
return json.dumps(parsed), False
|
148
|
+
if parsed['type'] == 'formula':
|
149
|
+
return self.build_eval(parsed['value'], parsed['type']), True
|
150
|
+
result = ''
|
151
|
+
for i in range(len(parsed['templates'])):
|
152
|
+
if parsed['templates'][i]:
|
153
|
+
result += (result and '+' or '') + json.dumps(parsed['templates'][i])
|
154
|
+
if i < len(parsed['values']):
|
155
|
+
if not result:
|
156
|
+
result = '""'
|
157
|
+
result += '+' + self.build_eval(parsed['values'][i], parsed['type'])
|
158
|
+
return result, True
|
159
|
+
|
160
|
+
# 构建 Error
|
161
|
+
def build_error(self, err: Exception) -> str:
|
162
|
+
constructor="Error"
|
163
|
+
if err.__class__.__name__ == constructor:
|
164
|
+
return f'new {constructor}({self.build_string(err.message)[0]})'
|
165
|
+
return f'Object.assign(new {constructor}({self.build_string(err.message)[0]}), {{name: {self.build_string(err.name)[0]}}})'
|
166
|
+
|
167
|
+
# 构建数组
|
168
|
+
def build_array(self, arr: List[Any]) -> str:
|
169
|
+
return f'[{", ".join(self.build_value(v) for v in arr)}]'
|
170
|
+
|
171
|
+
# 构建 ArrayBuffer
|
172
|
+
def build_array_buffer(self, buffer: Union[memoryview, bytearray]) -> str:
|
173
|
+
self.copyable.append(buffer[:])
|
174
|
+
return f'copyable[{len(self.copyable) - 1}][:]'
|
175
|
+
|
176
|
+
# 构建 ArrayBufferView
|
177
|
+
def build_array_buffer_view(self, view: memoryview) -> str:
|
178
|
+
self.copyable.append(view.tobytes())
|
179
|
+
return f'new {view.__class__.__name__}(copyable[{len(self.copyable) - 1}][:])'
|
180
|
+
|
181
|
+
# 构建对象
|
182
|
+
def build_object(self, obj: Dict[str, Any]) -> str:
|
183
|
+
result = ''
|
184
|
+
for key, value in obj.items():
|
185
|
+
if result:
|
186
|
+
result += ',\n'
|
187
|
+
if self.options['objectKeyMode'] == 'ignore':
|
188
|
+
result += json.dumps(key)
|
189
|
+
else:
|
190
|
+
e, is_expression = self.build_string(key)
|
191
|
+
if is_expression:
|
192
|
+
result += f'[{e}]'
|
193
|
+
else:
|
194
|
+
result += e
|
195
|
+
result += ':'
|
196
|
+
result += self.build_value(value)
|
197
|
+
return '{' + result + '}'
|
198
|
+
|
199
|
+
# 构建值
|
200
|
+
def build_value(self, value: Any) -> str:
|
201
|
+
if value is None:
|
202
|
+
return 'null'
|
203
|
+
if value is True:
|
204
|
+
return 'true'
|
205
|
+
if value is False:
|
206
|
+
return 'false'
|
207
|
+
if isinstance(value, (int, float)):
|
208
|
+
return str(value)
|
209
|
+
if isinstance(value, str):
|
210
|
+
return self.build_string(value)[0]
|
211
|
+
if isinstance(value, Exception):
|
212
|
+
return self.build_error(value)
|
213
|
+
if isinstance(value, list):
|
214
|
+
return self.build_array(value)
|
215
|
+
if is_array_buffer(value):
|
216
|
+
return self.build_array_buffer(value)
|
217
|
+
if isinstance(value, memoryview):
|
218
|
+
return self.build_array_buffer_view(value)
|
219
|
+
if isinstance(value, dict):
|
220
|
+
return self.build_object(value)
|
221
|
+
raise ValueError(f'Unsupported value: {type(value)}')
|
222
|
+
|
223
|
+
# 构建模板
|
224
|
+
def build(self) -> Any:
|
225
|
+
global seq
|
226
|
+
source = self.build_value(self.template)
|
227
|
+
if self.copyable:
|
228
|
+
self.params['copyable'] = self.copyable
|
229
|
+
params = list(self.params.items())
|
230
|
+
try:
|
231
|
+
result = eval(f'lambda context: ({source})')
|
232
|
+
result.source = source
|
233
|
+
return result
|
234
|
+
except Exception as e:
|
235
|
+
raise ValueError(f'Failed to compile template: {source}\n{str(e)}')
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
def template(templates,options={}):
|
240
|
+
def compile_template(expression, type):
|
241
|
+
if type == 'formula':
|
242
|
+
return f'context[{json.dumps(expression)}]'
|
243
|
+
elif type == 'interpolation':
|
244
|
+
return f"context[{json.dumps(expression)}] ?? ''"
|
245
|
+
raise ValueError(f'Unsupported type: {type}')
|
246
|
+
opt = {
|
247
|
+
'objectKeyMode': 'template',
|
248
|
+
'evaluator':{
|
249
|
+
'compile':compile_template
|
250
|
+
},
|
251
|
+
**options
|
252
|
+
}
|
253
|
+
return TemplateCompiler(templates, opt).build()
|
254
|
+
|
255
|
+
|
256
|
+
|
257
|
+
if __name__ == "__main__":
|
258
|
+
|
259
|
+
message =[1, 1, {'component_load_5_无功功率': [0], 'component_load_5_有功功率': [0], 'time': ['placeholder']}, {'data': {'title': '负荷5功率(kW)', 'traces': [{'name': '有功功率', 'type': 'scatter', 'x': '=time', 'y': '=component_load_5_有功功率'}, {'name': '无功功率', 'type': 'scatter', 'x': '=time', 'y': '=component_load_5_无功功率'}], 'xAxis': {'title': 'time'}, 'yAxis': {'title': '功率(kW)'}}, 'key': '/component_load_5_功率(kW)', 'type': 'plot', 'verb': 'append', 'version': 1}]
|
260
|
+
id =message[0]
|
261
|
+
|
262
|
+
templates=message[3:]
|
263
|
+
|
264
|
+
x= template(templates)
|
265
|
+
|
266
|
+
values=[1, 1, {'component_load_5_无功功率': [5.44544554016478], 'component_load_5_有功功率': [16.3363363363363], 'time': ['2021-08-19 09:00:00']}]
|
267
|
+
|
268
|
+
print(x)
|
269
|
+
|
270
|
+
data= values[2]
|
271
|
+
s=x(data)
|
272
|
+
|
273
|
+
print(s)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from cloudpss.job.TemplateCompiler import template
|
2
|
+
class TemplateManager():
|
3
|
+
|
4
|
+
def __init__(self) -> None:
|
5
|
+
self.templateMap = {}
|
6
|
+
|
7
|
+
def isCreate(self, value):
|
8
|
+
return type(value) == list and len(value) > 3 and type(value[0]) == int and value[1] == 1
|
9
|
+
|
10
|
+
def create(self, value):
|
11
|
+
if not self.isCreate(value):
|
12
|
+
print("is create")
|
13
|
+
return
|
14
|
+
id =value[0]
|
15
|
+
|
16
|
+
templates=value[3:]
|
17
|
+
if self.templateMap.get(id,None) is not None:
|
18
|
+
logging.debug(f"template {id} is already exist")
|
19
|
+
|
20
|
+
self.templateMap[id] = {'template':template(templates),'value':value}
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
def isInvoke(self, value):
|
25
|
+
return type(value) == list and len(value) == 3 and type(value[0]) == int and value[1] == 1
|
26
|
+
|
27
|
+
def invoke(self, value):
|
28
|
+
if not self.isInvoke(value):
|
29
|
+
return []
|
30
|
+
id,_version,args = value
|
31
|
+
|
32
|
+
t = self.templateMap.get(id,None)
|
33
|
+
if t is None:
|
34
|
+
return []
|
35
|
+
return t['template'](args)
|
36
|
+
|
cloudpss/job/job.py
CHANGED
@@ -202,7 +202,7 @@ class Job(Generic[T]):
|
|
202
202
|
if receiver is not None:
|
203
203
|
self.__receiver = receiver
|
204
204
|
if self.__receiver is None:
|
205
|
-
self.__receiver = MessageStreamReceiver(self)
|
205
|
+
self.__receiver = MessageStreamReceiver(self.output)
|
206
206
|
self.__receiver.connect(**kwargs)
|
207
207
|
return self.__receiver
|
208
208
|
|
@@ -216,7 +216,7 @@ class Job(Generic[T]):
|
|
216
216
|
if sender is not None:
|
217
217
|
self.__sender = sender
|
218
218
|
if self.__sender is None:
|
219
|
-
self.__sender = MessageStreamSender(self)
|
219
|
+
self.__sender = MessageStreamSender(self.input)
|
220
220
|
self.__sender.connect_legacy(**kwargs)
|
221
221
|
return self.__sender
|
222
222
|
|
@@ -1,5 +1,8 @@
|
|
1
1
|
import logging
|
2
2
|
import sys
|
3
|
+
|
4
|
+
from cloudpss.job.TemplateManager import TemplateManager
|
5
|
+
|
3
6
|
from .jobReceiver import JobReceiver
|
4
7
|
import os
|
5
8
|
from urllib.parse import urlparse
|
@@ -7,7 +10,6 @@ import websocket
|
|
7
10
|
import pytz
|
8
11
|
import threading
|
9
12
|
import time
|
10
|
-
|
11
13
|
utc_tz = pytz.timezone("UTC")
|
12
14
|
|
13
15
|
from ..utils.IO import IO
|
@@ -18,14 +20,15 @@ class Message(object):
|
|
18
20
|
self.id = id
|
19
21
|
self.token = token
|
20
22
|
|
21
|
-
|
23
|
+
|
24
|
+
|
22
25
|
class MessageStreamReceiver(JobReceiver):
|
23
|
-
def __init__(self,
|
26
|
+
def __init__(self, output):
|
24
27
|
super().__init__()
|
25
|
-
self.
|
26
|
-
self.id =self.job.output
|
28
|
+
self.id = output
|
27
29
|
self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
|
28
30
|
self.__hasOpen = False
|
31
|
+
self.templates=TemplateManager()
|
29
32
|
|
30
33
|
def __path(self, from_=None):
|
31
34
|
if self.id is None:
|
@@ -39,25 +42,36 @@ class MessageStreamReceiver(JobReceiver):
|
|
39
42
|
|
40
43
|
###下面是兼容Receiver部分功能实现
|
41
44
|
def __on_message_legacy(self, *args, **kwargs):
|
42
|
-
|
43
45
|
if type(args[0]) != websocket.WebSocketApp:
|
44
46
|
message = args[0]
|
45
47
|
else:
|
46
48
|
message = args[1]
|
47
49
|
return self.__on_message(message)
|
48
|
-
|
49
50
|
def __on_message(self, message):
|
50
51
|
|
51
52
|
data = IO.deserialize(message, "ubjson")
|
52
53
|
self.ws.url = self.__path(data["id"])
|
53
54
|
msg = IO.deserialize(data["data"], "ubjson")
|
55
|
+
|
56
|
+
if type(msg) is list:
|
57
|
+
if len(msg) == 3:
|
58
|
+
pass
|
59
|
+
|
60
|
+
templateMessage = self.templates.invoke(msg)
|
61
|
+
# print(templateMessage)
|
62
|
+
for m in templateMessage:
|
63
|
+
self.messages.append(m)
|
64
|
+
return
|
65
|
+
else:
|
66
|
+
self.templates.create(msg)
|
67
|
+
return
|
68
|
+
|
54
69
|
self.messages.append(msg)
|
55
|
-
if(msg['type']=='terminate'):
|
56
|
-
self.close(self.ws)
|
57
70
|
return msg
|
58
71
|
|
59
72
|
|
60
73
|
def __on_error(self, *args, **kwargs):
|
74
|
+
print(args)
|
61
75
|
logging.debug("MessageStreamReceiver error")
|
62
76
|
msg = {
|
63
77
|
"type": "log",
|
@@ -128,7 +142,7 @@ class MessageStreamReceiver(JobReceiver):
|
|
128
142
|
|
129
143
|
|
130
144
|
def connect(self):
|
131
|
-
self._status =
|
145
|
+
self._status = 0
|
132
146
|
path = self.__path()
|
133
147
|
logging.info(f"receive data from websocket: {path}")
|
134
148
|
self.ws = websocket.WebSocketApp(
|
@@ -12,9 +12,9 @@ import logging
|
|
12
12
|
|
13
13
|
|
14
14
|
class MessageStreamSender:
|
15
|
-
def __init__(self,
|
15
|
+
def __init__(self, input):
|
16
16
|
super().__init__()
|
17
|
-
self.
|
17
|
+
self.input = input
|
18
18
|
self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
|
19
19
|
self.__hasOpen = False
|
20
20
|
|
@@ -60,14 +60,14 @@ class MessageStreamSender:
|
|
60
60
|
同步方法连接ws
|
61
61
|
"""
|
62
62
|
self._status = 0
|
63
|
-
if self.
|
63
|
+
if self.input is None:
|
64
64
|
raise Exception("id is None")
|
65
|
-
if self.
|
65
|
+
if self.input == "00000000-0000-0000-0000-000000000000":
|
66
66
|
return
|
67
67
|
u = list(urlparse(self.origin))
|
68
68
|
head = "wss" if u[0] == "https" else "ws"
|
69
69
|
|
70
|
-
path = head + "://" + str(u[1]) + "/api/streams/token/" + self.
|
70
|
+
path = head + "://" + str(u[1]) + "/api/streams/token/" + self.input
|
71
71
|
logging.debug(f"MessageStreamSender data from websocket: {path}")
|
72
72
|
|
73
73
|
self.ws = websocket.WebSocketApp(
|