Compare commits
3 Commits
d4f6985cef
...
ece8338ac8
Author | SHA1 | Date | |
---|---|---|---|
ece8338ac8 | |||
fdc7ed4c05 | |||
a83e8cb22c |
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div v-if="(age === undefined) || (age > 0)" class="alert alert-warning">⚠ update error<template v-if="age >= 90000">; last updated {{Math.round(age/60000)}} minutes ago</template></div>
|
||||
<template v-if="age !== undefined">
|
||||
<div v-if="age == Infinity" class="alert alert-danger">❌ update error</div>
|
||||
<div v-else-if="age >= 90000" class="alert alert-warning">⚠ last updated <template v-if="age < 3600000">{{ts.toLocaleString()}}</template><template v-else>{{ts.toLocaleString()}}</template></div>
|
||||
</template>
|
||||
<table class="table" style="font-family: monospace;" v-if="appointments && appointments.length > 0">
|
||||
<thead>
|
||||
<tr><th style="width: 7rem;">Time</th><th>Clinic</th><th>Patient</th><th>Note</th><th style="width: 16rem;">Assignee</th></tr>
|
||||
@ -71,7 +74,7 @@
|
||||
return {
|
||||
appointments: [],
|
||||
ts: null,
|
||||
age: 0
|
||||
age: undefined
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -87,11 +90,14 @@
|
||||
async update() {
|
||||
try {
|
||||
this.appointments = (await this.client.SDEC_CRSCHED(this.selection.join('|') + '|', strfdate_vista(this.date_begin), strfdate_vista(this.date_end) + '@2359')).sort((a, b) => (new Date(a.START_TIME)) - (new Date(b.START_TIME)));
|
||||
this.ts = new Date();
|
||||
this.age = 0;
|
||||
var now = new Date();
|
||||
this.ts = this.appointments._ts ? new Date(1000*this.appointments._ts) : now;
|
||||
this.age = now - this.ts;
|
||||
this.timer = window.setTimeout(this.update, Math.max(60000 - this.age, 10000));
|
||||
} catch(ex) {
|
||||
this.age = this.ts ? (new Date()) - this.ts : undefined;
|
||||
this.age = this.ts ? (new Date()) - this.ts : Infinity;
|
||||
console.warn(ex);
|
||||
this.timer = window.setTimeout(this.update, 30000);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -99,14 +105,13 @@
|
||||
this.$watch(
|
||||
() => (this.client, this.selection, this.date_begin, this.date_end, {}),
|
||||
debounce(async () => {
|
||||
window.clearInterval(this.timer);
|
||||
window.clearTimeout(this.timer);
|
||||
this.update();
|
||||
this.timer = window.setInterval(this.update, 60000);
|
||||
}, 500)
|
||||
);
|
||||
},
|
||||
unmounted() {
|
||||
window.clearInterval(this.timer);
|
||||
window.clearTimeout(this.timer);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -14,19 +14,11 @@ export async function close(cid) {
|
||||
})).json();
|
||||
}
|
||||
|
||||
export async function call(cid, method, ...params) {
|
||||
export async function call(cid, body) {
|
||||
return await (await fetch('/v1/vista/' + cid, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ method: method, params: params, id: Date.now() })
|
||||
})).json();
|
||||
}
|
||||
|
||||
export async function callctx(cid, context, method, ...params) {
|
||||
return await (await fetch('/v1/vista/' + cid, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ method: method, params: params, context: context, id: Date.now() })
|
||||
body: JSON.stringify(body)
|
||||
})).json();
|
||||
}
|
||||
|
||||
@ -55,5 +47,5 @@ export async function authenticate(cid, avcode=null) {
|
||||
}
|
||||
|
||||
export default window.vista = {
|
||||
connect, close, call, callctx, serverinfo, userinfo, authenticate
|
||||
connect, close, call, serverinfo, userinfo, authenticate
|
||||
};
|
||||
|
@ -33,7 +33,10 @@ export function unwrapped(fn) {
|
||||
return async function(...args) {
|
||||
var res = await fn(...args);
|
||||
if(res.error) throw new RPCError(res.error.type, ...res.error.args);
|
||||
else return res.result;
|
||||
if(res.ts) try {
|
||||
res.result._ts = res.ts;
|
||||
} catch(ex) {}
|
||||
return res.result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,15 +292,19 @@ export function Client(cid, secret) {
|
||||
this.connected.value = false;
|
||||
return vista.close(cid);
|
||||
};
|
||||
this.call = async function(method, ...params) {
|
||||
var res = await vista.call(cid, method, ...params);
|
||||
this.call = async function(body, ...params) {
|
||||
body = (typeof body === 'string') || (body instanceof String) ? { method: body, params, id: Date.now() } : Object.assign({ id: Date.now() }, body);
|
||||
if(params.length > 0) {
|
||||
if(body.params) Array.prototype.push.apply(body.params, params);
|
||||
else body.params = params;
|
||||
}
|
||||
var res = await vista.call(cid, body);
|
||||
if((res.error) && (res.error.type == 'ConnectionResetError')) this.close();
|
||||
res._request = body;
|
||||
return res;
|
||||
};
|
||||
this.callctx = async function(context, method, ...params) {
|
||||
var res = vista.callctx(cid, context, method, ...params);
|
||||
if((res.error) && (res.error.type == 'ConnectionResetError')) this.close();
|
||||
return res;
|
||||
this.callctx = function(context, method, ...params) {
|
||||
return this.call({ context, method, params, id: Date.now() });
|
||||
};
|
||||
this.heartbeat = async function(interval=null) {
|
||||
if(!interval) interval = 0.45*1000*(await this.XWB_GET_BROKER_INFO())[0];
|
||||
@ -332,15 +339,15 @@ export function Client(cid, secret) {
|
||||
if(localstate.practitioner) delete localstate.practitioner;
|
||||
};
|
||||
|
||||
this.XWB_IM_HERE = unwrapped(logged(() => this.call('XWB_IM_HERE'), 'XWB_IM_HERE'));
|
||||
this.XWB_IM_HERE = unwrapped(logged(() => this.call({ method: 'XWB_IM_HERE', ttl: 30 }), 'XWB_IM_HERE'));
|
||||
|
||||
this.XUS_INTRO_MSG = memoized(unwrapped(logged(() => this.callctx(['XUCOMMAND'], 'XUS_INTRO_MSG'), 'XUS_INTRO_MSG')));
|
||||
this.XWB_GET_BROKER_INFO = memoized(unwrapped(logged(() => this.callctx(['XUCOMMAND'], 'XWB_GET_BROKER_INFO'), 'XWB_GET_BROKER_INFO')));
|
||||
this.XUS_GET_USER_INFO = memoized(unwrapped(logged(() => this.call('XUS_GET_USER_INFO'), 'XUS_GET_USER_INFO')));
|
||||
|
||||
this.SDEC_RESOURCE = memoized(unwrapped(logged(() => this.callctx(['SDECRPC'], 'SDEC_RESOURCE'), 'SDEC_RESOURCE')));
|
||||
this.SDEC_CLINLET = memoized(unwrapped(logged((...args) => this.callctx(['SDECRPC'], 'SDEC_CLINLET', ...args), 'SDEC_CLINLET')));
|
||||
this.SDEC_CRSCHED = unwrapped(logged((...args) => this.callctx(['SDECRPC'], 'SDEC_CRSCHED', ...args), 'SDEC_CRSCHED'));
|
||||
this.SDEC_RESOURCE = memoized(unwrapped(logged(() => this.call({ method: 'SDEC_RESOURCE', context: ['SDECRPC'], ttl: 2592000 }), 'SDEC_RESOURCE')));
|
||||
this.SDEC_CLINLET = unwrapped(logged((...args) => this.call({ method: 'SDEC_CLINLET', context: ['SDECRPC'], ttl: 30 }, ...args), 'SDEC_CLINLET'));
|
||||
this.SDEC_CRSCHED = unwrapped(logged((...args) => this.call({ method: 'SDEC_CRSCHED', context: ['SDECRPC'], ttl: 30 }, ...args), 'SDEC_CRSCHED'));
|
||||
|
||||
this.ORWPT_FULLSSN = memoized(caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_FULLSSN', ...args), 'ORWPT_FULLSSN')), ['dfn', 'name', 'date', 'pid']));
|
||||
this.ORWPT_LAST5 = memoized(caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWPT_LAST5', ...args), 'ORWPT_LAST5')), ['dfn', 'name', 'date', 'pid']));
|
||||
@ -362,15 +369,15 @@ export function Client(cid, secret) {
|
||||
this.ORWORR_AGET = memoized(caretseparated(sliced(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWORR_AGET', ...args), 'ORWORR_AGET')), 1), ['ifn', 'dgrp', 'time']));
|
||||
this.ORWORR_GET4LST = memoized(parsed_orderinfo(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWORR_GET4LST', ...args), 'ORWORR_GET4LST'))));
|
||||
|
||||
this.TIU_TEMPLATE_GETROOTS = caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_GETROOTS', ...args), 'TIU_TEMPLATE_GETROOTS')), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_GETPROOT = caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_GETPROOT', ...args), 'TIU_TEMPLATE_GETPROOT')), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_GETBOIL = parsed_text(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_GETBOIL', ...args), 'TIU_TEMPLATE_GETBOIL')));
|
||||
this.TIU_TEMPLATE_GETITEMS = caretseparated(parsed_nullarray(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_GETITEMS', ...args), 'TIU_TEMPLATE_GETITEMS'))), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_SET_ITEMS = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_SET_ITEMS', ...args), 'TIU_TEMPLATE_SET_ITEMS'));
|
||||
this.TIU_TEMPLATE_CREATE_MODIFY = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_CREATE/MODIFY', ...args), 'TIU_TEMPLATE_CREATE/MODIFY'));
|
||||
this.TIU_TEMPLATE_DELETE = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_DELETE', ...args), 'TIU_TEMPLATE_DELETE'));
|
||||
this.TIU_TEMPLATE_LOCK = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_LOCK', ...args), 'TIU_TEMPLATE_LOCK'));
|
||||
this.TIU_TEMPLATE_UNLOCK = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'TIU_TEMPLATE_UNLOCK', ...args), 'TIU_TEMPLATE_UNLOCK'));
|
||||
this.TIU_TEMPLATE_GETROOTS = caretseparated(unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_GETROOTS', context: ['OR CPRS GUI CHART'], ttl: 86400 }, ...args), 'TIU_TEMPLATE_GETROOTS')), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_GETPROOT = caretseparated(unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_GETPROOT', context: ['OR CPRS GUI CHART'], ttl: 86400 }, ...args), 'TIU_TEMPLATE_GETPROOT')), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_GETBOIL = parsed_text(unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_GETBOIL', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_GETBOIL')));
|
||||
this.TIU_TEMPLATE_GETITEMS = caretseparated(parsed_nullarray(unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_GETITEMS', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_GETITEMS'))), ['IEN', 'type', 'status', 'name', 'exclude_from_group_boilerplate', 'blank_lines', 'personal_owner', 'has_children_flag', 'dialog', 'display_only', 'first_line', 'one_item_only', 'hide_dialog_items', 'hide_tree_items', 'indent_items', 'reminder_dialog_ien', 'reminder_dialog_name', 'locked', 'com_object_pointer', 'com_object_parameter', 'link_pointer', 'reminder_dialog_patient_specific_value']);
|
||||
this.TIU_TEMPLATE_SET_ITEMS = unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_SET_ITEMS', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_SET_ITEMS'));
|
||||
this.TIU_TEMPLATE_CREATE_MODIFY = unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_CREATE/MODIFY', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_CREATE/MODIFY'));
|
||||
this.TIU_TEMPLATE_DELETE = unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_DELETE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_DELETE'));
|
||||
this.TIU_TEMPLATE_LOCK = unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_LOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_LOCK'));
|
||||
this.TIU_TEMPLATE_UNLOCK = unwrapped(logged((...args) => this.call({ method: 'TIU_TEMPLATE_UNLOCK', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'TIU_TEMPLATE_UNLOCK'));
|
||||
|
||||
this.ORWCV_VST = memoized(caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWCV_VST', ...args), 'ORWCV_VST')), ['apptinfo', 'datetime', 'location', 'status']));
|
||||
|
||||
@ -383,11 +390,11 @@ export function Client(cid, secret) {
|
||||
this.ORWDX_DLGID = memoized(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DLGID', ...args), 'ORWDX_DLGID')));
|
||||
this.ORWDX_DLGDEF = memoized(mapped(caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_DLGDEF', ...args), 'ORWDX_DLGDEF')), ['promptID', 'promptIEN', 'fmtSeq', 'fmtCode', 'omit', 'lead', 'trail', 'newLine', 'wrap', 'children', 'isChild']), 'promptID'));
|
||||
this.ORWDX_LOADRSP = memoized(mapped(parsed_orderoverrides(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_LOADRSP', ...args), 'ORWDX_LOADRSP')), ['promptID', 'promptIEN', 'fmtSeq', 'fmtCode', 'omit', 'lead', 'trail', 'newLine', 'wrap', 'children', 'isChild']), 'promptID'));
|
||||
this.ORWDX_SAVE = unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDX_SAVE', ...args), 'ORWDX_SAVE'));
|
||||
this.ORWDX_SAVE = unwrapped(logged((...args) => this.call({ method: 'ORWDX_SAVE', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'ORWDX_SAVE'));
|
||||
this.ORWDXM_MENU = memoized(parsed_ordermenu(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_MENU', ...args), 'ORWDXM_MENU'))));
|
||||
this.ORWDXM_DLGNAME = memoized(caretseparated1(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_DLGNAME', ...args), 'ORWDXM_DLGNAME')), ['InternalName', 'DisplayName', 'BaseDialogIEN', 'BaseDialogName']));
|
||||
this.ORWDXM_PROMPTS = memoized(mapped(parsed_caretseparated_detail(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM_PROMPTS', ...args), 'ORWDXM_PROMPTS')), ['id', 'req', 'hid', 'prompt', 'type', 'domain', 'default', 'idflt', 'help']), 'id'));
|
||||
this.ORWDXM1_BLDQRSP = caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWDXM1_BLDQRSP', ...args), 'ORWDXM1_BLDQRSP')), ['QuickLevel', 'ResponseID', 'Dialog', 'Type', 'FormID', 'DGrpLST']);
|
||||
this.ORWDXM1_BLDQRSP = caretseparated(unwrapped(logged((...args) => this.call({ method: 'ORWDXM1_BLDQRSP', context: ['OR CPRS GUI CHART'], ttl: 0, stale: false }, ...args), 'ORWDXM1_BLDQRSP')), ['QuickLevel', 'ResponseID', 'Dialog', 'Type', 'FormID', 'DGrpLST']);
|
||||
this.ORWUL_FV4DG = memoized(caretseparated1(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FV4DG', ...args), 'ORWUL_FV4DG')), ['IEN', 'count']));
|
||||
this.ORWUL_FVSUB = memoized(caretseparated(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FVSUB', ...args), 'ORWUL_FVSUB')), ['IEN', 'description']));
|
||||
this.ORWUL_FVIDX = memoized(caretseparated1(unwrapped(logged((...args) => this.callctx(['OR CPRS GUI CHART'], 'ORWUL_FVIDX', ...args), 'ORWUL_FVIDX')), ['index', 'description']));
|
||||
@ -456,7 +463,7 @@ Client.fromCookie = async function(secret, defaulthost='vista.northport.med.va.g
|
||||
console.log('Using saved secret and connection', secret);
|
||||
var cid = localstate.cid;
|
||||
var client = Client.fromID(cid, secret);
|
||||
if((await vista.call(cid, 'XWB_IM_HERE')).result == '1') {
|
||||
if((await vista.call(cid, { method: 'XWB_IM_HERE', ttl: 30, id: Date.now() })).result == '1') {
|
||||
var server = await client.serverinfo();
|
||||
if((host[0] == server.result.host) && (host[1] == server.result.port)) {
|
||||
localstate.host = host.join(':');
|
||||
|
57
main.py
57
main.py
@ -29,7 +29,7 @@ class CacheProxyRPC(util.CacheProxy):
|
||||
util.CacheProxy.__init__(self, obj)
|
||||
if volatile is None:
|
||||
volatile = util.Store().memo
|
||||
self._cache(('__call__', 'close', 'authenticate', 'keepalive', 'XWB_CREATE_CONTEXT', 'XWB_IM_HERE', 'TIU_TEMPLATE_GETROOTS', 'TIU_TEMPLATE_GETPROOT', 'TIU_TEMPLATE_GETBOIL', 'TIU_TEMPLATE_GET_DESCRIPTION', 'TIU_TEMPLATE_GETITEMS', 'TIU_TEMPLATE_SET ITEMS', 'TIU_TEMPLATE_CREATE/MODIFY', 'TIU_TEMPLATE_DELETE', 'TIU_TEMPLATE_LOCK', 'TIU_TEMPLATE_UNLOCK', 'SDEC_CRSCHED', 'ORWDX_SAVE', 'ORWDXM1_BLDQRSP'), None)
|
||||
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)
|
||||
self._cache(('XWB_GET_BROKER_INFO', 'XUS_INTRO_MSG'), volatile, prefix=prefix, ttl=float('inf'))
|
||||
self._cache(None, volatile, prefix=prefix, ttl=float('-inf'))
|
||||
self._cache_persistent(persistent=persistent, prefix=prefix)
|
||||
@ -38,6 +38,12 @@ class CacheProxyRPC(util.CacheProxy):
|
||||
persistent = util.Store().memo
|
||||
self._cache(('SDEC_RESOURCE', 'ORWU1_NEWLOC', 'ORWLRR_ALLTESTS_ALL', 'ORWORDG_ALLTREE', 'ORWORDG_REVSTS', 'ORWDX_DGNM', 'ORWDX_ORDITM'), persistent, prefix=prefix, ttl=float('inf'))
|
||||
|
||||
def jsonify_result(value, id=None):
|
||||
return jsonify({ 'result': value._base, 'error': None, 'id': request.json.get('id'), 'ts': value._ts } if isinstance(value, util.Cached) else { 'result': value, 'error': None, 'id': request.json.get('id') })
|
||||
|
||||
def jsonify_error(ex, id=None):
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': id })
|
||||
|
||||
def application():
|
||||
app = Flask(__name__)
|
||||
app.json = JSONProviderX(app)
|
||||
@ -58,12 +64,12 @@ def application():
|
||||
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))))
|
||||
return jsonify({ 'result': cid, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(cid, id=request.json.get('id'))
|
||||
else:
|
||||
return jsonify({ 'result': None, 'error': { 'type': 'Unauthorized', 'args': [] }, 'id': request.json.get('id') })
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>/close')
|
||||
def cb_close(cid):
|
||||
@ -71,28 +77,28 @@ def application():
|
||||
client = clients[cid]
|
||||
res = client.close()
|
||||
del clients[cid]
|
||||
return jsonify({ 'result': res, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(res, id=request.json.get('id'))
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>/serverinfo')
|
||||
def cb_serverinfo(cid):
|
||||
try:
|
||||
client = clients[cid]
|
||||
return jsonify({ 'result': client._obj._server, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(client._obj._server, id=request.json.get('id'))
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>/userinfo')
|
||||
def cb_userinfo(cid):
|
||||
try:
|
||||
client = clients[cid]
|
||||
return jsonify({ 'result': client._obj._user, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(client._obj._user, id=request.json.get('id'))
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>/authenticate')
|
||||
def cb_authenticate(cid):
|
||||
@ -102,41 +108,56 @@ def application():
|
||||
if 'avcode' in params:
|
||||
user = client.authenticate(params['avcode'])
|
||||
client._cache_persistent(persistent=util.Store(f'cache.{client._server["volume"].lower()}.{client._server["uci"].lower()}.{user[0]}.db', journal_mode='WAL').memo)
|
||||
return jsonify({ 'result': user, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(user, id=request.json.get('id'))
|
||||
else:
|
||||
from auth import XUIAMSSOi_MySsoTokenVBA
|
||||
if token := XUIAMSSOi_MySsoTokenVBA():
|
||||
user = client.authenticate(token)
|
||||
client._cache_persistent(persistent=util.Store(f'cache.{client._server["volume"].lower()}.{client._server["uci"].lower()}.{user[0]}.db', journal_mode='WAL').memo)
|
||||
return jsonify({ 'result': user, 'error': None, 'id': request.json.get('id') })
|
||||
return jsonify_result(user, id=request.json.get('id'))
|
||||
else:
|
||||
return jsonify({ 'result': None, 'error': { 'type': 'Unauthorized', 'args': [] }, 'id': request.json.get('id') })
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>')
|
||||
def cb_call1(cid):
|
||||
try:
|
||||
client = clients[cid]
|
||||
data = request.json
|
||||
kw = {}
|
||||
if 'context' in data:
|
||||
return jsonify({ 'result': getattr(client, data['method'].upper())(*data.get('params', ()), context=data['context']), 'error': None, 'id': data.get('id') })
|
||||
else:
|
||||
return jsonify({ 'result': getattr(client, data['method'].upper())(*data.get('params', ())), 'error': None, 'id': data.get('id') })
|
||||
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'))
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.post('/v1/vista/<cid>/<method>')
|
||||
def cb_call2(cid, method):
|
||||
try:
|
||||
client = clients[cid]
|
||||
data = request.json
|
||||
return jsonify({ 'result': getattr(client, method.upper())(*data.get('params', ())), 'error': None, 'id': data.get('id') })
|
||||
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'))
|
||||
except Exception as ex:
|
||||
logger.exception(request.url)
|
||||
return jsonify({ 'result': None, 'error': { 'type': ex.__class__.__name__, 'args': ex.args }, 'id': request.json.get('id') })
|
||||
return jsonify_error(ex, id=request.json.get('id'))
|
||||
|
||||
@app.get('/<path:path>')
|
||||
def cb_static(path):
|
||||
|
5
rpc.py
5
rpc.py
@ -5,12 +5,15 @@ import socket
|
||||
import threading
|
||||
import asyncio
|
||||
import warnings
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
|
||||
from XWBHash import encrypt0 as XWBHash_encrypt
|
||||
|
||||
from typing import Any, Union, Sequence
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class RPCExc(Exception): pass
|
||||
class RPCExcFormat(ValueError, RPCExc): pass
|
||||
class RPCExcAuth(RPCExc): pass
|
||||
@ -121,6 +124,7 @@ class ClientSync(object):
|
||||
if (res := rpc_unpack_result(next(self.recv_rpc_msg), encoding=encoding)) != '1':
|
||||
raise RPCExcInvalidResult('XWB CREATE CONTEXT', context[0], res)
|
||||
self.context = context[0]
|
||||
logger.warning(f'RPC: {name} [{self.context}] {args}' if context else f'{name} {args}')
|
||||
send_rpc_msg(self.sock, rpc_pack(name, *args, command=command, envelope=envelope, encoding=encoding))
|
||||
return rpc_unpack_result(next(self.recv_rpc_msg), encoding=encoding)
|
||||
def __getattr__(self, key: str, commands: set={'TCPConnect'}):
|
||||
@ -196,6 +200,7 @@ class ClientAsync(object):
|
||||
if (res := rpc_unpack_result(await self.arecv_rpc_msg.__anext__(), encoding=encoding)) != '1':
|
||||
raise RPCExcInvalidResult('XWB CREATE CONTEXT', context[0], res)
|
||||
self.context = context[0]
|
||||
logger.warning(f'RPC: {name} [{self.context}] {args}' if context else f'{name} {args}')
|
||||
await asend_rpc_msg(self.writer, rpc_pack(name, *args, command=command, envelope=envelope, encoding=encoding))
|
||||
return rpc_unpack_result(await self.arecv_rpc_msg.__anext__(), encoding=encoding)
|
||||
def __getattr__(self, key: str, commands: set={'TCPConnect'}):
|
||||
|
14
util.py
14
util.py
@ -16,6 +16,15 @@ except ImportError:
|
||||
|
||||
from typing import Any, Union, AsyncGenerator, Iterable, Tuple, Callable
|
||||
|
||||
class Cached(object):
|
||||
def __init__(self, base, ts=None):
|
||||
self._base = base
|
||||
self._ts = ts
|
||||
def __getattr__(self, key):
|
||||
return getattr(self._base, key)
|
||||
def __getitem__(self, key):
|
||||
return getitem(self._base, key)
|
||||
|
||||
class Store(object):
|
||||
def __init__(self, database: Union[sqlite3.Connection, str]=':memory:', synchronous: bool=None, journal_mode: bool=None, default_factory: Union[Callable, None]=None):
|
||||
self._db = database if isinstance(database, sqlite3.Connection) else sqlite3.connect(database, check_same_thread=False)
|
||||
@ -60,8 +69,8 @@ class Mapping(object):
|
||||
def get(self, key: Union[str, slice], ttl: float=float('inf'), now: float=0, **kw) -> Any:
|
||||
if isinstance(key, slice):
|
||||
key, ttl, now = key.start, key.stop, key.step
|
||||
for row in self._store.execute(f'SELECT value FROM "{self._tbl}" WHERE key = ? AND ts > ? LIMIT 1', (key, (now or time.time()) - ttl)):
|
||||
return loads(row[0])
|
||||
for row in self._store.execute(f'SELECT value, ts FROM "{self._tbl}" WHERE key = ? AND ts > ? LIMIT 1', (key, (now or time.time()) - ttl)):
|
||||
return Cached(loads(row[0]), row[1])
|
||||
if 'default' in kw:
|
||||
return kw['default']
|
||||
elif self._store._default_factory is not None:
|
||||
@ -148,6 +157,7 @@ class CacheProxy(object):
|
||||
return fetch(*args, **kw)
|
||||
else:
|
||||
return value
|
||||
thunk.cached = True
|
||||
setattr(self, key, thunk)
|
||||
return thunk
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user