This commit is contained in:
yumoqing 2024-04-21 06:27:07 +08:00
parent c8ff8f551e
commit 5447713c3a

View File

@ -3,66 +3,107 @@ from appPublic.httpclient import HttpClient, RESPONSE_TEXT, RESPONSE_JSON, RESPO
from appPublic.argsConvert import ArgsConvert from appPublic.argsConvert import ArgsConvert
class OAuthClient: class OAuthClient:
def __init__(self, desc, chunk_handle=None): """
OauthClient is a http(s) client for request a api annouce by other
it send https request and get back a json data
we can check the response json data to check if the call is success or failed
desc has the following format
{
"data": predefined data, and if nessory, you can add to new data to it
"method_name":{
"url"
"method",
"headers",
"params":arguments will appended to url with ?a=a&b=b...
"data":data will send in the request body, json format
"resp":[
{
"name":
"converter":default none, if not, convert response data first before set the returen data
"keys":resposne json data keys to achieve data
}
]
"error_if":{
"keys":
"op",
"value"
}
}
}
return:
if error:
return {
"status":"error",
"code":code returned by server
"message":"message returned by server
}
else:
return {
"status":"ok",
"data":...
}
"""
def __init__(self, desc, converters={}):
assert desc.get('data') assert desc.get('data')
assert desc.get('mapis')
self.desc = desc self.desc = desc
self.data = desc.get('data') self.data = desc.get('data')
self.mapis = desc.get('mapis') self.converters = converters
self.mkeys = self.mapis.keys()
self._chunk_handle = chunk_handle
self.ac = ArgsConvert('${', '}') self.ac = ArgsConvert('${', '}')
def stream_handle(self, chunk): def setup_req_datas(self, data=[], ns={}):
if self._chunk_handle: d = {}
self._chunk_handle(chunk) for h in headers:
else: d1 = self.setup_req_data(h, ns)
self.chunk_data = self.chunk_data + chunk d.update(d1)
if d == {}:
return None
return d
def setup_req_data(d, ns):
rd = {
d.name:d.value
}
nd = self.datalize(rd, ns)
if d.converter:
f = self.converters.get(d.converter)
if f:
nd[d.name] = f(nd.get(d.name))
return nd
async def __call__(self, mapi, params): async def __call__(self, mapi, params):
self.chunk_data = '' if not self.desc.get(mapi):
if mapi not in self.mkeys:
raise Exception(f'{mapi} not defined') raise Exception(f'{mapi} not defined')
d = self.mapis[mapi] self.api = self.desc[mapi]
if not self.api:
return {
"status":"error",
"code":'9999',
"message":f"{mapi} not defined"
}
assert d.get('url') assert d.get('url')
method = d.get('method', 'GET') method = d.get('method', 'GET')
headers = {} myheaders = self.setup_req_data(self.api.headers, params)
for h in d.get('headers',{}): myparams = self.setup_req_data(self.api.params, params)
headers[h.get('name')] = h.get('value') mydata = self.setup_req_data(self.api.data, params)
mydata = {} url = self.api.get('url')
for p in d.get('data', {}): response_type = RESPONSE_JSON
mydata[p.get('name')] = p.get('value')
myparams = {}
for p in d.get('params', {}):
myparams[p.get('name')] = p.get('value')
url = d.get('url')
_params = self.datalize(myparams, params)
_headers = self.datalize(headers, params)
_data = self.datalize(mydata, params)
response_type = RESPONSE_STREAM
hc = HttpClient() hc = HttpClient()
print(f'{url=}, {method=}, {_params=}, {_data=}, {_headers=}') print(f'{url=}, {method=}, {myparams=}, {mydata=}, {myheaders=}')
resp_data = await hc.request(url, method, response_type=response_type, resp_data = await hc.request(url, method, response_type=response_type,
params=_params, params=None if myparams is None else myparams,
data=None if _data == {} else json.dumps(_data), data=None if mydata is None else json.dumps(mydata),
stream_func=self.stream_handle, headers=myheaders)
headers=_headers)
if not self._chunk_handle:
resp_data = self.chunk_data
if resp_data is None: if resp_data is None:
raise Exception(f'request error:{url=}\n{method=}\n{response_type=}\n{_params=}\n{_headers=}') return {
errfield = d.get('error_field') "status":"error",
err = resp_data.get(errfield) "code":None
"message":"https error"
}
err = self.check_if_error(resp_data)
if err: if err:
msg = resp_data.get(d.get('error_msg_field')) return err
raise Exception(f'Error:{url}\n{msg}') return self.setup_return_data(resp_data)
respdesc= d.get('resp_set_data', [])
for r in respdesc:
v = resp_data[r['field']]
k = r['name']
self.data[k] = v
return resp_data
def datalize(self, dic, data={}): def datalize(self, dic, data={}):
mydata = self.data.copy() mydata = self.data.copy()
@ -70,9 +111,50 @@ class OAuthClient:
s1 = self.ac.convert(dic, mydata) s1 = self.ac.convert(dic, mydata)
return s1 return s1
def is_error(self, resp_data, error_field): def get_resp_data(self, resp, keys, converter=None):
if resp_data.get(error_feield): d = resp.get_dic_data_by_keys(desc.keys)
return True if converter:
f = self.converters.get(converter)
if f:
d = f(d)
return d
def setup_return_data(self, resp):
data = {}
for desc in self.api.resp:
k = desc.name
v = self.get_resp_data(resp, desc.keys, desc.converter)
data[k] = v
return {
"status":"ok",
"data":data
}
def check_if_error(self, resp, error_field):
if not self.api.error_if:
return None
ei = self.api.error_if
v = resp.get_dic_data_by_keys(ei.keys)
v1 = ei.value
if ei.converter:
f = self.converters.get(ei.converter)
if f:
v = f(v)
if not ei.op:
ei.op = '=='
if ei.op in ['==', '='] and v == v1 or ei.op == '!=' and v != v1:
code = None
message = None
if ei.code_keys:
code = resp.get_dic_data_by_keys(ei.code_keys)
if ei.msg_keys:
message = resp.get_dic_data_by_keys(ei.msg_keys)
return {
"status":"error",
"code:code,
"message":message
}
return None
def set_data(self, resp_data, data_desc): def set_data(self, resp_data, data_desc):
for dd in data_desc: for dd in data_desc: