pywebexec 1.4.17__py3-none-any.whl → 1.4.19__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 CHANGED
@@ -48,7 +48,7 @@ CONFDIR = os.path.expanduser("~/").rstrip('/')
48
48
  if os.path.isdir(f"{CONFDIR}/.config"):
49
49
  CONFDIR += '/.config'
50
50
  CONFDIR += "/.pywebexec"
51
-
51
+ COMMAND_ID = str(uuid.uuid4())
52
52
 
53
53
  # In-memory cache for command statuses
54
54
  command_status_cache = {}
@@ -291,17 +291,27 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
291
291
  except Exception as e:
292
292
  print(e)
293
293
 
294
- def start_term(command_id):
294
+ def start_term():
295
295
  os.environ["PYWEBEXEC"] = " (shared)"
296
296
  os.chdir(CWD)
297
297
  start_time = datetime.now().isoformat()
298
298
  user = pwd.getpwuid(os.getuid())[0]
299
- print(f"Starting terminal session for {user} : {command_id}")
300
- update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
301
- output_file_path = get_output_file_path(command_id)
299
+ print(f"Starting terminal session for {user} : {COMMAND_ID}")
300
+ update_command_status(COMMAND_ID, {
301
+ 'status': 'running',
302
+ 'command': 'term',
303
+ 'params': [user, os.ttyname(sys.stdout.fileno())],
304
+ 'start_time': start_time,
305
+ 'user': user
306
+ })
307
+ output_file_path = get_output_file_path(COMMAND_ID)
302
308
  res = script(output_file_path)
303
309
  end_time = datetime.now().isoformat()
304
- update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
310
+ update_command_status(COMMAND_ID, {
311
+ 'status': 'success',
312
+ 'end_time': end_time,
313
+ 'exit_code': res
314
+ })
305
315
  print("Terminal session ended")
306
316
  return res
307
317
 
@@ -371,7 +381,7 @@ def parseargs():
371
381
  os.mkdir(COMMAND_STATUS_DIR, mode=0o700)
372
382
  if args.action == "term":
373
383
  COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
374
- sys.exit(start_term(str(uuid.uuid4())))
384
+ sys.exit(start_term())
375
385
 
376
386
  (hostname, ip) = resolve(gethostname()) if args.listen == '0.0.0.0' else resolve(args.listen)
377
387
 
@@ -409,25 +419,11 @@ def get_status_file_path(command_id):
409
419
  def get_output_file_path(command_id):
410
420
  return os.path.join(COMMAND_STATUS_DIR, f'{command_id}_output.txt')
411
421
 
412
- def update_command_status(command_id, status, command=None, params=None, start_time=None, end_time=None, exit_code=None, pid=None, user=None):
422
+ def update_command_status(command_id, updates):
413
423
  status_file_path = get_status_file_path(command_id)
414
424
  status_data = read_command_status(command_id) or {}
415
- status_data['status'] = status
416
- if command is not None:
417
- status_data['command'] = command
418
- if params is not None:
419
- status_data['params'] = params
420
- if start_time is not None:
421
- status_data['start_time'] = start_time
422
- if end_time is not None:
423
- status_data['end_time'] = end_time
424
- if exit_code is not None:
425
- status_data['exit_code'] = exit_code
426
- if pid is not None:
427
- status_data['pid'] = pid
428
- if user is not None:
429
- status_data['user'] = user
430
- if status != 'running':
425
+ status_data.update(updates)
426
+ if status_data['status'] != 'running':
431
427
  output_file_path = get_output_file_path(command_id)
432
428
  if os.path.exists(output_file_path):
433
429
  status_data['last_output_line'] = get_last_non_empty_line_of_file(output_file_path)
@@ -435,7 +431,7 @@ def update_command_status(command_id, status, command=None, params=None, start_t
435
431
  json.dump(status_data, f)
436
432
 
437
433
  # Update cache if status is not "running"
438
- if status != 'running':
434
+ if status_data['status'] != 'running':
439
435
  command_status_cache[command_id] = status_data
440
436
  elif command_id in command_status_cache:
441
437
  del command_status_cache[command_id]
@@ -463,8 +459,12 @@ def read_command_status(command_id):
463
459
  def sigwinch_passthrough(sig, data):
464
460
  s = struct.pack("HHHH", 0, 0, 0, 0)
465
461
  a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s))
466
- global p
462
+ global p, COMMAND_ID
467
463
  p.setwinsize(a[0], a[1])
464
+ update_command_status(COMMAND_ID, {
465
+ 'rows': a[0],
466
+ 'cols': a[1],
467
+ })
468
468
 
469
469
 
