unisi 0.1.11__py3-none-any.whl → 0.1.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unisi/__init__.py +1 -1
- unisi/autotest.py +1 -24
- unisi/common.py +6 -7
- unisi/containers.py +2 -3
- unisi/guielements.py +3 -4
- unisi/multimon.py +101 -0
- unisi/proxy.py +3 -1
- unisi/server.py +7 -22
- unisi/users.py +80 -32
- unisi/utils.py +47 -1
- unisi/web/css/{662.64dbc68c.css → 493.824522cf.css} +1 -1
- unisi/web/index.html +1 -1
- unisi/web/js/493.97ca799d.js +1 -0
- unisi/web/js/app.cf197a5a.js +1 -0
- unisi/web/js/{vendor.d6797c01.js → vendor.eab68489.js} +2 -2
- {unisi-0.1.11.dist-info → unisi-0.1.13.dist-info}/METADATA +20 -21
- {unisi-0.1.11.dist-info → unisi-0.1.13.dist-info}/RECORD +19 -18
- {unisi-0.1.11.dist-info → unisi-0.1.13.dist-info}/WHEEL +1 -1
- unisi/web/js/662.5957b792.js +0 -1
- unisi/web/js/app.636fcf8d.js +0 -1
- {unisi-0.1.11.dist-info → unisi-0.1.13.dist-info}/licenses/LICENSE +0 -0
unisi/__init__.py
CHANGED
unisi/autotest.py
CHANGED
@@ -9,32 +9,9 @@ from .jsoncomparison import Compare, NO_DIFF
|
|
9
9
|
def obj2json(obj):
|
10
10
|
return json.loads(toJson(obj))
|
11
11
|
|
12
|
-
#setting config variables
|
13
|
-
testdir = 'autotest'
|
14
|
-
if not hasattr(config, testdir):
|
15
|
-
config.autotest = False
|
16
|
-
if not hasattr(config, 'port'):
|
17
|
-
config.port = 8000
|
18
|
-
if not hasattr(config, 'upload_dir'):
|
19
|
-
config.upload_dir = 'web'
|
20
|
-
if not hasattr(config, 'logfile'):
|
21
|
-
config.logfile = None
|
22
|
-
if not hasattr(config, 'hot_reload'):
|
23
|
-
config.hot_reload = False
|
24
|
-
if not hasattr(config, 'appname'):
|
25
|
-
config.appname = 'Unisi app'
|
26
|
-
if not hasattr(config, 'mirror'):
|
27
|
-
config.mirror = False
|
28
|
-
|
29
12
|
if not os.path.exists(config.upload_dir):
|
30
13
|
os.makedirs(config.upload_dir)
|
31
14
|
|
32
|
-
#start logging
|
33
|
-
format = "%(asctime)s - %(levelname)s - %(message)s"
|
34
|
-
logfile = config.logfile
|
35
|
-
handlers = [logging.FileHandler(logfile), logging.StreamHandler()] if logfile else []
|
36
|
-
logging.basicConfig(level = logging.WARNING, format = format, handlers = handlers)
|
37
|
-
|
38
15
|
comparator = Compare(rules = {'toolbar': '*'}).check
|
39
16
|
|
40
17
|
class Recorder:
|
@@ -202,7 +179,7 @@ def check_module(module):
|
|
202
179
|
def run_tests():
|
203
180
|
if not os.path.exists(testdir):
|
204
181
|
os.makedirs(testdir)
|
205
|
-
user = User.type(
|
182
|
+
user = User.type(testdir)
|
206
183
|
user.load()
|
207
184
|
errors = []
|
208
185
|
for module in user.screens:
|
unisi/common.py
CHANGED
@@ -9,16 +9,15 @@ def flatten(*arr):
|
|
9
9
|
|
10
10
|
class ArgObject:
|
11
11
|
def __init__(self, **kwargs):
|
12
|
-
|
13
|
-
setattr(self, key, value)
|
12
|
+
self.__dict__.update(kwargs)
|
14
13
|
|
15
14
|
class ReceivedMessage:
|
16
15
|
def __init__(self, data):
|
17
|
-
self.
|
18
|
-
self.
|
19
|
-
self.
|
20
|
-
|
21
|
-
self.
|
16
|
+
self.__dict__.update(data)
|
17
|
+
self.screen = data.get('screen')
|
18
|
+
self.value = data.get('value')
|
19
|
+
def __str__(self):
|
20
|
+
return f'{self.block}/{self.element}->{self.event}({self.value})'
|
22
21
|
|
23
22
|
def toJson(obj):
|
24
23
|
return jsonpickle.encode(obj,unpicklable = False)
|
unisi/containers.py
CHANGED
unisi/guielements.py
CHANGED
@@ -9,8 +9,7 @@ class Gui:
|
|
9
9
|
self.add(kwargs)
|
10
10
|
|
11
11
|
def add(self, kwargs):
|
12
|
-
|
13
|
-
setattr(self, key, value)
|
12
|
+
self.__dict__.update(kwargs)
|
14
13
|
|
15
14
|
def mutate(self, obj):
|
16
15
|
self.__dict__ = obj.__dict__
|
@@ -25,12 +24,12 @@ Line = Gui("Line", type = 'line')
|
|
25
24
|
|
26
25
|
def smart_complete(lst, min_input_length = 0, max_output_length = 20):
|
27
26
|
di = {it: it.lower() for it in lst}
|
28
|
-
def complete(
|
27
|
+
def complete(_, ustr):
|
29
28
|
if len(ustr) < min_input_length:
|
30
29
|
return []
|
31
30
|
ustr = ustr.lower()
|
32
31
|
arr = [(itlow.find(ustr), it, itlow) for it, itlow in di.items() if itlow.find(ustr) != -1]
|
33
|
-
arr.sort(key=lambda e: (e[0], e[2]))
|
32
|
+
arr.sort(key = lambda e: (e[0], e[2]))
|
34
33
|
if len(arr) > max_output_length:
|
35
34
|
arr = arr[: max_output_length]
|
36
35
|
return [e[1] for e in arr]
|
unisi/multimon.py
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
import multiprocessing, time, asyncio, logging, inspect
|
2
|
+
from .utils import start_logging
|
3
|
+
from config import froze_time, monitor_tick, profile, pool
|
4
|
+
|
5
|
+
def write_string_to(shared_array, input_string):
|
6
|
+
input_bytes = input_string.encode()
|
7
|
+
shared_array[:len(input_bytes)] = input_bytes
|
8
|
+
|
9
|
+
def read_string_from(shared_array):
|
10
|
+
return shared_array[:].decode().rstrip('\x00')
|
11
|
+
|
12
|
+
_multiprocessing_pool = None
|
13
|
+
|
14
|
+
def multiprocessing_pool():
|
15
|
+
global _multiprocessing_pool
|
16
|
+
if not _multiprocessing_pool:
|
17
|
+
_multiprocessing_pool = multiprocessing.Pool(pool)
|
18
|
+
return _multiprocessing_pool
|
19
|
+
|
20
|
+
async def run_external_process(long_running_task, *args, queue = None, progress_callback = None, **kwargs):
|
21
|
+
if progress_callback:
|
22
|
+
if queue is None:
|
23
|
+
queue = multiprocessing.Manager().Queue()
|
24
|
+
if args[-1] is None:
|
25
|
+
args = *args[:-1], queue
|
26
|
+
result = multiprocessing_pool().apply_async(long_running_task, args, kwargs)
|
27
|
+
if progress_callback:
|
28
|
+
while not result.ready() or not queue.empty():
|
29
|
+
message = queue.get()
|
30
|
+
if message is None:
|
31
|
+
break
|
32
|
+
await asyncio.gather(progress_callback(message), asyncio.sleep(monitor_tick))
|
33
|
+
return result.get()
|
34
|
+
|
35
|
+
logging_lock = multiprocessing.Lock()
|
36
|
+
|
37
|
+
splitter = '~'
|
38
|
+
|
39
|
+
def monitor_process(monitor_shared_arr):
|
40
|
+
timer = None
|
41
|
+
session_status = {}
|
42
|
+
sname = None
|
43
|
+
start_logging()
|
44
|
+
while True:
|
45
|
+
#Wait for data in the shared array
|
46
|
+
while monitor_shared_arr[0] == b'\x00':
|
47
|
+
time.sleep(0.005)
|
48
|
+
if timer is not None:
|
49
|
+
timer -= monitor_tick
|
50
|
+
if timer < 0:
|
51
|
+
timer = None
|
52
|
+
arr = list(session_status.items())
|
53
|
+
arr.sort(key = lambda s: s[1][1], reverse=True)
|
54
|
+
ct = time.time()
|
55
|
+
message = "Hangout is detected! Sessions in a queue and time waiting:" +\
|
56
|
+
''.join(f'\n {s[0]}, {s[1][0]}, {ct - s[1][1]} s' for s in arr)
|
57
|
+
with logging_lock:
|
58
|
+
logging.warning(message)
|
59
|
+
timer = None
|
60
|
+
# Read and process the data
|
61
|
+
status = read_string_from(monitor_shared_arr).split(splitter)
|
62
|
+
#free
|
63
|
+
monitor_shared_arr[0] = b'\x00'
|
64
|
+
sname = status[1]
|
65
|
+
match status[0]:
|
66
|
+
case '+' | 'e': #exit external process
|
67
|
+
session_status[sname] = [status[2], time.time()]
|
68
|
+
timer = froze_time
|
69
|
+
case '-':
|
70
|
+
event, tstart = session_status.get(sname, (None, 0))
|
71
|
+
if event:
|
72
|
+
duration = time.time() - tstart
|
73
|
+
if profile and duration > profile:
|
74
|
+
with logging_lock:
|
75
|
+
logging.warning(f'Event handler {event} was executed for {duration} seconds!')
|
76
|
+
del session_status[sname]
|
77
|
+
timer = None
|
78
|
+
case 'p': #call external process
|
79
|
+
session_status[sname] = [status[2], time.time()]
|
80
|
+
timer = None
|
81
|
+
|
82
|
+
if froze_time or profile:
|
83
|
+
# Create a shared memory array
|
84
|
+
monitor_shared_arr = multiprocessing.Array('c', 200)
|
85
|
+
monitor_shared_arr[0] != b'\x00'
|
86
|
+
|
87
|
+
async def notify_monitor(status, session, event):
|
88
|
+
s = f'{status}{splitter}{session}{splitter}{event}'
|
89
|
+
# Wait for the shared array to be empty
|
90
|
+
while monitor_shared_arr[0] != b'\x00':
|
91
|
+
await asyncio.sleep(monitor_tick)
|
92
|
+
write_string_to(monitor_shared_arr, s)
|
93
|
+
|
94
|
+
monitor_process = multiprocessing.Process(target=monitor_process, args=(monitor_shared_arr,))
|
95
|
+
monitor_process.start()
|
96
|
+
else:
|
97
|
+
notify_monitor = None
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
unisi/proxy.py
CHANGED
@@ -30,7 +30,9 @@ class Proxy:
|
|
30
30
|
addr_port = f'{wss_header if ssl else ws_header}{host_port}'
|
31
31
|
addr_port = f'{addr_port}{"" if addr_port.endswith("/") else "/"}{ws_path}'
|
32
32
|
self.host_port = f'{"https" if ssl else "http"}://{host_port}'
|
33
|
-
|
33
|
+
if session:
|
34
|
+
addr_port = f'{addr_port}?{session}'
|
35
|
+
self.conn = create_connection(addr_port, timeout = timeout)
|
34
36
|
self.screen = None
|
35
37
|
self.screens = {}
|
36
38
|
self.dialog = None
|
unisi/server.py
CHANGED
@@ -49,8 +49,6 @@ async def websocket_handler(request):
|
|
49
49
|
if not user:
|
50
50
|
await ws.send_str(toJson(status))
|
51
51
|
else:
|
52
|
-
user.transport = ws._writer.transport if divpath != '/' else None
|
53
|
-
|
54
52
|
async def send(res):
|
55
53
|
if type(res) != str:
|
56
54
|
res = toJson(user.prepare_result(res))
|
@@ -80,31 +78,18 @@ async def websocket_handler(request):
|
|
80
78
|
if message:
|
81
79
|
if recorder.record_file:
|
82
80
|
recorder.accept(message, user.prepare_result (result))
|
83
|
-
await user.reflect(message, result)
|
84
|
-
""" if user.reflections and not is_screen_switch(message):
|
85
|
-
if result:
|
86
|
-
await broadcast(result, user)
|
87
|
-
msg_object = user.find_element(message)
|
88
|
-
if not isinstance(result, Message) or not result.contains(msg_object):
|
89
|
-
await broadcast(toJson(user.prepare_result(msg_object)), user) """
|
81
|
+
await user.reflect(message, result)
|
90
82
|
elif msg.type == WSMsgType.ERROR:
|
91
83
|
user.log('ws connection closed with exception %s' % ws.exception())
|
92
|
-
except:
|
93
|
-
|
84
|
+
except BaseException as e:
|
85
|
+
if not isinstance(e, ConnectionResetError):
|
86
|
+
user.log(traceback.format_exc())
|
94
87
|
|
95
|
-
|
96
|
-
|
97
|
-
del uss[user.session]
|
98
|
-
|
99
|
-
if user.reflections: #reflections is common array
|
100
|
-
if len(user.reflections) == 2:
|
101
|
-
user.reflections.clear() #1 element in user.reflections has no sense
|
102
|
-
else:
|
103
|
-
user.reflections.remove(user)
|
104
|
-
return ws #?<->
|
88
|
+
await user.delete()
|
89
|
+
return ws
|
105
90
|
|
106
91
|
def start(appname = None, user_type = User, http_handlers = []):
|
107
|
-
if appname
|
92
|
+
if appname:
|
108
93
|
config.appname = appname
|
109
94
|
|
110
95
|
User.type = user_type
|
unisi/users.py
CHANGED
@@ -2,6 +2,7 @@ from .utils import *
|
|
2
2
|
from .guielements import *
|
3
3
|
from .common import *
|
4
4
|
from .containers import Dialog, Screen
|
5
|
+
from .multimon import notify_monitor, logging_lock, run_external_process
|
5
6
|
import sys, asyncio, logging, importlib
|
6
7
|
|
7
8
|
class User:
|
@@ -25,13 +26,22 @@ class User:
|
|
25
26
|
self.screens = []
|
26
27
|
self.reflections = []
|
27
28
|
self.screen_module = None
|
28
|
-
self.__handlers__ = {}
|
29
|
+
self.__handlers__ = {}
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
self.monitor(session, share)
|
32
|
+
|
33
|
+
async def run_process(self, long_running_task, *args, progress_callback = None, queue = None, **kwargs):
|
34
|
+
if progress_callback and notify_monitor and progress_callback != self.progress: #progress notifies the monitor
|
35
|
+
async def new_callback(value):
|
36
|
+
asyncio.gather(notify_monitor('e', self.session, self.last_message), progress_callback(value))
|
37
|
+
progress_callback = new_callback
|
38
|
+
return await run_external_process(long_running_task, *args, progress_callback = progress_callback,
|
39
|
+
queue = queue, **kwargs)
|
32
40
|
|
33
41
|
async def broadcast(self, message):
|
34
42
|
screen = self.screen_module
|
43
|
+
if type(message) != str:
|
44
|
+
message = toJson(self.prepare_result(message))
|
35
45
|
await asyncio.gather(*[user.send(message)
|
36
46
|
for user in self.reflections
|
37
47
|
if user is not self and screen is user.screen_module])
|
@@ -43,13 +53,15 @@ class User:
|
|
43
53
|
if message:
|
44
54
|
msg_object = self.find_element(message)
|
45
55
|
if not isinstance(result, Message) or not result.contains(msg_object):
|
46
|
-
await self.broadcast(
|
56
|
+
await self.broadcast(msg_object)
|
47
57
|
|
48
58
|
async def progress(self, str, *updates):
|
49
59
|
"""open or update progress window if str != null else close it """
|
50
60
|
if not self.testing:
|
51
61
|
msg = TypeMessage('progress', str, *updates, user = self)
|
52
62
|
await asyncio.gather(self.send(msg), self.reflect(None, msg))
|
63
|
+
if notify_monitor:
|
64
|
+
await notify_monitor('e', self.session, self.last_message)
|
53
65
|
|
54
66
|
def load_screen(self, file):
|
55
67
|
screen_vars = {
|
@@ -65,9 +77,8 @@ class User:
|
|
65
77
|
path = f'{screens_dir}{divpath}{file}'
|
66
78
|
spec = importlib.util.spec_from_file_location(name,path)
|
67
79
|
module = importlib.util.module_from_spec(spec)
|
80
|
+
module.user = self
|
68
81
|
|
69
|
-
module.user = self
|
70
|
-
|
71
82
|
spec.loader.exec_module(module)
|
72
83
|
screen = Screen(getattr(module, 'name', ''))
|
73
84
|
#set system vars
|
@@ -78,9 +89,22 @@ class User:
|
|
78
89
|
screen.toolbar += User.toolbar
|
79
90
|
else:
|
80
91
|
screen.toolbar = User.toolbar
|
81
|
-
|
82
|
-
module.screen = screen
|
92
|
+
module.screen = screen
|
83
93
|
return module
|
94
|
+
|
95
|
+
async def delete(self):
|
96
|
+
uss = User.sessions
|
97
|
+
if uss and uss.get(self.session):
|
98
|
+
del uss[self.session]
|
99
|
+
|
100
|
+
if self.reflections: #reflections is common array
|
101
|
+
if len(self.reflections) == 2:
|
102
|
+
self.reflections.clear() #1 element in user.reflections has no sense
|
103
|
+
else:
|
104
|
+
self.reflections.remove(self)
|
105
|
+
|
106
|
+
if notify_monitor:
|
107
|
+
await notify_monitor('-', self.session, self.last_message)
|
84
108
|
|
85
109
|
def set_clean(self):
|
86
110
|
#remove user modules from sys
|
@@ -99,7 +123,7 @@ class User:
|
|
99
123
|
self.screens.append(module)
|
100
124
|
|
101
125
|
if self.screens:
|
102
|
-
self.screens.sort(key=lambda s: s.
|
126
|
+
self.screens.sort(key=lambda s: s.order)
|
103
127
|
main = self.screens[0]
|
104
128
|
if 'prepare' in dir(main):
|
105
129
|
main.prepare()
|
@@ -115,7 +139,7 @@ class User:
|
|
115
139
|
|
116
140
|
@property
|
117
141
|
def testing(self):
|
118
|
-
return self.session ==
|
142
|
+
return self.session == testdir
|
119
143
|
|
120
144
|
@property
|
121
145
|
def screen(self):
|
@@ -125,16 +149,14 @@ class User:
|
|
125
149
|
return asyncio.run(self.process(ArgObject(block = 'root', element = None, value = name)))
|
126
150
|
|
127
151
|
async def result4message(self, message):
|
128
|
-
result = None
|
129
|
-
|
130
|
-
if dialog:
|
131
|
-
if message.element is None: #button pressed
|
152
|
+
result = None
|
153
|
+
self.last_message = message
|
154
|
+
if dialog := self.active_dialog:
|
155
|
+
if message.element is None: #dialog command button is pressed
|
132
156
|
self.active_dialog = None
|
133
157
|
if self.reflections:
|
134
|
-
await self.broadcast(TypeMessage('action', 'close'))
|
135
|
-
|
136
|
-
result = (await handler(dialog, message.value)) if asyncio.iscoroutinefunction(handler)\
|
137
|
-
else handler(dialog, message.value)
|
158
|
+
await self.broadcast(TypeMessage('action', 'close'))
|
159
|
+
result = await self.eval_handler(dialog.changed, dialog, message.value)
|
138
160
|
else:
|
139
161
|
el = self.find_element(message)
|
140
162
|
if el:
|
@@ -145,6 +167,15 @@ class User:
|
|
145
167
|
self.active_dialog = result
|
146
168
|
return result
|
147
169
|
|
170
|
+
async def eval_handler(self, handler, gui, value):
|
171
|
+
if notify_monitor:
|
172
|
+
await notify_monitor('+', self.session, self.last_message)
|
173
|
+
result = (await handler(gui, value)) if asyncio.iscoroutinefunction(handler)\
|
174
|
+
else handler(gui, value)
|
175
|
+
if notify_monitor:
|
176
|
+
await notify_monitor('-', self.session, None)
|
177
|
+
return result
|
178
|
+
|
148
179
|
@property
|
149
180
|
def blocks(self):
|
150
181
|
return [self.active_dialog] if self.active_dialog and \
|
@@ -188,8 +219,7 @@ class User:
|
|
188
219
|
raw = Message(*raw, user = self)
|
189
220
|
return raw
|
190
221
|
|
191
|
-
async def process(self, message):
|
192
|
-
self.last_message = message
|
222
|
+
async def process(self, message):
|
193
223
|
screen_change_message = getattr(message, 'screen',None) and self.screen.name != message.screen
|
194
224
|
if is_screen_switch(message) or screen_change_message:
|
195
225
|
for s in self.screens:
|
@@ -214,18 +244,16 @@ class User:
|
|
214
244
|
return Error(error)
|
215
245
|
|
216
246
|
async def process_element(self, elem, message):
|
217
|
-
event = message.event
|
247
|
+
event = message.event
|
218
248
|
query = event == 'complete' or event == 'append'
|
219
249
|
|
220
250
|
handler = self.__handlers__.get((elem, event), None)
|
221
251
|
if handler:
|
222
|
-
return
|
223
|
-
else handler(elem, message.value)
|
252
|
+
return await self.eval_handler(handler, elem, message.value)
|
224
253
|
|
225
254
|
handler = getattr(elem, event, False)
|
226
255
|
if handler:
|
227
|
-
result =
|
228
|
-
else handler(elem, message.value)
|
256
|
+
result = await self.eval_handler(handler, elem, message.value)
|
229
257
|
if query:
|
230
258
|
result = Answer(event, message, result)
|
231
259
|
return result
|
@@ -235,14 +263,27 @@ class User:
|
|
235
263
|
error = f"{message.block}/{message.element} doesn't contain '{event}' method type!"
|
236
264
|
self.log(error)
|
237
265
|
return Error(error)
|
266
|
+
|
267
|
+
def monitor(self, session, share):
|
268
|
+
if config.share and session != testdir:
|
269
|
+
self.log(f'User is connected, session: {session}, share: {share.session if share else None}', type = 'info')
|
270
|
+
|
271
|
+
def sync_send(self, obj):
|
272
|
+
asyncio.run(self.send(obj))
|
238
273
|
|
239
274
|
def log(self, str, type = 'error'):
|
240
275
|
scr = self.screen.name if self.screens else 'void'
|
241
276
|
str = f"session: {self.session}, screen: {scr}, message: {self.last_message}\n {str}"
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
277
|
+
with logging_lock:
|
278
|
+
if type == 'error':
|
279
|
+
logging.error(str)
|
280
|
+
elif type == 'warning':
|
281
|
+
logging.warning(str)
|
282
|
+
else:
|
283
|
+
func = logging.getLogger().setLevel
|
284
|
+
func(level = logging.INFO)
|
285
|
+
logging.info(str)
|
286
|
+
func(level = logging.WARNING)
|
246
287
|
|
247
288
|
User.type = User
|
248
289
|
User.last_user = None
|
@@ -250,15 +291,22 @@ User.toolbar = []
|
|
250
291
|
User.sessions = {}
|
251
292
|
User.count = 0
|
252
293
|
|
294
|
+
def context_user():
|
295
|
+
return context_object(User)
|
296
|
+
|
297
|
+
def context_screen():
|
298
|
+
user = context_user()
|
299
|
+
return user.screen if user else None
|
300
|
+
|
253
301
|
def make_user(request):
|
254
302
|
session = f'{request.remote}-{User.count}'
|
255
303
|
User.count += 1
|
256
|
-
requested_connect
|
257
|
-
if requested_connect:
|
304
|
+
if requested_connect := request.query_string if config.share else None:
|
258
305
|
user = User.sessions.get(requested_connect, None)
|
259
306
|
if not user:
|
260
307
|
error = f'Session id "{requested_connect}" is unknown. Connection refused!'
|
261
|
-
|
308
|
+
with logging_lock:
|
309
|
+
logging.error(error)
|
262
310
|
return None, Error(error)
|
263
311
|
user = User.type(session, user)
|
264
312
|
ok = user.screens
|
unisi/utils.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
import os, platform, requests
|
1
|
+
import os, platform, requests, inspect, logging
|
2
2
|
|
3
3
|
blocks_dir = 'blocks'
|
4
4
|
screens_dir = 'screens'
|
5
5
|
UpdateScreen = True
|
6
6
|
Redesign = 2
|
7
7
|
public_dirs = 'public_dirs'
|
8
|
+
testdir = 'autotest'
|
8
9
|
|
9
10
|
divpath = '\\' if platform.system() == 'Windows' else '/'
|
10
11
|
libpath = os.path.dirname(os.path.realpath(__file__))
|
@@ -26,6 +27,42 @@ appname = 'Unisi app'
|
|
26
27
|
import config
|
27
28
|
print("Config with default parameters is created!")
|
28
29
|
|
30
|
+
#setting config variables
|
31
|
+
defaults = {
|
32
|
+
testdir: False,
|
33
|
+
'appname' : 'Unisi app',
|
34
|
+
'upload_dir' : 'web',
|
35
|
+
'logfile': None,
|
36
|
+
'hot_reload' : False,
|
37
|
+
'mirror' : False,
|
38
|
+
'share' : False,
|
39
|
+
'profile' : 0,
|
40
|
+
'llm' : None,
|
41
|
+
'froze_time': None,
|
42
|
+
'monitor_tick' : 0.005,
|
43
|
+
'pool' : None
|
44
|
+
}
|
45
|
+
for param, value in defaults.items():
|
46
|
+
if not hasattr(config, param):
|
47
|
+
setattr(config, param, value)
|
48
|
+
|
49
|
+
if config.froze_time == 0:
|
50
|
+
print('froze_time in config.py can not be 0!')
|
51
|
+
config.froze_time = None
|
52
|
+
|
53
|
+
def context_object(target_type):
|
54
|
+
"""
|
55
|
+
Finds the first argument of a specific type in the current function call stack.
|
56
|
+
"""
|
57
|
+
frame = inspect.currentframe()
|
58
|
+
while frame:
|
59
|
+
args, _, _, values = inspect.getargvalues(frame)
|
60
|
+
if args and isinstance(values[args[0]], target_type):
|
61
|
+
return values[args[0]]
|
62
|
+
# Move to the previous frame in the call stack
|
63
|
+
frame = frame.f_back
|
64
|
+
return None
|
65
|
+
|
29
66
|
def is_screen_switch(message):
|
30
67
|
return message and message.block == 'root' and message.element is None
|
31
68
|
|
@@ -105,4 +142,13 @@ def Answer(type, message, result):
|
|
105
142
|
ms.message = message
|
106
143
|
return ms
|
107
144
|
|
145
|
+
def start_logging():
|
146
|
+
format = "%(asctime)s - %(levelname)s - %(message)s"
|
147
|
+
logfile = config.logfile
|
148
|
+
handlers = [logging.FileHandler(logfile), logging.StreamHandler()] if logfile else []
|
149
|
+
logging.basicConfig(level = logging.WARNING, format = format, handlers = handlers)
|
150
|
+
|
151
|
+
start_logging()
|
152
|
+
|
153
|
+
|
108
154
|
|
@@ -1 +1 @@
|
|
1
|
-
thead tr:first-child th{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:sticky;top:0;z-index:1000}:root{--scrollbar-width-height:10px;--scrollbar-thumb-hover:#2176d2;--scrollbar-thumb-dark:#2176d2;--scrollbar-thumb-hover-dark:#2176d2}::-webkit-scrollbar{height:var(--scrollbar-width-height);width:var(--scrollbar-width-height)}::-webkit-scrollbar-track{box-shadow:inset 0 0 4px var(--scrollbar-track-dark)}::-webkit-scrollbar-corner{background:var(--scrollbar-track-dark)}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-dark);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover-dark)}body[data-v-
|
1
|
+
thead tr:first-child th{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:sticky;top:0;z-index:1000}:root{--scrollbar-width-height:10px;--scrollbar-thumb-hover:#2176d2;--scrollbar-thumb-dark:#2176d2;--scrollbar-thumb-hover-dark:#2176d2}::-webkit-scrollbar{height:var(--scrollbar-width-height);width:var(--scrollbar-width-height)}::-webkit-scrollbar-track{box-shadow:inset 0 0 4px var(--scrollbar-track-dark)}::-webkit-scrollbar-corner{background:var(--scrollbar-track-dark)}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-dark);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover-dark)}body[data-v-6eb6b02a]{display:flex;justify-content:center}.custom-caption[data-v-6eb6b02a]{padding:5px!important}.web-camera-container[data-v-6eb6b02a]{align-items:center;border:1px solid #ccc;border-radius:4px;display:flex;flex-direction:column;justify-content:center;margin-bottom:2rem;margin-top:2rem;padding:2rem;width:500px}.web-camera-container .camera-button[data-v-6eb6b02a]{margin-bottom:2rem}.web-camera-container .camera-box .camera-shutter[data-v-6eb6b02a]{background-color:#fff;height:337.5px;opacity:0;position:absolute;width:450px}.web-camera-container .camera-box .camera-shutter.flash[data-v-6eb6b02a]{opacity:1}.web-camera-container .camera-shoot[data-v-6eb6b02a]{margin:1rem 0}.web-camera-container .camera-shoot button[data-v-6eb6b02a]{align-items:center;border-radius:100%;display:flex;height:60px;justify-content:center;width:60px}.web-camera-container .camera-shoot button img[data-v-6eb6b02a]{height:35px;object-fit:cover}.web-camera-container .camera-loading[data-v-6eb6b02a]{height:100%;margin:3rem 0 0 -1.2rem;min-height:150px;overflow:hidden;position:absolute;width:100%}.web-camera-container .camera-loading ul[data-v-6eb6b02a]{height:100%;margin:0;position:absolute;width:100%;z-index:999999}.web-camera-container .camera-loading .loader-circle[data-v-6eb6b02a]{display:block;height:14px;left:100%;margin:0 auto;padding:0;position:absolute;top:50%;transform:translateY(-50%);transform:translateX(-50%);width:100%}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]{animation:preload-6eb6b02a 1s infinite;background:#999;border-radius:100%;display:block;float:left;height:10px;line-height:10px;margin:0 0 0 4px;padding:0;position:relative;top:-50%;width:10px}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]:nth-child(2){animation-delay:.2s}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]:nth-child(3){animation-delay:.4s}@keyframes preload-6eb6b02a{0%{opacity:1}50%{opacity:.4}to{opacity:1}}.q-tab__label{font-size:16px;font-weight:700}
|
unisi/web/index.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src
|
1
|
+
<!DOCTYPE html><html><head><base href=/ ><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=/js/vendor.eab68489.js></script><script defer src=/js/app.cf197a5a.js></script><link href=/css/vendor.9ed7638d.css rel=stylesheet><link href=/css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
|