pywebexec 1.6.17__py3-none-any.whl → 1.7.0__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.
- pywebexec/pywebexec.py +23 -17
- pywebexec/static/js/script.js +1 -1
- pywebexec/version.py +2 -2
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/METADATA +1 -1
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/RECORD +9 -9
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/LICENSE +0 -0
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/WHEEL +0 -0
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.6.17.dist-info → pywebexec-1.7.0.dist-info}/top_level.txt +0 -0
pywebexec/pywebexec.py
CHANGED
@@ -58,7 +58,7 @@ CONFDIR += "/.pywebexec"
|
|
58
58
|
term_command_id = str(uuid.uuid4())
|
59
59
|
|
60
60
|
# In-memory cache for command statuses
|
61
|
-
|
61
|
+
status_cache = {}
|
62
62
|
|
63
63
|
def generate_random_password(length=12):
|
64
64
|
characters = string.ascii_letters + string.digits + string.punctuation
|
@@ -162,7 +162,6 @@ def generate_selfsigned_cert(hostname, ip_addresses=None, key=None):
|
|
162
162
|
return cert_pem, key_pem
|
163
163
|
|
164
164
|
|
165
|
-
|
166
165
|
class PyWebExec(Application):
|
167
166
|
|
168
167
|
def __init__(self, app, options=None):
|
@@ -242,7 +241,8 @@ def start_gunicorn(daemonized=False, baselog=None):
|
|
242
241
|
accesslog = None #"-"
|
243
242
|
options = {
|
244
243
|
'bind': '%s:%s' % (args.listen, args.port),
|
245
|
-
'workers':
|
244
|
+
'workers': 1,
|
245
|
+
'threads': 4,
|
246
246
|
'timeout': 600,
|
247
247
|
'certfile': args.cert,
|
248
248
|
'keyfile': args.key,
|
@@ -437,28 +437,27 @@ def update_command_status(command_id, updates):
|
|
437
437
|
output_file_path = get_output_file_path(command_id)
|
438
438
|
if os.path.exists(output_file_path):
|
439
439
|
status['last_output_line'] = get_last_line(output_file_path, status.get('cols'), status.get('rows'))
|
440
|
-
|
440
|
+
status_cache[command_id] = status
|
441
441
|
with open(status_file_path, 'w') as f:
|
442
442
|
json.dump(status, f)
|
443
443
|
|
444
444
|
def read_command_status(command_id):
|
445
445
|
# Return cached status if available
|
446
|
-
|
447
|
-
|
448
|
-
|
446
|
+
status_data = {}
|
447
|
+
if command_id in status_cache:
|
448
|
+
status_data = status_cache[command_id]
|
449
|
+
status = status_data.get('status')
|
450
|
+
if status and status != "running":
|
451
|
+
return status_data
|
449
452
|
status_file_path = get_status_file_path(command_id)
|
450
453
|
if not os.path.exists(status_file_path):
|
451
454
|
return None
|
452
455
|
with open(status_file_path, 'r') as f:
|
453
456
|
try:
|
454
|
-
status_data
|
457
|
+
status_data.update(json.load(f))
|
455
458
|
except json.JSONDecodeError:
|
456
459
|
return None
|
457
|
-
|
458
|
-
# Cache the status if it is not "running"
|
459
|
-
if status_data['status'] != 'running':
|
460
|
-
command_status_cache[command_id] = status_data
|
461
|
-
|
460
|
+
status_cache[command_id] = status_data
|
462
461
|
return status_data
|
463
462
|
|
464
463
|
def sigwinch_passthrough(sig, data):
|
@@ -562,6 +561,7 @@ def command_str(command, params):
|
|
562
561
|
|
563
562
|
|
564
563
|
def read_commands():
|
564
|
+
global status_cache
|
565
565
|
commands = []
|
566
566
|
for filename in os.listdir(COMMAND_STATUS_DIR):
|
567
567
|
if filename.endswith('.json'):
|
@@ -569,11 +569,17 @@ def read_commands():
|
|
569
569
|
status = read_command_status(command_id)
|
570
570
|
if status:
|
571
571
|
command = command_str(status.get('command', '-'), status.get('params', []))
|
572
|
-
|
573
|
-
if status.get('status') == 'running':
|
572
|
+
if status.get('status') == 'running' and status.get('last_update',0)<datetime.now().timestamp()-5:
|
574
573
|
output_file_path = get_output_file_path(command_id)
|
575
574
|
if os.path.exists(output_file_path):
|
576
|
-
|
575
|
+
size = os.path.getsize(output_file_path)
|
576
|
+
if size != status.get('size'):
|
577
|
+
status.update({
|
578
|
+
'size': size,
|
579
|
+
'last_update': datetime.now().timestamp(),
|
580
|
+
'last_output_line': get_last_line(output_file_path, status.get('cols'), status.get('rows')),
|
581
|
+
})
|
582
|
+
status_cache[command_id] = status
|
577
583
|
commands.append({
|
578
584
|
'command_id': command_id,
|
579
585
|
'status': status.get('status'),
|
@@ -581,7 +587,7 @@ def read_commands():
|
|
581
587
|
'end_time': status.get('end_time', 'N/A'),
|
582
588
|
'command': command,
|
583
589
|
'exit_code': status.get('exit_code', 'N/A'),
|
584
|
-
'last_output_line':
|
590
|
+
'last_output_line': status.get('last_output_line'),
|
585
591
|
})
|
586
592
|
return commands
|
587
593
|
|
pywebexec/static/js/script.js
CHANGED
@@ -120,7 +120,7 @@ document.getElementById('launchForm').addEventListener('submit', async (event) =
|
|
120
120
|
throw new Error('Failed to launch command');
|
121
121
|
}
|
122
122
|
const data = await response.json();
|
123
|
-
await new Promise(r => setTimeout(r, 300))
|
123
|
+
//await new Promise(r => setTimeout(r, 300));// not ok
|
124
124
|
fetchCommands();
|
125
125
|
viewOutput(data.command_id);
|
126
126
|
commandInput.focus()
|
pywebexec/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
2
|
-
pywebexec/pywebexec.py,sha256=
|
3
|
-
pywebexec/version.py,sha256=
|
2
|
+
pywebexec/pywebexec.py,sha256=J5cPqvF8OfdKAmuvNiRgVIGsiromBBdK1Nna80tNPro,33006
|
3
|
+
pywebexec/version.py,sha256=2fEqxujmrV2dsREie2BmOYFLu66FowyHtZT2AoLuIzU,411
|
4
4
|
pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
|
5
5
|
pywebexec/static/css/style.css,sha256=MJHUBpjWL4sLxM7a7DxypmPKaFJQbmA_ESNXsbLviNI,8201
|
6
6
|
pywebexec/static/css/xterm.css,sha256=uo5phWaUiJgcz0DAzv46uoByLLbJLeetYosL1xf68rY,5559
|
@@ -20,7 +20,7 @@ pywebexec/static/images/running.svg,sha256=fBCYwYb2O9K4N3waC2nURP25NRwZlqR4PbDZy
|
|
20
20
|
pywebexec/static/images/success.svg,sha256=NVwezvVMplt46ElW798vqGfrL21Mw_DWHUp_qiD_FU8,489
|
21
21
|
pywebexec/static/js/commands.js,sha256=h2fkd9qpypLBxvhEEbay23nwuqUwcKJA0vHugcyL8pU,7961
|
22
22
|
pywebexec/static/js/popup.js,sha256=I5TLYUm5s2p12a0VfFONOxxzhXLBmnpVzM-B5W-GPis,8294
|
23
|
-
pywebexec/static/js/script.js,sha256=
|
23
|
+
pywebexec/static/js/script.js,sha256=EPofQO0ec2bwIr2YdzzNY3dcXipW2_Mi2j34DIYvJeE,17096
|
24
24
|
pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
|
25
25
|
pywebexec/static/js/xterm/addon-canvas.js,sha256=ez6QTVvsmLVNJmdJlM-ZQ5bErwlxAQ_9DUmDIptl2TM,94607
|
26
26
|
pywebexec/static/js/xterm/addon-canvas.js.map,sha256=ECBA4B-BqUpdFeRzlsEWLSQnudnhLP-yPQJ8_hKquMo,379537
|
@@ -33,9 +33,9 @@ pywebexec/static/js/xterm/xterm.js.map,sha256=Y7O2Pb-fIS7Z8AC1D5s04_aiW_Jf1f4mCf
|
|
33
33
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
pywebexec/templates/index.html,sha256=5h8kLyzAhbvUDU9sEwrGIvD6FxAMcDZLXlN-ldlO8KU,2880
|
35
35
|
pywebexec/templates/popup.html,sha256=3ZqQcE9mYs-RXv0Lfb24zntOlvR137ZYI9mtCZNVAo0,1407
|
36
|
-
pywebexec-1.
|
37
|
-
pywebexec-1.
|
38
|
-
pywebexec-1.
|
39
|
-
pywebexec-1.
|
40
|
-
pywebexec-1.
|
41
|
-
pywebexec-1.
|
36
|
+
pywebexec-1.7.0.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
37
|
+
pywebexec-1.7.0.dist-info/METADATA,sha256=qEu0SeeVHBVgAhPPeM2Fe8Rhq6RhGNaPudJyJS1t-3k,8000
|
38
|
+
pywebexec-1.7.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
39
|
+
pywebexec-1.7.0.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
40
|
+
pywebexec-1.7.0.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
41
|
+
pywebexec-1.7.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|