pinokiod 3.85.0 → 3.87.0
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.
- package/Dockerfile +61 -0
- package/docker-entrypoint.sh +75 -0
- package/kernel/api/hf/index.js +1 -1
- package/kernel/api/index.js +8 -1
- package/kernel/api/shell/index.js +6 -0
- package/kernel/api/terminal/index.js +166 -0
- package/kernel/bin/caddy.js +10 -4
- package/kernel/bin/conda.js +3 -2
- package/kernel/bin/index.js +53 -2
- package/kernel/bin/setup.js +32 -0
- package/kernel/bin/vs.js +11 -2
- package/kernel/index.js +42 -2
- package/kernel/info.js +36 -0
- package/kernel/peer.js +42 -18
- package/kernel/prototype.js +1 -0
- package/kernel/router/index.js +23 -15
- package/kernel/router/localhost_static_router.js +0 -3
- package/kernel/router/pinokio_domain_router.js +333 -0
- package/kernel/shell.js +43 -2
- package/kernel/shells.js +21 -1
- package/kernel/util.js +4 -2
- package/package.json +2 -1
- package/pipe/views/login.ejs +1 -1
- package/script/install-mode.js +33 -0
- package/script/pinokio.json +7 -0
- package/server/index.js +636 -246
- package/server/public/Socket.js +48 -0
- package/server/public/common.js +1956 -257
- package/server/public/fseditor.js +71 -12
- package/server/public/install.js +1 -1
- package/server/public/layout.js +740 -0
- package/server/public/modalinput.js +0 -1
- package/server/public/opener.js +12 -11
- package/server/public/serve/style.css +1 -1
- package/server/public/style.css +122 -129
- package/server/public/tab-idle-notifier.js +629 -0
- package/server/public/terminal_input_tracker.js +63 -0
- package/server/public/urldropdown.css +780 -45
- package/server/public/urldropdown.js +806 -156
- package/server/public/window_storage.js +97 -28
- package/server/socket.js +40 -9
- package/server/views/404.ejs +1 -1
- package/server/views/500.ejs +3 -3
- package/server/views/app.ejs +3146 -1381
- package/server/views/bookmarklet.ejs +197 -0
- package/server/views/bootstrap.ejs +1 -1
- package/server/views/columns.ejs +2 -13
- package/server/views/connect/x.ejs +4 -4
- package/server/views/connect.ejs +13 -14
- package/server/views/container.ejs +3 -4
- package/server/views/d.ejs +225 -55
- package/server/views/download.ejs +1 -1
- package/server/views/editor.ejs +2 -2
- package/server/views/env_editor.ejs +3 -3
- package/server/views/explore.ejs +2 -2
- package/server/views/file_explorer.ejs +3 -3
- package/server/views/git.ejs +7 -7
- package/server/views/github.ejs +3 -3
- package/server/views/help.ejs +2 -2
- package/server/views/index.ejs +17 -16
- package/server/views/index2.ejs +7 -7
- package/server/views/init/index.ejs +15 -79
- package/server/views/install.ejs +4 -4
- package/server/views/keys.ejs +2 -2
- package/server/views/layout.ejs +105 -0
- package/server/views/mini.ejs +2 -2
- package/server/views/net.ejs +45 -13
- package/server/views/network.ejs +41 -27
- package/server/views/network2.ejs +11 -11
- package/server/views/old_network.ejs +10 -10
- package/server/views/partials/dynamic.ejs +3 -5
- package/server/views/partials/menu.ejs +3 -5
- package/server/views/partials/running.ejs +1 -1
- package/server/views/pro.ejs +369 -0
- package/server/views/prototype/index.ejs +3 -3
- package/server/views/required_env_editor.ejs +2 -2
- package/server/views/review.ejs +15 -27
- package/server/views/rows.ejs +2 -13
- package/server/views/screenshots.ejs +298 -142
- package/server/views/settings.ejs +6 -7
- package/server/views/setup.ejs +3 -4
- package/server/views/setup_home.ejs +2 -2
- package/server/views/share_editor.ejs +4 -4
- package/server/views/shell.ejs +280 -29
- package/server/views/start.ejs +2 -2
- package/server/views/task.ejs +2 -2
- package/server/views/terminal.ejs +326 -52
- package/server/views/tools.ejs +461 -17
package/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
|
+
const querystring = require("querystring");
|
|
2
3
|
const diff = require('diff')
|
|
3
4
|
const kill = require('kill-sync')
|
|
4
5
|
const { isBinaryFile } = require("isbinaryfile");
|
|
@@ -108,10 +109,53 @@ class Server {
|
|
|
108
109
|
stop() {
|
|
109
110
|
this.server.close()
|
|
110
111
|
}
|
|
112
|
+
killProcessTree(pid, label) {
|
|
113
|
+
const numericPid = typeof pid === 'string' ? parseInt(pid, 10) : pid
|
|
114
|
+
if (!Number.isInteger(numericPid) || numericPid <= 0) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
if (label) {
|
|
118
|
+
console.log(label, numericPid)
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
kill(numericPid, 'SIGKILL', true)
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error && error.code === 'ESRCH') {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
console.error(`Failed to kill pid ${numericPid}`, error)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
killTrackedProcesses() {
|
|
130
|
+
if (this.kernel && this.kernel.processes && this.kernel.processes.map) {
|
|
131
|
+
for (const [pid, name] of Object.entries(this.kernel.processes.map)) {
|
|
132
|
+
if (parseInt(pid, 10) === process.pid) {
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
this.killProcessTree(pid, `kill child ${name}`)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
shutdown(signalLabel) {
|
|
140
|
+
const label = signalLabel || 'Shutdown'
|
|
141
|
+
console.log(`[${label} event] Kill`, process.pid)
|
|
142
|
+
if (this.kernel && this.kernel.shell) {
|
|
143
|
+
try {
|
|
144
|
+
this.kernel.shell.reset()
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error('Failed to reset shells', error)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
this.killTrackedProcesses()
|
|
150
|
+
if (this.kernel && this.kernel.processes && this.kernel.processes.caddy_pid) {
|
|
151
|
+
this.killProcessTree(this.kernel.processes.caddy_pid, 'kill caddy')
|
|
152
|
+
}
|
|
153
|
+
this.killProcessTree(process.pid, 'kill self')
|
|
154
|
+
}
|
|
111
155
|
exists (s) {
|
|
112
156
|
return new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
|
|
113
157
|
}
|
|
114
|
-
running_dynamic (name, menu) {
|
|
158
|
+
running_dynamic (name, menu, selected_query) {
|
|
115
159
|
let cwd = this.kernel.path("api", name)
|
|
116
160
|
let running_dynamic = []
|
|
117
161
|
const traverse = (obj, indexPath) => {
|
|
@@ -136,9 +180,17 @@ class Server {
|
|
|
136
180
|
|
|
137
181
|
let id = `${filepath}?cwd=${cwd}`
|
|
138
182
|
//if (this.kernel.api.running[filepath]) {
|
|
139
|
-
if (this.kernel.api.running[id]) {
|
|
183
|
+
if (this.kernel.api.running[id] || selected_query.plugin === obj.src) {
|
|
140
184
|
obj.running = true
|
|
141
185
|
obj.display = "indent"
|
|
186
|
+
if (selected_query.plugin === obj.src) {
|
|
187
|
+
obj.default = true
|
|
188
|
+
for(let key in selected_query) {
|
|
189
|
+
if (key !== "plugin") {
|
|
190
|
+
obj.href = obj.href + "&" + key + "=" + encodeURIComponent(selected_query[key])
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
142
194
|
running_dynamic.push(obj)
|
|
143
195
|
}
|
|
144
196
|
} else if (href.startsWith("/run")) {
|
|
@@ -148,20 +200,109 @@ class Server {
|
|
|
148
200
|
let id = `${filepath}?cwd=${cwd}`
|
|
149
201
|
obj.script_id = id
|
|
150
202
|
//if (this.kernel.api.running[filepath]) {
|
|
151
|
-
if (
|
|
203
|
+
if (obj.src.startsWith("/run" + selected_query.plugin)) {
|
|
152
204
|
obj.running = true
|
|
153
205
|
obj.display = "indent"
|
|
206
|
+
obj.default = true
|
|
207
|
+
for(let key in selected_query) {
|
|
208
|
+
if (key !== "plugin") {
|
|
209
|
+
obj.href = obj.href + "&" + key + "=" + encodeURIComponent(selected_query[key])
|
|
210
|
+
}
|
|
211
|
+
}
|
|
154
212
|
running_dynamic.push(obj)
|
|
213
|
+
} else {
|
|
214
|
+
for(let running_id in this.kernel.api.running) {
|
|
215
|
+
if (running_id.startsWith(id)) {
|
|
216
|
+
let obj2 = structuredClone(obj)
|
|
217
|
+
obj2.running = true
|
|
218
|
+
obj2.display = "indent"
|
|
219
|
+
|
|
220
|
+
const query = running_id.split("?")[1];
|
|
221
|
+
const params = query ? querystring.parse(query) : {};
|
|
222
|
+
|
|
223
|
+
let queryStrippedHref = obj2.href.split("?")[0]
|
|
224
|
+
if (params && Object.keys(params).length > 0) {
|
|
225
|
+
obj2.href = queryStrippedHref + "?" + querystring.stringify(params)
|
|
226
|
+
} else {
|
|
227
|
+
obj2.href = queryStrippedHref
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
obj2.script_id = running_id
|
|
231
|
+
obj2.target = "@" + obj2.href
|
|
232
|
+
obj2.target_full = obj2.href
|
|
233
|
+
|
|
234
|
+
running_dynamic.push(obj2)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
155
237
|
}
|
|
156
238
|
}
|
|
157
239
|
} else if (key === "shell") {
|
|
240
|
+
const appendSession = (value, session) => {
|
|
241
|
+
if (!value || !session) {
|
|
242
|
+
return value
|
|
243
|
+
}
|
|
244
|
+
const hasPrefix = value.startsWith("@")
|
|
245
|
+
const raw = hasPrefix ? value.slice(1) : value
|
|
246
|
+
const [pathPart, queryPart] = raw.split("?")
|
|
247
|
+
const parsed = queryPart ? querystring.parse(queryPart) : {}
|
|
248
|
+
parsed.session = session
|
|
249
|
+
const qs = querystring.stringify(parsed)
|
|
250
|
+
const combined = qs ? `${pathPart}?${qs}` : pathPart
|
|
251
|
+
return hasPrefix ? `@${combined}` : combined
|
|
252
|
+
}
|
|
253
|
+
|
|
158
254
|
let unix_path = Util.p2u(this.kernel.path("api", name))
|
|
159
255
|
let shell_id = this.get_shell_id(unix_path, indexPath, obj[key])
|
|
160
256
|
let decoded_shell_id = decodeURIComponent(shell_id)
|
|
161
|
-
|
|
257
|
+
let id = "shell/" + decoded_shell_id
|
|
258
|
+
|
|
259
|
+
const originalHref = obj.href
|
|
260
|
+
const originalTarget = obj.target
|
|
261
|
+
|
|
262
|
+
const activeShells = (this.kernel.shell && Array.isArray(this.kernel.shell.shells))
|
|
263
|
+
? this.kernel.shell.shells.filter((entry) => {
|
|
264
|
+
if (!entry || !entry.id) {
|
|
265
|
+
return false
|
|
266
|
+
}
|
|
267
|
+
return entry.id === id || entry.id.startsWith(`${id}?session=`)
|
|
268
|
+
})
|
|
269
|
+
: []
|
|
270
|
+
|
|
271
|
+
if (activeShells.length > 0 || selected_query.plugin === id) {
|
|
162
272
|
obj.running = true
|
|
163
273
|
obj.display = "indent"
|
|
164
|
-
|
|
274
|
+
if (selected_query.plugin === id) {
|
|
275
|
+
obj.default = true
|
|
276
|
+
for(let key in selected_query) {
|
|
277
|
+
if (key !== "plugin") {
|
|
278
|
+
obj.href = obj.href + "&" + key + "=" + encodeURIComponent(selected_query[key])
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (activeShells.length === 0) {
|
|
284
|
+
running_dynamic.push(obj)
|
|
285
|
+
} else {
|
|
286
|
+
activeShells.forEach((shellEntry) => {
|
|
287
|
+
const clone = structuredClone(obj)
|
|
288
|
+
clone.running = true
|
|
289
|
+
clone.display = "indent"
|
|
290
|
+
clone.shell_id = shellEntry.id
|
|
291
|
+
const sessionMatch = /[?&]session=([^&]+)/.exec(shellEntry.id)
|
|
292
|
+
if (sessionMatch && sessionMatch[1]) {
|
|
293
|
+
const sessionValue = sessionMatch[1]
|
|
294
|
+
clone.href = appendSession(originalHref, sessionValue)
|
|
295
|
+
const baseTarget = originalTarget || `@${originalHref}`
|
|
296
|
+
clone.target = appendSession(baseTarget, sessionValue)
|
|
297
|
+
clone.target_full = clone.href
|
|
298
|
+
} else {
|
|
299
|
+
clone.href = originalHref
|
|
300
|
+
clone.target = originalTarget ? originalTarget : `@${clone.href}`
|
|
301
|
+
clone.target_full = clone.href
|
|
302
|
+
}
|
|
303
|
+
running_dynamic.push(clone)
|
|
304
|
+
})
|
|
305
|
+
}
|
|
165
306
|
}
|
|
166
307
|
}
|
|
167
308
|
traverse(obj[key], indexPath);
|
|
@@ -292,30 +433,29 @@ class Server {
|
|
|
292
433
|
}
|
|
293
434
|
}
|
|
294
435
|
} else {
|
|
295
|
-
cfg = await this.renderIndex(name)
|
|
436
|
+
cfg = await this.renderIndex(name, cfg)
|
|
296
437
|
}
|
|
297
438
|
} else {
|
|
298
|
-
cfg = await this.renderIndex(name)
|
|
439
|
+
cfg = await this.renderIndex(name, cfg)
|
|
299
440
|
}
|
|
300
441
|
return cfg
|
|
301
442
|
}
|
|
302
|
-
async renderIndex(name) {
|
|
443
|
+
async renderIndex(name, cfg) {
|
|
303
444
|
let p = this.kernel.path("api", name)
|
|
304
445
|
let html_path = path.resolve(p, "index.html")
|
|
305
446
|
let html_exists = await this.kernel.exists(html_path)
|
|
306
|
-
console.log({ html_path, html_exists })
|
|
307
447
|
if (html_exists) {
|
|
308
|
-
return {
|
|
448
|
+
return Object.assign({
|
|
309
449
|
title: name,
|
|
310
450
|
menu: [{
|
|
311
451
|
default: true,
|
|
312
452
|
icon: "fa-solid fa-link",
|
|
313
453
|
text: "index.html",
|
|
314
|
-
href:
|
|
454
|
+
href: `/asset/api/${name}/index.html`,
|
|
315
455
|
}]
|
|
316
|
-
}
|
|
456
|
+
}, cfg)
|
|
317
457
|
} else {
|
|
318
|
-
return {
|
|
458
|
+
return Object.assign({
|
|
319
459
|
title: name,
|
|
320
460
|
menu: [{
|
|
321
461
|
default: true,
|
|
@@ -323,12 +463,26 @@ class Server {
|
|
|
323
463
|
text: "Project Files",
|
|
324
464
|
href: `/files/api/${name}`,
|
|
325
465
|
}]
|
|
326
|
-
}
|
|
466
|
+
}, cfg)
|
|
327
467
|
}
|
|
328
468
|
}
|
|
329
469
|
async getGit(ref, filepath) {
|
|
330
470
|
let dir = this.kernel.path("api", filepath)
|
|
331
471
|
let branches = await git.listBranches({ fs, dir });
|
|
472
|
+
// no branch, means no git repo => initialize
|
|
473
|
+
if (branches.length === 0) {
|
|
474
|
+
return {}
|
|
475
|
+
// const defaultBranch = 'main';
|
|
476
|
+
// await git.init({ fs, dir, defaultBranch });
|
|
477
|
+
// branches = await git.listBranches({ fs, dir });
|
|
478
|
+
// const current = await git.currentBranch({ fs, dir, fullname: false }) || defaultBranch;
|
|
479
|
+
// if (!branches.includes(current)) {
|
|
480
|
+
// branches.unshift(current);
|
|
481
|
+
// }
|
|
482
|
+
// if (!ref || ref === 'HEAD') {
|
|
483
|
+
// ref = current;
|
|
484
|
+
// }
|
|
485
|
+
}
|
|
332
486
|
let log = []
|
|
333
487
|
try {
|
|
334
488
|
log = await git.log({ fs, dir, depth: 50, ref: ref }); // fetch last 50 commits
|
|
@@ -509,7 +663,6 @@ class Server {
|
|
|
509
663
|
}
|
|
510
664
|
}
|
|
511
665
|
|
|
512
|
-
|
|
513
666
|
let uri = this.kernel.path("api")
|
|
514
667
|
try {
|
|
515
668
|
let launcher = await this.kernel.api.launcher(name)
|
|
@@ -520,9 +673,7 @@ class Server {
|
|
|
520
673
|
err = e.stack
|
|
521
674
|
}
|
|
522
675
|
|
|
523
|
-
console.log("renderMenu before", config)
|
|
524
676
|
await this.renderMenu(req, uri, name, config, [])
|
|
525
|
-
console.log("renderMenu after", config)
|
|
526
677
|
|
|
527
678
|
let platform = os.platform()
|
|
528
679
|
|
|
@@ -557,30 +708,30 @@ class Server {
|
|
|
557
708
|
}
|
|
558
709
|
const env = await this.kernel.env("api/" + name)
|
|
559
710
|
|
|
560
|
-
// profile + feed
|
|
561
|
-
const repositoryPath = path.resolve(this.kernel.api.userdir, name)
|
|
562
|
-
|
|
563
|
-
try {
|
|
564
|
-
await git.resolveRef({ fs, dir: repositoryPath, ref: 'HEAD' });
|
|
565
|
-
} catch (err) {
|
|
566
|
-
// repo doesn't exist. initialize.
|
|
567
|
-
console.log(`repo doesn't exist at ${repositoryPath}. initialize`)
|
|
568
|
-
await git.init({ fs, dir: repositoryPath });
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
let gitRemote = await git.getConfig({ fs, http, dir: repositoryPath, path: 'remote.origin.url' })
|
|
572
|
-
let profile
|
|
573
|
-
let feed
|
|
574
|
-
if (gitRemote) {
|
|
575
|
-
gitRemote = gitRemote.replace(/\.git$/i, '')
|
|
576
|
-
|
|
577
|
-
let system_env = {}
|
|
578
|
-
if (this.kernel.homedir) {
|
|
579
|
-
system_env = await Environment.get(this.kernel.homedir, this.kernel)
|
|
580
|
-
}
|
|
581
|
-
profile = this.profile(gitRemote)
|
|
582
|
-
feed = this.newsfeed(gitRemote)
|
|
583
|
-
}
|
|
711
|
+
// // profile + feed
|
|
712
|
+
// const repositoryPath = path.resolve(this.kernel.api.userdir, name)
|
|
713
|
+
//
|
|
714
|
+
// try {
|
|
715
|
+
// await git.resolveRef({ fs, dir: repositoryPath, ref: 'HEAD' });
|
|
716
|
+
// } catch (err) {
|
|
717
|
+
// // repo doesn't exist. initialize.
|
|
718
|
+
// console.log(`repo doesn't exist at ${repositoryPath}. initialize`)
|
|
719
|
+
// await git.init({ fs, dir: repositoryPath });
|
|
720
|
+
// }
|
|
721
|
+
//
|
|
722
|
+
// let gitRemote = await git.getConfig({ fs, http, dir: repositoryPath, path: 'remote.origin.url' })
|
|
723
|
+
// let profile
|
|
724
|
+
// let feed
|
|
725
|
+
// if (gitRemote) {
|
|
726
|
+
// gitRemote = gitRemote.replace(/\.git$/i, '')
|
|
727
|
+
//
|
|
728
|
+
// let system_env = {}
|
|
729
|
+
// if (this.kernel.homedir) {
|
|
730
|
+
// system_env = await Environment.get(this.kernel.homedir, this.kernel)
|
|
731
|
+
// }
|
|
732
|
+
// profile = this.profile(gitRemote)
|
|
733
|
+
// feed = this.newsfeed(gitRemote)
|
|
734
|
+
// }
|
|
584
735
|
|
|
585
736
|
// git
|
|
586
737
|
|
|
@@ -602,7 +753,11 @@ class Server {
|
|
|
602
753
|
let plugin = await this.getPlugin(req, plugin_config, name)
|
|
603
754
|
if (plugin && plugin.menu && Array.isArray(plugin.menu)) {
|
|
604
755
|
plugin = structuredClone(plugin)
|
|
605
|
-
|
|
756
|
+
let default_plugin_query
|
|
757
|
+
if (req.query) {
|
|
758
|
+
default_plugin_query = req.query
|
|
759
|
+
}
|
|
760
|
+
plugin_menu = this.running_dynamic(name, plugin.menu, default_plugin_query)
|
|
606
761
|
}
|
|
607
762
|
|
|
608
763
|
let posix_path = Util.p2u(this.kernel.path("api", name))
|
|
@@ -617,6 +772,18 @@ class Server {
|
|
|
617
772
|
let dev_tab = "/p/" + name + "/dev"
|
|
618
773
|
let review_tab = "/p/" + name + "/review"
|
|
619
774
|
|
|
775
|
+
let dynamic_url = "/pinokio/dynamic/" + name;
|
|
776
|
+
if (Object.values(req.query).length > 0) {
|
|
777
|
+
let index = 0
|
|
778
|
+
for(let key in req.query) {
|
|
779
|
+
if (index === 0) {
|
|
780
|
+
dynamic_url = dynamic_url + `?${key}=${encodeURIComponent(req.query[key])}`
|
|
781
|
+
} else {
|
|
782
|
+
dynamic_url = dynamic_url + `&${key}=${encodeURIComponent(req.query[key])}`
|
|
783
|
+
}
|
|
784
|
+
index++;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
620
787
|
|
|
621
788
|
const result = {
|
|
622
789
|
dev_link,
|
|
@@ -639,12 +806,12 @@ class Server {
|
|
|
639
806
|
sidebar: "/pinokio/sidebar/" + name,
|
|
640
807
|
repos: "/pinokio/repos/" + name,
|
|
641
808
|
ai: "/pinokio/ai/" + name,
|
|
642
|
-
dynamic:
|
|
809
|
+
dynamic: dynamic_url,
|
|
643
810
|
// dynamic: "/pinokio/dynamic/" + name,
|
|
644
811
|
dynamic_content: null,
|
|
645
812
|
name,
|
|
646
|
-
profile,
|
|
647
|
-
feed,
|
|
813
|
+
// profile,
|
|
814
|
+
// feed,
|
|
648
815
|
tabs: (this.tabs[name] || []),
|
|
649
816
|
config,
|
|
650
817
|
// sidebar_url: "/pinokio/sidebar/" + name,
|
|
@@ -1019,7 +1186,6 @@ class Server {
|
|
|
1019
1186
|
template = "editor"
|
|
1020
1187
|
}
|
|
1021
1188
|
|
|
1022
|
-
console.log("check requirements")
|
|
1023
1189
|
let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
|
|
1024
1190
|
//bin: this.kernel.bin.preset("ai"),
|
|
1025
1191
|
bin: this.kernel.bin.preset("dev"),
|
|
@@ -1076,7 +1242,6 @@ class Server {
|
|
|
1076
1242
|
if (platform === "win32") {
|
|
1077
1243
|
root_path = root_path.replace(/\\/g, '\\\\')
|
|
1078
1244
|
}
|
|
1079
|
-
console.log({ cwd, api_path, root, root_path })
|
|
1080
1245
|
res.render("required_env_editor", {
|
|
1081
1246
|
portal: this.portal,
|
|
1082
1247
|
agent: req.agent,
|
|
@@ -1360,9 +1525,51 @@ class Server {
|
|
|
1360
1525
|
}
|
|
1361
1526
|
// check if there is a running process with this folder name
|
|
1362
1527
|
let runningApps = new Set()
|
|
1528
|
+
const item_path = this.kernel.path("api", items[i].name)
|
|
1529
|
+
const normalizedItemPath = path.normalize(item_path)
|
|
1530
|
+
const itemPathWithSep = normalizedItemPath.endsWith(path.sep)
|
|
1531
|
+
? normalizedItemPath
|
|
1532
|
+
: normalizedItemPath + path.sep
|
|
1533
|
+
const unix_item_path = Util.p2u(item_path)
|
|
1534
|
+
const shellPrefix = "shell/" + unix_item_path + "_"
|
|
1535
|
+
const matchesShell = (candidate) => {
|
|
1536
|
+
if (!candidate) return false
|
|
1537
|
+
const idMatches = typeof candidate.id === "string" && candidate.id.startsWith(shellPrefix)
|
|
1538
|
+
const shellPath = typeof candidate.path === "string" ? path.normalize(candidate.path) : null
|
|
1539
|
+
const groupPath = typeof candidate.group === "string" ? path.normalize(candidate.group) : null
|
|
1540
|
+
const parentCwd = candidate.params && candidate.params.$parent && typeof candidate.params.$parent.cwd === "string"
|
|
1541
|
+
? path.normalize(candidate.params.$parent.cwd)
|
|
1542
|
+
: null
|
|
1543
|
+
const paramsCwd = candidate.params && typeof candidate.params.cwd === "string"
|
|
1544
|
+
? path.normalize(candidate.params.cwd)
|
|
1545
|
+
: null
|
|
1546
|
+
const pathMatches = shellPath && (shellPath === normalizedItemPath || shellPath.startsWith(itemPathWithSep))
|
|
1547
|
+
const groupMatches = groupPath && (groupPath === normalizedItemPath || groupPath.startsWith(itemPathWithSep))
|
|
1548
|
+
const parentMatches = parentCwd && (parentCwd === normalizedItemPath || parentCwd.startsWith(itemPathWithSep))
|
|
1549
|
+
const paramsMatches = paramsCwd && (paramsCwd === normalizedItemPath || paramsCwd.startsWith(itemPathWithSep))
|
|
1550
|
+
return idMatches || pathMatches || groupMatches || parentMatches || paramsMatches
|
|
1551
|
+
}
|
|
1552
|
+
const shellMatches = (this.kernel.shell && typeof this.kernel.shell.find === "function")
|
|
1553
|
+
? this.kernel.shell.find({ filter: matchesShell })
|
|
1554
|
+
: []
|
|
1555
|
+
const addShellEntries = () => {
|
|
1556
|
+
if (!shellMatches || shellMatches.length === 0) {
|
|
1557
|
+
return
|
|
1558
|
+
}
|
|
1559
|
+
if (!items[i].running_scripts) {
|
|
1560
|
+
items[i].running_scripts = []
|
|
1561
|
+
}
|
|
1562
|
+
for (const sh of shellMatches) {
|
|
1563
|
+
if (!sh || !sh.id) continue
|
|
1564
|
+
const exists = items[i].running_scripts.some((entry) => entry && entry.id === sh.id)
|
|
1565
|
+
if (!exists) {
|
|
1566
|
+
items[i].running_scripts.push({ id: sh.id, name: sh.params.$title || "Shell", type: "shell" })
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1363
1570
|
for(let key in this.kernel.api.running) {
|
|
1364
1571
|
//let p = this.kernel.path("api", items[i].name) + path.sep
|
|
1365
|
-
let p =
|
|
1572
|
+
let p = item_path
|
|
1366
1573
|
|
|
1367
1574
|
// not only should include the pattern, but also end with it (otherwise can include similar patterns such as /api/qqqa, /api/qqqaaa, etc.
|
|
1368
1575
|
|
|
@@ -1386,7 +1593,6 @@ class Server {
|
|
|
1386
1593
|
if (chunks.length > 1) {
|
|
1387
1594
|
let folder = chunks[0]
|
|
1388
1595
|
/// if the folder name matches, it's running
|
|
1389
|
-
let item_path = this.kernel.path("api", items[i].name)
|
|
1390
1596
|
if (item_path === folder) {
|
|
1391
1597
|
is_running = true
|
|
1392
1598
|
}
|
|
@@ -1403,12 +1609,15 @@ class Server {
|
|
|
1403
1609
|
//if (key.includes(p) && key.endsWith(p)) {
|
|
1404
1610
|
if (is_running) {
|
|
1405
1611
|
// add to running
|
|
1406
|
-
|
|
1612
|
+
if (!items[i].running) {
|
|
1613
|
+
running.push(items[i])
|
|
1614
|
+
items[i].running = true
|
|
1615
|
+
items[i].index = index
|
|
1616
|
+
index++
|
|
1617
|
+
}
|
|
1407
1618
|
if (!items[i].running_scripts) {
|
|
1408
1619
|
items[i].running_scripts = []
|
|
1409
1620
|
}
|
|
1410
|
-
items[i].running = true
|
|
1411
|
-
items[i].index = index
|
|
1412
1621
|
|
|
1413
1622
|
// add the running script to running_scripts array
|
|
1414
1623
|
// 1. normal api script
|
|
@@ -1429,24 +1638,17 @@ class Server {
|
|
|
1429
1638
|
items[i].running_scripts.push({ id: key, name })
|
|
1430
1639
|
}
|
|
1431
1640
|
} else {
|
|
1432
|
-
|
|
1433
|
-
filter: (shell) => {
|
|
1434
|
-
let item_path = this.kernel.path("api", items[i].name)
|
|
1435
|
-
let unix_item_path = Util.p2u(item_path)
|
|
1436
|
-
return shell.id.startsWith("shell/" + unix_item_path + "_")
|
|
1437
|
-
}
|
|
1438
|
-
})
|
|
1439
|
-
if (shell.length > 0) {
|
|
1440
|
-
items[i].running = true
|
|
1441
|
-
items[i].index = index
|
|
1442
|
-
for(let sh of shell) {
|
|
1443
|
-
items[i].running_scripts.push({ id: sh.id, name: "Terminal", type: "shell" })
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1641
|
+
addShellEntries()
|
|
1446
1642
|
}
|
|
1447
|
-
index++;
|
|
1448
1643
|
}
|
|
1449
1644
|
}
|
|
1645
|
+
if (!items[i].running && shellMatches && shellMatches.length > 0) {
|
|
1646
|
+
running.push(items[i])
|
|
1647
|
+
items[i].running = true
|
|
1648
|
+
items[i].index = index
|
|
1649
|
+
addShellEntries()
|
|
1650
|
+
index++
|
|
1651
|
+
}
|
|
1450
1652
|
if (!items[i].running) {
|
|
1451
1653
|
items[i].index = index
|
|
1452
1654
|
index++;
|
|
@@ -1613,7 +1815,6 @@ class Server {
|
|
|
1613
1815
|
items
|
|
1614
1816
|
})
|
|
1615
1817
|
} else {
|
|
1616
|
-
console.log("RENDER FILE EXPLORER")
|
|
1617
1818
|
res.render("file_explorer", {
|
|
1618
1819
|
docs: this.docs,
|
|
1619
1820
|
portal: this.portal,
|
|
@@ -1793,15 +1994,19 @@ class Server {
|
|
|
1793
1994
|
// }
|
|
1794
1995
|
menuitem.href = "/shell/" + shell_id + "?" + params.toString()
|
|
1795
1996
|
let decoded_shell_id = decodeURIComponent(shell_id)
|
|
1796
|
-
|
|
1797
|
-
|
|
1997
|
+
const shellPrefixId = "shell/" + decoded_shell_id
|
|
1998
|
+
let shell = this.kernel.shell.get(shellPrefixId)
|
|
1999
|
+
if (!shell && this.kernel.shell && Array.isArray(this.kernel.shell.shells)) {
|
|
2000
|
+
shell = this.kernel.shell.shells.find((entry) => {
|
|
2001
|
+
if (!entry || !entry.id) {
|
|
2002
|
+
return false
|
|
2003
|
+
}
|
|
2004
|
+
return entry.id === shellPrefixId || entry.id.startsWith(`${shellPrefixId}?session=`)
|
|
2005
|
+
})
|
|
2006
|
+
}
|
|
2007
|
+
menuitem.shell_id = shellPrefixId
|
|
1798
2008
|
if (shell) {
|
|
1799
2009
|
menuitem.running = true
|
|
1800
|
-
} else {
|
|
1801
|
-
let shell = this.kernel.shell.get(decoded_shell_id)
|
|
1802
|
-
if (shell) {
|
|
1803
|
-
menuitem.running = true
|
|
1804
|
-
}
|
|
1805
2010
|
}
|
|
1806
2011
|
}
|
|
1807
2012
|
return menuitem
|
|
@@ -1920,10 +2125,11 @@ class Server {
|
|
|
1920
2125
|
} else if (menuitem.href.startsWith("/")) {
|
|
1921
2126
|
let run_path = "/run"
|
|
1922
2127
|
if (menuitem.href.startsWith(run_path)) {
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
2128
|
+
menuitem.src = menuitem.href
|
|
2129
|
+
// u = new URL("http://localhost" + menuitem.href.slice(run_path.length))
|
|
2130
|
+
// cwd = u.searchParams.get("cwd")
|
|
2131
|
+
// u.search = ""
|
|
2132
|
+
// menuitem.src = u.pathname
|
|
1927
2133
|
} else {
|
|
1928
2134
|
u = new URL("http://localhost" + menuitem.href)
|
|
1929
2135
|
cwd = u.searchParams.get("cwd")
|
|
@@ -2033,7 +2239,6 @@ class Server {
|
|
|
2033
2239
|
if (menuitem.image.startsWith("/")) {
|
|
2034
2240
|
imagePath = menuitem.image
|
|
2035
2241
|
} else {
|
|
2036
|
-
console.log({ launcher_root, name, image: menuitem.image })
|
|
2037
2242
|
if (launcher_root) {
|
|
2038
2243
|
imagePath = `/api/${name}/${launcher_root}/${menuitem.image}?raw=true`
|
|
2039
2244
|
} else {
|
|
@@ -2063,16 +2268,19 @@ class Server {
|
|
|
2063
2268
|
if (config.menu[i].popout) {
|
|
2064
2269
|
config.menu[i].target = "_blank"
|
|
2065
2270
|
} else {
|
|
2066
|
-
config.menu[i].
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
if (config.menu[i].href && config.menu[i].href.startsWith("http")) {
|
|
2071
|
-
if (req.agent !== "electron") {
|
|
2072
|
-
config.menu[i].target = "_blank"
|
|
2271
|
+
const targetBase = config.menu[i].id || config.menu[i].src || config.menu[i].href
|
|
2272
|
+
config.menu[i].target = targetBase ? "@" + targetBase : undefined
|
|
2273
|
+
if (config.menu[i].href) {
|
|
2274
|
+
config.menu[i].target_full = config.menu[i].href
|
|
2073
2275
|
}
|
|
2074
2276
|
}
|
|
2075
2277
|
|
|
2278
|
+
//if (config.menu[i].href && config.menu[i].href.startsWith("http")) {
|
|
2279
|
+
// if (req.agent !== "electron") {
|
|
2280
|
+
// config.menu[i].target = "_blank"
|
|
2281
|
+
// }
|
|
2282
|
+
//}
|
|
2283
|
+
|
|
2076
2284
|
if (menuitem.shell_id) {
|
|
2077
2285
|
config.menu[i].shell_id = menuitem.shell_id
|
|
2078
2286
|
}
|
|
@@ -2398,7 +2606,7 @@ class Server {
|
|
|
2398
2606
|
// }
|
|
2399
2607
|
}
|
|
2400
2608
|
async setConfig(config) {
|
|
2401
|
-
let home = this.kernel.store.get("home")
|
|
2609
|
+
let home = this.kernel.store.get("home") || process.env.PINOKIO_HOME
|
|
2402
2610
|
let theme = this.kernel.store.get("theme")
|
|
2403
2611
|
let mode = this.kernel.store.get("mode")
|
|
2404
2612
|
// let drive = this.kernel.store.get("drive")
|
|
@@ -2463,9 +2671,9 @@ class Server {
|
|
|
2463
2671
|
// }
|
|
2464
2672
|
|
|
2465
2673
|
|
|
2466
|
-
home = this.kernel.store.get("home")
|
|
2674
|
+
home = this.kernel.store.get("home") || process.env.PINOKIO_HOME
|
|
2467
2675
|
theme = this.kernel.store.get("theme")
|
|
2468
|
-
let new_home = this.kernel.store.get("new_home")
|
|
2676
|
+
let new_home = this.kernel.store.get("new_home") || process.env.PINOKIO_HOME
|
|
2469
2677
|
|
|
2470
2678
|
// Handle environment variables
|
|
2471
2679
|
// HTTP_PROXY
|
|
@@ -2538,6 +2746,66 @@ class Server {
|
|
|
2538
2746
|
return true
|
|
2539
2747
|
}
|
|
2540
2748
|
}
|
|
2749
|
+
add_extra_urls(info) {
|
|
2750
|
+
// get only the parts not from this peer
|
|
2751
|
+
for(let host in this.kernel.peer.info) {
|
|
2752
|
+
let host_info = this.kernel.peer.info[host]
|
|
2753
|
+
|
|
2754
|
+
let host_rewrites = host_info.rewrite_mapping
|
|
2755
|
+
for(let key in host_rewrites) {
|
|
2756
|
+
info.push({
|
|
2757
|
+
online: true,
|
|
2758
|
+
host: {
|
|
2759
|
+
ip: host,
|
|
2760
|
+
local: this.kernel.peer.host === host,
|
|
2761
|
+
name: host_info.name,
|
|
2762
|
+
platform: host_info.platform,
|
|
2763
|
+
arch: host_info.arch
|
|
2764
|
+
},
|
|
2765
|
+
name: `[Files] ${host_rewrites[key].name}`,
|
|
2766
|
+
ip: host_rewrites[key].external_ip
|
|
2767
|
+
})
|
|
2768
|
+
}
|
|
2769
|
+
if (this.kernel.peer.host !== host) {
|
|
2770
|
+
let host_routers = host_info.router_info
|
|
2771
|
+
for(let host_router of host_routers) {
|
|
2772
|
+
let ip
|
|
2773
|
+
// the peer sharing works only if external_ip is available (caddy is installed)
|
|
2774
|
+
if (host_router.external_ip) {
|
|
2775
|
+
ip = host_router.external_ip
|
|
2776
|
+
} else {
|
|
2777
|
+
// if caddy is not turned on, set ip as null, so that it suggests turning on peer sharing
|
|
2778
|
+
ip = null
|
|
2779
|
+
}
|
|
2780
|
+
info.push({
|
|
2781
|
+
online: true,
|
|
2782
|
+
host: {
|
|
2783
|
+
ip: host,
|
|
2784
|
+
name: host_info.name,
|
|
2785
|
+
platform: host_info.platform,
|
|
2786
|
+
arch: host_info.arch
|
|
2787
|
+
},
|
|
2788
|
+
name: host_router.title || host_router.name,
|
|
2789
|
+
ip
|
|
2790
|
+
})
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
for(let app of host_info.installed) {
|
|
2795
|
+
info.push({
|
|
2796
|
+
host: {
|
|
2797
|
+
ip: host,
|
|
2798
|
+
local: this.kernel.peer.host === host,
|
|
2799
|
+
name: host_info.name,
|
|
2800
|
+
platform: host_info.platform,
|
|
2801
|
+
arch: host_info.arch
|
|
2802
|
+
},
|
|
2803
|
+
name: app.title || app.folder,
|
|
2804
|
+
ip: app.http_href.replace("http://", "")
|
|
2805
|
+
})
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2541
2809
|
async terminals(filepath) {
|
|
2542
2810
|
let venvs = await Util.find_venv(filepath)
|
|
2543
2811
|
let terminal
|
|
@@ -2564,14 +2832,14 @@ class Server {
|
|
|
2564
2832
|
}
|
|
2565
2833
|
terminal = {
|
|
2566
2834
|
icon: "fa-solid fa-terminal",
|
|
2567
|
-
title: "
|
|
2835
|
+
title: "Terminal",
|
|
2568
2836
|
subtitle: "Open the terminal in the browser",
|
|
2569
2837
|
menu: terminals
|
|
2570
2838
|
}
|
|
2571
2839
|
} else {
|
|
2572
2840
|
terminal = {
|
|
2573
2841
|
icon: "fa-solid fa-terminal",
|
|
2574
|
-
title: "
|
|
2842
|
+
title: "Terminal",
|
|
2575
2843
|
subtitle: "Work with the terminal directly in the browser",
|
|
2576
2844
|
menu: [this.renderShell(filepath, 0, 0, {
|
|
2577
2845
|
icon: "fa-solid fa-terminal",
|
|
@@ -2753,7 +3021,7 @@ class Server {
|
|
|
2753
3021
|
await this.syncConfig()
|
|
2754
3022
|
|
|
2755
3023
|
try {
|
|
2756
|
-
let _home = this.kernel.store.get("home")
|
|
3024
|
+
let _home = this.kernel.store.get("home") || process.env.PINOKIO_HOME
|
|
2757
3025
|
if (_home) {
|
|
2758
3026
|
await this.startLogging(_home)
|
|
2759
3027
|
}
|
|
@@ -2789,7 +3057,7 @@ class Server {
|
|
|
2789
3057
|
}
|
|
2790
3058
|
|
|
2791
3059
|
let version = this.kernel.store.get("version")
|
|
2792
|
-
let home = this.kernel.store.get("home")
|
|
3060
|
+
let home = this.kernel.store.get("home") || process.env.PINOKIO_HOME
|
|
2793
3061
|
|
|
2794
3062
|
let needInitHome = false
|
|
2795
3063
|
if (home) {
|
|
@@ -3075,7 +3343,6 @@ class Server {
|
|
|
3075
3343
|
...result
|
|
3076
3344
|
})
|
|
3077
3345
|
}
|
|
3078
|
-
console.log(JSON.stringify(bundles, null, 2))
|
|
3079
3346
|
res.render("tools", {
|
|
3080
3347
|
current_host: this.kernel.peer.host,
|
|
3081
3348
|
pending,
|
|
@@ -3102,17 +3369,25 @@ class Server {
|
|
|
3102
3369
|
})
|
|
3103
3370
|
}))
|
|
3104
3371
|
this.app.get("/columns", ex(async (req, res) => {
|
|
3372
|
+
const originSrc = req.query.origin || req.get('Referrer') || '/';
|
|
3373
|
+
const targetSrc = req.query.target || originSrc;
|
|
3105
3374
|
res.render("columns", {
|
|
3106
3375
|
theme: this.theme,
|
|
3107
3376
|
agent: req.agent,
|
|
3108
|
-
|
|
3377
|
+
originSrc,
|
|
3378
|
+
targetSrc,
|
|
3379
|
+
src: originSrc
|
|
3109
3380
|
})
|
|
3110
3381
|
}))
|
|
3111
3382
|
this.app.get("/rows", ex(async (req, res) => {
|
|
3383
|
+
const originSrc = req.query.origin || req.get('Referrer') || '/';
|
|
3384
|
+
const targetSrc = req.query.target || originSrc;
|
|
3112
3385
|
res.render("rows", {
|
|
3113
3386
|
theme: this.theme,
|
|
3114
3387
|
agent: req.agent,
|
|
3115
|
-
|
|
3388
|
+
originSrc,
|
|
3389
|
+
targetSrc,
|
|
3390
|
+
src: originSrc
|
|
3116
3391
|
})
|
|
3117
3392
|
}))
|
|
3118
3393
|
|
|
@@ -3125,6 +3400,23 @@ class Server {
|
|
|
3125
3400
|
})
|
|
3126
3401
|
}))
|
|
3127
3402
|
|
|
3403
|
+
this.app.get("/bookmarklet", ex(async (req, res) => {
|
|
3404
|
+
const protocol = (req.$source && req.$source.protocol) || req.protocol || 'http';
|
|
3405
|
+
const host = req.get('host') || `localhost:${this.port}`;
|
|
3406
|
+
const baseUrl = `${protocol}://${host}`;
|
|
3407
|
+
const targetBase = `${baseUrl}/?create=1&prompt=`;
|
|
3408
|
+
const safeTargetBase = targetBase.replace(/'/g, "\\'");
|
|
3409
|
+
const bookmarkletHref = `javascript:(()=>{window.open('${safeTargetBase}'+encodeURIComponent(window.location.href),'_blank');})();`;
|
|
3410
|
+
|
|
3411
|
+
res.render("bookmarklet", {
|
|
3412
|
+
theme: this.theme,
|
|
3413
|
+
agent: req.agent,
|
|
3414
|
+
baseUrl,
|
|
3415
|
+
targetBase,
|
|
3416
|
+
bookmarkletHref
|
|
3417
|
+
});
|
|
3418
|
+
}))
|
|
3419
|
+
|
|
3128
3420
|
//let home = this.kernel.homedir
|
|
3129
3421
|
//let home = this.kernel.store.get("home")
|
|
3130
3422
|
this.app.get("/launch", ex(async (req, res) => {
|
|
@@ -3145,7 +3437,6 @@ class Server {
|
|
|
3145
3437
|
autolaunch = true
|
|
3146
3438
|
}
|
|
3147
3439
|
let chunks = host.split(".")
|
|
3148
|
-
console.log("GET /launch", { url, host, chunks })
|
|
3149
3440
|
if (chunks[chunks.length-1] === "localhost") {
|
|
3150
3441
|
// if <...>.<kernel.peer.name>.localhost
|
|
3151
3442
|
let nameChunks
|
|
@@ -3172,7 +3463,6 @@ class Server {
|
|
|
3172
3463
|
for(let folder of folders) {
|
|
3173
3464
|
let pattern1 = `${folder}.${this.kernel.peer.name}.localhost`
|
|
3174
3465
|
let pattern2 = `${folder}.localhost`
|
|
3175
|
-
console.log("checking", { pattern1, pattern2, chunks: chunks.join(".") })
|
|
3176
3466
|
if (pattern1 === chunks.join(".")) {
|
|
3177
3467
|
matched = true
|
|
3178
3468
|
nameChunks = chunks.slice(0, -2)
|
|
@@ -3193,20 +3483,16 @@ class Server {
|
|
|
3193
3483
|
// look for any matching peer names
|
|
3194
3484
|
// if exists, redirect to that host
|
|
3195
3485
|
for(let name of peer_names) {
|
|
3196
|
-
console.log({ host, name })
|
|
3197
3486
|
if (host.endsWith(`.${name}.localhost`)) {
|
|
3198
|
-
console.log("matched. redirecting")
|
|
3199
3487
|
res.redirect(`https://pinokio.${name}.localhost/launch?url=${url}`)
|
|
3200
3488
|
return
|
|
3201
3489
|
}
|
|
3202
3490
|
}
|
|
3203
3491
|
}
|
|
3204
3492
|
} else {
|
|
3205
|
-
console.log("> 3")
|
|
3206
3493
|
nameChunks = chunks
|
|
3207
3494
|
}
|
|
3208
3495
|
let name = nameChunks.join(".")
|
|
3209
|
-
console.log({ nameChunks, chunks, name })
|
|
3210
3496
|
let api_path = this.kernel.path("api", name)
|
|
3211
3497
|
let exists = await this.exists(api_path)
|
|
3212
3498
|
if (exists) {
|
|
@@ -3243,7 +3529,7 @@ class Server {
|
|
|
3243
3529
|
link: null
|
|
3244
3530
|
})
|
|
3245
3531
|
}))
|
|
3246
|
-
|
|
3532
|
+
const renderHomePage = ex(async (req, res) => {
|
|
3247
3533
|
// check bin folder
|
|
3248
3534
|
// let bin_path = this.kernel.path("bin/miniconda")
|
|
3249
3535
|
// let bin_exists = await this.exists(bin_path)
|
|
@@ -3260,7 +3546,7 @@ class Server {
|
|
|
3260
3546
|
// }
|
|
3261
3547
|
|
|
3262
3548
|
if (req.query.mode !== "settings" && !home) {
|
|
3263
|
-
res.redirect("
|
|
3549
|
+
res.redirect("/home?mode=settings")
|
|
3264
3550
|
return
|
|
3265
3551
|
}
|
|
3266
3552
|
if (req.query.mode === "help") {
|
|
@@ -3282,7 +3568,6 @@ class Server {
|
|
|
3282
3568
|
return
|
|
3283
3569
|
}
|
|
3284
3570
|
|
|
3285
|
-
|
|
3286
3571
|
if (req.query.mode === 'settings') {
|
|
3287
3572
|
|
|
3288
3573
|
let platform = os.platform()
|
|
@@ -3303,7 +3588,7 @@ class Server {
|
|
|
3303
3588
|
"* NO exFAT drives",
|
|
3304
3589
|
],
|
|
3305
3590
|
val: this.kernel.homedir ? this.kernel.homedir : _home,
|
|
3306
|
-
placeholder: "Enter the absolute path to use as your Pinokio home folder (D
|
|
3591
|
+
placeholder: "Enter the absolute path to use as your Pinokio home folder (D\\pinokio, /Users/alice/pinokiofs, etc.)"
|
|
3307
3592
|
// }, {
|
|
3308
3593
|
// key: "drive",
|
|
3309
3594
|
// val: path.resolve(this.kernel.homedir, "drive"),
|
|
@@ -3376,6 +3661,58 @@ class Server {
|
|
|
3376
3661
|
meta[folder] = await this.kernel.api.meta(folder)
|
|
3377
3662
|
}
|
|
3378
3663
|
await this.render(req, res, [], meta)
|
|
3664
|
+
})
|
|
3665
|
+
|
|
3666
|
+
this.app.get("/", ex(async (req, res) => {
|
|
3667
|
+
const protocol = (req.$source && req.$source.protocol) || req.protocol || 'http'
|
|
3668
|
+
const host = req.get('host') || `localhost:${this.port}`
|
|
3669
|
+
const baseUrl = `${protocol}://${host}`
|
|
3670
|
+
|
|
3671
|
+
const initialUrl = new URL('/home', baseUrl)
|
|
3672
|
+
const defaultUrl = new URL('/home', baseUrl)
|
|
3673
|
+
|
|
3674
|
+
for (const [key, value] of Object.entries(req.query)) {
|
|
3675
|
+
if (key === 'session') {
|
|
3676
|
+
continue
|
|
3677
|
+
}
|
|
3678
|
+
if (Array.isArray(value)) {
|
|
3679
|
+
value.forEach((val) => {
|
|
3680
|
+
initialUrl.searchParams.append(key, val)
|
|
3681
|
+
})
|
|
3682
|
+
} else if (value != null) {
|
|
3683
|
+
initialUrl.searchParams.set(key, value)
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3687
|
+
if (!home) {
|
|
3688
|
+
defaultUrl.searchParams.set('mode', 'settings')
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
res.render('layout', {
|
|
3692
|
+
theme: this.theme,
|
|
3693
|
+
agent: req.agent,
|
|
3694
|
+
initialPath: initialUrl.pathname + initialUrl.search + initialUrl.hash,
|
|
3695
|
+
defaultPath: defaultUrl.pathname + defaultUrl.search + defaultUrl.hash,
|
|
3696
|
+
sessionId: typeof req.query.session === 'string' ? req.query.session : null
|
|
3697
|
+
})
|
|
3698
|
+
}))
|
|
3699
|
+
|
|
3700
|
+
this.app.get("/home", renderHomePage)
|
|
3701
|
+
|
|
3702
|
+
|
|
3703
|
+
this.app.get("/bundle/:name", ex(async (req, res) => {
|
|
3704
|
+
let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
|
|
3705
|
+
bin: this.kernel.bin.preset(req.params.name),
|
|
3706
|
+
})
|
|
3707
|
+
if (!requirements_pending && install_required) {
|
|
3708
|
+
res.json({
|
|
3709
|
+
available: false,
|
|
3710
|
+
})
|
|
3711
|
+
} else {
|
|
3712
|
+
res.json({
|
|
3713
|
+
available: true,
|
|
3714
|
+
})
|
|
3715
|
+
}
|
|
3379
3716
|
}))
|
|
3380
3717
|
|
|
3381
3718
|
this.app.get("/init", ex(async (req, res) => {
|
|
@@ -3556,7 +3893,6 @@ class Server {
|
|
|
3556
3893
|
} catch (e) {
|
|
3557
3894
|
console.log(e)
|
|
3558
3895
|
}
|
|
3559
|
-
console.log({ https_running })
|
|
3560
3896
|
if (!https_running) {
|
|
3561
3897
|
// res.json({ error: "pinokio.host not yet available" })
|
|
3562
3898
|
res.redirect("/setup/connect?callback=/connect/" + req.params.provider)
|
|
@@ -3574,7 +3910,6 @@ class Server {
|
|
|
3574
3910
|
break
|
|
3575
3911
|
}
|
|
3576
3912
|
}
|
|
3577
|
-
console.log({ router_running })
|
|
3578
3913
|
if (!router_running) {
|
|
3579
3914
|
// res.json({ error: "pinokio.localhost not yet available" })
|
|
3580
3915
|
res.redirect("/setup/connect?callback=/connect/" + req.params.provider)
|
|
@@ -3677,7 +4012,6 @@ class Server {
|
|
|
3677
4012
|
res.json({ success: true })
|
|
3678
4013
|
}))
|
|
3679
4014
|
this.app.post("/go", ex(async (req, res) => {
|
|
3680
|
-
console.log("GO", req.body)
|
|
3681
4015
|
Util.openURL(req.body.url)
|
|
3682
4016
|
res.json({ success: true })
|
|
3683
4017
|
}))
|
|
@@ -3691,7 +4025,6 @@ class Server {
|
|
|
3691
4025
|
// relpath : ...
|
|
3692
4026
|
let relpath = req.body.asset_path.split("/").filter((x) => { return x }).slice(1).join("/")
|
|
3693
4027
|
let filepath = this.kernel.path(relpath)
|
|
3694
|
-
console.log({ filepath, relpath })
|
|
3695
4028
|
Util.openfs(filepath, req.body, this.kernel)
|
|
3696
4029
|
} else if (req.body.path) {
|
|
3697
4030
|
Util.openfs(req.body.path, req.body, this.kernel)
|
|
@@ -3701,7 +4034,6 @@ class Server {
|
|
|
3701
4034
|
this.app.post("/keys", ex(async (req, res) => {
|
|
3702
4035
|
let p = this.kernel.path("key.json")
|
|
3703
4036
|
let keys = (await this.kernel.loader.load(p)).resolved
|
|
3704
|
-
console.log("update", req.body)
|
|
3705
4037
|
for(let host in req.body) {
|
|
3706
4038
|
let updated = req.body[host]
|
|
3707
4039
|
for(let indexStr in updated) {
|
|
@@ -3806,8 +4138,6 @@ class Server {
|
|
|
3806
4138
|
|
|
3807
4139
|
let hosts = await this.get_github_hosts()
|
|
3808
4140
|
|
|
3809
|
-
console.log("hosts", hosts)
|
|
3810
|
-
|
|
3811
4141
|
let items
|
|
3812
4142
|
if (hosts.length > 0) {
|
|
3813
4143
|
// logged in => display logout
|
|
@@ -3955,7 +4285,12 @@ class Server {
|
|
|
3955
4285
|
GET /shell/:unix_path => shell id: 'shell/:unix_path'
|
|
3956
4286
|
*/
|
|
3957
4287
|
|
|
3958
|
-
let
|
|
4288
|
+
let baseShellId = "shell/" + decodeURIComponent(req.params.id)
|
|
4289
|
+
const sessionId = typeof req.query.session === "string" && req.query.session.length > 0 ? req.query.session : null
|
|
4290
|
+
let id = baseShellId
|
|
4291
|
+
if (sessionId) {
|
|
4292
|
+
id = `${baseShellId}?session=${sessionId}`
|
|
4293
|
+
}
|
|
3959
4294
|
let target = req.query.target ? req.query.target : null
|
|
3960
4295
|
let cwd = this.kernel.path(this.kernel.api.filePath(decodeURIComponent(req.query.path)))
|
|
3961
4296
|
let message = req.query.message ? decodeURIComponent(req.query.message) : null
|
|
@@ -4018,6 +4353,16 @@ class Server {
|
|
|
4018
4353
|
running: (shell ? true : false)
|
|
4019
4354
|
})
|
|
4020
4355
|
}))
|
|
4356
|
+
this.app.get("/pro", ex(async (req, res) => {
|
|
4357
|
+
let target = req.query.target ? req.query.target : null
|
|
4358
|
+
let cwd = this.kernel.path("api")
|
|
4359
|
+
res.render("pro", {
|
|
4360
|
+
target,
|
|
4361
|
+
cwd,
|
|
4362
|
+
theme: this.theme,
|
|
4363
|
+
agent: req.agent,
|
|
4364
|
+
})
|
|
4365
|
+
}))
|
|
4021
4366
|
// this.app.get("/terminal/:api/:id", ex(async (req, res) => {
|
|
4022
4367
|
// res.render("shell", {
|
|
4023
4368
|
// theme: this.theme,
|
|
@@ -4089,7 +4434,6 @@ class Server {
|
|
|
4089
4434
|
if (cr.has("caddy")) {
|
|
4090
4435
|
wait = "caddy"
|
|
4091
4436
|
}
|
|
4092
|
-
console.log({ wait, cr })
|
|
4093
4437
|
|
|
4094
4438
|
let current = req.query.callback || req.originalUrl
|
|
4095
4439
|
|
|
@@ -4212,7 +4556,11 @@ class Server {
|
|
|
4212
4556
|
return serverless_mapping[name]
|
|
4213
4557
|
})
|
|
4214
4558
|
let current_urls = await this.current_urls(req.originalUrl.slice(1))
|
|
4559
|
+
let static_routes = Object.keys(this.kernel.router.rewrite_mapping).map((key) => {
|
|
4560
|
+
return this.kernel.router.rewrite_mapping[key]
|
|
4561
|
+
})
|
|
4215
4562
|
res.render("net", {
|
|
4563
|
+
static_routes,
|
|
4216
4564
|
selected_name: req.params.name,
|
|
4217
4565
|
current_urls,
|
|
4218
4566
|
docs: this.docs,
|
|
@@ -4245,9 +4593,7 @@ class Server {
|
|
|
4245
4593
|
|
|
4246
4594
|
// let list = this.getPeerInfo()
|
|
4247
4595
|
// console.log("peeerInfo", JSON.stringify(list, null, 2))
|
|
4248
|
-
console.time("check peers")
|
|
4249
4596
|
await this.kernel.peer.check_peers()
|
|
4250
|
-
console.timeEnd("check peers")
|
|
4251
4597
|
|
|
4252
4598
|
|
|
4253
4599
|
let peers = []
|
|
@@ -4731,6 +5077,7 @@ class Server {
|
|
|
4731
5077
|
// }))
|
|
4732
5078
|
this.app.post("/env", ex(async (req, res) => {
|
|
4733
5079
|
let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
|
|
5080
|
+
console.log({ fullpath })
|
|
4734
5081
|
let updated = req.body.vals
|
|
4735
5082
|
let hosts = req.body.hosts
|
|
4736
5083
|
await Util.update_env(fullpath, updated)
|
|
@@ -4828,7 +5175,6 @@ class Server {
|
|
|
4828
5175
|
//const repositoryPath = this.kernel.path(pathComponents[0], pathComponents[1])
|
|
4829
5176
|
//const repositoryPath = this.kernel.path(pathComponents[0])
|
|
4830
5177
|
const repositoryPath = path.resolve(this.kernel.api.userdir, api_path)
|
|
4831
|
-
console.log({ repositoryPath })
|
|
4832
5178
|
gitRemote = await git.getConfig({
|
|
4833
5179
|
fs,
|
|
4834
5180
|
http,
|
|
@@ -4974,7 +5320,6 @@ class Server {
|
|
|
4974
5320
|
if (config) {
|
|
4975
5321
|
if (config.xterm) {
|
|
4976
5322
|
this.xterm = config.xterm
|
|
4977
|
-
console.log("this.xterm", this.xterm)
|
|
4978
5323
|
}
|
|
4979
5324
|
}
|
|
4980
5325
|
}
|
|
@@ -5040,7 +5385,7 @@ class Server {
|
|
|
5040
5385
|
}
|
|
5041
5386
|
}
|
|
5042
5387
|
} catch (err) {
|
|
5043
|
-
console.log("git status matrix error", err)
|
|
5388
|
+
// console.log("git status matrix error 1", err)
|
|
5044
5389
|
}
|
|
5045
5390
|
} else {
|
|
5046
5391
|
try {
|
|
@@ -5099,7 +5444,7 @@ class Server {
|
|
|
5099
5444
|
});
|
|
5100
5445
|
}
|
|
5101
5446
|
} catch (err) {
|
|
5102
|
-
console.log("git diff error", err);
|
|
5447
|
+
console.log("git diff error 2", err);
|
|
5103
5448
|
}
|
|
5104
5449
|
}
|
|
5105
5450
|
let git_commit_url = `/run/scripts/git/commit.json?cwd=${dir}&callback_target=parent&callback=$location.href`
|
|
@@ -5198,22 +5543,15 @@ class Server {
|
|
|
5198
5543
|
}
|
|
5199
5544
|
|
|
5200
5545
|
|
|
5201
|
-
let
|
|
5546
|
+
let response = await this.getGit(req.params.ref, req.params[0])
|
|
5202
5547
|
|
|
5203
5548
|
res.render("git", {
|
|
5204
|
-
config,
|
|
5205
|
-
remote,
|
|
5206
|
-
connected,
|
|
5207
|
-
log,
|
|
5208
|
-
branch,
|
|
5209
|
-
branches,
|
|
5210
|
-
ref,
|
|
5211
5549
|
path: req.params[0],
|
|
5212
5550
|
// changes,
|
|
5213
|
-
dir,
|
|
5214
5551
|
theme: this.theme,
|
|
5215
5552
|
platform: this.kernel.platform,
|
|
5216
5553
|
agent: req.agent,
|
|
5554
|
+
...response
|
|
5217
5555
|
})
|
|
5218
5556
|
}))
|
|
5219
5557
|
this.app.get("/d/*", ex(async (req, res) => {
|
|
@@ -5275,9 +5613,10 @@ class Server {
|
|
|
5275
5613
|
// console.log("online_terminal", online_terminal)
|
|
5276
5614
|
terminal.menus = href_menus
|
|
5277
5615
|
let dynamic = [
|
|
5616
|
+
terminal,
|
|
5278
5617
|
{
|
|
5279
5618
|
icon: "fa-solid fa-robot",
|
|
5280
|
-
title: "AI
|
|
5619
|
+
title: "AI Terminal",
|
|
5281
5620
|
subtitle: "Let AI work on this app",
|
|
5282
5621
|
menu: shell_menus
|
|
5283
5622
|
},
|
|
@@ -5287,7 +5626,6 @@ class Server {
|
|
|
5287
5626
|
subtitle: "Open this project in 3rd party apps",
|
|
5288
5627
|
menu: exec_menus
|
|
5289
5628
|
},
|
|
5290
|
-
terminal
|
|
5291
5629
|
]
|
|
5292
5630
|
let spec = ""
|
|
5293
5631
|
try {
|
|
@@ -5309,7 +5647,6 @@ class Server {
|
|
|
5309
5647
|
})
|
|
5310
5648
|
}))
|
|
5311
5649
|
this.app.get("/dev/*", ex(async (req, res) => {
|
|
5312
|
-
console.log("GET /dev/*", req.params)
|
|
5313
5650
|
let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
|
|
5314
5651
|
bin: this.kernel.bin.preset("dev"),
|
|
5315
5652
|
})
|
|
@@ -5444,7 +5781,11 @@ class Server {
|
|
|
5444
5781
|
if (plugin) {
|
|
5445
5782
|
if (plugin && plugin.menu && Array.isArray(plugin.menu)) {
|
|
5446
5783
|
plugin = structuredClone(plugin)
|
|
5447
|
-
|
|
5784
|
+
let default_plugin_query
|
|
5785
|
+
if (req.query) {
|
|
5786
|
+
default_plugin_query = req.query
|
|
5787
|
+
}
|
|
5788
|
+
plugin_menu = this.running_dynamic(req.params.name, plugin.menu, default_plugin_query)
|
|
5448
5789
|
html = await new Promise((resolve, reject) => {
|
|
5449
5790
|
ejs.renderFile(path.resolve(__dirname, "views/partials/dynamic.ejs"), { dynamic: plugin_menu }, (err, html) => {
|
|
5450
5791
|
resolve(html)
|
|
@@ -5578,12 +5919,122 @@ class Server {
|
|
|
5578
5919
|
// res.json({ success: true })
|
|
5579
5920
|
// }))
|
|
5580
5921
|
|
|
5922
|
+
|
|
5923
|
+
this.app.get("/info/scripts", ex(async (req, res) => {
|
|
5924
|
+
/*
|
|
5925
|
+
returns something like this by using the this.kernel.memory.local variable, extracting the api name and adding all running scripts in each associated array, setting the uri as the script path, and the local variables as the local attribute
|
|
5926
|
+
the api name in the following examples are "comfyui" and "gradio", therefore there are two top level attributes "comfyui" and "gradio", each of which has an array value made up of all scripts running under that api
|
|
5927
|
+
{
|
|
5928
|
+
“comfyui”: [{
|
|
5929
|
+
“uri”: “/data/pinokio/api/comfyui/start.js”,
|
|
5930
|
+
“local”: {
|
|
5931
|
+
"port": 42008,
|
|
5932
|
+
"url": "http://127.0.0.1:42008"
|
|
5933
|
+
}
|
|
5934
|
+
}],
|
|
5935
|
+
“gradio”: [{
|
|
5936
|
+
“uri”: “/data/pinokio/api/gradio/start.js”,
|
|
5937
|
+
“local”: {
|
|
5938
|
+
"port": 7860,
|
|
5939
|
+
"url": "http://127.0.0.1:7860"
|
|
5940
|
+
}
|
|
5941
|
+
}]
|
|
5942
|
+
}
|
|
5943
|
+
*/
|
|
5944
|
+
if (!this.kernel || !this.kernel.info || typeof this.kernel.info.scriptsByApi !== 'function') {
|
|
5945
|
+
res.json({})
|
|
5946
|
+
return
|
|
5947
|
+
}
|
|
5948
|
+
|
|
5949
|
+
const scriptsByApi = this.kernel.info.scriptsByApi()
|
|
5950
|
+
res.json(scriptsByApi)
|
|
5951
|
+
}))
|
|
5952
|
+
this.app.get("/info/local", ex(async (req, res) => {
|
|
5953
|
+
if (this.kernel && this.kernel.memory && this.kernel.memory.local) {
|
|
5954
|
+
res.json(this.kernel.memory.local)
|
|
5955
|
+
} else {
|
|
5956
|
+
res.json({})
|
|
5957
|
+
}
|
|
5958
|
+
}))
|
|
5959
|
+
|
|
5960
|
+
|
|
5581
5961
|
this.app.get("/info/procs", ex(async (req, res) => {
|
|
5582
5962
|
await this.kernel.processes.refresh()
|
|
5583
5963
|
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5964
|
+
const requestedProtocol = ((req.$source && req.$source.protocol) || req.protocol || '').toLowerCase()
|
|
5965
|
+
const preferHttps = requestedProtocol === 'https'
|
|
5966
|
+
|
|
5967
|
+
const routerInfo = (preferHttps && this.kernel.router && this.kernel.router.info && this.kernel.peer)
|
|
5968
|
+
? (this.kernel.router.info[this.kernel.peer.host] || {})
|
|
5969
|
+
: null
|
|
5970
|
+
|
|
5971
|
+
const resolveHttpsHosts = (proc) => {
|
|
5972
|
+
if (!routerInfo) {
|
|
5973
|
+
return []
|
|
5974
|
+
}
|
|
5975
|
+
const possibleKeys = new Set()
|
|
5976
|
+
if (proc.ip) {
|
|
5977
|
+
possibleKeys.add(proc.ip)
|
|
5978
|
+
}
|
|
5979
|
+
if (proc.port) {
|
|
5980
|
+
possibleKeys.add(`127.0.0.1:${proc.port}`)
|
|
5981
|
+
possibleKeys.add(`localhost:${proc.port}`)
|
|
5982
|
+
possibleKeys.add(`0.0.0.0:${proc.port}`)
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
const hosts = new Set()
|
|
5986
|
+
for (const key of possibleKeys) {
|
|
5987
|
+
const matches = routerInfo[key]
|
|
5988
|
+
if (!matches || matches.length === 0) {
|
|
5989
|
+
continue
|
|
5990
|
+
}
|
|
5991
|
+
for (const match of matches) {
|
|
5992
|
+
if (typeof match === 'string' && match.trim().length > 0) {
|
|
5993
|
+
hosts.add(match.trim())
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
return Array.from(hosts)
|
|
5998
|
+
}
|
|
5999
|
+
|
|
6000
|
+
const preferFriendlyHost = (hosts) => {
|
|
6001
|
+
if (!hosts || hosts.length === 0) {
|
|
6002
|
+
return null
|
|
6003
|
+
}
|
|
6004
|
+
for (const host of hosts) {
|
|
6005
|
+
if (!/^\d+\.localhost$/i.test(host)) {
|
|
6006
|
+
return host
|
|
6007
|
+
}
|
|
6008
|
+
}
|
|
6009
|
+
return hosts[0]
|
|
6010
|
+
}
|
|
6011
|
+
|
|
6012
|
+
const info = this.kernel.processes.info.map((item) => {
|
|
6013
|
+
const httpUrl = item.ip ? `http://${item.ip}` : null
|
|
6014
|
+
let httpsHosts = []
|
|
6015
|
+
if (preferHttps) {
|
|
6016
|
+
httpsHosts = resolveHttpsHosts(item)
|
|
6017
|
+
}
|
|
6018
|
+
const httpsUrls = httpsHosts.map((host) => {
|
|
6019
|
+
if (!host) {
|
|
6020
|
+
return null
|
|
6021
|
+
}
|
|
6022
|
+
const trimmed = host.trim()
|
|
6023
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
6024
|
+
return trimmed.replace(/^http:\/\//i, 'https://')
|
|
6025
|
+
}
|
|
6026
|
+
return `https://${trimmed}`
|
|
6027
|
+
}).filter(Boolean)
|
|
6028
|
+
|
|
6029
|
+
const preferredHttpsUrl = preferFriendlyHost(httpsHosts)
|
|
6030
|
+
const displayHttpsUrl = preferredHttpsUrl
|
|
6031
|
+
? (preferredHttpsUrl.startsWith('http') ? preferredHttpsUrl.replace(/^http:/i, 'https:') : `https://${preferredHttpsUrl}`)
|
|
6032
|
+
: (httpsUrls[0] || null)
|
|
6033
|
+
|
|
6034
|
+
const selectedUrl = (preferHttps && displayHttpsUrl) ? displayHttpsUrl : httpUrl
|
|
6035
|
+
const protocol = (preferHttps && displayHttpsUrl) ? 'https' : 'http'
|
|
6036
|
+
|
|
6037
|
+
return {
|
|
5587
6038
|
online: true,
|
|
5588
6039
|
host: {
|
|
5589
6040
|
ip: this.kernel.peer.host,
|
|
@@ -5593,65 +6044,16 @@ class Server {
|
|
|
5593
6044
|
arch: this.kernel.arch,
|
|
5594
6045
|
},
|
|
5595
6046
|
...item,
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
let host_rewrites = host_info.rewrite_mapping
|
|
5602
|
-
for(let key in host_rewrites) {
|
|
5603
|
-
info.push({
|
|
5604
|
-
online: true,
|
|
5605
|
-
host: {
|
|
5606
|
-
ip: host,
|
|
5607
|
-
local: this.kernel.peer.host === host,
|
|
5608
|
-
name: host_info.name,
|
|
5609
|
-
platform: host_info.platform,
|
|
5610
|
-
arch: host_info.arch
|
|
5611
|
-
},
|
|
5612
|
-
name: `[Files] ${host_rewrites[key].name}`,
|
|
5613
|
-
ip: host_rewrites[key].external_ip
|
|
5614
|
-
})
|
|
5615
|
-
}
|
|
5616
|
-
if (this.kernel.peer.host !== host) {
|
|
5617
|
-
let host_routers = host_info.router_info
|
|
5618
|
-
for(let host_router of host_routers) {
|
|
5619
|
-
let ip
|
|
5620
|
-
// the peer sharing works only if external_ip is available (caddy is installed)
|
|
5621
|
-
if (host_router.external_ip) {
|
|
5622
|
-
ip = host_router.external_ip
|
|
5623
|
-
} else {
|
|
5624
|
-
// if caddy is not turned on, set ip as null, so that it suggests turning on peer sharing
|
|
5625
|
-
ip = null
|
|
5626
|
-
}
|
|
5627
|
-
info.push({
|
|
5628
|
-
online: true,
|
|
5629
|
-
host: {
|
|
5630
|
-
ip: host,
|
|
5631
|
-
name: host_info.name,
|
|
5632
|
-
platform: host_info.platform,
|
|
5633
|
-
arch: host_info.arch
|
|
5634
|
-
},
|
|
5635
|
-
name: host_router.title || host_router.name,
|
|
5636
|
-
ip
|
|
5637
|
-
})
|
|
6047
|
+
url: selectedUrl,
|
|
6048
|
+
protocol,
|
|
6049
|
+
urls: {
|
|
6050
|
+
http: httpUrl,
|
|
6051
|
+
https: httpsUrls
|
|
5638
6052
|
}
|
|
5639
6053
|
}
|
|
6054
|
+
})
|
|
5640
6055
|
|
|
5641
|
-
|
|
5642
|
-
info.push({
|
|
5643
|
-
host: {
|
|
5644
|
-
ip: host,
|
|
5645
|
-
local: this.kernel.peer.host === host,
|
|
5646
|
-
name: host_info.name,
|
|
5647
|
-
platform: host_info.platform,
|
|
5648
|
-
arch: host_info.arch
|
|
5649
|
-
},
|
|
5650
|
-
name: app.title || app.folder,
|
|
5651
|
-
ip: app.http_href.replace("http://", "")
|
|
5652
|
-
})
|
|
5653
|
-
}
|
|
5654
|
-
}
|
|
6056
|
+
// this.add_extra_urls(info)
|
|
5655
6057
|
res.json({
|
|
5656
6058
|
info
|
|
5657
6059
|
})
|
|
@@ -5691,6 +6093,10 @@ class Server {
|
|
|
5691
6093
|
})
|
|
5692
6094
|
}
|
|
5693
6095
|
}))
|
|
6096
|
+
this.app.get("/info/shells", ex(async (req,res) => {
|
|
6097
|
+
let shells = this.kernel.shell.info()
|
|
6098
|
+
res.json(shells)
|
|
6099
|
+
}))
|
|
5694
6100
|
this.app.get("/info/api/:name", ex(async (req,res) => {
|
|
5695
6101
|
// api related info
|
|
5696
6102
|
let c = this.kernel.path("api", req.params.name)
|
|
@@ -5752,7 +6158,6 @@ class Server {
|
|
|
5752
6158
|
let gitRemote = null
|
|
5753
6159
|
try {
|
|
5754
6160
|
const repositoryPath = path.resolve(this.kernel.api.userdir, req.params.name)
|
|
5755
|
-
console.log({ repositoryPath })
|
|
5756
6161
|
gitRemote = await git.getConfig({
|
|
5757
6162
|
fs,
|
|
5758
6163
|
http,
|
|
@@ -5775,7 +6180,7 @@ class Server {
|
|
|
5775
6180
|
title: name,
|
|
5776
6181
|
url: gitRemote,
|
|
5777
6182
|
//redirect_uri: "http://localhost:3001/apps/redirect?git=" + gitRemote,
|
|
5778
|
-
redirect_uri: "https://app
|
|
6183
|
+
redirect_uri: "https://app.pinokio.co/apps/redirect?git=" + gitRemote,
|
|
5779
6184
|
platform: this.kernel.platform,
|
|
5780
6185
|
theme: this.theme,
|
|
5781
6186
|
agent: req.agent,
|
|
@@ -5897,7 +6302,7 @@ class Server {
|
|
|
5897
6302
|
}))
|
|
5898
6303
|
this.app.get("/pinokio/download", ex((req, res) => {
|
|
5899
6304
|
let queryStr = new URLSearchParams(req.query).toString()
|
|
5900
|
-
res.redirect("
|
|
6305
|
+
res.redirect("/home?mode=download&" + queryStr)
|
|
5901
6306
|
}))
|
|
5902
6307
|
this.app.post("/pinokio/install", ex((req, res) => {
|
|
5903
6308
|
req.session.requirements = req.body.requirements
|
|
@@ -5905,7 +6310,6 @@ class Server {
|
|
|
5905
6310
|
res.redirect("/pinokio/install")
|
|
5906
6311
|
}))
|
|
5907
6312
|
this.app.get("/pinokio/install", ex((req, res) => {
|
|
5908
|
-
console.log("render /pinokio/install")
|
|
5909
6313
|
let requirements = req.session.requirements
|
|
5910
6314
|
let callback = req.session.callback
|
|
5911
6315
|
req.session.requirements = null
|
|
@@ -6042,6 +6446,31 @@ class Server {
|
|
|
6042
6446
|
res.status(404).send("Missing attribute: path")
|
|
6043
6447
|
}
|
|
6044
6448
|
}))
|
|
6449
|
+
const ensureCaptureDir = async () => {
|
|
6450
|
+
await fs.promises.mkdir(this.kernel.path("screenshots"), { recursive: true }).catch(() => {});
|
|
6451
|
+
};
|
|
6452
|
+
|
|
6453
|
+
const saveCaptureFiles = async (files, fallbackExt = '.png') => {
|
|
6454
|
+
await ensureCaptureDir();
|
|
6455
|
+
const saved = [];
|
|
6456
|
+
if (Array.isArray(files)) {
|
|
6457
|
+
for (const file of files) {
|
|
6458
|
+
if (!file || !file.buffer) continue;
|
|
6459
|
+
const origName = file.originalname || '';
|
|
6460
|
+
let ext = path.extname(origName);
|
|
6461
|
+
if (!ext && file.mimetype) {
|
|
6462
|
+
const mapped = mime.extension(file.mimetype);
|
|
6463
|
+
if (mapped) ext = `.${mapped}`;
|
|
6464
|
+
}
|
|
6465
|
+
if (!ext) ext = fallbackExt;
|
|
6466
|
+
const name = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`;
|
|
6467
|
+
await fs.promises.writeFile(this.kernel.path("screenshots", name), file.buffer);
|
|
6468
|
+
saved.push({ name, url: `/asset/screenshots/${name}` });
|
|
6469
|
+
}
|
|
6470
|
+
}
|
|
6471
|
+
return saved;
|
|
6472
|
+
};
|
|
6473
|
+
|
|
6045
6474
|
this.app.get("/snapshots", ex(async (req, res) => {
|
|
6046
6475
|
let files = []
|
|
6047
6476
|
try {
|
|
@@ -6083,14 +6512,13 @@ class Server {
|
|
|
6083
6512
|
res.status(500).json({ error: "Failed to delete file: " + e.message })
|
|
6084
6513
|
}
|
|
6085
6514
|
}))
|
|
6515
|
+
this.app.post("/capture", this.upload.any(), ex(async (req, res) => {
|
|
6516
|
+
const saved = await saveCaptureFiles(req.files);
|
|
6517
|
+
res.json({ saved });
|
|
6518
|
+
}))
|
|
6086
6519
|
this.app.post("/screenshot", this.upload.any(), ex(async (req, res) => {
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
let file = req.files[key]
|
|
6090
|
-
console.log({ file, key })
|
|
6091
|
-
let ts = String(Date.now()) + ".png"
|
|
6092
|
-
await fs.promises.writeFile(this.kernel.path("screenshots", ts), file.buffer)
|
|
6093
|
-
}
|
|
6520
|
+
const saved = await saveCaptureFiles(req.files);
|
|
6521
|
+
res.json({ saved });
|
|
6094
6522
|
}))
|
|
6095
6523
|
this.app.post("/pinokio/fs", this.upload.any(), ex(async (req, res) => {
|
|
6096
6524
|
/*
|
|
@@ -6272,13 +6700,12 @@ class Server {
|
|
|
6272
6700
|
ready = false;
|
|
6273
6701
|
}
|
|
6274
6702
|
if (ready) {
|
|
6275
|
-
res.json({ success: true })
|
|
6703
|
+
res.json({ success: true, peer_name: this.kernel.peer.name })
|
|
6276
6704
|
} else {
|
|
6277
6705
|
res.json({ success: false })
|
|
6278
6706
|
}
|
|
6279
6707
|
} else {
|
|
6280
6708
|
// if network is not active, return success immediately (just checking if the server is up)
|
|
6281
|
-
console.log("this.kernel.router.published()")
|
|
6282
6709
|
res.json({ success: true })
|
|
6283
6710
|
}
|
|
6284
6711
|
}))
|
|
@@ -6340,48 +6767,11 @@ class Server {
|
|
|
6340
6767
|
})
|
|
6341
6768
|
});
|
|
6342
6769
|
process.on('SIGINT', () => {
|
|
6343
|
-
|
|
6344
|
-
// console.log("shell reset")
|
|
6345
|
-
// this.kernel.shell.reset(() => {
|
|
6346
|
-
// process.exit()
|
|
6347
|
-
// })
|
|
6348
|
-
//} else {
|
|
6349
|
-
// process.exit()
|
|
6350
|
-
//}
|
|
6351
|
-
console.log("[SigInt event] Kill", process.pid)
|
|
6352
|
-
if (this.kernel.processes.caddy_pid) {
|
|
6353
|
-
console.log("kill caddy", this.kernel.processes.caddy_pid)
|
|
6354
|
-
kill(this.kernel.processes.caddy_pid, "SIGKILL", true)
|
|
6355
|
-
}
|
|
6356
|
-
console.log("kill self")
|
|
6357
|
-
kill(process.pid, 'SIGKILL', true)
|
|
6358
|
-
//kill(process.pid, map, 'SIGKILL', () => {
|
|
6359
|
-
// console.log("child procs killed for", process.pid)
|
|
6360
|
-
// process.exit()
|
|
6361
|
-
//});
|
|
6770
|
+
this.shutdown('SigInt')
|
|
6362
6771
|
})
|
|
6363
6772
|
|
|
6364
6773
|
process.on('SIGTERM', () => {
|
|
6365
|
-
|
|
6366
|
-
// console.log("shell reset")
|
|
6367
|
-
// this.kernel.shell.reset(() => {
|
|
6368
|
-
// process.exit()
|
|
6369
|
-
// })
|
|
6370
|
-
// } else {
|
|
6371
|
-
// process.exit()
|
|
6372
|
-
// }
|
|
6373
|
-
console.log("[Sigterm event] Kill", process.pid)
|
|
6374
|
-
if (this.kernel.processes.caddy_pid) {
|
|
6375
|
-
console.log("kill caddy", this.kernel.processes.caddy_pid)
|
|
6376
|
-
kill(this.kernel.processes.caddy_pid, "SIGKILL", true)
|
|
6377
|
-
}
|
|
6378
|
-
console.log("kill self")
|
|
6379
|
-
kill(process.pid, 'SIGKILL', true)
|
|
6380
|
-
//let map = this.kernel.processes.map || {}
|
|
6381
|
-
//kill(process.pid, map, 'SIGKILL', () => {
|
|
6382
|
-
// console.log("child procs killed for", process.pid)
|
|
6383
|
-
// process.exit()
|
|
6384
|
-
//});
|
|
6774
|
+
this.shutdown('SigTerm')
|
|
6385
6775
|
})
|
|
6386
6776
|
// process.on('exit', () => {
|
|
6387
6777
|
// console.log("[Exit event]")
|