bugfix
This commit is contained in:
parent
66f16d3e87
commit
54109828b6
13
json/uapi.json
Normal file
13
json/uapi.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"tblname":"uapi",
|
||||||
|
"params":{
|
||||||
|
"title":"API",
|
||||||
|
"description":"API定义",
|
||||||
|
"sortby":"name",
|
||||||
|
"browserfields":{
|
||||||
|
"exclouded":["id"],
|
||||||
|
"alters":{}
|
||||||
|
},
|
||||||
|
"editexclouded":["id", "usid"]
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,13 @@
|
|||||||
"exclouded":["id"],
|
"exclouded":["id"],
|
||||||
"alters":{}
|
"alters":{}
|
||||||
},
|
},
|
||||||
"editexclouded":["id"]
|
"editexclouded":["id"],
|
||||||
|
"subtables":[
|
||||||
|
{
|
||||||
|
"field":"uapiid",
|
||||||
|
"subtable": "uapi",
|
||||||
|
"title": "API"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,18 @@
|
|||||||
"exclouded":["id"],
|
"exclouded":["id"],
|
||||||
"alters":{}
|
"alters":{}
|
||||||
},
|
},
|
||||||
"editexclouded":["id"]
|
"editexclouded":["id"],
|
||||||
|
"subtables":[
|
||||||
|
{
|
||||||
|
"field":"upappid",
|
||||||
|
"subtable": "upappapis",
|
||||||
|
"title": "API集"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field":"upappid",
|
||||||
|
"subtable": "upappkey",
|
||||||
|
"title": "APIKEY"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
"exclouded":["id"],
|
"exclouded":["id"],
|
||||||
"alters":{}
|
"alters":{}
|
||||||
},
|
},
|
||||||
"editexclouded":["id"]
|
"editexclouded":["id", "upappid"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"tblname":"upappkey",
|
"tblname":"upappkey",
|
||||||
"params":{
|
"params":{
|
||||||
"title":"上位系统密码",
|
"title":"上位系统密码",
|
||||||
|
"logined_userorgid":"ownerid",
|
||||||
"description":"上位系统密码",
|
"description":"上位系统密码",
|
||||||
"sortby":"name",
|
"sortby":"name",
|
||||||
"confidential_fields":["akikey", "userpwd" ],
|
"confidential_fields":["akikey", "userpwd" ],
|
||||||
@ -9,6 +10,6 @@
|
|||||||
"exclouded":["id"],
|
"exclouded":["id"],
|
||||||
"alters":{}
|
"alters":{}
|
||||||
},
|
},
|
||||||
"editexclouded":["id"]
|
"editexclouded":["id", "upappid", "ownerid"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
models/uapi.xlsx
BIN
models/uapi.xlsx
Binary file not shown.
Binary file not shown.
52
setup.py
52
setup.py
@ -1,52 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from uapi.version import __version__
|
|
||||||
try:
|
|
||||||
from setuptools import setup
|
|
||||||
except ImportError:
|
|
||||||
from distutils.core import setup
|
|
||||||
required = []
|
|
||||||
with open('requirements.txt', 'r') as f:
|
|
||||||
ls = f.read()
|
|
||||||
required = ls.split('\n')
|
|
||||||
|
|
||||||
with open('uapi/version.py', 'r') as f:
|
|
||||||
x = f.read()
|
|
||||||
y = x[x.index("'")+1:]
|
|
||||||
z = y[:y.index("'")]
|
|
||||||
version = z
|
|
||||||
with open("README.md", "r") as fh:
|
|
||||||
long_description = fh.read()
|
|
||||||
|
|
||||||
name = "uapi"
|
|
||||||
description = "uapi"
|
|
||||||
author = "yumoqing"
|
|
||||||
email = "yumoqing@gmail.com"
|
|
||||||
|
|
||||||
package_data = {}
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="uapi",
|
|
||||||
version=version,
|
|
||||||
|
|
||||||
# uncomment the following lines if you fill them out in release.py
|
|
||||||
description=description,
|
|
||||||
author=author,
|
|
||||||
author_email=email,
|
|
||||||
platforms='any',
|
|
||||||
install_requires=required ,
|
|
||||||
packages=[
|
|
||||||
"uapi"
|
|
||||||
],
|
|
||||||
package_data=package_data,
|
|
||||||
keywords = [
|
|
||||||
],
|
|
||||||
url="https://github.com/yumoqing/uapi",
|
|
||||||
long_description=long_description,
|
|
||||||
long_description_content_type="text/markdown",
|
|
||||||
classifiers = [
|
|
||||||
'Operating System :: OS Independent',
|
|
||||||
'Programming Language :: Python :: 3',
|
|
||||||
'License :: OSI Approved :: MIT License',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1 +0,0 @@
|
|||||||
from .version import __version__
|
|
244
uapi/appapi.py
244
uapi/appapi.py
@ -1,17 +1,174 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from traceback import format_exc
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from sqlor.dbpools import DBPools
|
from sqlor.dbpools import DBPools
|
||||||
from appPublic.httpclient import JsonHttpAPI
|
from appPublic.streamhttpclient import StreamHttpClient, liner
|
||||||
from appPublic.log import debug, exception,
|
from appPublic.log import debug, exception, error
|
||||||
from ahserver.globalEnv import password_decode
|
from ahserver.globalEnv import password_decode
|
||||||
from aiohttp import web
|
|
||||||
|
|
||||||
class AppAPI(JsonHttpAPI):
|
def get_dbname():
|
||||||
|
f = get_serverenv('get_module_dbname')
|
||||||
|
dbname = f('uapi')
|
||||||
|
return dbname
|
||||||
|
|
||||||
|
class UAPI(StreamHttpClient):
|
||||||
def __init__(self, appid, env={}):
|
def __init__(self, appid, env={}):
|
||||||
self.appid = appid
|
self.appid = appid
|
||||||
super().__init__(env=env)
|
super().__init__()
|
||||||
|
self.te = MyTemplateEngine([], env=env)
|
||||||
|
self.env = env
|
||||||
self.auth_api = None
|
self.auth_api = None
|
||||||
self.auth_ret = None
|
self.auth_ret = None
|
||||||
|
|
||||||
|
async def tmplrender(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)
|
||||||
|
|
||||||
|
async def make_call(self, request, upapiid, callerid,
|
||||||
|
params={},
|
||||||
|
stream=False,
|
||||||
|
env={}):
|
||||||
|
self.env.update(env)
|
||||||
|
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)
|
||||||
|
self.env.update(kinfo)
|
||||||
|
auth_uapi = None
|
||||||
|
if kinfo.auth_apiid:
|
||||||
|
auth_upapi = await self.get_upappapis(kinfo.auth_apiid)
|
||||||
|
auth_uapi = await self.get_uapi(sor, kinfo.auth_upapi.uapiid)
|
||||||
|
uapi = await self.get_uapi(sor, upapi.uapiid)
|
||||||
|
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 def do_auth(self, auth_uapi):
|
||||||
|
b = await self.do_call(auth_uapi)
|
||||||
|
d = json.loads(b.encode('utf-8'))
|
||||||
|
self.env.update(d)
|
||||||
|
return
|
||||||
|
|
||||||
|
async def do_call(self, request, 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)
|
||||||
|
_params = self.rendertmpl(api.params, params=params)
|
||||||
|
if _params:
|
||||||
|
_params = json.loads(_params)
|
||||||
|
b = await self.request(method, url,
|
||||||
|
headers=headers,
|
||||||
|
body=body,
|
||||||
|
params=_params)
|
||||||
|
|
||||||
|
d = json.loads(b.encode('utf-8'))
|
||||||
|
if api.response:
|
||||||
|
return 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)
|
||||||
|
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)
|
||||||
|
if body:
|
||||||
|
bdy = json.loads(body)
|
||||||
|
bdy['stream'] = True
|
||||||
|
body = bdy.dumps(bdy, ensure_ascii=False)
|
||||||
|
_params = self.rendertmpl(api.params, params=params)
|
||||||
|
if _params:
|
||||||
|
_params = json.loads(_params)
|
||||||
|
hc = StreamHttpClient()
|
||||||
|
gen = hc(method, url,
|
||||||
|
headers=headers,
|
||||||
|
body=body,
|
||||||
|
params=_params)
|
||||||
|
self.chunk_match = self.api.chunk_match or ''
|
||||||
|
async for line in liner(gen):
|
||||||
|
self.streamline_handle(line)
|
||||||
|
return self.resp
|
||||||
|
|
||||||
|
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'
|
||||||
|
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()
|
||||||
|
except Exception as e:
|
||||||
|
exception(f'{line=}\n{e=},{format_exc()}')
|
||||||
|
return
|
||||||
|
|
||||||
|
async def get_upappapis(self, sor, upapiid):
|
||||||
|
recs = await sor.R('upappapis', {'id': upapiid})
|
||||||
|
if len(recs) < 1:
|
||||||
|
e = Exception(f'{upapiid} not found in table(upappapis)')
|
||||||
|
exception(f'{e}\n{format_exc()}')
|
||||||
|
raise e
|
||||||
|
return recs[0]
|
||||||
|
|
||||||
|
async def get_uapi(self, sor, uapiid):
|
||||||
|
recs = await sor.R('uapi', {'id': uapiid})
|
||||||
|
if len(recs) < 1:
|
||||||
|
e = Exception(f'{uapiid} not found in table(uapi)')
|
||||||
|
exception(f'{e}\n{format_exc()}')
|
||||||
|
raise e
|
||||||
|
return recs[0]
|
||||||
|
|
||||||
|
async def get_orgapikey(self, sor, upappid, callerid):
|
||||||
|
"""
|
||||||
|
argumemts:
|
||||||
|
upappid: upappid which will make call to
|
||||||
|
orgid: owner organization or user which as the caller of the call
|
||||||
|
return:
|
||||||
|
None: this orgid has not gotton apikey from upapp
|
||||||
|
dict if apikey and upapp infos
|
||||||
|
"""
|
||||||
|
sql = """select
|
||||||
|
a.myappid,
|
||||||
|
a.apisetid,
|
||||||
|
a.auth_apiid,
|
||||||
|
a.baseurl,
|
||||||
|
b.*,
|
||||||
|
from upapp a, upappkey b
|
||||||
|
where a.id = b.upappid
|
||||||
|
and a.id = ${appid}$
|
||||||
|
and b.ownerid = ${orgid}$"""
|
||||||
|
recs = await sor.sqlExe(sql, {'appid':upappid, 'orgid': callerid})
|
||||||
|
if len(recs) < 1:
|
||||||
|
e = Exception(f'{appid=}, {callerid=} has not apikey')
|
||||||
|
exception(f'{e}, {format_exc()}')
|
||||||
|
raise e
|
||||||
|
r = recs[0]
|
||||||
|
return {
|
||||||
|
'apikey':r.apikey,
|
||||||
|
'secretkey':r.secretkey,
|
||||||
|
'apisetid': r.apisetid,
|
||||||
|
'auth_apiid': r.auth.apiid,
|
||||||
|
'myappid': r.myappid
|
||||||
|
}
|
||||||
|
|
||||||
async def get_authapi(self, sor):
|
async def get_authapi(self, sor):
|
||||||
sql = "select * from jsonhttpapi where name = 'auth' and appid=${appid}$"
|
sql = "select * from jsonhttpapi where name = 'auth' and appid=${appid}$"
|
||||||
recs = await sor.sqlExe(sql, {'appid': self.appid})
|
recs = await sor.sqlExe(sql, {'appid': self.appid})
|
||||||
@ -59,80 +216,3 @@ where
|
|||||||
return recs[0]
|
return recs[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def request(self, apiname, ns):
|
|
||||||
orgs = ns.get('orgs')
|
|
||||||
api = await self.get_apiinfo(orgs, apiname)
|
|
||||||
if api is None:
|
|
||||||
e = Exception(f'{self.appid} app has not {apiname} api')
|
|
||||||
exception(f'{e=}, {format_exc()}')
|
|
||||||
raise e
|
|
||||||
ns1 = self.env.copy()
|
|
||||||
ns1['apikey'] = api.apikey
|
|
||||||
ns1['secretkey'] = api.secretkey
|
|
||||||
ns1.update(ns)
|
|
||||||
if api.need_auth:
|
|
||||||
if self.auth_ret is None:
|
|
||||||
auth_url = api.baseurl + self.auth_api.path
|
|
||||||
self.auth_ret = await self.call(auth_url,
|
|
||||||
method=self.auth_api.httpmethod,
|
|
||||||
ns=ns1,
|
|
||||||
headerstmpl=self.auth_api.headers,
|
|
||||||
paramstmpl=self.auth_api.params,
|
|
||||||
datatmpl=self.auth_api.data,
|
|
||||||
resptmpl=self.auth_api.response)
|
|
||||||
if self.auth_ret is None:
|
|
||||||
e = Exception(f'{self.appid} app auth error')
|
|
||||||
exception(f'{e=}, {format_exc()}')
|
|
||||||
raise e
|
|
||||||
ns1.update(self.auth_ret)
|
|
||||||
stream_func = None
|
|
||||||
if api.stream:
|
|
||||||
await self.stream_begin()
|
|
||||||
stream_func = partial(self.stream_func, api, ns1)
|
|
||||||
url = api.baseurl + api.path
|
|
||||||
ret = await self.call(url, method=api.httpmethod, ns=ns1,
|
|
||||||
stream_func = stream_func,
|
|
||||||
headerstmpl=api.headers,
|
|
||||||
paramstmpl=api.params,
|
|
||||||
datatmpl=api.data,
|
|
||||||
resptmpl=api.response)
|
|
||||||
if api.stream:
|
|
||||||
return await self.stream_end()
|
|
||||||
return ret
|
|
||||||
|
|
||||||
async def stream_begin(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def stream_end(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def stream_func(self, api, ns, chunk):
|
|
||||||
if api.chunk_match:
|
|
||||||
chunk = chunk[len(api.chunk_match):]
|
|
||||||
d = chunk
|
|
||||||
if api.streamresponse:
|
|
||||||
d = json.loads(chunk)
|
|
||||||
ns1 = ns.copy()
|
|
||||||
ns1.update(d)
|
|
||||||
d = self.te.renders(api.streamresponse, ns1)
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
class AiohttpAppAPI(AppAPI):
|
|
||||||
async def request(self, request, apiname, ns):
|
|
||||||
self.request = request
|
|
||||||
return await super().request(apiname, ns)
|
|
||||||
|
|
||||||
async def stream_begin(self):
|
|
||||||
self.resp = web.StreamResponse()
|
|
||||||
await self.resp.prepare(request)
|
|
||||||
|
|
||||||
async def stream_end(self):
|
|
||||||
return self.resp
|
|
||||||
|
|
||||||
async def stream_func(self, api, ns, chunk):
|
|
||||||
d = super().stream_func(api, ns, chuck)
|
|
||||||
b = d.encode('utf-8')
|
|
||||||
await self.resp.write(bin)
|
|
||||||
await self.resp.drain()
|
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from ahserver.serverenv import ServerEnv
|
from ahserver.serverenv import ServerEnv
|
||||||
from .appapi import AppAPI, AiohttpAppAPI
|
from .appapi import UAPI
|
||||||
|
|
||||||
def load_uapi():
|
def load_uapi():
|
||||||
g = ServerEnv()
|
g = ServerEnv()
|
||||||
g.AiohttpAppAPI = AiohttpAppAPI
|
g.UAPI = UAPI
|
||||||
g.AppAPI = AppAPI
|
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
__version__ = '0.0.1'
|
|
Loading…
Reference in New Issue
Block a user