This commit is contained in:
yumoqing 2025-07-09 17:23:32 +08:00
parent 90423ea035
commit 0b484b0adf
5 changed files with 112 additions and 56 deletions

View File

@ -1,6 +1,30 @@
{
"tblname":"uapi",
"params":{
"toolbar":{
"tools":[
{
"selected_row":true,
"name":"test",
"icon":"{{entire_url('/imgs/test.svg')}}",
"label": "api测试"
}
]
},
"binds":[
{
"wid":"self",
"event":"test",
"actiontype": "urlwidget",
"target":"PopupWindow",
"options":{
"methid":"POST",
"params":{},
"url":"{{entire_url('/uapi/uapi_test.ui')}}"
}
}
],
"title":"API",
"description":"API定义",
"sortby":"name",

View File

@ -11,7 +11,7 @@
"editexclouded":["id"],
"subtables":[
{
"field":"uapiid",
"field":"usid",
"subtable": "uapi",
"title": "API"
}

View File

@ -1,6 +1,26 @@
{
"tblname":"upappapis",
"params":{
"toolbar":{
"tools":[
{
"name":"test",
"icon":"{{entire_url('/imgs/test.svg')}}",
"label": "测试",
"selected_row":true
}
]
},
"binds":[
{
"wid":"self",
"event":"test",
"actiontype": "urlwidget",
"options":{
"url":"{{entire_url('/uapi/apitest.dspy')}}"
}
}
],
"title":"使用api集",
"description":"此系统使用的API集",
"sortby":"name",

View File

@ -4,10 +4,9 @@
"title":"上位系统密码",
"logined_userorgid":"ownerid",
"description":"上位系统密码",
"sortby":"name",
"confidential_fields":["akikey", "userpwd" ],
"confidential_fields":["apikey", "apipasswd" ],
"browserfields":{
"exclouded":["id"],
"exclouded":["id", "ownerid"],
"alters":{}
},
"editexclouded":["id", "upappid", "ownerid"]

View File

@ -4,55 +4,68 @@ from traceback import format_exc
from functools import partial
from sqlor.dbpools import DBPools
from appPublic.streamhttpclient import StreamHttpClient, liner
from appPublic.dictObject import DictObject
from appPublic.myTE import MyTemplateEngine
from appPublic.log import debug, exception, error
from ahserver.globalEnv import password_decode
from ahserver.serverenv import get_serverenv
def get_dbname():
f = get_serverenv('get_module_dbname')
dbname = f('uapi')
return dbname
class UAPI(StreamHttpClient):
def __init__(self, appid, env={}):
self.appid = appid
super().__init__()
class UAPI:
def __init__(self, env={}):
self.te = MyTemplateEngine([], env=env)
self.env = env
self.auth_api = None
self.auth_ret = None
async def tmplrender(self, tmplstr, params={}):
async def rendertmpl(self, tmplstr, params={}):
if tmplstr is None:
return None
ns = self.env.copy()
ns.update(params)
te = MyTemplateEngine([], env=self.env)
return te.renders(headerstmpl, ns)
return te.renders(tmplstr, ns)
async def make_call(self, request, upapiid, callerid,
params={},
stream=False,
env={}):
self.env.update(env)
async def cvt_upappapi2uapi(self, upappapiid, callerid, params={}):
self.env.update(params)
db = DBPools()
dbname = get_dbname()
uapi = None
auth_uapi = None
async with db.sqlorContext(dbname) as sor:
upapi = await self.get_upappapis(upapiid)
kinfo = await self.get_orgapikey(sor, upapi.upappid, callerid)
upappapi = await self.get_upappapis(sor, upappapiid)
kinfo = await self.get_orgapikey(sor, upappapi.upappid, callerid)
self.env.update(kinfo)
auth_uapi = None
if kinfo.auth_apiid:
auth_upapi = await self.get_upappapis(kinfo.auth_apiid)
auth_upapi = await self.get_upappapis(sor, kinfo.auth_apiid)
auth_uapi = await self.get_uapi(sor, kinfo.auth_upapi.uapiid)
uapi = await self.get_uapi(sor, upapi.uapiid)
uapi = await self.get_uapi(sor, upappapi.uapiid)
return auth_uapi, uapi
return None, None
async def __call__(self, upapiid, callerid, params={}):
"""
"""
auth_uapi, uapi = await self.cvt_upappapi2uapi(upapiid,
callerid, params=params)
if uapi is None:
return
if auth_uapi:
await self.do_auth(auth_uapi)
if stream:
return await self.do_stream_call(self, request, uapi, params=params)
else:
return await self.do_call(self, request, uapi, params=params)
async for line in self.stream_gen(uapi):
yield line
async def request(self, upapiid, callerid, params={}):
auth_uapi, uapi = await self.cvt_upappapi2uapi(upapiid,
callerid, params=params)
if auth_uapi:
await self.do_auth(auth_uapi)
return await self.do_call(uapi)
async def do_auth(self, auth_uapi):
b = await self.do_call(auth_uapi)
@ -60,65 +73,65 @@ class UAPI(StreamHttpClient):
self.env.update(d)
return
async def do_call(self, request, api, params={}):
async def do_call(self, api, params={}):
url = self.env.get('baseurl') + api.path
method = auth_uapi.httpmethod
header = self.rendertmpl(api.headers, params=params)
method = api.httpmethod
header = await self.rendertmpl(api.headers)
header = json.loads(headers)
body = self.rendertmpl(api.body, params=params)
_params = self.rendertmpl(api.params, params=params)
body = await self.rendertmpl(api.body)
_params = await self.rendertmpl(api.params)
if _params:
_params = json.loads(_params)
b = await self.request(method, url,
shc = StreamHttpClient()
b = await shc.request(method, url,
headers=headers,
body=body,
data=body,
params=_params)
d = json.loads(b.encode('utf-8'))
if api.response:
return self.rendertmpl(api.response, params=d)
return await self.rendertmpl(api.response, params=d)
return d
async def do_stream_call(self, request, api, params={}):
self.resp = web.StreamResponse()
await self.resp.prepare(request)
async def stream_gen(self, api, params={}):
url = self.env.get('baseurl') + api.path
method = auth_uapi.httpmethod
header = self.rendertmpl(api.headers, params=params)
header = json.loads(headers)
body = self.rendertmpl(api.body, params=params)
method = api.httpmethod
headers = await self.rendertmpl(api.headers)
headers = json.loads(headers)
body = await self.rendertmpl(api.body)
if body:
bdy = json.loads(body)
bdy['stream'] = True
body = bdy.dumps(bdy, ensure_ascii=False)
_params = self.rendertmpl(api.params, params=params)
_params = await self.rendertmpl(api.params)
if _params:
_params = json.loads(_params)
hc = StreamHttpClient()
gen = hc(method, url,
shc = StreamHttpClient()
gen = shc(method, url,
headers=headers,
body=body,
data=body,
params=_params)
self.chunk_match = self.api.chunk_match or ''
chunk_match = api.chunk_match or ''
cmlen = len(chunk_match)
async for line in liner(gen):
self.streamline_handle(line)
return self.resp
if line.startswith(chunk_match):
cvt_line = self.streamline_handle(line[cmlen:],
api.streamresponse)
if cvt_line is not None:
yield cvt_line
async def streamline_handle(self, line, resptmpl):
cnt = len(self.chunk_match)
line = line[cnt:]
try:
dic = json.loads(line)
if resptmpl:
jstr = self.rendertmpl(resptmpl, dic) + '\n'
jstr = await self.rendertmpl(resptmpl, params=dic)
jstr += '\n'
else:
jstr = json.dumps(self.resp_json, ensure_ascii=False) + '\n'
bin = jstr.encode('utf-8')
await self.resp.write(bin)
await self.resp.drain()
return jstr
except Exception as e:
exception(f'{line=}\n{e=},{format_exc()}')
return
return None
async def get_upappapis(self, sor, upapiid):
recs = await sor.R('upappapis', {'id': upapiid})
@ -150,7 +163,7 @@ a.myappid,
a.apisetid,
a.auth_apiid,
a.baseurl,
b.*,
b.*
from upapp a, upappkey b
where a.id = b.upappid
and a.id = ${appid}$
@ -161,13 +174,13 @@ where a.id = b.upappid
exception(f'{e}, {format_exc()}')
raise e
r = recs[0]
return {
return DictObject(**{
'apikey':r.apikey,
'secretkey':r.secretkey,
'apisetid': r.apisetid,
'auth_apiid': r.auth.apiid,
'auth_apiid': r.auth_apiid,
'myappid': r.myappid
}
})
async def get_authapi(self, sor):
sql = "select * from jsonhttpapi where name = 'auth' and appid=${appid}$"