pinokiod 3.8.91 → 3.8.93

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.
@@ -15,7 +15,7 @@ class Caddy {
15
15
  let response = await axios.get('http://127.0.0.1:2019/config/')
16
16
  return true
17
17
  } catch (e) {
18
- console.log(e)
18
+ console.log(e.message)
19
19
  return false
20
20
  }
21
21
  }
@@ -34,7 +34,6 @@ class Caddy {
34
34
  message: `caddy run --watch`,
35
35
  path: this.kernel.homedir,
36
36
  }, (e) => {
37
- console.log("[CADDY] " + e.cleaned)
38
37
  if (!resolved) {
39
38
  if (/endpoint started/i.test(e.cleaned)) {
40
39
  console.log("######### match")
@@ -46,273 +45,6 @@ class Caddy {
46
45
  })
47
46
  this.kernel.refresh(true)
48
47
  }
49
- // const config = {
50
- // "apps": {
51
- // "http": {
52
- // "servers": {
53
- // "main": {
54
- // "listen": ["127.0.0.1:443"],
55
- // "routes": [
56
- // {
57
- // "match": [{ "method": ["OPTIONS"] }],
58
- // "handle": [
59
- // {
60
- // "handler": "headers",
61
- // "response": {
62
- // "set": {
63
- // "Access-Control-Allow-Origin": ["*"],
64
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
65
- // "Access-Control-Allow-Headers": ["*"],
66
- // "Vary": ["Origin"]
67
- // }
68
- // }
69
- // },
70
- // {
71
- // "handler": "static_response",
72
- // "status_code": 204
73
- // }
74
- // ]
75
- // },
76
- // {
77
- // "match": [{ "host": ["pinokio.localhost"] }],
78
- // "handle": [
79
- // {
80
- // "handler": "reverse_proxy",
81
- // "upstreams": [{ "dial": "127.0.0.1:42000" }]
82
- // },
83
- // {
84
- // "handler": "headers",
85
- // "response": {
86
- // "set": {
87
- // "Access-Control-Allow-Origin": ["*"],
88
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
89
- // "Access-Control-Allow-Headers": ["*"],
90
- // "Vary": ["Origin"]
91
- // }
92
- // }
93
- // }
94
- // ]
95
- // },
96
- // {
97
- // "match": [{ "host": ["l.pinokio.localhost"] }],
98
- // "handle": [
99
- // {
100
- // "handler": "reverse_proxy",
101
- // "upstreams": [{ "dial": "127.0.0.1:1234" }]
102
- // },
103
- // {
104
- // "handler": "headers",
105
- // "response": {
106
- // "set": {
107
- // "Access-Control-Allow-Origin": ["*"],
108
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
109
- // "Access-Control-Allow-Headers": ["*"],
110
- // "Vary": ["Origin"]
111
- // }
112
- // }
113
- // }
114
- // ]
115
- // },
116
- // {
117
- // "match": [{ "host": ["o.pinokio.localhost"] }],
118
- // "handle": [
119
- // {
120
- // "handler": "reverse_proxy",
121
- // "upstreams": [{ "dial": "127.0.0.1:11434" }]
122
- // },
123
- // {
124
- // "handler": "headers",
125
- // "response": {
126
- // "set": {
127
- // "Access-Control-Allow-Origin": ["*"],
128
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
129
- // "Access-Control-Allow-Headers": ["*"],
130
- // "Vary": ["Origin"]
131
- // }
132
- // }
133
- // }
134
- // ]
135
- // },
136
- // {
137
- // "match": [{ "host": ["a.pinokio.localhost"] }],
138
- // "handle": [
139
- // {
140
- // "handler": "reverse_proxy",
141
- // "upstreams": [{ "dial": "127.0.0.1:7860" }]
142
- // },
143
- // {
144
- // "handler": "headers",
145
- // "response": {
146
- // "set": {
147
- // "Access-Control-Allow-Origin": ["*"],
148
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
149
- // "Access-Control-Allow-Headers": ["*"],
150
- // "Vary": ["Origin"]
151
- // }
152
- // }
153
- // }
154
- // ]
155
- // },
156
- // {
157
- // "match": [{ "host": ["b.pinokio.localhost"] }],
158
- // "handle": [
159
- // {
160
- // "handler": "reverse_proxy",
161
- // "upstreams": [{ "dial": "127.0.0.1:7861" }]
162
- // },
163
- // {
164
- // "handler": "headers",
165
- // "response": {
166
- // "set": {
167
- // "Access-Control-Allow-Origin": ["*"],
168
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
169
- // "Access-Control-Allow-Headers": ["*"],
170
- // "Vary": ["Origin"]
171
- // }
172
- // }
173
- // }
174
- // ]
175
- // },
176
- // {
177
- // "match": [{ "host": ["c.pinokio.localhost"] }],
178
- // "handle": [
179
- // {
180
- // "handler": "reverse_proxy",
181
- // "upstreams": [{ "dial": "127.0.0.1:7862" }]
182
- // },
183
- // {
184
- // "handler": "headers",
185
- // "response": {
186
- // "set": {
187
- // "Access-Control-Allow-Origin": ["*"],
188
- // "Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
189
- // "Access-Control-Allow-Headers": ["*"],
190
- // "Vary": ["Origin"]
191
- // }
192
- // }
193
- // }
194
- // ]
195
- // }
196
- // ]
197
- // }
198
- // }
199
- // }
200
- // }
201
- // }
202
- //
203
- // const config2 = {
204
- // "apps": {
205
- // "http": {
206
- // "servers": {
207
- // "main": {
208
- // "listen": [":443"],
209
- // //"listen": [":80"],
210
- // "handle_response": [
211
- // {
212
- // "handler": "headers",
213
- // "headers": {
214
- // "Access-Control-Allow-Origin": ["*"],
215
- // "Access-Control-Allow-Methods": ["GET", "POST", "OPTIONS", "PUT", "DELETE"],
216
- // "Access-Control-Allow-Headers": ["*"]
217
- // }
218
- // }
219
- // ],
220
- // "routes": [
221
- // {
222
- // "match": [{ "method": ["OPTIONS"] }],
223
- // "handle": [
224
- // {
225
- // "handler": "static_response",
226
- // "headers": {
227
- // "Access-Control-Allow-Origin": ["*"],
228
- // "Access-Control-Allow-Methods": ["GET", "POST", "OPTIONS", "PUT", "DELETE"],
229
- // "Access-Control-Allow-Headers": ["*"]
230
- // },
231
- // "status_code": 204
232
- // }
233
- // ]
234
- // },
235
- // {
236
- // "match": [{ "host": ["pinokio.localhost"] }],
237
- // "handle": [
238
- // {
239
- // "handler": "reverse_proxy",
240
- // "upstreams": [{ "dial": "localhost:42000" }]
241
- // }
242
- // ]
243
- // },
244
- // {
245
- // "match": [{ "host": ["l.pinokio.localhost"] }],
246
- // "handle": [
247
- // {
248
- // "handler": "reverse_proxy",
249
- // "upstreams": [{ "dial": "localhost:1234" }]
250
- // }
251
- // ]
252
- // },
253
- // {
254
- // "match": [{ "host": ["a.pinokio.localhost"] }],
255
- // "handle": [
256
- // {
257
- // "handler": "reverse_proxy",
258
- // "upstreams": [{ "dial": "localhost:7860" }]
259
- // }
260
- // ]
261
- // },
262
- // {
263
- // "match": [{ "host": ["b.pinokio.localhost"] }],
264
- // "handle": [
265
- // {
266
- // "handler": "reverse_proxy",
267
- // "upstreams": [{ "dial": "localhost:7861" }]
268
- // }
269
- // ]
270
- // },
271
- // {
272
- // "match": [{ "host": ["c.pinokio.localhost"] }],
273
- // "handle": [
274
- // {
275
- // "handler": "reverse_proxy",
276
- // "upstreams": [{ "dial": "localhost:7862" }]
277
- // }
278
- // ]
279
- // }
280
- // ]
281
- // }
282
- // }
283
- // },
284
- //// "tls": {
285
- //// "automation": {
286
- //// "policies": [
287
- //// {
288
- //// "subjects": [
289
- //// "pinokio.localhost",
290
- //// "a.pinokio.localhost",
291
- //// "b.pinokio.localhost",
292
- //// "c.pinokio.localhost"
293
- //// ],
294
- //// "issuers": [
295
- //// {
296
- //// "module": "internal"
297
- //// }
298
- //// ]
299
- //// }
300
- //// ]
301
- //// }
302
- //// }
303
- // }
304
- // }
305
- //
306
- //
307
- //
308
- //
309
- // console.log("Make request to caddy", config)
310
- // let response = await axios.post('http://127.0.0.1:2019/load', config, {
311
- // headers: { 'Content-Type': 'application/json' }
312
- // }).catch((e) => {
313
- // console.log("EEEEEEEEEEEEE", e)
314
- // })
315
- // console.log("Caddy Response", { response })
316
48
  }
