2022-09-22 07:10:08 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import json
|
|
|
|
import secrets
|
|
|
|
import string
|
2023-05-16 23:27:13 -04:00
|
|
|
import time
|
2022-09-22 07:10:08 -04:00
|
|
|
from flask import Flask, request, send_from_directory
|
|
|
|
from flask.json import jsonify
|
|
|
|
from flask.json.provider import DefaultJSONProvider
|
|
|
|
|
|
|
|
import rpc
|
|
|
|
import util
|
2022-10-01 07:31:25 -04:00
|
|
|
import protoswitch
|
2022-09-22 07:10:08 -04:00
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
handler = logging.StreamHandler()
|
|
|
|
handler.setFormatter(logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s'))
|
|
|
|
logger.addHandler(handler)
|
|
|
|
logger.setLevel(logging.WARNING)
|
|
|
|
|
|
|
|
class JSONProviderX(DefaultJSONProvider):
|
|
|
|
@staticmethod
|
|
|
|
def default(obj):
|
|
|
|
return json.dumps(obj, sort_keys=True, default=str)
|
|
|
|
|
|
|
|
class CacheProxyRPC(util.CacheProxy):
|
|
|
|
def __init__(self, obj, persistent=None, volatile=None, prefix=''):
|
|
|
|
util.CacheProxy.__init__(self, obj)
|
|
|
|
if volatile is None:
|
|
|
|
volatile = util.Store().memo
|
2023-04-29 18:28:24 -04:00
|
|
|
self._cache(('__call__', 'close', 'authenticate', 'keepalive', 'XWB_CREATE_CONTEXT', 'TIU_TEMPLATE_SET_ITEMS', 'TIU_TEMPLATE_CREATE/MODIFY', 'TIU_TEMPLATE_DELETE', 'TIU_TEMPLATE_LOCK', 'TIU_TEMPLATE_UNLOCK', 'ORWDX_SAVE', 'ORWDXM1_BLDQRSP'), None)
|
2022-09-22 07:10:08 -04:00
|
|
|
self._cache(('XWB_GET_BROKER_INFO', 'XUS_INTRO_MSG'), volatile, prefix=prefix, ttl=float('inf'))
|
|
|
|
self._cache(None, volatile, prefix=prefix, ttl=float('-inf'))
|
2023-04-29 17:18:08 -04:00
|
|
|
self._cache_persistent(persistent=persistent, prefix=prefix)
|
2022-09-22 07:10:08 -04:00
|
|
|
def _cache_persistent(self, persistent=None, prefix=''):
|
|
|
|
if persistent is None:
|
|
|
|
persistent = util.Store().memo
|
2023-04-29 17:18:08 -04:00
|
|
|
self._cache(('SDEC_RESOURCE', 'ORWU1_NEWLOC', 'ORWLRR_ALLTESTS_ALL', 'ORWORDG_ALLTREE', 'ORWORDG_REVSTS', 'ORWDX_DGNM', 'ORWDX_ORDITM'), persistent, prefix=prefix, ttl=float('inf'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
2023-04-29 18:23:20 -04:00
|
|
|
def jsonify_result(value, id=None):
|
2023-05-16 23:27:13 -04:00
|
|
|
return jsonify({ 'result': value._base, 'error': None, 'id': request.json.get('id'), 'ts': value._ts, 'cached': True } if isinstance(value, util.Cached) else { 'result': value, 'error': None, 'id': request.json.get('id'), 'ts': time.time() })
|
2023-04-29 18:23:20 -04:00
|
|
|
|
|
|
|
def jsonify_error(ex, id=None):
|
|
|
|
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': id })
|
|
|
|
|
2022-09-22 07:10:08 -04:00
|
|
|
def application():
|
|
|
|
app = Flask(__name__)
|
|
|
|
app.json = JSONProviderX(app)
|
|
|
|
|
|
|
|
app.secret = secret = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for i in range(64))
|
|
|
|
clients = {}
|
|
|
|
|
|
|
|
@app.get('/')
|
|
|
|
def cb_index():
|
|
|
|
return send_from_directory('./htdocs', 'index.html')
|
|
|
|
|
|
|
|
@app.post('/v1/vista')
|
|
|
|
def cb_connect():
|
|
|
|
params = request.json['params']
|
2022-09-27 21:34:41 -04:00
|
|
|
try:
|
|
|
|
if params.get('secret') == secret:
|
2022-09-22 07:10:08 -04:00
|
|
|
cid = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for i in range(64))
|
2022-09-27 21:34:41 -04:00
|
|
|
while cid in clients:
|
|
|
|
cid = ''.join(secrets.choice(string.ascii_lowercase + string.digits) for i in range(64))
|
|
|
|
clients[cid] = client = CacheProxyRPC(rpc.ClientSync(host=params.get('host', 'test.northport.med.va.gov'), port=int(params.get('port', 19009))))
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_result(cid, id=request.json.get('id'))
|
2022-09-27 21:34:41 -04:00
|
|
|
else:
|
|
|
|
return jsonify({ 'result': None, 'error': { 'type': 'Unauthorized', 'args': [] }, 'id': request.json.get('id') })
|
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
2022-09-26 17:38:27 -04:00
|
|
|
@app.post('/v1/vista/<cid>/close')
|
|
|
|
def cb_close(cid):
|
|
|
|
try:
|
|
|
|
client = clients[cid]
|
|
|
|
res = client.close()
|
|
|
|
del clients[cid]
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_result(res, id=request.json.get('id'))
|
2022-09-26 17:38:27 -04:00
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-26 17:38:27 -04:00
|
|
|
|
2022-09-22 07:10:08 -04:00
|
|
|
@app.post('/v1/vista/<cid>/serverinfo')
|
|
|
|
def cb_serverinfo(cid):
|
|
|
|
try:
|
|
|
|
client = clients[cid]
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_result(client._obj._server, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
2023-05-29 18:32:13 -04:00
|
|
|
@app.post('/v1/vista/<cid>/authinfo')
|
|
|
|
def cb_authinfo(cid):
|
2022-09-22 07:10:08 -04:00
|
|
|
try:
|
|
|
|
client = clients[cid]
|
2023-05-29 18:32:13 -04:00
|
|
|
return jsonify_result(client._obj._auth, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
|
|
|
@app.post('/v1/vista/<cid>/authenticate')
|
|
|
|
def cb_authenticate(cid):
|
|
|
|
params = request.json['params']
|
|
|
|
try:
|
|
|
|
client = clients[cid]
|
|
|
|
if 'avcode' in params:
|
|
|
|
user = client.authenticate(params['avcode'])
|
2022-09-24 14:42:35 -04:00
|
|
|
client._cache_persistent(persistent=util.Store(f'cache.{client._server["volume"].lower()}.{client._server["uci"].lower()}.{user[0]}.db', journal_mode='WAL').memo)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_result(user, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
else:
|
|
|
|
from auth import XUIAMSSOi_MySsoTokenVBA
|
|
|
|
if token := XUIAMSSOi_MySsoTokenVBA():
|
|
|
|
user = client.authenticate(token)
|
2022-09-24 14:42:35 -04:00
|
|
|
client._cache_persistent(persistent=util.Store(f'cache.{client._server["volume"].lower()}.{client._server["uci"].lower()}.{user[0]}.db', journal_mode='WAL').memo)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_result(user, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
else:
|
|
|
|
return jsonify({ 'result': None, 'error': { 'type': 'Unauthorized', 'args': [] }, 'id': request.json.get('id') })
|
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
|
|
|
@app.post('/v1/vista/<cid>')
|
|
|
|
def cb_call1(cid):
|
|
|
|
try:
|
|
|
|
client = clients[cid]
|
|
|
|
data = request.json
|
2023-04-29 18:23:20 -04:00
|
|
|
kw = {}
|
2022-09-22 07:10:08 -04:00
|
|
|
if 'context' in data:
|
2023-04-29 18:23:20 -04:00
|
|
|
kw['context'] = data['context']
|
|
|
|
thunk = getattr(client, data['method'].upper())
|
|
|
|
if getattr(thunk, 'cached', False):
|
|
|
|
if 'ttl' in data:
|
|
|
|
kw['_cache_ttl'] = data['ttl']
|
|
|
|
if 'stale' in data:
|
|
|
|
kw['_cache_stale'] = data['stale']
|
|
|
|
return jsonify_result(thunk(*data.get('params', ()), **kw), id=data.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
|
|
|
@app.post('/v1/vista/<cid>/<method>')
|
|
|
|
def cb_call2(cid, method):
|
|
|
|
try:
|
|
|
|
client = clients[cid]
|
|
|
|
data = request.json
|
2023-04-29 18:23:20 -04:00
|
|
|
kw = {}
|
|
|
|
if 'context' in data:
|
|
|
|
kw['context'] = data['context']
|
|
|
|
thunk = getattr(client, method.upper())
|
|
|
|
if getattr(thunk, 'cached', False):
|
|
|
|
if 'ttl' in data:
|
|
|
|
kw['_cache_ttl'] = data['ttl']
|
|
|
|
if 'stale' in data:
|
|
|
|
kw['_cache_stale'] = data['stale']
|
|
|
|
return jsonify_result(thunk(*data.get('params', ()), **kw), id=data.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
except Exception as ex:
|
|
|
|
logger.exception(request.url)
|
2023-04-29 18:23:20 -04:00
|
|
|
return jsonify_error(ex, id=request.json.get('id'))
|
2022-09-22 07:10:08 -04:00
|
|
|
|
|
|
|
@app.get('/<path:path>')
|
|
|
|
def cb_static(path):
|
|
|
|
return send_from_directory('./htdocs', path if '.' in path.rsplit('/', 1)[-1] else 'index.html')
|
|
|
|
|
|
|
|
return app
|
|
|
|
|
|
|
|
def get_port():
|
|
|
|
import socket
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
sock.bind(('localhost', 0))
|
|
|
|
port = sock.getsockname()[1]
|
|
|
|
sock.close()
|
|
|
|
return port
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import webbrowser
|
2023-04-24 23:10:19 -04:00
|
|
|
|
2022-09-22 07:10:08 -04:00
|
|
|
app = application()
|
|
|
|
port = get_port()
|
|
|
|
print(f'http://localhost:{port}/#{app.secret}')
|
|
|
|
webbrowser.open(f'http://localhost:{port}/#{app.secret}')
|
2022-10-01 07:31:25 -04:00
|
|
|
app.run(port=port, request_handler=protoswitch.SwitchingRequestHandler)
|