diff --git a/appPublic/oauth_client.py b/appPublic/oauth_client.py index 7ff5d30..931c76d 100644 --- a/appPublic/oauth_client.py +++ b/appPublic/oauth_client.py @@ -3,66 +3,107 @@ from appPublic.httpclient import HttpClient, RESPONSE_TEXT, RESPONSE_JSON, RESPO from appPublic.argsConvert import ArgsConvert 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('mapis') self.desc = desc self.data = desc.get('data') - self.mapis = desc.get('mapis') - self.mkeys = self.mapis.keys() - self._chunk_handle = chunk_handle + self.converters = converters self.ac = ArgsConvert('${', '}') - def stream_handle(self, chunk): - if self._chunk_handle: - self._chunk_handle(chunk) - else: - self.chunk_data = self.chunk_data + chunk + def setup_req_datas(self, data=[], ns={}): + d = {} + for h in headers: + d1 = self.setup_req_data(h, ns) + 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): - self.chunk_data = '' - if mapi not in self.mkeys: + if not self.desc.get(mapi): 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') method = d.get('method', 'GET') - headers = {} - for h in d.get('headers',{}): - headers[h.get('name')] = h.get('value') - mydata = {} - for p in d.get('data', {}): - 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 + myheaders = self.setup_req_data(self.api.headers, params) + myparams = self.setup_req_data(self.api.params, params) + mydata = self.setup_req_data(self.api.data, params) + url = self.api.get('url') + response_type = RESPONSE_JSON 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, - params=_params, - data=None if _data == {} else json.dumps(_data), - stream_func=self.stream_handle, - headers=_headers) - if not self._chunk_handle: - resp_data = self.chunk_data + params=None if myparams is None else myparams, + data=None if mydata is None else json.dumps(mydata), + headers=myheaders) if resp_data is None: - raise Exception(f'request error:{url=}\n{method=}\n{response_type=}\n{_params=}\n{_headers=}') - errfield = d.get('error_field') - err = resp_data.get(errfield) + return { + "status":"error", + "code":None + "message":"https error" + } + err = self.check_if_error(resp_data) if err: - msg = resp_data.get(d.get('error_msg_field')) - raise Exception(f'Error:{url}\n{msg}') - - 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 + return err + return self.setup_return_data(resp_data) def datalize(self, dic, data={}): mydata = self.data.copy() @@ -70,10 +111,51 @@ class OAuthClient: s1 = self.ac.convert(dic, mydata) return s1 - def is_error(self, resp_data, error_field): - if resp_data.get(error_feield): - return True - + def get_resp_data(self, resp, keys, converter=None): + d = resp.get_dic_data_by_keys(desc.keys) + 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): for dd in data_desc: f = dd['field']