470
470
  def script(output_file):
@@ -481,12 +481,22 @@ def script(output_file):
481
481
 
482
482
  def run_command(command, params, command_id, user):
483
483
  start_time = datetime.now().isoformat()
484
- update_command_status(command_id, 'running', command=command, params=params, start_time=start_time, user=user)
484
+ update_command_status(command_id, {
485
+ 'status': 'running',
486
+ 'command': command,
487
+ 'params': params,
488
+ 'start_time': start_time,
489
+ 'user': user
490
+ })
485
491
  output_file_path = get_output_file_path(command_id)
486
492
  try:
487
493
  with open(output_file_path, 'wb') as fd:
488
494
  p = pexpect.spawn(command, params, ignore_sighup=True, timeout=None)
489
- update_command_status(command_id, 'running', pid=p.pid, user=user)
495
+ update_command_status(command_id, {
496
+ 'status': 'running',
497
+ 'pid': p.pid,
498
+ 'user': user
499
+ })
490
500
  p.setwinsize(24, 125)
491
501
  p.logfile = fd
492
502
  p.expect(pexpect.EOF)
@@ -496,16 +506,36 @@ def run_command(command, params, command_id, user):
496
506
  # Update the status based on the result
497
507
  if status is None:
498
508
  exit_code = -15
499
- update_command_status(command_id, 'aborted', end_time=end_time, exit_code=exit_code, user=user)
509
+ update_command_status(command_id, {
510
+ 'status': 'aborted',
511
+ 'end_time': end_time,
512
+ 'exit_code': exit_code,
513
+ 'user': user
514
+ })
500
515
  else:
501
516
  exit_code = status
502
517
  if exit_code == 0:
503
- update_command_status(command_id, 'success', end_time=end_time, exit_code=exit_code, user=user)
518
+ update_command_status(command_id, {
519
+ 'status': 'success',
520
+ 'end_time': end_time,
521
+ 'exit_code': exit_code,
522
+ 'user': user
523
+ })
504
524
  else:
505
- update_command_status(command_id, 'failed', end_time=end_time, exit_code=exit_code, user=user)
525
+ update_command_status(command_id, {
526
+ 'status': 'failed',
527
+ 'end_time': end_time,
528
+ 'exit_code': exit_code,
529
+ 'user': user
530
+ })
506
531
  except Exception as e:
507
532
  end_time = datetime.now().isoformat()
508
- update_command_status(command_id, 'failed', end_time=end_time, exit_code=1, user=user)
533
+ update_command_status(command_id, {
534
+ 'status': 'failed',
535
+ 'end_time': end_time,
536
+ 'exit_code': 1,
537
+ 'user': user
538
+ })
509
539
  with open(get_output_file_path(command_id), 'a') as output_file:
510
540
  output_file.write(str(e))
511
541
 
@@ -618,14 +648,16 @@ def run_command_endpoint():
618
648
  except ValueError as e:
619
649
  return jsonify({'error': str(e)}), 400
620
650
 
621
- # Generate a unique command_id
622
- command_id = str(uuid.uuid4())
623
-
624
651
  # Get the user from the session
625
652
  user = session.get('username', '-')
626
-
653
+ command_id = str(uuid.uuid4())
627
654
  # Set the initial status to running and save command details
628
- update_command_status(command_id, 'running', command, params, user=user)
655
+ update_command_status(command_id, {
656
+ 'status': 'running',
657
+ 'command': command,
658
+ 'params': params,
659
+ 'user': user
660
+ })
629
661
 
630
662
  # Run the command in a separate thread
631
663
  thread = threading.Thread(target=run_command, args=(command_path, params, command_id, user))
@@ -698,6 +730,7 @@ def get_command_output(command_id):
698
730
  response = {
699
731
  'output': output[-maxsize:],
700
732
  'status': status_data.get("status"),
733
+ 'cols': status_data.get("cols"),
701
734
  'links': {
702
735
  'next': f'{request.url_root}command_output/{command_id}?offset={new_offset}&maxsize={maxsize}{token_param}'
703
736
  }
@@ -735,9 +768,8 @@ def main():
735
768
  sys.argv.remove("shareterm")
736
769
  with open(basef + ".log", "ab+") as log:
737
770
  pywebexec = subprocess.Popen([sys.executable] + sys.argv, stdout=log, stderr=log)
738
- command_id = str(uuid.uuid4())
739
- print_urls(command_id)
740
- res = start_term(command_id)
771
+ print_urls(COMMAND_ID)
772
+ res = start_term()
741
773
  print("Stopping server")
742
774
  time.sleep(1)
743
775
  pywebexec.terminate()
@@ -55,6 +55,9 @@ async function fetchOutput(url) {
55
55
  terminal.write(data.error);
56
56
  clearInterval(outputInterval);
57
57
  } else {
58
+ if (data.cols) {
59
+ terminal.resize(data.cols, terminal.rows);
60
+ } else fitAddon.fit();
58
61
  percentage = slider.value;
59
62
  fullOutput += data.output;
60
63
  if (fullOutput.length > maxSize)
@@ -32,6 +32,10 @@ function initTerminal()
32
32
  },
33
33
  customGlyphs: false,
34
34
  rescaleOverlappingGlyphs: true,
35
+ // windowsPty: {
36
+ // backend: 'conpty',
37
+ // buildnumber: 21376,
38
+ // }
35
39
  });
