pywebexec 1.6.15__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,15 +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, 1)
187
- stream = pyte.Stream(screen)
188
- stream.feed(line)
189
- return screen.display[0].strip(" ")
190
- except:
191
- return ""
192
183
  #38;2;66;59;165m
193
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])')
194
185
 
@@ -205,22 +196,34 @@ def decode_line(line: bytes) -> str:
205
196
  return ""
206
197
 
207
198
 
208
- 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):
209
218
  """Retrieve last non empty line after vt100 interpretation"""
219
+ cols = cols or 125
220
+ rows = rows or 24
210
221
  with open(file_path, 'rb') as fd:
211
222
  try:
212
223
  fd.seek(-maxsize, os.SEEK_END)
213
224
  except OSError:
214
225
  fd.seek(0)
215
- lines = fd.read().split(b"\n")
216
- if len(lines) == 1:
217
- return ""
218
- line = ""
219
- while True:
220
- line = decode_line(lines.pop())
221
- if line or not lines:
222
- break
223
- return line
226
+ return get_visible_output(fd.read(), cols, rows)
224
227
 
225
228
 
226
229
  def start_gunicorn(daemonized=False, baselog=None):
@@ -428,21 +431,16 @@ def get_output_file_path(command_id):
428
431
 
429
432
  def update_command_status(command_id, updates):
430
433
  status_file_path = get_status_file_path(command_id)
431
- status_data = read_command_status(command_id) or {}
432
- status_data.update(updates)
433
- if status_data['status'] != 'running':
434
+ status = read_command_status(command_id) or {}
435
+ status.update(updates)
436
+ if status.get('status') != 'running':
434
437
  output_file_path = get_output_file_path(command_id)
435
438
  if os.path.exists(output_file_path):
436
- 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
437
441
  with open(status_file_path, 'w') as f:
438
- json.dump(status_data, f)
442
+ json.dump(status, f)
439
443
 
440
- # Update cache if status is not "running"
441
- if status_data['status'] != 'running':
442
- command_status_cache[command_id] = status_data
443
- elif command_id in command_status_cache:
444
- del command_status_cache[command_id]
445
-
446
444
  def read_command_status(command_id):
447
445
  # Return cached status if available
448
446
  if command_id in command_status_cache:
@@ -572,13 +570,13 @@ def read_commands():
572
570
  if status:
573
571
  command = command_str(status.get('command', '-'), status.get('params', []))
574
572
  last_line = status.get('last_output_line')
575
- if last_line is None:
573
+ if status.get('status') == 'running':
576
574
  output_file_path = get_output_file_path(command_id)
577
575
  if os.path.exists(output_file_path):
578
- last_line = get_last_line(output_file_path)
576
+ last_line = get_last_line(output_file_path, status.get('cols'), status.get('rows'))
579
577
  commands.append({
580
578
  'command_id': command_id,
581
- 'status': status['status'],
579
+ 'status': status.get('status'),
582
580
  'start_time': status.get('start_time', 'N/A'),
583
581
  'end_time': status.get('end_time', 'N/A'),
584
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.15'
16
- __version_tuple__ = version_tuple = (1, 6, 15)
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.15
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=mABzDShwZEykXOLg0C8xMXFT1kG-9uOxl_FdlD6MXvI,32541
3
- pywebexec/version.py,sha256=G6p4cF-LZDRxAX98giKjw_I7RSw9Ya1xCzihpDrYDsA,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.15.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
37
- pywebexec-1.6.15.dist-info/METADATA,sha256=6EUhbgPlcOPc8ccnsMYgcboAvFqz-CSTdNy8qgvOw0E,8001
38
- pywebexec-1.6.15.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
39
- pywebexec-1.6.15.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
40
- pywebexec-1.6.15.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
41
- pywebexec-1.6.15.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,,