317
49
  async install(req, ondata, kernel, id) {
318
50
  await this.kernel.bin.exec({
@@ -328,7 +60,6 @@ class Caddy {
328
60
  path: this.kernel.homedir,
329
61
  }, (e) => {
330
62
  resolve()
331
- console.log("[CADDY] " + e.cleaned)
332
63
  if (!resolved) {
333
64
  if (/endpoint started/i.test(e.cleaned)) {
334
65
  console.log("######### match")
package/kernel/index.js CHANGED
@@ -33,6 +33,7 @@ const Proto = require('./prototype')
33
33
  const Router = require("./router")
34
34
  const Procs = require('./procs')
35
35
  const Peer = require('./peer')
36
+ const kill = require('./tree-kill');
36
37
  const VARS = {
37
38
  pip: {
38
39
  install: {
@@ -79,16 +80,16 @@ class Kernel {
79
80
  this.jsdom = jsdom
80
81
  this.exposed = {}
81
82
  this.envs = {}
82
- this.info = new Info(this)
83
- this.pipe = new Pipe(this)
84
- this.proto = new Proto(this)
85
- this.processes = new Procs()
86
- this.kv = new KV(this)
87
- this.cloudflare = new Cloudflare()
83
+ // this.info = new Info(this)
84
+ // this.pipe = new Pipe(this)
85
+ // this.proto = new Proto(this)
86
+ // this.processes = new Procs()
87
+ // this.kv = new KV(this)
88
+ // this.cloudflare = new Cloudflare()
89
+ // this.peer = new Peer()
88
90
  this.shellpath = shellPath.sync()
89
91
 
90
92
 
91
- this.peer = new Peer()
92
93
  }
93
94
  /*
94
95
  kernel.env() => return the system environment
@@ -258,20 +259,23 @@ class Kernel {
258
259
  log(data, group, info) {
259
260
  this.log_queue.push({ data, group, info })
260
261
  }
261
- async refresh(broadcast) {
262
- console.log("kernel.refresh", { broadcast })
262
+ async refresh(notify_peers) {
263
+ console.log("kernel.refresh", { notify_peers })
263
264
  await Promise.all([
264
265
  // refresh proc info
265
266
  this.processes.refresh(),
266
267
  // refresh peer info
267
268
  this.peer.refresh()
268
269
  ])
270
+ console.log("proc info", this.processes.info)
271
+ console.log("peer info", this.peer.info)
269
272
  // refresh router info
270
273
  await this.router.refresh()
274
+ console.log("router info", this.router.published())
271
275
 
272
- if (broadcast) {
273
- // broadcast to peers
274
- await this.peer.broadcast()
276
+ if (notify_peers) {
277
+ // broadcast to peers to refresh
278
+ await this.peer.notify_peers()
275
279
  }
276
280
  }
277
281
  async clearLog(group) {
@@ -477,12 +481,35 @@ class Kernel {
477
481
  }
478
482
  }
479
483
  async init(options) {
484
+
480
485
  let home = this.store.get("home")
481
486
 
482
487
  // reset shells if they exist
488
+ console.log("KERNEL INIT")
483
489
  if (this.shell) {
490
+ console.log("> shell reset")
484
491
  this.shell.reset()
485
492
  }
493
+ if (this.peer) {
494
+ console.log("> peer stop")
495
+ this.peer.stop()
496
+ }
497
+
498
+ // kill all processes just in case
499
+ await new Promise((resolve, reject) => {
500
+ kill(process.pid, 'SIGKILL', () => {
501
+ console.log("child procs killed for", process.pid)
502
+ resolve()
503
+ });
504
+ })
505
+
506
+ this.info = new Info(this)
507
+ this.pipe = new Pipe(this)
508
+ this.proto = new Proto(this)
509
+ this.processes = new Procs()
510
+ this.kv = new KV(this)
511
+ this.cloudflare = new Cloudflare()
512
+ this.peer = new Peer()
486
513
 
487
514
  this.homedir = home
488
515
 
package/kernel/loader.js CHANGED
@@ -6,6 +6,14 @@ const clearModule = require('clear-module');
6
6
 
7
7
  class Loader {
8
8
  async load(_path) {
9
+
10
+ let exists = await new Promise(r=>fs.access(_path, fs.constants.F_OK, e => r(!e)))
11
+ if (!exists) {
12
+ console.log(`[load] ${_path} does not exist`)
13
+ return { resolved: null }
14
+ }
15
+
16
+
9
17
  let resolved
10
18
  let dirname
11
19
  let extension = path.extname(_path)
package/kernel/peer.js CHANGED
@@ -1,80 +1,69 @@
1
1
  const dgram = require('dgram');
2
2
  const axios = require('axios');
3
3
  const os = require('os')
4
+ const Environment = require("./environment")
4
5
  class PeerDiscovery {
5
6
  constructor(port = 41234, message = 'ping', interval = 1000) {
6
7
  this.port = port;
7
8
  this.message = Buffer.from(message);
8
9
  this.interval = interval;
9
10
  this.peers = new Set();
10
- this.name = os.userInfo().username
11
11
  this.host = this._getLocalIPAddress()
12
12
  this.default_port = 42000
13
13
  // this.start();
14
14
  }
15
- start() {
16
- // Listen for incoming pings
17
- console.log("kernel.peer start")
18
- this.socket = dgram.createSocket('udp4');
19
- this.socket.on('message', (msg, rinfo) => {
20
- console.log("peer message", { msg, rinfo })
21
- const ip = rinfo.address;
22
- console.log({rinfo})
23
- if (msg.toString() === this.message.toString() && this._isLocalLAN(ip)) {
24
- if (!this.peers.has(ip)) {
25
- console.log(`Discovered peer: ${ip}`);
26
- this.peers.add(ip);
27
- this.refresh()
28
- }
29
- }
30
- });
31
-
32
- // Enable broadcast
33
- console.log("binding socket")
34
- this.socket.bind(this.port, () => {
35
- console.log("socket bound")
36
- this.socket.setBroadcast(true);
37
-
38
- // Send broadcast pings every interval
39
- setInterval(() => {
40
- console.log("send message to peers")
41
- this.socket.send(this.message, 0, this.message.length, this.port, '255.255.255.255');
15
+ stop() {
16
+ if (this.socket) {
17
+ console.log("peer stop")
18
+ clearInterval(this.interval)
19
+ this.socket.close()
20
+ }
21
+ }
22
+ async start(kernel) {
23
+ let env = await Environment.get(kernel.homedir)
42
24
 
43
- // if peer exists but info doesn't exist, refresh
44
- for(let peer of this.peers) {
45
- let refresh_needed = false;
46
- let refresh_code;
47
- if (this.info[peer]) {
48
- if (this.info[peer].router && Object.keys(this.info[peer].router).length > 0) {
49
- // router initialized
50
- refresh_needed = false;
51
- } else {
52
- // router not initialized. try again
53
- refresh_needed = true;
54
- refresh_code = 1
55
- }
25
+ // by default expose to the local network
26
+ this.active = false
27
+ // if PINOKIO_NETWORK_SHARE is 0 or false, turn it off
28
+ if (env && env.PINOKIO_NETWORK_ACTIVE && (env.PINOKIO_NETWORK_ACTIVE==="1" || env.PINOKIO_NETWORK_ACTIVE.toLowerCase()==="true")) {
29
+ this.active = true
30
+ }
56
31
 
57
- if (this.info[peer].proc && this.info[peer].proc.length > 0) {
58
- // router initialized
59
- refresh_needed = false;
60
- } else {
61
- // router not initialized. try again
62
- refresh_needed = true;
63
- refresh_code = 2
64
- }
32
+ this.name = os.userInfo().username
33
+ if (env && env.PINOKIO_NETWORK_NAME && env.PINOKIO_NETWORK_NAME.length > 0) {
34
+ this.name = env.PINOKIO_NETWORK_NAME
35
+ }
65
36
 
66
- } else {
67
- // try again
68
- refresh_needed = true;
69
- refresh_code = 3
70
- }
71
- if (refresh_needed) {
72
- console.log("refresh needed", refresh_code)
73
- this.refresh([peer])
37
+ if (this.active) {
38
+ // Listen for incoming pings
39
+ console.log("kernel.peer start")
40
+ this.socket = dgram.createSocket('udp4');
41
+ this.socket.on('message', (msg, rinfo) => {
42
+ console.log("peer message", { msg, rinfo })
43
+ const ip = rinfo.address;
44
+ console.log({rinfo})
45
+ if (msg.toString() === this.message.toString() && this._isLocalLAN(ip)) {
46
+ if (!this.peers.has(ip)) {
47
+ console.log(`Discovered peer: ${ip}`);
48
+ this.peers.add(ip);
49
+ this.refresh()
74
50
  }
75
51
  }
76
- }, this.interval);
77
- });
52
+ });
53
+
54
+ // Enable broadcast
55
+ console.log("binding socket")
56
+ this.socket.bind(this.port, () => {
57
+ console.log("socket bound")
58
+ this.socket.setBroadcast(true);
59
+
60
+ // Send broadcast pings every interval
61
+ this.interval = setInterval(() => {
62
+ console.log("send message to peers")
63
+ this.socket.send(this.message, 0, this.message.length, this.port, '255.255.255.255');
64
+ }, this.interval);
65
+ });
66
+ }
78
67
  }
79
68
  async _refresh(host) {
80
69
  try {
@@ -98,36 +87,40 @@ class PeerDiscovery {
98
87
  }
99
88
  }
100
89
  // notify peers to refresh my info
101
- async broadcast() {
102
- let res = await Promise.all(Array.from(this.peers).map((host) => {
103
- return this._broadcast(host)
104
- }))
105
- return res
90
+ async notify_peers() {
91
+ if (this.active) {
92
+ let res = await Promise.all(Array.from(this.peers).map((host) => {
93
+ return this._broadcast(host)
94
+ }))
95
+ return res
96
+ }
106
97
  }
107
98
  // refresh peer info
108
99
  async refresh(peers) {
109
- let refresh_peers
110
- if (peers) {
111
- refresh_peers = peers
112
- } else {
113
- this.info = {}
114
- refresh_peers = Array.from(this.peers)
115
- }
116
- let peer_info = await Promise.all(refresh_peers.map((host) => {
117
- return this._refresh(host)
118
- }))
119
- console.log({ peer_info })
120
- for(let i=0; i<peer_info.length; i++) {
121
- let peer = peer_info[i]
122
- if (peer) {
123
- this.info[peer.host] = {
124
- host: peer.host,
125
- ...peer
100
+ if (this.active) {
101
+ let refresh_peers
102
+ if (peers) {
103
+ refresh_peers = peers
104
+ } else {
105
+ this.info = {}
106
+ refresh_peers = Array.from(this.peers)
107
+ }
108
+ let peer_info = await Promise.all(refresh_peers.map((host) => {
109
+ return this._refresh(host)
110
+ }))
111
+ console.log({ peer_info })
112
+ for(let i=0; i<peer_info.length; i++) {
113
+ let peer = peer_info[i]
114
+ if (peer) {
115
+ this.info[peer.host] = {
116
+ host: peer.host,
117
+ ...peer
118
+ }
126
119
  }
127
120
  }
121
+ console.log("REFRESH", this.info)
122
+ return this.info
128
123
  }
129
- console.log("REFRESH", this.info)
130
- return this.info
131
124
  }
132
125
  _isLocalLAN(ip) {
133
126
  return ip.startsWith('192.168.');
@@ -198,7 +198,7 @@ class Router {
198
198
  let response = await axios.post('http://127.0.0.1:2019/load', this.config, {
199
199
  headers: { 'Content-Type': 'application/json' }
200
200
  }).catch((e) => {
201
- console.log("EEEEEEEEEEEEE", e)
201
+ console.log("EEEEEEEEEEEEE", e.message)
202
202
  })
203
203
  console.log("Caddy Response", { response })
204
204
  }
package/kernel/shell.js CHANGED
@@ -2,7 +2,7 @@ const { Terminal } = require('xterm-headless');
2
2
  const { SerializeAddon } = require("xterm-addon-serialize");
3
3
  const sanitize = require("sanitize-filename");
4
4
  const YAML = require('yaml')
5
- const kill = require('tree-kill');
5
+ const kill = require('./tree-kill');
6
6
  const fastq = require('fastq')
7
7
  const { v4: uuidv4 } = require('uuid');
8
8
  const os = require('os');
@@ -251,6 +251,7 @@ class Shell {
251
251
  this.ondata({ raw: `\r\n████\r\n██ Starting Shell ${this.id}\r\n` })
252
252
 
253
253
 
254
+ this.params = params
254
255
 
255
256
  // 3. path => path can be http, relative, absolute
256
257
  this.path = params.path
@@ -258,6 +259,7 @@ class Shell {
258
259
  // automatically add self to the shells registry
259
260
  this.kernel.shell.add(this)
260
261
 
262
+
261
263
  if (params.sudo) {
262
264
  let options = {
263
265
  name: "Pinokio",
@@ -977,23 +979,30 @@ class Shell {
977
979
  this.queue.killAndDrain()
978
980
  if (this.ptyProcess) {
979
981
  if (cb) {
980
- console.log("tree kill", this.ptyProcess.pid)
981
982
  kill(this.ptyProcess.pid, 'SIGKILL', () => {
983
+ console.log("child procs killed for", this.ptyProcess.pid)
982
984
  this.ptyProcess.kill()
983
985
  this.ptyProcess = undefined
986
+ // automatically remove the shell from this.kernel.shells
987
+ this.kernel.shell.rm(this.id)
988
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
984
989
  cb()
985
990
  });
986
991
  } else {
987
- console.log("tree kill", this.ptyProcess.pid)
988
992
  kill(this.ptyProcess.pid, 'SIGKILL');
993
+ console.log("child procs killed for", this.ptyProcess.pid)
989
994
  this.ptyProcess.kill()
990
995
  this.ptyProcess = undefined
996
+ // automatically remove the shell from this.kernel.shells
997
+ this.kernel.shell.rm(this.id)
998
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
991
999
  }
1000
+ } else {
1001
+ // // automatically remove the shell from this.kernel.shells
1002
+ this.kernel.shell.rm(this.id)
1003
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
992
1004
  }
993
1005
 
994
- // automatically remove the shell from this.kernel.shells
995
- this.kernel.shell.rm(this.id)
996
- this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
997
1006
 
998
1007
  }
999
1008
  log() {
package/kernel/shells.js CHANGED
@@ -362,7 +362,7 @@ class Shells {
362
362
  let info = this.shells.map((s) => {
363
363
  return { id: s.id, group: s.group, cmd: s.cmd }
364
364
  })
365
- if (this.shells) {
365
+ if (this.shells && this.shells.length > 0) {
366
366
  let shells = []
367
367
  for(let i=0; i<this.shells.length; i++) {
368
368
  shells.push(this.shells[i])
@@ -381,6 +381,9 @@ class Shells {
381
381
  shell.kill("", true)
382
382
  }
383
383
  }
384
+ } else {
385
+ console.log("no shells running")
386
+ cb()
384
387
  }
385
388
  }
386
389
  kill(request, message) {
@@ -448,7 +451,6 @@ class Shells {
448
451
  }
449
452
  }
450
453
  rm(id) {
451
- console.log("SHELL RM", id)
452
454
  for(let i=0; i<this.shells.length; i++) {
453
455
  let shell = this.shells[i]
454
456
  if (shell.id === id) {
@@ -0,0 +1,165 @@
1
+ 'use strict';
2
+
3
+ var childProcess = require('child_process');
4
+ var spawn = childProcess.spawn;
5
+ var exec = childProcess.exec;
6
+ var execSync = childProcess.execSync;
7
+
8
+ module.exports = function (pid, signal, callback) {
9
+ if (typeof signal === 'function' && callback === undefined) {
10
+ callback = signal;
11
+ signal = undefined;
12
+ }
13
+
14
+ pid = parseInt(pid);
15
+ if (Number.isNaN(pid)) {
16
+ if (callback) {
17
+ return callback(new Error("pid must be a number"));
18
+ } else {
19
+ throw new Error("pid must be a number");
20
+ }
21
+ }
22
+
23
+ var tree = {};
24
+ var pidsToProcess = {};
25
+ tree[pid] = [];
26
+ pidsToProcess[pid] = 1;
27
+
28
+ switch (process.platform) {
29
+ case 'win32':
30
+ exec('taskkill /pid ' + pid + ' /T /F', callback);
31
+ break;
32
+ case 'darwin':
33
+ buildProcessTreeMacOS(pid, tree, pidsToProcess, function () {
34
+ killAll(tree, signal, callback);
35
+ });
36
+ break;
37
+ // case 'sunos':
38
+ // buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
39
+ // killAll(tree, signal, callback);
40
+ // });
41
+ // break;
42
+ default: // Linux
43
+ buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
44
+ return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
45
+ }, function () {
46
+ killAll(tree, signal, callback);
47
+ });
48
+ break;
49
+ }
50
+ };
51
+
52
+ function killAll (tree, signal, callback) {
53
+ var killed = {};
54
+ try {
55
+ Object.keys(tree).forEach(function (pid) {
56
+ tree[pid].forEach(function (pidpid) {
57
+ if (!killed[pidpid]) {
58
+ killPid(pidpid, signal);
59
+ killed[pidpid] = 1;
60
+ }
61
+ });
62
+ // exception: if the pid is the current process,
63
+ // kill all subprocesses, but do NOT kill the current process
64
+ if (String(pid) === String(process.pid)) {
65
+ return
66
+ }
67
+ if (!killed[pid]) {
68
+ killPid(pid, signal);
69
+ killed[pid] = 1;
70
+ }
71
+ });
72
+ } catch (err) {
73
+ if (callback) {
74
+ return callback(err);
75
+ } else {
76
+ throw err;
77
+ }
78
+ }
79
+ if (callback) {
80
+ return callback();
81
+ }
82
+ }
83
+
84
+ function killPid(pid, signal) {
85
+ try {
86
+ process.kill(parseInt(pid, 10), signal);
87
+ }
88
+ catch (err) {
89
+ if (err.code !== 'ESRCH') throw err;
90
+ }
91
+ }
92
+
93
+ function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
94
+ var ps = spawnChildProcessesList(parentPid);
95
+ var allData = '';
96
+ ps.stdout.on('data', function (data) {
97
+ var data = data.toString('ascii');
98
+ allData += data;
99
+ });
100
+
101
+ var onClose = function (code) {
102
+ delete pidsToProcess[parentPid];
103
+
104
+ if (code != 0) {
105
+ // no more parent processes
106
+ if (Object.keys(pidsToProcess).length == 0) {
107
+ cb();
108
+ }
109
+ return;
110
+ }
111
+
112
+ allData.match(/\d+/g).forEach(function (pid) {
113
+ pid = parseInt(pid, 10);
114
+ tree[parentPid].push(pid);
115
+ tree[pid] = [];
116
+ pidsToProcess[pid] = 1;
117
+ buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
118
+ });
119
+ };
120
+
121
+ ps.on('close', onClose);
122
+ }
123
+
124
+ function buildProcessTreeMacOS(parentPid, tree, pidsToProcess, cb) {
125
+ try {
126
+ let stdout = '';
127
+ try {
128
+ stdout = execSync('pgrep -P ' + parentPid, {
129
+ encoding: 'utf8',
130
+ timeout: 2000,
131
+ maxBuffer: 1024 * 1024
132
+ });
133
+ } catch (execError) {
134
+ if (execError.status !== 1) {
135
+ throw execError;
136
+ }
137
+ }
138
+
139
+ delete pidsToProcess[parentPid];
140
+
141
+ const childPids = stdout.trim().split('\n').filter(Boolean);
142
+
143
+ if (childPids.length === 0) {
144
+ if (Object.keys(pidsToProcess).length === 0) {
145
+ cb();
146
+ }
147
+ return;
148
+ }
149
+
150
+ childPids.forEach(function(pidStr) {
151
+ const pid = parseInt(pidStr, 10);
152
+ if (!isNaN(pid)) {
153
+ tree[parentPid].push(pid);
154
+ tree[pid] = [];
155
+ pidsToProcess[pid] = 1;
156
+ buildProcessTreeMacOS(pid, tree, pidsToProcess, cb);
157
+ }
158
+ });
159
+ } catch (err) {
160
+ delete pidsToProcess[parentPid];
161
+ if (Object.keys(pidsToProcess).length === 0) {
162
+ cb();
163
+ }
164
+ }
165
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.8.91",
3
+ "version": "3.8.93",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -59,7 +59,6 @@
59
59
  "sudo-prompt-programfiles-x86": "^9.2.10",
60
60
  "symlink-dir": "^5.2.1",
61
61
  "systeminformation": "^5.18.4",
62
- "tree-kill": "^1.2.2",
63
62
  "uuid": "^9.0.0",
64
63
  "wait-on": "^7.2.0",
65
64
  "which": "^5.0.0",
package/server/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const express = require('express');
2
+ const kill = require('../kernel/tree-kill');
2
3
  const portfinder = require('portfinder-cp');
3
4
  const proxy = require('express-http-proxy-cp');
4
5
  const sudo = require("sudo-prompt-programfiles-x86");
@@ -2256,6 +2257,8 @@ class Server {
2256
2257
  }
2257
2258
  }
2258
2259
  // initialize kernel
2260
+
2261
+
2259
2262
  await this.kernel.init({ port: this.port})
2260
2263
 
2261
2264
 
@@ -2623,6 +2626,7 @@ class Server {
2623
2626
  }))
2624
2627
  this.app.get("/network", ex(async (req, res) => {
2625
2628
  let list = []
2629
+
2626
2630
  // let peers_info = await this.kernel.peer.refresh()
2627
2631
  let peers_info = {}
2628
2632
  if (this.kernel.peer.info) {
@@ -2677,31 +2681,6 @@ class Server {
2677
2681
  }
2678
2682
  }
2679
2683
  console.log({ peers_info })
2680
-
2681
- // if (this.kernel.processes.info) {
2682
- // console.log("proc info", this.kernel.processes.info)
2683
- // list = this.kernel.processes.info.map((item) => {
2684
- // console.log("item", item)
2685
- // console.log("item.ip", item.ip)
2686
- // let internal_port = item.ip.split(":")[1]
2687
- // let external_port = this.kernel.router.port_mapping[internal_port]
2688
- // if (external_port) {
2689
- // let external_ip = `${this.kernel.peer.host}:${external_port}`
2690
- // console.log({ internal_port, external_port, external_ip })
2691
- // return {
2692
- // //proxy: this.kernel.caddy.mapping[item.ip] || [],
2693
- // router: info[this.kernel.peer.host][external_ip] || [],
2694
- // external_ip,
2695
- // ...item
2696
- // }
2697
- // } else {
2698
- // return {
2699
- // router: [],
2700
- // ...item
2701
- // }
2702
- // }
2703
- // })
2704
- // }
2705
2684
 
2706
2685
  let peers = []
2707
2686
  for(let host in peers_info) {
@@ -2713,20 +2692,6 @@ class Server {
2713
2692
  router: `https://pinokio.${peer_info.name}.localhost/proxy`
2714
2693
  })
2715
2694
  }
2716
-
2717
- // let peers = this.kernel.peer.get()
2718
- // peers = peers.map((x) => {
2719
- // let account = this.kernel.peer.account(x)
2720
- // let domain = `https://pinokio.${account}.localhost`
2721
- // let proxy_page = `https://pinokio.${account}.localhost/proxy`
2722
- // return {
2723
- // ip: x,
2724
- // account,
2725
- // domain,
2726
- // proxy_page
2727
- // }
2728
- // })
2729
-
2730
2695
  let live_proxies = this.kernel.api.proxies["/proxy"]
2731
2696
  if (!live_proxies) live_proxies = []
2732
2697
  let proxies = []
@@ -2798,6 +2763,8 @@ class Server {
2798
2763
  ip: this.kernel.peer.current_ip,
2799
2764
  peers,
2800
2765
  list,
2766
+ name: this.kernel.peer.name,
2767
+ active: this.kernel.peer.active,
2801
2768
  port_mapping: this.kernel.router.port_mapping,
2802
2769
  // port_mapping: this.kernel.caddy.port_mapping,
2803
2770
  // ip_mapping: this.kernel.caddy.ip_mapping,
@@ -3336,7 +3303,7 @@ class Server {
3336
3303
  }))
3337
3304
  this.app.get("/pinokio/peer", ex(async (req, res) => {
3338
3305
  console.log("/pinokio/peer", { proc: this.kernel.processes.info })
3339
- await this.kernel.refresh()
3306
+ // await this.kernel.refresh()
3340
3307
  res.json({
3341
3308
  home: this.kernel.homedir,
3342
3309
  arch: this.kernel.arch,
@@ -3904,6 +3871,36 @@ class Server {
3904
3871
  console.log({ requirements_pending })
3905
3872
  res.json({ requirements_pending })
3906
3873
  }))
3874
+ this.app.get("/check_peer", ex((req, res) => {
3875
+ if (this.kernel.peer.active) {
3876
+ // if network is active, return success only if the router is up for all of its peers (including itself)
3877
+ console.log({ peer_info: this.kernel.peer.info })
3878
+ let ready = true
3879
+ if (this.kernel.peer.info) {
3880
+ for(let host in this.kernel.peer.info) {
3881
+ let info = this.kernel.peer.info[host]
3882
+ if (info.router && Object.keys(info.router).length > 0) {
3883
+ ready = true
3884
+ } else {
3885
+ ready = false
3886
+ break;
3887
+ }
3888
+ }
3889
+ } else {
3890
+ ready = false;
3891
+ }
3892
+ console.log({ info: this.kernel.peer.info, ready })
3893
+ if (ready) {
3894
+ res.json({ success: true })
3895
+ } else {
3896
+ res.json({ success: false })
3897
+ }
3898
+ } else {
3899
+ // if network is not active, return success immediately (just checking if the server is up)
3900
+ console.log("this.kernel.router.published()")
3901
+ res.json({ success: true })
3902
+ }
3903
+ }))
3907
3904
  this.app.get("/check", ex((req, res) => {
3908
3905
  res.json({ success: true })
3909
3906
  }))
@@ -3911,6 +3908,16 @@ class Server {
3911
3908
  console.log("post /restart")
3912
3909
  this.start({ debug: this.debug, browser: this.browser })
3913
3910
  }))
3911
+ this.app.post("/network", ex(async (req, res) => {
3912
+ if (this.kernel.homedir) {
3913
+ let fullpath = path.resolve(this.kernel.homedir, "ENVIRONMENT")
3914
+ await Util.update_env(fullpath, req.body)
3915
+ res.json({ success: true })
3916
+ } else {
3917
+ res.json({ error: "homedir doesn't exist" })
3918
+ }
3919
+ }))
3920
+
3914
3921
  this.app.post("/config", ex(async (req, res) => {
3915
3922
  try {
3916
3923
  await this.setConfig(req.body)
@@ -3932,24 +3939,33 @@ class Server {
3932
3939
  })
3933
3940
  });
3934
3941
  process.on('SIGINT', () => {
3935
- console.log("SIGINT Event")
3936
- if (this.kernel && this.kernel.shell) {
3937
- this.kernel.shell.reset(() => {
3938
- process.exit()
3939
- })
3940
- } else {
3942
+ //if (this.kernel && this.kernel.shell) {
3943
+ // console.log("shell reset")
3944
+ // this.kernel.shell.reset(() => {
3945
+ // process.exit()
3946
+ // })
3947
+ //} else {
3948
+ // process.exit()
3949
+ //}
3950
+ kill(process.pid, 'SIGKILL', () => {
3951
+ console.log("child procs killed for", process.pid)
3941
3952
  process.exit()
3942
- }
3953
+ });
3943
3954
  })
3955
+
3944
3956
  process.on('SIGTERM', () => {
3945
- console.log("SIGTERM Event")
3946
- if (this.kernel && this.kernel.shell) {
3947
- this.kernel.shell.reset(() => {
3948
- process.exit()
3949
- })
3950
- } else {
3957
+ // if (this.kernel && this.kernel.shell) {
3958
+ // console.log("shell reset")
3959
+ // this.kernel.shell.reset(() => {
3960
+ // process.exit()
3961
+ // })
3962
+ // } else {
3963
+ // process.exit()
3964
+ // }
3965
+ kill(process.pid, 'SIGKILL', () => {
3966
+ console.log("child procs killed for", process.pid)
3951
3967
  process.exit()
3952
- }
3968
+ });
3953
3969
  })
3954
3970
  // process.on('exit', () => {
3955
3971
  // console.log("exit Event")
@@ -3973,7 +3989,7 @@ class Server {
3973
3989
  server: this.listening
3974
3990
  });
3975
3991
  })
3976
- this.kernel.peer.start()
3992
+ this.kernel.peer.start(this.kernel)
3977
3993
 
3978
3994
 
3979
3995
  }
@@ -156,7 +156,9 @@ body.dark .browser-options-row {
156
156
  padding: 0;
157
157
  font-size: 50px;
158
158
  letter-spacing: -1px;
159
+ /*
159
160
  text-align: center;
161
+ */
160
162
  text-transform: capitalize;
161
163
  }
162
164
  .header-label-sub h1 {
@@ -181,7 +183,6 @@ body.dark .browser-options-row {
181
183
  box-sizing: border-box;
182
184
  }
183
185
  .container {
184
- margin-top: 20px;
185
186
  display: grid;
186
187
  grid-template-columns: repeat(<%=list.length%>, 1fr);
187
188
  }
@@ -194,8 +195,10 @@ body.dark .browser-options-row {
194
195
  box-sizing: border-box;
195
196
  }
196
197
  .desc {
198
+ /*
197
199
  text-align:center;
198
- padding: 10px;
200
+ */
201
+ padding: 10px 0;
199
202
  }
200
203
  .container-row table {
201
204
  width: 100%;
@@ -222,6 +225,105 @@ td:first-child, th:first-child {
222
225
  font-size: 14px;
223
226
  padding: 2px;
224
227
  }
228
+
229
+ .config {
230
+ background: rgba(0,0,0,0.9);
231
+ color: white;
232
+ padding: 30px;
233
+ text-align: left;
234
+ }
235
+ .config-header {
236
+ }
237
+ .config-body {
238
+ display: flex;
239
+ align-items: flex-end;
240
+ }
241
+ .config .btn {
242
+ font-size: 16px;
243
+ font-weight: bold;
244
+ width: 100px;
245
+ background: royalblue;
246
+ flex-shrink: 0;
247
+ }
248
+ .config-row {
249
+ padding: 10px 20px 0 0;
250
+ }
251
+ .config-row .label {
252
+ padding-bottom: 5px;
253
+ font-weight: bold;
254
+ }
255
+ .config-row input[type=text] {
256
+ padding: 7px;
257
+ }
258
+
259
+ .switcher {
260
+ position: relative;
261
+ display: inline-block;
262
+ width: 60px;
263
+ height: 34px;
264
+ }
265
+
266
+ .switcher input {
267
+ opacity: 0;
268
+ width: 0;
269
+ height: 0;
270
+ }
271
+
272
+ .slider {
273
+ position: absolute;
274
+ cursor: pointer;
275
+ top: 0;
276
+ left: 0;
277
+ right: 0;
278
+ bottom: 0;
279
+ background-color: #ccc;
280
+ -webkit-transition: .4s;
281
+ transition: .4s;
282
+ }
283
+
284
+ .slider:before {
285
+ position: absolute;
286
+ content: "";
287
+ height: 26px;
288
+ width: 26px;
289
+ left: 4px;
290
+ bottom: 4px;
291
+ background-color: white;
292
+ -webkit-transition: .4s;
293
+ transition: .4s;
294
+ }
295
+
296
+ input:checked + .slider {
297
+ /*
298
+ background-color: #2196F3;
299
+ */
300
+ background-color: royalblue;
301
+ }
302
+
303
+ input:focus + .slider {
304
+ box-shadow: 0 0 1px #2196F3;
305
+ }
306
+
307
+ input:checked + .slider:before {
308
+ -webkit-transform: translateX(26px);
309
+ -ms-transform: translateX(26px);
310
+ transform: translateX(26px);
311
+ }
312
+
313
+ /* Rounded sliders */
314
+ .slider.round {
315
+ border-radius: 34px;
316
+ }
317
+
318
+ .slider.round:before {
319
+ border-radius: 50%;
320
+ }
321
+ .loading {
322
+ text-align: center;
323
+ padding: 50px;
324
+ }
325
+
326
+
225
327
  @media only screen and (max-width: 480px) {
226
328
  .btn2 {
227
329
  padding: 5px;
@@ -254,8 +356,30 @@ td:first-child, th:first-child {
254
356
  </h1>
255
357
  </header>
256
358
  <main>
257
- <div class='header-label'><i class='fa-solid fa-wifi'></i> Network</div>
258
- <div class='desc'>Serve Pinokio, installed apps, and even external apps to any device on the same network.</div>
359
+ <div class='config'>
360
+ <div class='config-header'>
361
+ <div class='header-label'><i class='fa-solid fa-wifi'></i> Network</div>
362
+ <div class='desc'>Serve Pinokio, installed apps, and even external apps to any device on the same network.</div>
363
+ </div>
364
+ <div class='config-body'>
365
+ <div class='config-row'>
366
+ <div class='label'>Network Name</div>
367
+ <input id='name' type='text' value="<%=name%>">
368
+ </div>
369
+ <div class='config-row'>
370
+ <div class='label'>Network Share</div>
371
+ <label class="switcher">
372
+ <input id='active' type="checkbox" <%=active ? 'checked' : ''%>>
373
+ <span class="slider"></span>
374
+ </label>
375
+ </div>
376
+ <div class='flexible'></div>
377
+ <button class='btn save'>Save</button>
378
+ </div>
379
+ </div>
380
+ <div class='loading hidden'>
381
+ <i class="fa-solid fa-circle-notch fa-spin"></i> Stand by. Do not close this window..
382
+ </div>
259
383
  <!--
260
384
  <div class='header-container'>
261
385
  <div class='header-label-sub'><i class="fa-solid fa-podcast"></i> Local Network</div>
@@ -393,8 +517,57 @@ td:first-child, th:first-child {
393
517
  </div>
394
518
  </main>
395
519
  <script>
396
- document.querySelector(".container").addEventListener("click", async (e) => {
520
+ document.querySelector("main").addEventListener("click", async (e) => {
397
521
  let target
522
+
523
+ if (e.target.classList.contains("save")) {
524
+ target = e.target
525
+ } else {
526
+ target = e.target.closest(".save")
527
+ }
528
+
529
+ if (target) {
530
+ let body = {
531
+ PINOKIO_NETWORK_NAME: document.querySelector("#name").value,
532
+ PINOKIO_NETWORK_ACTIVE: (document.querySelector("#active").checked ? "1": "0")
533
+ }
534
+ console.log(body)
535
+ debugger
536
+ let r = await fetch("/network", {
537
+ method: "post",
538
+ headers: { "Content-Type": "application/json" },
539
+ body: JSON.stringify(body)
540
+ }).then((res) => {
541
+ return res.json()
542
+ })
543
+ if (r.success) {
544
+ //alert("Successfully updated the pinokio home to " + val)
545
+ document.querySelector(".loading").classList.remove("hidden")
546
+ document.querySelector(".save").classList.add("hidden")
547
+ fetch("/restart", {
548
+ method: "post"
549
+ }, () => {
550
+ })
551
+ setInterval(async () => {
552
+ try {
553
+ let res = await fetch("/check_peer").then((res) => {
554
+ return res.json()
555
+ })
556
+ if (res.success) {
557
+ document.querySelector(".loading").classList.add("hidden")
558
+ location.href = location.href
559
+ }
560
+ } catch (e) {
561
+ console.log(e)
562
+ }
563
+ }, 1000)
564
+ } else if (r.error) {
565
+ alert(r.error)
566
+ location.href = location.href
567
+ }
568
+ return
569
+ }
570
+
398
571
  if (e.target.classList.contains("stop")) {
399
572
  target = e.target
400
573
  } else {
@@ -467,6 +640,7 @@ document.querySelector(".container").addEventListener("click", async (e) => {
467
640
  })
468
641
  }
469
642
 
643
+
470
644
  })
471
645
  if (document.querySelector("#back")) {
472
646
  document.querySelector("#back").addEventListener("click", (e) => {