36
40
  }
37
41
  let terminal = initTerminal()
@@ -137,6 +141,9 @@ async function fetchOutput(url) {
137
141
  terminal.write(data.error);
138
142
  clearInterval(outputInterval);
139
143
  } else {
144
+ if (data.cols) {
145
+ terminal.resize(data.cols, terminal.rows);
146
+ } else fitAddon.fit();
140
147
  fullOutput += data.output;
141
148
  if (fullOutput.length > maxSize)
142
149
  fullOutput = fullOutput.slice(-maxSize);
pywebexec/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.17'
16
- __version_tuple__ = version_tuple = (1, 4, 17)
15
+ __version__ = version = '1.4.19'
16
+ __version_tuple__ = version_tuple = (1, 4, 19)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.4.17
3
+ Version: 1.4.19
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,6 +1,6 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
- pywebexec/pywebexec.py,sha256=095dLydKEtrihG4ld78yqy5QIbFIWO_JdugtHj10FzI,28134
3
- pywebexec/version.py,sha256=SWUyms4VxRCFHq27p43L6ONua9907mV6gcqRfpenKW8,413
2
+ pywebexec/pywebexec.py,sha256=hacpB6OnS_ZN1SBmuReTUkvAuenl6czD6aD_yV8wusY,28462
3
+ pywebexec/version.py,sha256=uoD5RETbNPgiYh3HM3h7SS3IHV8yYSaVY1iOmNCumf8,413
4
4
  pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
5
5
  pywebexec/static/css/style.css,sha256=cGJHPFj23SQ_bFpesfUaFA3VFxhXtpRUOL_zzx3x_X8,5726
6
6
  pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
@@ -14,8 +14,8 @@ pywebexec/static/images/popup.svg,sha256=0Bl9A_v5cBsMPn6FnOlVWlAQKgd2zqiWQbhjcL9
14
14
  pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
15
15
  pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
16
16
  pywebexec/static/js/commands.js,sha256=8JDb3Q55EJOYf2Q9Uy6qEuqAnn1oGjM0RndgQ4aOjqo,7725
17
- pywebexec/static/js/popup.js,sha256=i7BPBh6oS0Q6H528DwP6KwJ8CKh7ULwm1rLHSbyvDhk,4656
18
- pywebexec/static/js/script.js,sha256=kHfJuQQs1H9kfHGruuDnECV5O71keuMc21JPX9l1jss,12046
17
+ pywebexec/static/js/popup.js,sha256=JdBHm09MBYpbh5It_LYj0DH_MXj5Z407-AXscHOny4Y,4779
18
+ pywebexec/static/js/script.js,sha256=KSYOWNHtRrGZX4UZ60BzEK-06SgLonDpxU6EEhdeiQo,12276
19
19
  pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
20
20
  pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
21
21
  pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
@@ -23,9 +23,9 @@ pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeo
23
23
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
25
25
  pywebexec/templates/popup.html,sha256=T6_tAOUoA58sA1oxB5pb8i42RenoMdCsH8T86Gccb6Q,945
26
- pywebexec-1.4.17.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
27
- pywebexec-1.4.17.dist-info/METADATA,sha256=kNMbOsvL81CZzPgQuZMIvn_zInRVbb0mWygCjYiH7J8,7801
28
- pywebexec-1.4.17.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
- pywebexec-1.4.17.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
30
- pywebexec-1.4.17.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
31
- pywebexec-1.4.17.dist-info/RECORD,,
26
+ pywebexec-1.4.19.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
27
+ pywebexec-1.4.19.dist-info/METADATA,sha256=bAlOxVzchw1tY4ocEf-FriPyY990xvl3S1dIrb2vEb4,7801
28
+ pywebexec-1.4.19.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
+ pywebexec-1.4.19.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
30
+ pywebexec-1.4.19.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
31
+ pywebexec-1.4.19.dist-info/RECORD,,