pywebexec 1.6.16__py3-none-any.whl → 1.6.17__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
@@ -180,18 +180,6 @@ class PyWebExec(Application):
180
180
 
181
181
  def load(self):
182
182
  return self.application
183
-
184
- def get_visible_output(line):
185
- try:
186
- screen = pyte.Screen(len(line)+1, 2)
187
- stream = pyte.Stream(screen)
188
- stream.feed(line)
189
- visible_line = screen.display[1].strip(" ")
190
- if visible_line:
191
- return visible_line
192
- return screen.display[0].strip(" ")
193
- except:
194
- return ""
195
183
  #38;2;66;59;165m
196
184
  ANSI_ESCAPE = re.compile(br'(?:\x1B[@-Z\\-_]|\x1B([(]B|>)|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~]|\x1B\[([0-9]{1,2};){0,4}[0-9]{1,3}[m|K]|\x1B\[[0-9;]*[mGKHF]|[\x00-\x1F\x7F])')
197
185
 
@@ -208,22 +196,34 @@ def decode_line(line: bytes) -> str:
208
196
  return ""
209
197
 
210
198
 
211
- def get_last_line(file_path, maxsize=1024):
199
+ def get_visible_output(line, cols, rows):
200
+ """pyte vt100 render to get last line"""
201
+ try:
202
+ screen = pyte.Screen(cols, rows)
203
+ stream = pyte.ByteStream(screen)
204
+ stream.feed(line)
205
+ visible_line = ""
206
+ row = rows - 1
207
+ while row > 0:
208
+ visible_line = screen.display[row].strip(" ")
209
+ if visible_line:
210
+ return visible_line
211
+ row -= 1
212
+ except:
213
+ return ""
214
+ return ""
215
+
216
+
217
+ def get_last_line(file_path, cols=None, rows=None, maxsize=2048):
212
218
  """Retrieve last non empty line after vt100 interpretation"""
219
+ cols = cols or 125
220
+ rows = rows or 24
213
221
  with open(file_path, 'rb') as fd:
214
222
  try:
215
223
  fd.seek(-maxsize, os.SEEK_END)
216
224
  except OSError:
217
225
  fd.seek(0)
218
- lines = fd.read().split(b"\n")
219
- if len(lines) == 1:
220
- return ""
221
- line = ""
222
- while True:
223
- line = decode_line(lines.pop())
224
- if line or not lines:
225
- break
226
- return line
226
+ return get_visible_output(fd.read(), cols, rows)
227
227
 
228
228
 
229
229
  def start_gunicorn(daemonized=False, baselog=None):
@@ -431,21 +431,16 @@ def get_output_file_path(command_id):
431
431
 
432
432
  def update_command_status(command_id, updates):
433
433
  status_file_path = get_status_file_path(command_id)
434
- status_data = read_command_status(command_id) or {}
435
- status_data.update(updates)
436
- if status_data['status'] != 'running':
434
+ status = read_command_status(command_id) or {}
435
+ status.update(updates)
436
+ if status.get('status') != 'running':
437
437
  output_file_path = get_output_file_path(command_id)
438
438
  if os.path.exists(output_file_path):
439
- status_data['last_output_line'] = get_last_line(output_file_path)
439
+ status['last_output_line'] = get_last_line(output_file_path, status.get('cols'), status.get('rows'))
440
+ command_status_cache[command_id] = status
440
441
  with open(status_file_path, 'w') as f:
441
- json.dump(status_data, f)
442
+ json.dump(status, f)
442
443
 
443
- # Update cache if status is not "running"
444
- if status_data['status'] != 'running':
445
- command_status_cache[command_id] = status_data
446
- elif command_id in command_status_cache:
447
- del command_status_cache[command_id]
448
-
449
444
  def read_command_status(command_id):
450
445
  # Return cached status if available
451
446
  if command_id in command_status_cache:
@@ -575,13 +570,13 @@ def read_commands():
575
570
  if status:
576
571
  command = command_str(status.get('command', '-'), status.get('params', []))
577
572
  last_line = status.get('last_output_line')
578
- if last_line is None:
573
+ if status.get('status') == 'running':
579
574
  output_file_path = get_output_file_path(command_id)
580
575
  if os.path.exists(output_file_path):
581
- last_line = get_last_line(output_file_path)
576
+ last_line = get_last_line(output_file_path, status.get('cols'), status.get('rows'))
582
577
  commands.append({
583
578
  'command_id': command_id,
584
- 'status': status['status'],
579
+ 'status': status.get('status'),
585
580
  'start_time': status.get('start_time', 'N/A'),
586
581
  'end_time': status.get('end_time', 'N/A'),
587
582
  'command': command,
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.6.16'
16
- __version_tuple__ = version_tuple = (1, 6, 16)
15
+ __version__ = version = '1.6.17'
16
+ __version_tuple__ = version_tuple = (1, 6, 17)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.6.16
3
+ Version: 1.6.17
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=bfE0QBiErt3k5GCsobOLZOP5OT6JJs-39GvLkzWqnB0,32650
3
- pywebexec/version.py,sha256=Krs1A6GFKeSDM3HlmJuBHtdakqIKMggtBrGf0aTD85E,413
2
+ pywebexec/pywebexec.py,sha256=mCNUbnttBIloCVmVl3jRuqA3kE6K9SlYLlDEAHb-dL0,32556
3
+ pywebexec/version.py,sha256=bUNPwAsnC5Y4wwmtKw5lZfH0PuKwJg_38vSI9Pv11Qo,413
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
@@ -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.6.16.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
37
- pywebexec-1.6.16.dist-info/METADATA,sha256=sU0xp2d2_UIe1pvIdJKvnZ3zK7ThZ7jueOKNVssIu3o,8001
38
- pywebexec-1.6.16.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
39
- pywebexec-1.6.16.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
40
- pywebexec-1.6.16.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
41
- pywebexec-1.6.16.dist-info/RECORD,,
36
+ pywebexec-1.6.17.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
37
+ pywebexec-1.6.17.dist-info/METADATA,sha256=WOoqeA6-jB64mcwinFFIrJatxvesYYJAhXruiXmf0rA,8001
38
+ pywebexec-1.6.17.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
39
+ pywebexec-1.6.17.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
40
+ pywebexec-1.6.17.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
41
+ pywebexec-1.6.17.dist-info/RECORD,,