meerschaum 2.7.8__py3-none-any.whl → 2.7.9__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- meerschaum/_internal/term/TermPageHandler.py +54 -4
- meerschaum/_internal/term/__init__.py +13 -5
- meerschaum/_internal/term/tools.py +41 -6
- meerschaum/actions/start.py +25 -10
- meerschaum/api/dash/callbacks/dashboard.py +43 -2
- meerschaum/api/dash/components.py +13 -6
- meerschaum/api/dash/keys.py +82 -108
- meerschaum/api/dash/pages/dashboard.py +17 -17
- meerschaum/api/dash/sessions.py +1 -0
- meerschaum/api/dash/webterm.py +17 -6
- meerschaum/api/resources/static/js/terminado.js +0 -2
- meerschaum/api/resources/templates/termpage.html +47 -4
- meerschaum/api/routes/_webterm.py +15 -11
- meerschaum/config/_default.py +6 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +2 -2
- meerschaum/core/Pipe/_sync.py +7 -7
- meerschaum/core/Pipe/_verify.py +1 -1
- meerschaum/utils/daemon/Daemon.py +15 -9
- meerschaum/utils/dtypes/__init__.py +9 -0
- meerschaum/utils/dtypes/sql.py +19 -13
- meerschaum/utils/formatting/_pprint.py +1 -1
- meerschaum/utils/misc.py +16 -0
- meerschaum/utils/venv/__init__.py +10 -14
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/METADATA +1 -1
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/RECORD +32 -32
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/LICENSE +0 -0
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/NOTICE +0 -0
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/WHEEL +0 -0
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/top_level.txt +0 -0
- {meerschaum-2.7.8.dist-info → meerschaum-2.7.9.dist-info}/zip-safe +0 -0
meerschaum/api/dash/keys.py
CHANGED
@@ -105,59 +105,58 @@ action_dropdown_row = html.Div(
|
|
105
105
|
dbc.Col(
|
106
106
|
html.Div(
|
107
107
|
dcc.Dropdown(
|
108
|
-
id
|
109
|
-
multi
|
110
|
-
placeholder
|
111
|
-
options
|
112
|
-
value
|
108
|
+
id='flags-dropdown',
|
109
|
+
multi=True,
|
110
|
+
placeholder='Boolean flags',
|
111
|
+
options=[],
|
112
|
+
value=[],
|
113
113
|
),
|
114
|
-
id
|
115
|
-
className
|
114
|
+
id='flags-dropdown-div',
|
115
|
+
className='dbc_dark input-text',
|
116
116
|
),
|
117
|
-
width
|
117
|
+
width=widths['flags'],
|
118
118
|
),
|
119
119
|
],
|
120
120
|
),
|
121
121
|
html.Br(),
|
122
122
|
html.Div(id='input-flags-div'),
|
123
123
|
dbc.Row(
|
124
|
-
children
|
124
|
+
children=[
|
125
125
|
dbc.Col(
|
126
|
-
children
|
126
|
+
children=[
|
127
127
|
html.Div(
|
128
|
-
children
|
128
|
+
children=[
|
129
129
|
dbc.Button(
|
130
130
|
'Additional parameters',
|
131
|
-
id
|
132
|
-
color
|
133
|
-
size
|
134
|
-
outline
|
135
|
-
style
|
131
|
+
id='show-arguments-collapse-button',
|
132
|
+
color='link',
|
133
|
+
size='md',
|
134
|
+
outline=True,
|
135
|
+
style={'display': 'none'},
|
136
136
|
),
|
137
|
-
# html.Br(),
|
138
137
|
dbc.Collapse(
|
139
|
-
children
|
138
|
+
children=[
|
140
139
|
dbc.Button(
|
141
140
|
'Clear',
|
142
|
-
id
|
143
|
-
color
|
144
|
-
size
|
141
|
+
id='clear-begin-end-datepicker-button',
|
142
|
+
color='link',
|
143
|
+
size='sm',
|
145
144
|
),
|
146
145
|
dcc.DatePickerRange(
|
147
|
-
id
|
146
|
+
id='begin-end-datepicker',
|
148
147
|
),
|
149
148
|
],
|
150
|
-
id
|
149
|
+
id='arguments-collapse',
|
151
150
|
),
|
152
151
|
], ### end of div children
|
153
152
|
),
|
154
153
|
], ### end of col children
|
155
|
-
width
|
154
|
+
width=widths['arguments'],
|
156
155
|
),
|
157
156
|
], ### end of row children
|
158
157
|
),
|
159
158
|
], ### end of parent div children
|
160
|
-
id
|
159
|
+
id='action-div',
|
161
160
|
)
|
162
161
|
|
163
162
|
|
@@ -167,49 +166,49 @@ dropdown_keys_row = dbc.Row(
|
|
167
166
|
html.Div(
|
168
167
|
[
|
169
168
|
dcc.Dropdown(
|
170
|
-
id
|
171
|
-
options
|
172
|
-
placeholder
|
173
|
-
multi
|
169
|
+
id='connector-keys-dropdown',
|
170
|
+
options=[],
|
171
|
+
placeholder=placeholders['ck'],
|
172
|
+
multi=True,
|
174
173
|
),
|
175
174
|
],
|
176
|
-
className
|
175
|
+
className='dbc_dark',
|
177
176
|
),
|
178
|
-
lg
|
179
|
-
md
|
180
|
-
sm
|
177
|
+
lg=4,
|
178
|
+
md=12,
|
179
|
+
sm=12,
|
181
180
|
),
|
182
181
|
dbc.Col(
|
183
182
|
html.Div(
|
184
183
|
[
|
185
184
|
dcc.Dropdown(
|
186
|
-
id
|
187
|
-
options
|
188
|
-
placeholder
|
189
|
-
multi
|
185
|
+
id='metric-keys-dropdown',
|
186
|
+
options=[],
|
187
|
+
placeholder=placeholders['mk'],
|
188
|
+
multi=True,
|
190
189
|
),
|
191
190
|
],
|
192
|
-
className
|
191
|
+
className='dbc_dark'
|
193
192
|
),
|
194
|
-
lg
|
195
|
-
md
|
196
|
-
sm
|
193
|
+
lg=4,
|
194
|
+
md=12,
|
195
|
+
sm=12,
|
197
196
|
),
|
198
197
|
dbc.Col(
|
199
198
|
html.Div(
|
200
199
|
[
|
201
200
|
dcc.Dropdown(
|
202
|
-
id
|
203
|
-
options
|
204
|
-
placeholder
|
205
|
-
multi
|
201
|
+
id='location-keys-dropdown',
|
202
|
+
options=[],
|
203
|
+
placeholder=placeholders['lk'],
|
204
|
+
multi=True,
|
206
205
|
),
|
207
206
|
],
|
208
|
-
className
|
207
|
+
className='dbc_dark'
|
209
208
|
),
|
210
|
-
lg
|
211
|
-
md
|
212
|
-
sm
|
209
|
+
lg=4,
|
210
|
+
md=12,
|
211
|
+
sm=12,
|
213
212
|
),
|
214
213
|
] ### end of filters row children
|
215
214
|
)
|
@@ -217,10 +216,9 @@ dropdown_tab_content = html.Div([
|
|
217
216
|
dbc.Card(
|
218
217
|
dbc.CardBody(
|
219
218
|
[
|
220
|
-
# html.P('Pipe Keys'),
|
221
219
|
dropdown_keys_row,
|
222
220
|
], ### end of card children
|
223
|
-
className
|
221
|
+
className='card-text',
|
224
222
|
)
|
225
223
|
),
|
226
224
|
html.Br(),
|
@@ -229,7 +227,7 @@ dropdown_tab_content = html.Div([
|
|
229
227
|
[
|
230
228
|
action_dropdown_row,
|
231
229
|
],
|
232
|
-
className
|
230
|
+
className='card-text',
|
233
231
|
),
|
234
232
|
),
|
235
233
|
])
|
@@ -242,75 +240,66 @@ text_tab_content = dbc.Card(
|
|
242
240
|
dbc.Col(html.Div(className='dbc_dark', children=[
|
243
241
|
dbc.InputGroup(
|
244
242
|
[
|
245
|
-
# dbc.InputGroupAddon(
|
246
243
|
dbc.Button(
|
247
244
|
'Clear',
|
248
|
-
id
|
249
|
-
color
|
250
|
-
size
|
245
|
+
id='clear-connector-keys-input-button',
|
246
|
+
color='link',
|
247
|
+
size='sm',
|
251
248
|
),
|
252
|
-
# addon_type = 'prepend',
|
253
|
-
# ),
|
254
249
|
dbc.Input(
|
255
|
-
id
|
256
|
-
placeholder
|
257
|
-
type
|
258
|
-
value
|
259
|
-
list
|
260
|
-
className
|
250
|
+
id='connector-keys-input',
|
251
|
+
placeholder=placeholders['ck'],
|
252
|
+
type='text',
|
253
|
+
value='',
|
254
|
+
list='connector-keys-list',
|
255
|
+
className='dbc_dark'
|
261
256
|
),
|
262
257
|
],
|
263
|
-
size
|
258
|
+
size=input_group_sizes['ck'],
|
264
259
|
)]),
|
265
|
-
width
|
260
|
+
width=4,
|
266
261
|
),
|
267
262
|
dbc.Col(
|
268
263
|
dbc.InputGroup(
|
269
264
|
[
|
270
|
-
# dbc.InputGroupAddon(
|
271
265
|
dbc.Button(
|
272
266
|
'Clear',
|
273
|
-
id
|
274
|
-
color
|
275
|
-
size
|
267
|
+
id='clear-metric-keys-input-button',
|
268
|
+
color='link',
|
269
|
+
size='sm',
|
276
270
|
),
|
277
|
-
# addon_type = 'prepend',
|
278
|
-
# ),
|
279
271
|
dbc.Input(
|
280
|
-
id
|
281
|
-
placeholder
|
282
|
-
type
|
283
|
-
value
|
284
|
-
list
|
272
|
+
id='metric-keys-input',
|
273
|
+
placeholder=placeholders['mk'],
|
274
|
+
type='text',
|
275
|
+
value='',
|
276
|
+
list='metric-keys-list',
|
285
277
|
),
|
286
278
|
],
|
287
|
-
size
|
279
|
+
size=input_group_sizes['mk'],
|
288
280
|
),
|
289
|
-
width
|
281
|
+
width=4,
|
290
282
|
),
|
291
283
|
dbc.Col(
|
292
284
|
dbc.InputGroup(
|
293
285
|
[
|
294
|
-
# dbc.InputGroupAddon(
|
295
286
|
dbc.Button(
|
296
287
|
'Clear',
|
297
|
-
id
|
298
|
-
color
|
299
|
-
size
|
288
|
+
id='clear-location-keys-input-button',
|
289
|
+
color='link',
|
290
|
+
size='sm',
|
300
291
|
),
|
301
|
-
# addon_type = 'prepend',
|
302
|
-
# ),
|
303
292
|
dbc.Input(
|
304
|
-
id
|
305
|
-
placeholder
|
306
|
-
type
|
307
|
-
value
|
308
|
-
list
|
293
|
+
id='location-keys-input',
|
294
|
+
placeholder=placeholders['lk'],
|
295
|
+
type='text',
|
296
|
+
value='',
|
297
|
+
list='location-keys-list',
|
309
298
|
),
|
310
299
|
],
|
311
|
-
size
|
300
|
+
size=input_group_sizes['lk'],
|
312
301
|
),
|
313
|
-
width
|
302
|
+
width=4,
|
314
303
|
),
|
315
304
|
]
|
316
305
|
),
|
@@ -319,23 +308,9 @@ text_tab_content = dbc.Card(
|
|
319
308
|
dbc.Col(
|
320
309
|
dbc.InputGroup(
|
321
310
|
[
|
322
|
-
# dbc.InputGroupAddon(
|
323
|
-
# dbc.Button(
|
324
|
-
# 'Clear',
|
325
|
-
# id = 'clear-params-textarea-button',
|
326
|
-
# color = 'link',
|
327
|
-
# size = 'sm',
|
328
|
-
# ),
|
329
|
-
# addon_type = 'prepend',
|
330
|
-
# ),
|
331
311
|
search_parameters_editor,
|
332
|
-
# dbc.Textarea(
|
333
|
-
# id = 'params-textarea',
|
334
|
-
# placeholder = placeholders['params'],
|
335
|
-
# value = '',
|
336
|
-
# )
|
337
312
|
],
|
338
|
-
size
|
313
|
+
size=input_group_sizes['params'],
|
339
314
|
)
|
340
315
|
)
|
341
316
|
),
|
@@ -348,4 +323,3 @@ keys_lists_content = html.Div([
|
|
348
323
|
html.Datalist(id='metric-keys-list'),
|
349
324
|
html.Datalist(id='location-keys-list'),
|
350
325
|
], hidden=True)
|
351
|
-
|
@@ -65,16 +65,16 @@ layout = html.Div(
|
|
65
65
|
children = [
|
66
66
|
dbc.Tab(
|
67
67
|
dropdown_tab_content,
|
68
|
-
label
|
69
|
-
id
|
70
|
-
tab_id
|
68
|
+
label='Filters',
|
69
|
+
id='pipes-filter-dropdown-tab',
|
70
|
+
tab_id='dropdown',
|
71
71
|
),
|
72
72
|
dbc.Tab(
|
73
73
|
text_tab_content,
|
74
|
-
label
|
75
|
-
id
|
76
|
-
tab_id
|
77
|
-
tab_style
|
74
|
+
label='Text',
|
75
|
+
id='pipes-filter-input-tab',
|
76
|
+
tab_id='input',
|
77
|
+
tab_style={"display": "none"},
|
78
78
|
),
|
79
79
|
]
|
80
80
|
),
|
@@ -83,12 +83,12 @@ layout = html.Div(
|
|
83
83
|
test_button,
|
84
84
|
html.Div(id='ws-div'),
|
85
85
|
],
|
86
|
-
id
|
87
|
-
md
|
88
|
-
lg
|
86
|
+
id='content-col-left',
|
87
|
+
md=12,
|
88
|
+
lg=6,
|
89
89
|
),
|
90
90
|
dbc.Col(
|
91
|
-
children
|
91
|
+
children=[
|
92
92
|
dbc.Col([
|
93
93
|
html.Div(id='success-alert-div'),
|
94
94
|
html.Div(id='instance-alert-div')
|
@@ -97,20 +97,20 @@ layout = html.Div(
|
|
97
97
|
),
|
98
98
|
html.Div(id='webterm-div'),
|
99
99
|
html.Div(
|
100
|
-
id
|
101
|
-
children
|
100
|
+
id='content-div-right',
|
101
|
+
children=[console_div],
|
102
102
|
),
|
103
103
|
html.Div(id='terminal'),
|
104
104
|
],
|
105
|
-
md
|
106
|
-
lg
|
107
|
-
id
|
105
|
+
md=12,
|
106
|
+
lg=6,
|
107
|
+
id='content-col-right',
|
108
108
|
),
|
109
109
|
],
|
110
110
|
style = {'max-width': '100%', 'padding': '15px'},
|
111
111
|
), ### end of Row
|
112
112
|
className = 'container-fluid',
|
113
113
|
), ### end of Div
|
114
|
-
html.P('', id='line-buffer', style
|
114
|
+
html.P('', id='line-buffer', style={'display': 'none'}),
|
115
115
|
],
|
116
116
|
)
|
meerschaum/api/dash/sessions.py
CHANGED
meerschaum/api/dash/webterm.py
CHANGED
@@ -14,10 +14,12 @@ from meerschaum.utils.typing import WebState, Tuple, Any
|
|
14
14
|
from meerschaum.utils.packages import attempt_import, import_html, import_dcc
|
15
15
|
from meerschaum._internal.term.tools import is_webterm_running
|
16
16
|
from meerschaum.utils.threading import Thread, RLock
|
17
|
+
from meerschaum.utils.misc import is_tmux_available
|
17
18
|
dcc, html = import_dcc(check_update=CHECK_UPDATE), import_html(check_update=CHECK_UPDATE)
|
18
19
|
dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
|
19
20
|
|
20
21
|
MAX_WEBTERM_ATTEMPTS: int = 10
|
22
|
+
TMUX_IS_AVAILABLE: bool = is_tmux_available()
|
21
23
|
|
22
24
|
_locks = {'webterm_thread': RLock()}
|
23
25
|
|
@@ -32,7 +34,7 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
|
|
32
34
|
return (
|
33
35
|
html.Div(
|
34
36
|
html.Pre(msg, id='console-pre'),
|
35
|
-
id
|
37
|
+
id="console-div",
|
36
38
|
),
|
37
39
|
[alert_from_success_tuple((
|
38
40
|
False,
|
@@ -41,12 +43,21 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
|
|
41
43
|
)
|
42
44
|
|
43
45
|
for i in range(MAX_WEBTERM_ATTEMPTS):
|
44
|
-
if is_webterm_running('localhost', 8765):
|
46
|
+
if is_webterm_running('localhost', 8765, session_id=(username or session_id)):
|
45
47
|
return (
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
[
|
49
|
+
html.Div(
|
50
|
+
[
|
51
|
+
dbc.Button('Refresh', color='black', id='webterm-refresh-button'),
|
52
|
+
dbc.Button('New Tab', color='black', id='webterm-new-tab-button'),
|
53
|
+
],
|
54
|
+
id='webterm-controls-div',
|
55
|
+
),
|
56
|
+
html.Iframe(
|
57
|
+
src=f"/webterm/{session_id}",
|
58
|
+
id="webterm-iframe",
|
59
|
+
),
|
60
|
+
],
|
50
61
|
[]
|
51
62
|
)
|
52
63
|
time.sleep(1)
|
@@ -15,9 +15,7 @@ function make_terminal(element, size, ws_url) {
|
|
15
15
|
term.attachCustomKeyEventHandler(copyPasteKeyEventHandler);
|
16
16
|
term.open(element);
|
17
17
|
|
18
|
-
sessionStore = localStorage.getItem("session-store");
|
19
18
|
ws.onopen = function (event) {
|
20
|
-
ws.send(sessionStore);
|
21
19
|
ws.send(
|
22
20
|
JSON.stringify([
|
23
21
|
"set_size",
|
@@ -84,6 +84,15 @@ window.addEventListener(
|
|
84
84
|
flags_str += " " + fl + " " + fl_val;
|
85
85
|
}
|
86
86
|
|
87
|
+
let line = "";
|
88
|
+
if (action_str === "__TMUX_NEW_WINDOW") {
|
89
|
+
line = "\x02:";
|
90
|
+
window.terminal.socket.send(JSON.stringify(["stdin", line]));
|
91
|
+
line = "new-window python3 -m meerschaum\r";
|
92
|
+
window.terminal.socket.send(JSON.stringify(["stdin", line]));
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
87
96
|
line = (
|
88
97
|
"\x03"
|
89
98
|
+ action_str
|
@@ -98,6 +107,26 @@ window.addEventListener(
|
|
98
107
|
false,
|
99
108
|
);
|
100
109
|
|
110
|
+
let reconnectTimeout;
|
111
|
+
|
112
|
+
function cleanUpWebSocket(socket) {
|
113
|
+
if (!socket) { return; }
|
114
|
+
socket.onopen = null;
|
115
|
+
socket.onmessage = null;
|
116
|
+
socket.onerror = null;
|
117
|
+
socket.onclose = null;
|
118
|
+
|
119
|
+
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
|
120
|
+
socket.close(1000, "Reconnecting");
|
121
|
+
}
|
122
|
+
|
123
|
+
if (reconnectTimeout) {
|
124
|
+
clearTimeout(reconnectTimeout);
|
125
|
+
reconnectTimeout = null;
|
126
|
+
}
|
127
|
+
|
128
|
+
socket = null;
|
129
|
+
}
|
101
130
|
|
102
131
|
window.onload = function() {
|
103
132
|
var termRowHeight = 0.0 + 0.95*document.getElementById("dummy-screen").offsetHeight / 25;
|
@@ -115,15 +144,29 @@ window.onload = function() {
|
|
115
144
|
|
116
145
|
xterm_div = document.getElementById("xterm-div");
|
117
146
|
size = calculate_size(window);
|
118
|
-
|
119
|
-
|
147
|
+
|
148
|
+
function init_webterm() {
|
149
|
+
old_terminal = window.terminal;
|
150
|
+
if (old_terminal){
|
151
|
+
xterm_div.innerHTML = "";
|
152
|
+
cleanUpWebSocket(old_terminal.socket);
|
153
|
+
}
|
154
|
+
window.terminal = make_terminal(xterm_div, size, ws_url);
|
155
|
+
window.terminal.socket.onclose = function (event) {
|
156
|
+
if (!event.wasClean && event.code !== 1005) {
|
157
|
+
reconnectTimeout = setTimeout(init_webterm, 1000);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
init_webterm();
|
120
163
|
|
121
164
|
window.onresize = function() {
|
122
165
|
var geom = calculate_size(window);
|
123
166
|
rows = geom.rows;
|
124
167
|
cols = geom.cols;
|
125
|
-
terminal.term.resize(cols, rows);
|
126
|
-
terminal.socket.send(
|
168
|
+
window.terminal.term.resize(cols, rows);
|
169
|
+
window.terminal.socket.send(
|
127
170
|
JSON.stringify(
|
128
171
|
["set_size", rows, cols, xterm_div.innerHeight, xterm_div.innerWidth]
|
129
172
|
)
|
@@ -10,7 +10,7 @@ import asyncio
|
|
10
10
|
from meerschaum.utils.typing import Optional
|
11
11
|
from meerschaum.api import app, endpoints
|
12
12
|
from meerschaum.utils.packages import attempt_import
|
13
|
-
from meerschaum.api.dash.sessions import is_session_authenticated
|
13
|
+
from meerschaum.api.dash.sessions import is_session_authenticated, get_username_from_session
|
14
14
|
fastapi, fastapi_responses = attempt_import('fastapi', 'fastapi.responses')
|
15
15
|
import starlette
|
16
16
|
|
@@ -27,12 +27,12 @@ PlainTextResponse = fastapi_responses.PlainTextResponse
|
|
27
27
|
@app.get(endpoints['webterm'], tags=["Webterm"])
|
28
28
|
async def get_webterm(
|
29
29
|
request: Request,
|
30
|
-
|
30
|
+
session_id: str,
|
31
31
|
) -> HTMLResponse:
|
32
32
|
"""
|
33
33
|
Get the main HTML template for the Webterm.
|
34
34
|
"""
|
35
|
-
if not is_session_authenticated(
|
35
|
+
if not is_session_authenticated(session_id):
|
36
36
|
return HTMLResponse(
|
37
37
|
"""
|
38
38
|
<html>
|
@@ -69,35 +69,39 @@ async def get_webterm(
|
|
69
69
|
status_code = 401,
|
70
70
|
)
|
71
71
|
|
72
|
+
username = get_username_from_session(session_id)
|
72
73
|
async with httpx.AsyncClient() as client:
|
73
|
-
|
74
|
+
webterm_url = f"http://localhost:8765/webterm/{username or session_id}"
|
75
|
+
response = await client.get(webterm_url)
|
74
76
|
text = response.text
|
75
77
|
if request.url.scheme == 'https':
|
76
78
|
text = text.replace('ws://', 'wss://')
|
79
|
+
text = text.replace(f'_websocket/{username}', f'_websocket/{session_id}')
|
77
80
|
return HTMLResponse(
|
78
|
-
content
|
79
|
-
status_code
|
80
|
-
headers
|
81
|
+
content=text,
|
82
|
+
status_code=response.status_code,
|
83
|
+
headers=request.headers,
|
81
84
|
)
|
82
85
|
|
83
86
|
|
84
87
|
@app.websocket(endpoints['webterm_websocket'])
|
85
|
-
async def webterm_websocket(websocket: WebSocket):
|
88
|
+
async def webterm_websocket(websocket: WebSocket, session_id: str):
|
86
89
|
"""
|
87
90
|
Connect to the Webterm's websocket.
|
88
91
|
"""
|
89
92
|
try:
|
90
93
|
await websocket.accept()
|
91
|
-
session_doc = await websocket.receive_json()
|
92
94
|
except starlette.websockets.WebSocketDisconnect:
|
93
95
|
return
|
94
|
-
session_id = (session_doc or {}).get('session-id', 'no-auth')
|
95
96
|
|
96
97
|
if not is_session_authenticated(session_id):
|
97
98
|
await websocket.close()
|
98
99
|
return
|
99
100
|
|
100
|
-
|
101
|
+
username = get_username_from_session(session_id)
|
102
|
+
|
103
|
+
ws_url = f"ws://localhost:8765/_websocket/{username or session_id}"
|
104
|
+
async with websockets.connect(ws_url) as ws:
|
101
105
|
async def forward_messages():
|
102
106
|
try:
|
103
107
|
while True:
|
meerschaum/config/_default.py
CHANGED
@@ -127,6 +127,12 @@ default_system_config = {
|
|
127
127
|
},
|
128
128
|
'protocol': default_meerschaum_config['connectors']['api']['default']['protocol'],
|
129
129
|
},
|
130
|
+
'webterm': {
|
131
|
+
'tmux': {
|
132
|
+
'enabled': True,
|
133
|
+
'session_suffix': '_mrsm',
|
134
|
+
},
|
135
|
+
},
|
130
136
|
'experimental': {
|
131
137
|
'fetch': False,
|
132
138
|
'cache': True,
|
meerschaum/config/_version.py
CHANGED
@@ -32,8 +32,8 @@ STATIC_CONFIG: Dict[str, Any] = {
|
|
32
32
|
'chaining': '/chaining',
|
33
33
|
'websocket': '/ws',
|
34
34
|
'dash': '/dash',
|
35
|
-
'webterm': '/webterm',
|
36
|
-
'webterm_websocket': '/
|
35
|
+
'webterm': r'/webterm/{session_id}',
|
36
|
+
'webterm_websocket': r'/_websocket/{session_id}',
|
37
37
|
'info': '/info',
|
38
38
|
'healthcheck': '/healthcheck',
|
39
39
|
},
|
meerschaum/core/Pipe/_sync.py
CHANGED
@@ -327,15 +327,15 @@ def sync(
|
|
327
327
|
_chunk_success, _chunk_msg = False, str(e)
|
328
328
|
if not _chunk_success:
|
329
329
|
failed_chunks.append(_chunk)
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
+ '\n'
|
335
|
-
+ _chunk_msg
|
336
|
-
)
|
330
|
+
_chunk_msg = (
|
331
|
+
self._get_chunk_label(_chunk, dt_col)
|
332
|
+
+ '\n'
|
333
|
+
+ _chunk_msg
|
337
334
|
)
|
338
335
|
|
336
|
+
mrsm.pprint((_chunk_success, _chunk_msg), calm=True)
|
337
|
+
return _chunk_success, _chunk_msg
|
338
|
+
|
339
339
|
results = sorted(
|
340
340
|
[(chunk_success, chunk_msg)] + (
|
341
341
|
list(pool.imap(_process_chunk, df))
|