pinokiod 3.8.92 → 3.8.94

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
@@ -480,12 +481,35 @@ class Kernel {
480
481
  }
481
482
  }
482
483
  async init(options) {
484
+
483
485
  let home = this.store.get("home")
484
486
 
485
487
  // reset shells if they exist
488
+ console.log("KERNEL INIT")
486
489
  if (this.shell) {
490
+ console.log("> shell reset")
487
491
  this.shell.reset()
488
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()
489
513
 
490
514
  this.homedir = home
491
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
- });
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)
31
24
 
32
- // Enable broadcast
33
- console.log("binding socket")
34
- this.socket.bind(this.port, () => {
35
- console.log("socket bound")
36
- this.socket.setBroadcast(true);
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
+ }
37
31
 
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');
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
+ }
42
36
 
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
- // }
56
- //
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
- // }
65
- //
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])
74
- // }
75
- // }
76
- }, this.interval);
77
- });
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()
50
+ }
51
+ }
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 {
@@ -99,35 +88,39 @@ class PeerDiscovery {
99
88
  }
100
89
  // notify peers to refresh my info
101
90
  async notify_peers() {
102
- let res = await Promise.all(Array.from(this.peers).map((host) => {
103
- return this._broadcast(host)
104
- }))
105
- return res
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,11 @@ class Shells {
381
381
  shell.kill("", true)
382
382
  }
383
383
  }
384
+ } else {
385
+ console.log("no shells running")
386
+ if (cb) {
387
+ cb()
388
+ }
384
389
  }
385
390
  }
386
391
  kill(request, message) {
@@ -448,7 +453,6 @@ class Shells {
448
453
  }
449
454
  }
450
455
  rm(id) {
451
- console.log("SHELL RM", id)
452
456
  for(let i=0; i<this.shells.length; i++) {
453
457
  let shell = this.shells[i]
454
458
  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.92",
3
+ "version": "3.8.94",
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
 
@@ -2678,31 +2681,6 @@ class Server {
2678
2681
  }
2679
2682
  }
2680
2683
  console.log({ peers_info })
2681
-
2682
- // if (this.kernel.processes.info) {
2683
- // console.log("proc info", this.kernel.processes.info)
2684
- // list = this.kernel.processes.info.map((item) => {
2685
- // console.log("item", item)
2686
- // console.log("item.ip", item.ip)
2687
- // let internal_port = item.ip.split(":")[1]
2688
- // let external_port = this.kernel.router.port_mapping[internal_port]
2689
- // if (external_port) {
2690
- // let external_ip = `${this.kernel.peer.host}:${external_port}`
2691
- // console.log({ internal_port, external_port, external_ip })
2692
- // return {
2693
- // //proxy: this.kernel.caddy.mapping[item.ip] || [],
2694
- // router: info[this.kernel.peer.host][external_ip] || [],
2695
- // external_ip,
2696
- // ...item
2697
- // }
2698
- // } else {
2699
- // return {
2700
- // router: [],
2701
- // ...item
2702
- // }
2703
- // }
2704
- // })
2705
- // }
2706
2684
 
2707
2685
  let peers = []
2708
2686
  for(let host in peers_info) {
@@ -2714,20 +2692,6 @@ class Server {
2714
2692
  router: `https://pinokio.${peer_info.name}.localhost/proxy`
2715
2693
  })
2716
2694
  }
2717
-
2718
- // let peers = this.kernel.peer.get()
2719
- // peers = peers.map((x) => {
2720
- // let account = this.kernel.peer.account(x)
2721
- // let domain = `https://pinokio.${account}.localhost`
2722
- // let proxy_page = `https://pinokio.${account}.localhost/proxy`
2723
- // return {
2724
- // ip: x,
2725
- // account,
2726
- // domain,
2727
- // proxy_page
2728
- // }
2729
- // })
2730
-
2731
2695
  let live_proxies = this.kernel.api.proxies["/proxy"]
2732
2696
  if (!live_proxies) live_proxies = []
2733
2697
  let proxies = []
@@ -2799,6 +2763,8 @@ class Server {
2799
2763
  ip: this.kernel.peer.current_ip,
2800
2764
  peers,
2801
2765
  list,
2766
+ name: this.kernel.peer.name,
2767
+ active: this.kernel.peer.active,
2802
2768
  port_mapping: this.kernel.router.port_mapping,
2803
2769
  // port_mapping: this.kernel.caddy.port_mapping,
2804
2770
  // ip_mapping: this.kernel.caddy.ip_mapping,
@@ -3905,6 +3871,36 @@ class Server {
3905
3871
  console.log({ requirements_pending })
3906
3872
  res.json({ requirements_pending })
3907
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
+ }))
3908
3904
  this.app.get("/check", ex((req, res) => {
3909
3905
  res.json({ success: true })
3910
3906
  }))
@@ -3912,6 +3908,16 @@ class Server {
3912
3908
  console.log("post /restart")
3913
3909
  this.start({ debug: this.debug, browser: this.browser })
3914
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
+
3915
3921
  this.app.post("/config", ex(async (req, res) => {
3916
3922
  try {
3917
3923
  await this.setConfig(req.body)
@@ -3933,24 +3939,33 @@ class Server {
3933
3939
  })
3934
3940
  });
3935
3941
  process.on('SIGINT', () => {
3936
- console.log("SIGINT Event")
3937
- if (this.kernel && this.kernel.shell) {
3938
- this.kernel.shell.reset(() => {
3939
- process.exit()
3940
- })
3941
- } 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)
3942
3952
  process.exit()
3943
- }
3953
+ });
3944
3954
  })
3955
+
3945
3956
  process.on('SIGTERM', () => {
3946
- console.log("SIGTERM Event")
3947
- if (this.kernel && this.kernel.shell) {
3948
- this.kernel.shell.reset(() => {
3949
- process.exit()
3950
- })
3951
- } 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)
3952
3967
  process.exit()
3953
- }
3968
+ });
3954
3969
  })
3955
3970
  // process.on('exit', () => {
3956
3971
  // console.log("exit Event")
@@ -3974,7 +3989,7 @@ class Server {
3974
3989
  server: this.listening
3975
3990
  });
3976
3991
  })
3977
- this.kernel.peer.start()
3992
+ this.kernel.peer.start(this.kernel)
3978
3993
 
3979
3994
 
3980
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) => {