pinokiod 1.3.40 → 1.3.42
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/kernel/api/cloudflare/index.js +1 -3
- package/kernel/api/fs/index.js +30 -5
- package/kernel/api/index.js +49 -25
- package/kernel/api/local/index.js +43 -0
- package/kernel/api/proxy/index.js +16 -2
- package/kernel/api/shell/index.js +10 -0
- package/kernel/environment.js +138 -0
- package/kernel/index.js +35 -49
- package/kernel/shell.js +4 -46
- package/kernel/util.js +22 -0
- package/package.json +2 -1
- package/server/index.js +62 -35
- package/server/views/editor.ejs +22 -12
- package/server/views/general_editor.ejs +208 -0
- package/server/views/index.ejs +1 -1
- package/server/views/settings.ejs +9 -0
|
@@ -24,7 +24,6 @@ class C {
|
|
|
24
24
|
let options = {}
|
|
25
25
|
if (req.cwd) options.cwd = req.cwd
|
|
26
26
|
if (req.parent && req.parent.path) options.group = req.parent.path
|
|
27
|
-
console.log("shells before", kernel.shell.shells)
|
|
28
27
|
let pattern = /(https:.+?trycloudflare\.com)/
|
|
29
28
|
let cloudflare_url = await new Promise((resolve, reject) => {
|
|
30
29
|
kernel.shell.start(params, options, (e) => {
|
|
@@ -35,9 +34,8 @@ class C {
|
|
|
35
34
|
}
|
|
36
35
|
})
|
|
37
36
|
})
|
|
38
|
-
console.log("cloudflare_url", cloudflare_url)
|
|
39
37
|
|
|
40
|
-
ondata({ raw: yellow("\r\n## Scan the QR code to open in any device\r\n\r\n") })
|
|
38
|
+
ondata({ raw: yellow("\r\n## [CLOUDFLARE SHARING] Scan the QR code to open in any device\r\n\r\n") })
|
|
41
39
|
ondata({ raw: blue(`${cloudflare_url}\r\n\r\n`) })
|
|
42
40
|
|
|
43
41
|
await new Promise((resolve, reject) => {
|
package/kernel/api/fs/index.js
CHANGED
|
@@ -9,7 +9,8 @@ const randomUseragent = require('random-useragent');
|
|
|
9
9
|
const symlinkDir = require('symlink-dir')
|
|
10
10
|
const retry = require('async-retry');
|
|
11
11
|
const { createHash } = require('crypto');
|
|
12
|
-
|
|
12
|
+
const Environment = require("../../environment")
|
|
13
|
+
const Util = require("../../util")
|
|
13
14
|
|
|
14
15
|
const log = (msgs, ondata) => {
|
|
15
16
|
for(let msg of msgs) {
|
|
@@ -127,6 +128,22 @@ class FS {
|
|
|
127
128
|
|
|
128
129
|
ondata({ raw: "\r\ncreating a shared drive:\r\n" + JSON.stringify(req.params, null, 2).replace(/\n/g, "\r\n") })
|
|
129
130
|
|
|
131
|
+
|
|
132
|
+
let api_path = await Util.api_path(req.parent.path, kernel)
|
|
133
|
+
let current_env = await Environment.get(api_path)
|
|
134
|
+
let default_env = await Environment.get(kernel.homedir)
|
|
135
|
+
current_env = Object.assign(process.env, default_env, current_env)
|
|
136
|
+
|
|
137
|
+
let env_drive_path = current_env.PINOKIO_DRIVE
|
|
138
|
+
let drive_home
|
|
139
|
+
if (env_drive_path) {
|
|
140
|
+
let api_path = `${kernel.homedir}${path.sep}api`
|
|
141
|
+
let rel_path = path.relative(api_path, req.parent.path)
|
|
142
|
+
let api_name = rel_path.split(path.sep)[0]
|
|
143
|
+
let current_api_path = `${api_path}${path.sep}${api_name}`
|
|
144
|
+
drive_home = path.resolve(current_api_path, env_drive_path)
|
|
145
|
+
}
|
|
146
|
+
|
|
130
147
|
if (req.params.venv) {
|
|
131
148
|
// pip sharing
|
|
132
149
|
// 1. get all pip items
|
|
@@ -150,7 +167,7 @@ class FS {
|
|
|
150
167
|
// symlink:
|
|
151
168
|
// from => :package_path
|
|
152
169
|
// to => /drives/packages/pip/:package_name/:package_version
|
|
153
|
-
const drivePath = kernel.path("drive")
|
|
170
|
+
const drivePath = drive_home || kernel.path("drive")
|
|
154
171
|
const drive = new Pdrive(drivePath)
|
|
155
172
|
for(let name in res) {
|
|
156
173
|
/*
|
|
@@ -259,10 +276,18 @@ class FS {
|
|
|
259
276
|
}
|
|
260
277
|
|
|
261
278
|
for(let relpath of copy) {
|
|
262
|
-
|
|
279
|
+
if (drive_home) {
|
|
280
|
+
d.copy[relpath] = path.resolve(drive_home, p, relpath)
|
|
281
|
+
} else {
|
|
282
|
+
d.copy[relpath] = kernel.path("drive", p, relpath)
|
|
283
|
+
}
|
|
263
284
|
}
|
|
264
285
|
for(let relpath of move) {
|
|
265
|
-
|
|
286
|
+
if (drive_home) {
|
|
287
|
+
d.move[relpath] = path.resolve(drive_home, p, relpath)
|
|
288
|
+
} else {
|
|
289
|
+
d.move[relpath] = kernel.path("drive", p, relpath)
|
|
290
|
+
}
|
|
266
291
|
}
|
|
267
292
|
ondata({
|
|
268
293
|
raw: "\r\nLINKING DRIVES:\r\n" + JSON.stringify(d, null, 2).replace(/\n/g, "\r\n")
|
|
@@ -279,7 +304,7 @@ class FS {
|
|
|
279
304
|
|
|
280
305
|
}
|
|
281
306
|
} else if (req.params.drive) {
|
|
282
|
-
const drivePath = kernel.path("drive")
|
|
307
|
+
const drivePath = drive_home || kernel.path("drive")
|
|
283
308
|
const drive = new Pdrive(drivePath)
|
|
284
309
|
for(const route in req.params.drive) {
|
|
285
310
|
const link = req.params.drive[route]
|
package/kernel/api/index.js
CHANGED
|
@@ -560,6 +560,7 @@ class Api {
|
|
|
560
560
|
// 6. rpc must have method names
|
|
561
561
|
if (rpc.method) {
|
|
562
562
|
|
|
563
|
+
|
|
563
564
|
// 7. resolve the rpc
|
|
564
565
|
let resolved = await this.resolveMethod(rpc, cwd)
|
|
565
566
|
|
|
@@ -666,31 +667,46 @@ class Api {
|
|
|
666
667
|
data: rpc
|
|
667
668
|
})
|
|
668
669
|
|
|
669
|
-
//
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
670
|
+
// DEPRECATED APIS
|
|
671
|
+
// If deprecated, just ignore and move on
|
|
672
|
+
const deprecated = [
|
|
673
|
+
"proxy.start"
|
|
674
|
+
]
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
let result
|
|
678
|
+
if (deprecated.includes(rpc.method)) {
|
|
679
|
+
const msg = `DEPRECATED API ${rpc.method}. Ignored`
|
|
680
|
+
console.log(msg)
|
|
681
|
+
} else {
|
|
682
|
+
// 11. actually make the rpc call
|
|
683
|
+
result = await this.run(resolved.method, rpc, (stream, type) => {
|
|
684
|
+
let m = {
|
|
685
|
+
id: request.path,
|
|
686
|
+
caller: request.caller,
|
|
687
|
+
type: (type ? type : "stream"),
|
|
688
|
+
index: i,
|
|
689
|
+
total,
|
|
690
|
+
data: stream,
|
|
691
|
+
rpc,
|
|
692
|
+
rawrpc
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// if (["input", "modal"].includes(m.type)) {
|
|
696
|
+
// // if a message requires user feedback, do not modify id
|
|
697
|
+
// } else {
|
|
698
|
+
// // if a message does not require user feedback
|
|
699
|
+
// // if the current session has a "caller" (parent process),
|
|
700
|
+
// // set the id to request.caller so the terminal prints the logs
|
|
701
|
+
// if (request.caller) {
|
|
702
|
+
// m.id = request.caller
|
|
703
|
+
// }
|
|
704
|
+
// }
|
|
705
|
+
this.ondata(m)
|
|
706
|
+
})
|
|
707
|
+
}
|
|
708
|
+
|
|
681
709
|
|
|
682
|
-
// if (["input", "modal"].includes(m.type)) {
|
|
683
|
-
// // if a message requires user feedback, do not modify id
|
|
684
|
-
// } else {
|
|
685
|
-
// // if a message does not require user feedback
|
|
686
|
-
// // if the current session has a "caller" (parent process),
|
|
687
|
-
// // set the id to request.caller so the terminal prints the logs
|
|
688
|
-
// if (request.caller) {
|
|
689
|
-
// m.id = request.caller
|
|
690
|
-
// }
|
|
691
|
-
// }
|
|
692
|
-
this.ondata(m)
|
|
693
|
-
})
|
|
694
710
|
|
|
695
711
|
if (result && rpc.returns) {
|
|
696
712
|
// set the scope variable from the return value
|
|
@@ -1037,10 +1053,18 @@ class Api {
|
|
|
1037
1053
|
} else if (request.method) {
|
|
1038
1054
|
|
|
1039
1055
|
if (request.params && request.params.path) {
|
|
1040
|
-
|
|
1056
|
+
if (request.cwd) {
|
|
1057
|
+
console.log("request.cwd", request.cwd)
|
|
1058
|
+
let rendered_cwd = this.kernel.template.render(request.cwd, { kernel: this.kernel }, { allow_undefined: true })
|
|
1059
|
+
console.log("rendered_cwd", rendered_cwd)
|
|
1060
|
+
request.params.path = this.resolvePath(rendered_cwd, request.params.path)
|
|
1061
|
+
} else {
|
|
1062
|
+
request.params.path = this.resolvePath(this.userdir, request.params.path)
|
|
1063
|
+
}
|
|
1041
1064
|
}
|
|
1042
1065
|
|
|
1043
1066
|
// Kernel Call
|
|
1067
|
+
console.log("REQUEST", request)
|
|
1044
1068
|
let resolved = await this.resolveMethod(request)
|
|
1045
1069
|
try {
|
|
1046
1070
|
resolved.dirname = resolved.dirname
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const set = require("../set")
|
|
2
2
|
const rm = require("../rm")
|
|
3
|
+
const Cloudflare = require("../cloudflare")
|
|
4
|
+
const Proxy = require('../proxy')
|
|
5
|
+
const Environment = require('../../environment')
|
|
6
|
+
const Util = require("../../util")
|
|
3
7
|
class Local {
|
|
4
8
|
async import(req, ondata, kernel) {
|
|
5
9
|
/*
|
|
@@ -48,6 +52,45 @@ class Local {
|
|
|
48
52
|
}
|
|
49
53
|
})
|
|
50
54
|
let res = await set(converted, ondata, kernel)
|
|
55
|
+
|
|
56
|
+
// handle special local variables
|
|
57
|
+
/*
|
|
58
|
+
req :- {
|
|
59
|
+
method: "set",
|
|
60
|
+
params: {
|
|
61
|
+
"url": k
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
let api_path = await Util.api_path(req.parent.path, kernel)
|
|
67
|
+
let current_env = await Environment.get(api_path)
|
|
68
|
+
let default_env = await Environment.get(kernel.homedir)
|
|
69
|
+
current_env = Object.assign(process.env, default_env, current_env)
|
|
70
|
+
|
|
71
|
+
// if the key at current_env.PINOKIO_SHARE_VAR (by default it's 'url') is the variable being set, trigger the share logic
|
|
72
|
+
if (current_env.PINOKIO_SHARE_VAR && current_env.PINOKIO_SHARE_VAR in req.params) {
|
|
73
|
+
// the share logic is triggered ONLY IF the env.PINOKIO_SHARE is non-empty and contains "cloudflare", "local", or "cloudflare,local"
|
|
74
|
+
const KEY = current_env.PINOKIO_SHARE_VAR
|
|
75
|
+
if ("PINOKIO_SHARE_CLOUDFLARE" in current_env) {
|
|
76
|
+
let val = current_env.PINOKIO_SHARE_CLOUDFLARE.trim().toLowerCase()
|
|
77
|
+
if (val === "true" || val === "1") {
|
|
78
|
+
const c = new Cloudflare()
|
|
79
|
+
req.params.uri = req.params[KEY]
|
|
80
|
+
await c.tunnel(req, ondata, kernel)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if ("PINOKIO_SHARE_LOCAL" in current_env) {
|
|
84
|
+
let val = current_env.PINOKIO_SHARE_LOCAL.trim().toLowerCase()
|
|
85
|
+
if (val === "true" || val === "1") {
|
|
86
|
+
const p = new Proxy()
|
|
87
|
+
req.params.name = "Local Sharing",
|
|
88
|
+
req.params.uri = req.params[KEY]
|
|
89
|
+
await p.start(req, ondata, kernel)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
51
94
|
return res
|
|
52
95
|
}
|
|
53
96
|
async rm(req, ondata, kernel) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { yellow, green, blue } = require('kleur');
|
|
2
|
+
const QRCode = require('qrcode');
|
|
1
3
|
class P {
|
|
2
4
|
async start (req, ondata, kernel) {
|
|
3
5
|
/*
|
|
@@ -16,14 +18,26 @@ class P {
|
|
|
16
18
|
// if exists, don't do anything
|
|
17
19
|
} catch (e) {
|
|
18
20
|
ondata({
|
|
19
|
-
raw: `\r\n[Start
|
|
21
|
+
raw: `\r\n[Start Local Sharing]\r\n`
|
|
20
22
|
})
|
|
21
23
|
let { name, uri, ...o } = req.params
|
|
22
24
|
console.log("proxy.start", { name, uri, o })
|
|
23
25
|
let response = await kernel.api.startProxy(req.parent.path, req.params.uri, req.params.name, o)
|
|
24
26
|
|
|
27
|
+
ondata({ raw: yellow("\r\n## [LOCAL NETWORK SHARING] Scan the QR code to open in any device\r\n\r\n") })
|
|
25
28
|
ondata({
|
|
26
|
-
raw:
|
|
29
|
+
raw: `${blue(response.proxy)}\r\n\r\n`
|
|
30
|
+
})
|
|
31
|
+
await new Promise((resolve, reject) => {
|
|
32
|
+
QRCode.toString(response.proxy, {
|
|
33
|
+
type: "terminal"
|
|
34
|
+
}, function(err, data) {
|
|
35
|
+
ondata({ raw: green(data.replaceAll("\n", "\r\n")) })
|
|
36
|
+
ondata({ raw: "\r\n" })
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
resolve()
|
|
39
|
+
}, 2000)
|
|
40
|
+
});
|
|
27
41
|
})
|
|
28
42
|
|
|
29
43
|
return response
|
|
@@ -37,6 +37,10 @@ class Shell {
|
|
|
37
37
|
req.params.cols = req.client.cols
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
if (req.params) {
|
|
41
|
+
req.params.$parent = req.parent
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
// // create a persistent session
|
|
41
45
|
// req.params.persistent = true
|
|
42
46
|
|
|
@@ -85,6 +89,9 @@ class Shell {
|
|
|
85
89
|
if (!req.params.id) {
|
|
86
90
|
req.params.id = req.cwd
|
|
87
91
|
}
|
|
92
|
+
if (req.params) {
|
|
93
|
+
req.params.$parent = req.parent
|
|
94
|
+
}
|
|
88
95
|
|
|
89
96
|
console.log("#### shell.enter", req.params)
|
|
90
97
|
|
|
@@ -111,6 +118,9 @@ class Shell {
|
|
|
111
118
|
}
|
|
112
119
|
}
|
|
113
120
|
*/
|
|
121
|
+
if (req.params) {
|
|
122
|
+
req.params.$parent = req.parent
|
|
123
|
+
}
|
|
114
124
|
let options = {}
|
|
115
125
|
if (req.cwd) options.cwd = req.cwd
|
|
116
126
|
if (req.parent && req.parent.path) options.group = req.parent.path
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const util = require('./util')
|
|
4
|
+
const ENVS = [{
|
|
5
|
+
type: "cache_folder",
|
|
6
|
+
key: "HF_HOME",
|
|
7
|
+
}, {
|
|
8
|
+
type: "cache_folder",
|
|
9
|
+
key: "TORCH_HOME",
|
|
10
|
+
}, {
|
|
11
|
+
type: "cache_folder",
|
|
12
|
+
key: "HOMEBREW_CACHE",
|
|
13
|
+
}, {
|
|
14
|
+
type: "cache_folder",
|
|
15
|
+
key: "XDG_CACHE_HOME",
|
|
16
|
+
}, {
|
|
17
|
+
type: "cache_folder",
|
|
18
|
+
key: "PIP_CACHE_DIR",
|
|
19
|
+
}, {
|
|
20
|
+
type: "cache_folder",
|
|
21
|
+
key: "PIP_TMPDIR",
|
|
22
|
+
}, {
|
|
23
|
+
type: "cache_folder",
|
|
24
|
+
key: "TMPDIR",
|
|
25
|
+
}, {
|
|
26
|
+
type: "cache_folder",
|
|
27
|
+
key: "TEMP",
|
|
28
|
+
}, {
|
|
29
|
+
type: "cache_folder",
|
|
30
|
+
key: "TMP",
|
|
31
|
+
}, {
|
|
32
|
+
type: "cache_folder",
|
|
33
|
+
key: "XDG_DATA_HOME",
|
|
34
|
+
}, {
|
|
35
|
+
type: "cache_folder",
|
|
36
|
+
key: "XDG_CONFIG_HOME",
|
|
37
|
+
}, {
|
|
38
|
+
type: "cache_folder",
|
|
39
|
+
key: "XDG_STATE_HOME",
|
|
40
|
+
}, {
|
|
41
|
+
type: "cache_folder",
|
|
42
|
+
key: "GRADIO_TEMP_DIR",
|
|
43
|
+
}, {
|
|
44
|
+
key: "PIP_CONFIG_FILE",
|
|
45
|
+
val: (home) => {
|
|
46
|
+
return path.resolve(home, "pipconfig")
|
|
47
|
+
}
|
|
48
|
+
}, {
|
|
49
|
+
key: "CONDARC",
|
|
50
|
+
val: (home) => {
|
|
51
|
+
return path.resolve(home, "condarc")
|
|
52
|
+
},
|
|
53
|
+
}, {
|
|
54
|
+
key: "PS1",
|
|
55
|
+
val: (home) => {
|
|
56
|
+
return "<<PINOKIO SHELL>> "
|
|
57
|
+
},
|
|
58
|
+
}, {
|
|
59
|
+
key: "PINOKIO_SHARE_VAR",
|
|
60
|
+
val: (home) => {
|
|
61
|
+
return "url"
|
|
62
|
+
},
|
|
63
|
+
}, {
|
|
64
|
+
type: "folder",
|
|
65
|
+
key: "PINOKIO_DRIVE",
|
|
66
|
+
val: (home) => {
|
|
67
|
+
return path.resolve(home, "drive")
|
|
68
|
+
}
|
|
69
|
+
}];
|
|
70
|
+
const folders = ENVS.filter((env) => {
|
|
71
|
+
return env.type === "cache_folder" || env.type === "folder"
|
|
72
|
+
}).map((e) => {
|
|
73
|
+
return e.key
|
|
74
|
+
})
|
|
75
|
+
const ENV = (homedir) => {
|
|
76
|
+
const lines = ENVS.map((e) => {
|
|
77
|
+
if (e.type) {
|
|
78
|
+
if (e.type === "cache_folder") {
|
|
79
|
+
return `${e.key}=${path.resolve(homedir, "cache", e.key)}`
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
if (e.val) {
|
|
83
|
+
return `${e.key}=${e.val(homedir)}`
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
return lines.join("\n")
|
|
88
|
+
}
|
|
89
|
+
const APP_ENV = () => {
|
|
90
|
+
const items = [
|
|
91
|
+
"####################################################################",
|
|
92
|
+
"# GRADIO_TEMP_DIR",
|
|
93
|
+
"# All files uploaded through gradio goes here.",
|
|
94
|
+
"# Delete or comment this line",
|
|
95
|
+
"GRADIO_TEMP_DIR=cache/GRADIO_TEMP_DIR",
|
|
96
|
+
"",
|
|
97
|
+
"####################################################################",
|
|
98
|
+
"# PINOKIO_SHARE_LOCAL",
|
|
99
|
+
"# Set this variable to true to share the app on the local network.",
|
|
100
|
+
"PINOKIO_SHARE_LOCAL=true",
|
|
101
|
+
"",
|
|
102
|
+
"####################################################################",
|
|
103
|
+
"# PINOKIO_SHARE_CLOUDFLARE",
|
|
104
|
+
"# Set this variable to share the app publicly via cloudflare tunnel.",
|
|
105
|
+
"PINOKIO_SHARE_CLOUDFLARE=false",
|
|
106
|
+
]
|
|
107
|
+
return items.join("\n")
|
|
108
|
+
}
|
|
109
|
+
const init_folders = async (homedir) => {
|
|
110
|
+
// get the environment object from homedir
|
|
111
|
+
const current_env = await get(homedir)
|
|
112
|
+
|
|
113
|
+
// filter out only the folder keys
|
|
114
|
+
|
|
115
|
+
// create folders
|
|
116
|
+
for(let key in current_env) {
|
|
117
|
+
// env key included in folders
|
|
118
|
+
if (folders.includes(key)) {
|
|
119
|
+
// mkdir
|
|
120
|
+
let full_path = path.resolve(homedir, current_env[key])
|
|
121
|
+
await fs.promises.mkdir(full_path, { recursive: true }).catch((e) => {})
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const get = async (homedir) => {
|
|
127
|
+
const env_path = path.resolve(homedir, "ENVIRONMENT")
|
|
128
|
+
const current_env = await util.parse_env(env_path)
|
|
129
|
+
// if the key is a folder/cache_folder type, resolve the path
|
|
130
|
+
for(let key in current_env) {
|
|
131
|
+
if (folders.includes(key)) {
|
|
132
|
+
let full_path = path.resolve(homedir, current_env[key])
|
|
133
|
+
current_env[key] = full_path
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return current_env
|
|
137
|
+
}
|
|
138
|
+
module.exports = { ENV, get, init_folders, APP_ENV }
|
package/kernel/index.js
CHANGED
|
@@ -7,7 +7,6 @@ const fastq = require('fastq')
|
|
|
7
7
|
const fetch = require('cross-fetch');
|
|
8
8
|
const waitOn = require('wait-on');
|
|
9
9
|
const system = require('systeminformation');
|
|
10
|
-
//const hostile = require('hostile');
|
|
11
10
|
const Sysinfo = require('./sysinfo')
|
|
12
11
|
const portfinder = require('portfinder');
|
|
13
12
|
const Loader = require("./loader")
|
|
@@ -19,6 +18,8 @@ const Template = require('jimini')
|
|
|
19
18
|
const Shells = require("./shells")
|
|
20
19
|
const Key = require("./key")
|
|
21
20
|
const Script = require('./script')
|
|
21
|
+
const Environment = require("./environment")
|
|
22
|
+
const Util = require('./util')
|
|
22
23
|
const Config = require("./pinokio.json")
|
|
23
24
|
const VARS = {
|
|
24
25
|
pip: {
|
|
@@ -30,7 +31,7 @@ const VARS = {
|
|
|
30
31
|
//const memwatch = require('@airbnb/node-memwatch');
|
|
31
32
|
class Kernel {
|
|
32
33
|
//schema = ">=1.0.0"
|
|
33
|
-
schema = "<=1.
|
|
34
|
+
schema = "<=1.7.0"
|
|
34
35
|
constructor(store) {
|
|
35
36
|
this.fetch = fetch
|
|
36
37
|
this.store = store
|
|
@@ -40,6 +41,7 @@ class Kernel {
|
|
|
40
41
|
this.key = new Key()
|
|
41
42
|
this.jsdom = jsdom
|
|
42
43
|
this.exposed = {}
|
|
44
|
+
this.envs = {}
|
|
43
45
|
}
|
|
44
46
|
resumeprocess(uri) {
|
|
45
47
|
let proc = this.procs[uri]
|
|
@@ -99,7 +101,6 @@ class Kernel {
|
|
|
99
101
|
return portfinder.getPortPromise()
|
|
100
102
|
}
|
|
101
103
|
path(...args) {
|
|
102
|
-
console.log("ARGS", args)
|
|
103
104
|
return path.resolve(this.homedir, ...args)
|
|
104
105
|
}
|
|
105
106
|
exists(...args) {
|
|
@@ -173,7 +174,8 @@ class Kernel {
|
|
|
173
174
|
await waitOn(options)
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
async init() {
|
|
177
|
+
async init(options) {
|
|
178
|
+
this.port = options.port
|
|
177
179
|
let home = this.store.get("home")
|
|
178
180
|
|
|
179
181
|
// reset shells if they exist
|
|
@@ -237,30 +239,32 @@ class Kernel {
|
|
|
237
239
|
}
|
|
238
240
|
this.procs = {}
|
|
239
241
|
this.template = new Template()
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
242
|
try {
|
|
244
243
|
if (this.homedir) {
|
|
244
|
+
|
|
245
|
+
// 0. create homedir
|
|
245
246
|
await fs.promises.mkdir(this.homedir, { recursive: true }).catch((e) => {})
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
"
|
|
253
|
-
"TMPDIR",
|
|
254
|
-
"TEMP",
|
|
255
|
-
"TMP",
|
|
256
|
-
"XDG_DATA_HOME",
|
|
257
|
-
"XDG_CONFIG_HOME",
|
|
258
|
-
"XDG_STATE_HOME",
|
|
259
|
-
"GRADIO_TEMP_DIR"
|
|
260
|
-
]
|
|
261
|
-
for(let folder of cache_folders) {
|
|
262
|
-
await fs.promises.mkdir(path.resolve(this.homedir, "cache", folder), { recursive: true }).catch((e) => {})
|
|
247
|
+
|
|
248
|
+
// 1. check if ENVIRONMENT exists
|
|
249
|
+
// if it doesn't exist, write to ~/pinokio/ENVIRONMENT
|
|
250
|
+
let e = await this.exists(this.homedir, "ENVIRONMENT")
|
|
251
|
+
if (!e) {
|
|
252
|
+
let str = Environment.ENV(this.homedir)
|
|
253
|
+
await fs.promises.writeFile(path.resolve(this.homedir, "ENVIRONMENT"), str)
|
|
263
254
|
}
|
|
255
|
+
// 2. mkdir all the folders if not already created
|
|
256
|
+
await Environment.init_folders(this.homedir)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
// // 3. check if Caddyfile exists
|
|
260
|
+
// let e2 = await this.exists(this.homedir, "Caddyfile")
|
|
261
|
+
// if (!e2) {
|
|
262
|
+
// let str = `pinokio.local {
|
|
263
|
+
// reverse_proxy localhost:${this.port}
|
|
264
|
+
//}`
|
|
265
|
+
// await fs.promises.writeFile(path.resolve(this.homedir, "Caddyfile"), str)
|
|
266
|
+
// }
|
|
267
|
+
|
|
264
268
|
|
|
265
269
|
}
|
|
266
270
|
|
|
@@ -301,34 +305,16 @@ class Kernel {
|
|
|
301
305
|
// userDataDir: this.bin.path("puppet")
|
|
302
306
|
// });
|
|
303
307
|
|
|
304
|
-
|
|
305
|
-
// set hosts
|
|
306
|
-
//hostile.get(false, async (err, lines) => {
|
|
307
|
-
// if (err) {
|
|
308
|
-
// console.error(err.message)
|
|
309
|
-
// }
|
|
310
|
-
// let hostSet
|
|
311
|
-
// for(let line of lines) {
|
|
312
|
-
// if (line.includes("pinokio.network")) {
|
|
313
|
-
// hostSet = true
|
|
314
|
-
// }
|
|
315
|
-
// }
|
|
316
|
-
// console.log({ hostSet })
|
|
317
|
-
// if (!hostSet) {
|
|
318
|
-
// console.log("setting hosts")
|
|
319
|
-
// await this.exec({
|
|
320
|
-
// sudo: true,
|
|
321
|
-
// message: "npx hostile set 127.0.0.1 pinokio.network"
|
|
322
|
-
// }, (e) => {
|
|
323
|
-
// console.log(e)
|
|
324
|
-
// })
|
|
325
|
-
// console.log("success")
|
|
326
|
-
// }
|
|
327
|
-
//})
|
|
328
|
-
|
|
329
308
|
} catch (e) {
|
|
330
309
|
console.log("### ERROR", e)
|
|
331
310
|
}
|
|
311
|
+
|
|
312
|
+
// await this.exec({
|
|
313
|
+
// message: "caddy run",
|
|
314
|
+
// path: this.homedir
|
|
315
|
+
// }, (e) => {
|
|
316
|
+
// process.stdout.write(e.raw)
|
|
317
|
+
// })
|
|
332
318
|
}
|
|
333
319
|
async update_sysinfo() {
|
|
334
320
|
try {
|
package/kernel/shell.js
CHANGED
|
@@ -12,6 +12,8 @@ const path = require("path")
|
|
|
12
12
|
const sudo = require("sudo-prompt-programfiles-x86");
|
|
13
13
|
const unparse = require('yargs-unparser-custom-flag');
|
|
14
14
|
const shellPath = require('shell-path');
|
|
15
|
+
const util = require('./util')
|
|
16
|
+
const Environment = require('./environment')
|
|
15
17
|
const home = os.homedir()
|
|
16
18
|
class Shell {
|
|
17
19
|
/*
|
|
@@ -111,25 +113,8 @@ class Shell {
|
|
|
111
113
|
this.env.CMAKE_OBJECT_PATH_MAX = 1024
|
|
112
114
|
|
|
113
115
|
// Well Known Cache
|
|
114
|
-
|
|
115
|
-
this.env
|
|
116
|
-
this.env.HOMEBREW_CACHE = path.resolve(this.kernel.homedir, "cache", "TORCH_HOME")
|
|
117
|
-
this.env.XDG_CACHE_HOME = path.resolve(this.kernel.homedir, "cache", "XDG_CACHE_HOME")
|
|
118
|
-
this.env.PIP_CACHE_DIR = path.resolve(this.kernel.homedir, "cache", "PIP_CACHE_DIR")
|
|
119
|
-
this.env.PIP_TMPDIR = path.resolve(this.kernel.homedir, "cache", "PIP_TMPDIR")
|
|
120
|
-
this.env.TMPDIR = path.resolve(this.kernel.homedir, "cache", "TMPDIR")
|
|
121
|
-
this.env.TEMP = path.resolve(this.kernel.homedir, "cache", "TEMP")
|
|
122
|
-
this.env.TMP = path.resolve(this.kernel.homedir, "cache", "TMP")
|
|
123
|
-
this.env.XDG_DATA_HOME = path.resolve(this.kernel.homedir, "cache", "XDG_DATA_HOME")
|
|
124
|
-
this.env.XDG_CONFIG_HOME = path.resolve(this.kernel.homedir, "cache", "XDG_CONFIG_HOME")
|
|
125
|
-
this.env.XDG_STATE_HOME = path.resolve(this.kernel.homedir, "cache", "XDG_STATE_HOME")
|
|
126
|
-
this.env.GRADIO_TEMP_DIR = path.resolve(this.kernel.homedir, "cache", "GRADIO_TEMP_DIR")
|
|
127
|
-
this.env.PIP_CONFIG_FILE = path.resolve(this.kernel.homedir, "pipconfig")
|
|
128
|
-
this.env.CONDARC = path.resolve(this.kernel.homedir, "condarc")
|
|
129
|
-
|
|
130
|
-
this.env.PS1 = "<<PINOKIO SHELL>> "
|
|
131
|
-
// this.env.PROMPT_COMMAND = "export PS1=\"<<PINOKIO SHELL>> \""
|
|
132
|
-
|
|
116
|
+
let home_env = await Environment.get(this.kernel.homedir)
|
|
117
|
+
this.env = Object.assign(this.env, home_env)
|
|
133
118
|
let PATH_KEY;
|
|
134
119
|
if (this.env.Path) {
|
|
135
120
|
PATH_KEY = "Path"
|
|
@@ -149,32 +134,6 @@ class Shell {
|
|
|
149
134
|
|
|
150
135
|
this.env[PATH_KEY] = this.env[PATH_KEY] + path.delimiter + path.resolve(this.kernel.homedir, 'bin')
|
|
151
136
|
|
|
152
|
-
// custom env was passed in
|
|
153
|
-
|
|
154
|
-
// override cache folders if cache is specified
|
|
155
|
-
if (params.cache) {
|
|
156
|
-
// cache data files
|
|
157
|
-
let cache_path = path.resolve(params.path, params.cache)
|
|
158
|
-
let types = [
|
|
159
|
-
"HF_HOME", // huggingface models
|
|
160
|
-
"TORCH_HOME", // torch hub models
|
|
161
|
-
"GRADIO_TEMP_DIR" // gradio data
|
|
162
|
-
// "XDG_CACHE_HOME",
|
|
163
|
-
// "PIP_CACHE_DIR",
|
|
164
|
-
// "TMPDIR",
|
|
165
|
-
// "TEMP",
|
|
166
|
-
// "TMP",
|
|
167
|
-
// "XDG_DATA_HOME",
|
|
168
|
-
// "XDG_CONFIG_HOME",
|
|
169
|
-
// "XDG_STATE_HOME",
|
|
170
|
-
]
|
|
171
|
-
for(let type of types) {
|
|
172
|
-
let p = path.resolve(cache_path, type)
|
|
173
|
-
this.env[type] = p
|
|
174
|
-
await fs.promises.mkdir(p, { recursive: true }).catch((e) => { })
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
137
|
|
|
179
138
|
if (params.env) {
|
|
180
139
|
for(let key in params.env) {
|
|
@@ -226,7 +185,6 @@ class Shell {
|
|
|
226
185
|
delete this.env[key]
|
|
227
186
|
}
|
|
228
187
|
}
|
|
229
|
-
|
|
230
188
|
// 3. path => path can be http, relative, absolute
|
|
231
189
|
this.path = params.path
|
|
232
190
|
|
package/kernel/util.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const dotenv = require('dotenv')
|
|
4
|
+
const parse_env = async (filename) => {
|
|
5
|
+
try {
|
|
6
|
+
const buf = await fs.promises.readFile(filename)
|
|
7
|
+
const config = dotenv.parse(buf) // will return an object
|
|
8
|
+
return config
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return {}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const api_path = async (fullpath, kernel) => {
|
|
14
|
+
let api_path = `${kernel.homedir}${path.sep}api`
|
|
15
|
+
let rel_path = path.relative(api_path, fullpath)
|
|
16
|
+
let api_name = rel_path.split(path.sep)[0]
|
|
17
|
+
let current_api_path = `${api_path}${path.sep}${api_name}`
|
|
18
|
+
return current_api_path
|
|
19
|
+
}
|
|
20
|
+
module.exports = {
|
|
21
|
+
parse_env, api_path
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinokiod",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.42",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"cross-fetch": "^3.1.5",
|
|
20
20
|
"csv-parse": "^5.3.10",
|
|
21
21
|
"decompress": "^4.2.1",
|
|
22
|
+
"dotenv": "^16.4.5",
|
|
22
23
|
"ejs": "^3.1.9",
|
|
23
24
|
"express": "^4.18.2",
|
|
24
25
|
"express-http-proxy-cp": "^2.0.3",
|
package/server/index.js
CHANGED
|
@@ -34,6 +34,7 @@ const ejs = require('ejs');
|
|
|
34
34
|
const Socket = require('./socket')
|
|
35
35
|
const Kernel = require("../kernel")
|
|
36
36
|
const packagejson = require("../package.json")
|
|
37
|
+
const Environment = require("../kernel/environment")
|
|
37
38
|
class Server {
|
|
38
39
|
constructor(config) {
|
|
39
40
|
this.tabs = {}
|
|
@@ -326,6 +327,14 @@ class Server {
|
|
|
326
327
|
// }
|
|
327
328
|
// }
|
|
328
329
|
|
|
330
|
+
if (path.basename(filepath) === "ENVIRONMENT") {
|
|
331
|
+
// if environment.json doesn't exist,
|
|
332
|
+
let exists = await this.exists(filepath)
|
|
333
|
+
if (!exists) {
|
|
334
|
+
let content = await Environment.APP_ENV()
|
|
335
|
+
await fs.promises.writeFile(filepath, content)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
329
338
|
|
|
330
339
|
let stat = await fs.promises.stat(filepath)
|
|
331
340
|
if (pathComponents.length === 0 && req.query.mode === "explore") {
|
|
@@ -353,7 +362,7 @@ class Server {
|
|
|
353
362
|
name: "zip",
|
|
354
363
|
}, {
|
|
355
364
|
type: "conda",
|
|
356
|
-
name: ["nodejs", "ffmpeg"],
|
|
365
|
+
name: ["nodejs", "ffmpeg", ],
|
|
357
366
|
args: "-c conda-forge"
|
|
358
367
|
}]
|
|
359
368
|
let platform = os.platform()
|
|
@@ -397,8 +406,6 @@ class Server {
|
|
|
397
406
|
}
|
|
398
407
|
}
|
|
399
408
|
|
|
400
|
-
console.log({ type: 1, requirements })
|
|
401
|
-
|
|
402
409
|
let error = null
|
|
403
410
|
try {
|
|
404
411
|
this.compatible()
|
|
@@ -458,7 +465,6 @@ class Server {
|
|
|
458
465
|
...folders
|
|
459
466
|
})
|
|
460
467
|
} else if (stat.isFile()) {
|
|
461
|
-
|
|
462
468
|
if (req.query && req.query.raw) {
|
|
463
469
|
try {
|
|
464
470
|
// res.setHeader('Content-Disposition', 'inline');
|
|
@@ -518,7 +524,12 @@ class Server {
|
|
|
518
524
|
|
|
519
525
|
let rawpath = `/raw/${pathComponents.join('/')}` + "?frame=true"
|
|
520
526
|
if (editmode) {
|
|
521
|
-
let content
|
|
527
|
+
let content
|
|
528
|
+
try {
|
|
529
|
+
content = await fs.promises.readFile(filepath, "utf8")
|
|
530
|
+
} catch (e) {
|
|
531
|
+
content = ""
|
|
532
|
+
}
|
|
522
533
|
|
|
523
534
|
/********************************************************************
|
|
524
535
|
*
|
|
@@ -621,7 +632,7 @@ class Server {
|
|
|
621
632
|
name: "zip",
|
|
622
633
|
}, {
|
|
623
634
|
type: "conda",
|
|
624
|
-
name: ["nodejs", "ffmpeg"],
|
|
635
|
+
name: ["nodejs", "ffmpeg", ],
|
|
625
636
|
args: "-c conda-forge"
|
|
626
637
|
}]
|
|
627
638
|
let platform = os.platform()
|
|
@@ -756,8 +767,6 @@ class Server {
|
|
|
756
767
|
return r.relevant
|
|
757
768
|
})
|
|
758
769
|
|
|
759
|
-
console.log({ type: 2, requirements })
|
|
760
|
-
|
|
761
770
|
|
|
762
771
|
let mem = this.getMemory(filepath)
|
|
763
772
|
// let localMem = this.kernel.memory.local[filepath]
|
|
@@ -1214,8 +1223,14 @@ class Server {
|
|
|
1214
1223
|
|
|
1215
1224
|
|
|
1216
1225
|
async renderMenu(uri, name, config, pathComponents) {
|
|
1217
|
-
console.log("config.menu =" ,config.menu)
|
|
1218
1226
|
if (config.menu) {
|
|
1227
|
+
|
|
1228
|
+
config.menu = [{
|
|
1229
|
+
text: "Configure",
|
|
1230
|
+
href: "ENVIRONMENT?mode=source",
|
|
1231
|
+
icon: "fa-solid fa-gear"
|
|
1232
|
+
}].concat(config.menu)
|
|
1233
|
+
|
|
1219
1234
|
for(let i=0; i<config.menu.length; i++) {
|
|
1220
1235
|
let menuitem = config.menu[i]
|
|
1221
1236
|
|
|
@@ -1370,31 +1385,34 @@ class Server {
|
|
|
1370
1385
|
return item.btn
|
|
1371
1386
|
})
|
|
1372
1387
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
1388
|
|
|
1376
|
-
// get all proxies that belong to this repository
|
|
1377
|
-
let childProxies = []
|
|
1378
|
-
for(let scriptPath in this.kernel.api.proxies) {
|
|
1379
|
-
let proxies = this.kernel.api.proxies[scriptPath]
|
|
1380
|
-
for(let proxy of proxies) {
|
|
1381
|
-
if (scriptPath.startsWith(this.kernel.path("api", name))) {
|
|
1382
|
-
childProxies.push(proxy)
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
1389
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
btn: `<i class="fa-solid fa-wifi"></i> <strong>WiFi</strong> - ${proxy.name}`,
|
|
1391
|
-
target: "_blank",
|
|
1392
|
-
href: proxy.proxy
|
|
1393
|
-
})
|
|
1394
|
-
}
|
|
1395
|
-
config.menu = proxyMenu.concat(config.menu)
|
|
1390
|
+
console.log("MENU", config.menu)
|
|
1391
|
+
|
|
1392
|
+
|
|
1396
1393
|
|
|
1397
|
-
|
|
1394
|
+
// // get all proxies that belong to this repository
|
|
1395
|
+
// let childProxies = []
|
|
1396
|
+
// for(let scriptPath in this.kernel.api.proxies) {
|
|
1397
|
+
// let proxies = this.kernel.api.proxies[scriptPath]
|
|
1398
|
+
// for(let proxy of proxies) {
|
|
1399
|
+
// if (scriptPath.startsWith(this.kernel.path("api", name))) {
|
|
1400
|
+
// childProxies.push(proxy)
|
|
1401
|
+
// }
|
|
1402
|
+
// }
|
|
1403
|
+
// }
|
|
1404
|
+
//
|
|
1405
|
+
// let proxyMenu = []
|
|
1406
|
+
// for(let proxy of childProxies) {
|
|
1407
|
+
// proxyMenu.push({
|
|
1408
|
+
// btn: `<i class="fa-solid fa-wifi"></i> <strong>WiFi</strong> - ${proxy.name}`,
|
|
1409
|
+
// target: "_blank",
|
|
1410
|
+
// href: proxy.proxy
|
|
1411
|
+
// })
|
|
1412
|
+
// }
|
|
1413
|
+
// config.menu = proxyMenu.concat(config.menu)
|
|
1414
|
+
//
|
|
1415
|
+
// console.log("MENU", JSON.stringify(config.menu, null, 2))
|
|
1398
1416
|
|
|
1399
1417
|
|
|
1400
1418
|
return config
|
|
@@ -1798,7 +1816,7 @@ class Server {
|
|
|
1798
1816
|
await this.syncConfig()
|
|
1799
1817
|
|
|
1800
1818
|
// initialize kernel
|
|
1801
|
-
await this.kernel.init()
|
|
1819
|
+
await this.kernel.init({ port: this.port})
|
|
1802
1820
|
|
|
1803
1821
|
// start proxy for Pinokio itself
|
|
1804
1822
|
await this.kernel.api.startProxy("/", `http://127.0.0.1:${this.port}`, "/")
|
|
@@ -2002,9 +2020,18 @@ class Server {
|
|
|
2002
2020
|
// }
|
|
2003
2021
|
})
|
|
2004
2022
|
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2023
|
+
this.app.get("/edit/*", async (req, res) => {
|
|
2024
|
+
let pathComponents = req.params[0].split("/")
|
|
2025
|
+
let filepath = path.resolve(this.kernel.homedir, req.params[0])
|
|
2026
|
+
const content = await fs.promises.readFile(filepath, "utf8")
|
|
2027
|
+
console.log({ pathComponents, content })
|
|
2028
|
+
res.render("general_editor", {
|
|
2029
|
+
theme: this.theme,
|
|
2030
|
+
filepath,
|
|
2031
|
+
content,
|
|
2032
|
+
agent: this.agent,
|
|
2033
|
+
})
|
|
2034
|
+
})
|
|
2008
2035
|
this.app.get("/script/:name", (req, res) => {
|
|
2009
2036
|
if (req.params.name === "start") {
|
|
2010
2037
|
res.json(this.startScripts)
|
package/server/views/editor.ejs
CHANGED
|
@@ -129,6 +129,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
129
129
|
maxLines: Infinity, // set to a large number
|
|
130
130
|
minLines: 1 // set to a small number
|
|
131
131
|
});
|
|
132
|
+
console.log("location.pathname", location.pathname)
|
|
132
133
|
<% if (mod) { %>
|
|
133
134
|
<% if (js) { %>
|
|
134
135
|
editor.session.setMode("ace/mode/javascript");
|
|
@@ -136,6 +137,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
136
137
|
editor.session.setMode("ace/mode/json");
|
|
137
138
|
<% } %>
|
|
138
139
|
<% } %>
|
|
140
|
+
if (location.pathname.endsWith("ENVIRONMENT")) {
|
|
141
|
+
editor.session.setMode("ace/mode/python");
|
|
142
|
+
}
|
|
139
143
|
//editor.session.setMode("ace/mode/javascript");
|
|
140
144
|
//editor.setValue(file)
|
|
141
145
|
editor.clearSelection()
|
|
@@ -191,14 +195,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
191
195
|
this.socket.run({
|
|
192
196
|
method: "kernel.api.stop",
|
|
193
197
|
params: {
|
|
194
|
-
uri: "<%=execUrl%>",
|
|
198
|
+
//uri: "<%=execUrl%>",
|
|
199
|
+
uri: "~" + location.pathname
|
|
195
200
|
}
|
|
196
201
|
}, (stream) => {
|
|
197
202
|
})
|
|
198
203
|
}
|
|
199
204
|
save() {
|
|
200
205
|
return new Promise((resolve, reject) => {
|
|
201
|
-
let cwd = "<%=execUrl%>"
|
|
206
|
+
//let cwd = "<%=execUrl%>"
|
|
207
|
+
let cwd = "~" + location.pathname
|
|
208
|
+
debugger
|
|
202
209
|
this.socket.close()
|
|
203
210
|
this.socket.run({
|
|
204
211
|
method: "fs.write",
|
|
@@ -226,7 +233,8 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
226
233
|
this.socket.run({
|
|
227
234
|
//uri: location.pathname.slice(1).replace("api/", ""),
|
|
228
235
|
//uri: "~" + location.pathname,
|
|
229
|
-
uri: "<%=execUrl%>",
|
|
236
|
+
//uri: "<%=execUrl%>",
|
|
237
|
+
uri: "~" + location.pathname,
|
|
230
238
|
mode,
|
|
231
239
|
input: query,
|
|
232
240
|
client: {
|
|
@@ -689,15 +697,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
689
697
|
// await reloadMemory()
|
|
690
698
|
// }
|
|
691
699
|
// })
|
|
692
|
-
document.querySelector("#lv")
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
m.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
700
|
+
if (document.querySelector("#lv")) {
|
|
701
|
+
document.querySelector("#lv").addEventListener("click", (e) => {
|
|
702
|
+
let m = e.target.closest(".memory")
|
|
703
|
+
m.classList.toggle("collapsed")
|
|
704
|
+
if (m.classList.contains("collapsed")) {
|
|
705
|
+
m.querySelector("i").className = "fa-solid fa-sort-down"
|
|
706
|
+
} else {
|
|
707
|
+
m.querySelector("i").className = "fa-solid fa-sort-up"
|
|
708
|
+
}
|
|
709
|
+
})
|
|
710
|
+
}
|
|
701
711
|
})
|
|
702
712
|
const reloadMemory = async () => {
|
|
703
713
|
let url = "/pinokio/memory?filepath=" + encodeURI("<%-filepath%>")
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<html class='columns'>
|
|
2
|
+
<head>
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
|
4
|
+
<script src="/hotkeys.min.js"></script>
|
|
5
|
+
<script src="/ace/ace.js"></script>
|
|
6
|
+
<script src="/noty.js"></script>
|
|
7
|
+
<script src="/notyq.js"></script>
|
|
8
|
+
<script src="/xterm.js"></script>
|
|
9
|
+
<script src="/xterm-addon-fit.js"></script>
|
|
10
|
+
<script src="/xterm-addon-web-links.js"></script>
|
|
11
|
+
<script src="/xterm-theme.js"></script>
|
|
12
|
+
<script src="/xterm-addon-search.js"></script>
|
|
13
|
+
<script src="/xterm-addon-search-bar.js"></script>
|
|
14
|
+
<script src="/sweetalert2.js"></script>
|
|
15
|
+
<script src="/Socket.js"></script>
|
|
16
|
+
<script src="/common.js"></script>
|
|
17
|
+
<script src="/he.js"></script>
|
|
18
|
+
<script src="/opener.js"></script>
|
|
19
|
+
<script src="/nav.js"></script>
|
|
20
|
+
<script src="/autoexpand.js"></script>
|
|
21
|
+
<script src="/modalinput.js"></script>
|
|
22
|
+
<script src="/simplemodal.js"></script>
|
|
23
|
+
<script src="/waitmodal.js"></script>
|
|
24
|
+
<script src="/notifyinput.js"></script>
|
|
25
|
+
<script src="/report.js"></script>
|
|
26
|
+
<link href="/xterm.min.css" rel="stylesheet" />
|
|
27
|
+
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
|
28
|
+
<link href="/css/solid.min.css" rel="stylesheet">
|
|
29
|
+
<link href="/css/regular.min.css" rel="stylesheet">
|
|
30
|
+
<link href="/css/brands.min.css" rel="stylesheet">
|
|
31
|
+
<link href="/style.css" rel="stylesheet"/>
|
|
32
|
+
<link href="/noty.css" rel="stylesheet"/>
|
|
33
|
+
<% if (agent === "electron") { %>
|
|
34
|
+
<link href="/electron.css" rel="stylesheet"/>
|
|
35
|
+
<% } %>
|
|
36
|
+
<style>
|
|
37
|
+
body.frozen {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
height: 100%;
|
|
41
|
+
}
|
|
42
|
+
#table > table {
|
|
43
|
+
border-left: 2px solid black;
|
|
44
|
+
padding-left: 5px;
|
|
45
|
+
margin: 10px 0;
|
|
46
|
+
}
|
|
47
|
+
.highlight {
|
|
48
|
+
background: yellow;
|
|
49
|
+
width: 100px;
|
|
50
|
+
}
|
|
51
|
+
th {
|
|
52
|
+
background: rgba(0,0,0,0.1);
|
|
53
|
+
padding: 10px;
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
}
|
|
56
|
+
td {
|
|
57
|
+
font-size: 12px;
|
|
58
|
+
padding: 10px;
|
|
59
|
+
}
|
|
60
|
+
td.val {
|
|
61
|
+
background: rgba(0,0,0,0.06);
|
|
62
|
+
}
|
|
63
|
+
td.key {
|
|
64
|
+
background: rgba(0,0,0,0.1);
|
|
65
|
+
}
|
|
66
|
+
.button {
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
background: rgba(0,0,0,0.8);
|
|
69
|
+
color: white;
|
|
70
|
+
padding: 5px 10px;
|
|
71
|
+
border-radius: 4px;
|
|
72
|
+
}
|
|
73
|
+
.button:hover {
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
#editor {
|
|
77
|
+
background: var(--dark-bg);
|
|
78
|
+
}
|
|
79
|
+
header .runner {
|
|
80
|
+
padding: 10px 0 0;
|
|
81
|
+
}
|
|
82
|
+
.disabled {
|
|
83
|
+
opacity: 0.7;
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
86
|
+
<script>
|
|
87
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
88
|
+
let editor = ace.edit("editor");
|
|
89
|
+
//editor.setTheme("ace/theme/tomorrow");
|
|
90
|
+
//editor.setTheme("ace/theme/ambiance");
|
|
91
|
+
//editor.setTheme("ace/theme/idle_fingers");
|
|
92
|
+
editor.setTheme("ace/theme/nord_dark");
|
|
93
|
+
//editor.setTheme("ace/theme/textmate");
|
|
94
|
+
editor.setOptions({
|
|
95
|
+
maxLines: Infinity, // set to a large number
|
|
96
|
+
minLines: 1 // set to a small number
|
|
97
|
+
});
|
|
98
|
+
console.log("location.pathname", location.pathname)
|
|
99
|
+
if (location.pathname.endsWith("ENVIRONMENT")) {
|
|
100
|
+
editor.session.setMode("ace/mode/python");
|
|
101
|
+
}
|
|
102
|
+
//editor.session.setMode("ace/mode/javascript");
|
|
103
|
+
//editor.setValue(file)
|
|
104
|
+
editor.clearSelection()
|
|
105
|
+
if (location.hash && location.hash.length > 1) {
|
|
106
|
+
let parsedHash = location.hash.slice(1)
|
|
107
|
+
let line_re = /L([0-9]+)/
|
|
108
|
+
let line_match = line_re.exec(parsedHash)
|
|
109
|
+
if (line_match && line_match.length > 0) {
|
|
110
|
+
let line = parseInt(line_match[1])
|
|
111
|
+
editor.gotoLine(line)
|
|
112
|
+
editor.selection.selectLine()
|
|
113
|
+
editor.gotoLine(line)
|
|
114
|
+
editor.focus()
|
|
115
|
+
}
|
|
116
|
+
// let range_re = /L[0-9]+-L[0-9]+/
|
|
117
|
+
|
|
118
|
+
// let range_match = range_re.exec(parsedHash)
|
|
119
|
+
// if (range_match && range_match.length > 0) {
|
|
120
|
+
//
|
|
121
|
+
// }
|
|
122
|
+
}
|
|
123
|
+
let dirty
|
|
124
|
+
let str;
|
|
125
|
+
let original = editor.getValue()
|
|
126
|
+
editor.getSession().on("change", () => {
|
|
127
|
+
let v = editor.getValue()
|
|
128
|
+
if (original === v) {
|
|
129
|
+
dirty = false
|
|
130
|
+
document.querySelector("#save").classList.add("disabled")
|
|
131
|
+
} else {
|
|
132
|
+
dirty = true
|
|
133
|
+
document.querySelector("#save").classList.remove("disabled")
|
|
134
|
+
}
|
|
135
|
+
str = v
|
|
136
|
+
});
|
|
137
|
+
const n = new N()
|
|
138
|
+
class RPC {
|
|
139
|
+
constructor() {
|
|
140
|
+
this.socket = new Socket()
|
|
141
|
+
}
|
|
142
|
+
save() {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
// remove `/edit/`
|
|
145
|
+
let filepath = location.pathname.slice(6)
|
|
146
|
+
this.socket.close()
|
|
147
|
+
this.socket.run({
|
|
148
|
+
method: "fs.write",
|
|
149
|
+
cwd: "{{kernel.homedir}}",
|
|
150
|
+
params: {
|
|
151
|
+
path: filepath,
|
|
152
|
+
text: str,
|
|
153
|
+
}
|
|
154
|
+
}, (packet) => {
|
|
155
|
+
if (packet.type === "result" && packet.id === "fs.write") {
|
|
156
|
+
dirty = false
|
|
157
|
+
document.querySelector("#save").classList.add("disabled")
|
|
158
|
+
resolve()
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const rpc = new RPC()
|
|
165
|
+
if (document.querySelector("#save")) {
|
|
166
|
+
document.querySelector("#save").addEventListener("click", async (e) => {
|
|
167
|
+
console.log("SAVE")
|
|
168
|
+
await rpc.save()
|
|
169
|
+
n.Noty({
|
|
170
|
+
text: `saved`,
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
if (document.querySelector("#lv")) {
|
|
175
|
+
document.querySelector("#lv").addEventListener("click", (e) => {
|
|
176
|
+
let m = e.target.closest(".memory")
|
|
177
|
+
m.classList.toggle("collapsed")
|
|
178
|
+
if (m.classList.contains("collapsed")) {
|
|
179
|
+
m.querySelector("i").className = "fa-solid fa-sort-down"
|
|
180
|
+
} else {
|
|
181
|
+
m.querySelector("i").className = "fa-solid fa-sort-up"
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
</script>
|
|
187
|
+
</head>
|
|
188
|
+
<body class='columns <%=theme%>'>
|
|
189
|
+
<header class='navheader grabbable'>
|
|
190
|
+
<h1>
|
|
191
|
+
<a class='home' href="/"><i class="fa-solid fa-house"></i></a>
|
|
192
|
+
<%=filepath%>
|
|
193
|
+
</h1>
|
|
194
|
+
<div class='runner'>
|
|
195
|
+
<div id='save' class='btn disabled'>
|
|
196
|
+
<span class='save'><i class="fa-solid fa-check"></i> Save</span>
|
|
197
|
+
</div>
|
|
198
|
+
<button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> Open in File Explorer</button>
|
|
199
|
+
</div>
|
|
200
|
+
</header>
|
|
201
|
+
<div class='containers'>
|
|
202
|
+
<main>
|
|
203
|
+
<div id='editor'><%=content%></div>
|
|
204
|
+
</main>
|
|
205
|
+
</div>
|
|
206
|
+
<footer><b>Ready</b></footer>
|
|
207
|
+
</body>
|
|
208
|
+
</html>
|
package/server/views/index.ejs
CHANGED
|
@@ -126,9 +126,9 @@ header .runner {
|
|
|
126
126
|
<a class='btn2' href="/?mode=help"><div><i class="fa-regular fa-face-smile"></i></div><div>Community</div></a>
|
|
127
127
|
<% if (agent === "electron") { %>
|
|
128
128
|
<a class='btn2' data-filepath="<%=filepath%>"><div><i class="fa-regular fa-folder-open"></i></div><div>Files</div></a>
|
|
129
|
+
<a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-arrow-up-right-from-square"></i></div><div>Popout</div></a>
|
|
129
130
|
<% } %>
|
|
130
131
|
<a id='wifi' data-proxy="<%=proxy.proxy%>" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>WiFi Share</div></a>
|
|
131
|
-
<a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-arrow-up-right-from-square"></i></div><div>Popout</div></a>
|
|
132
132
|
<!--
|
|
133
133
|
<a class='btn2' id='report'><div><i class="fa-solid fa-bug"></i></div><div>Report Bug</div></a>
|
|
134
134
|
<a class='btn2' href='https://discord.gg/TQdNwadtE4' target="_blank"><div><i class="fa-brands fa-discord"></i></div><div>Discord</div></a>
|
|
@@ -291,6 +291,15 @@ hr {
|
|
|
291
291
|
<i class="fa-solid fa-circle-notch fa-spin"></i> Stand by. Do not close this window..
|
|
292
292
|
</div>
|
|
293
293
|
<hr/>
|
|
294
|
+
<div class='advanced'>
|
|
295
|
+
<h1>Advanced Settings</h1>
|
|
296
|
+
<br>
|
|
297
|
+
<br>
|
|
298
|
+
<div>Edit the system ENVIRONMENT file to customize pinokio system wide settings, such as where files are stored, terminal behavior, etc.</div>
|
|
299
|
+
<br>
|
|
300
|
+
<a class='btn' href="/edit/ENVIRONMENT">Edit ENVIRONMENT</a>
|
|
301
|
+
</div>
|
|
302
|
+
<hr/>
|
|
294
303
|
<% if (locals.bin) { %>
|
|
295
304
|
<div class='troubleshoot'>
|
|
296
305
|
<h1>Troubleshoot</h1>
|