pinokiod 3.6.29 → 3.6.30

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/server/socket.js CHANGED
@@ -1,8 +1,10 @@
1
1
  const WebSocket = require('ws');
2
+ const Util = require("../kernel/util")
2
3
  class Socket {
3
4
  constructor(parent) {
4
5
  this.buffer = {}
5
6
  this.connected = {}
7
+ this.active_shell = {}
6
8
  this.parent = parent
7
9
  this.server = parent.server
8
10
  // this.kernel = parent.kernel
@@ -25,42 +27,65 @@ class Socket {
25
27
  // look for repos that match
26
28
 
27
29
  if (req.uri) {
28
- /******************************************************************
29
- *
30
- * req.uri is ALWAYS either of the two:
31
- * 1. ~/...
32
- * 2. https://github.com/...
33
- *
34
- * Need to turn it into absolute file path before subscribing
35
- *
36
- ******************************************************************/
37
-
38
- // req.uri is always http or absolute path
39
- let id = this.parent.kernel.api.filePath(req.uri)
40
-
41
- if (req.status) {
42
- ws.send(JSON.stringify({
43
- data: this.parent.kernel.api.running[id] ? true : false
44
- }))
45
- } else if (req.stop) {
46
- this.parent.kernel.api.stop({ params: req })
30
+ if (req.mode === "open") {
31
+ // get the default script and respond
32
+ let id = this.parent.kernel.api.filePath(req.uri)
33
+ try {
34
+ let default_url = await this.parent.kernel.api.get_default(id)
35
+ console.log({ id, default_url })
36
+ ws.send(JSON.stringify({
37
+ data: {
38
+ uri: default_url
39
+ }
40
+ }))
41
+ } catch (e) {
42
+ console.log(e)
43
+ }
47
44
  } else {
48
- this.subscribe(ws, id)
49
-
50
- if (req.mode !== "listen") {
51
- // Run only if currently not running
52
- if (!this.parent.kernel.api.running[id]) {
53
-
54
- // clear the log first
55
-
56
- await this.parent.kernel.clearLog(id)
57
-
58
-
59
- this.parent.kernel.api.process(req)
45
+ console.log("REQ.URI", req.uri)
46
+ if (req.uri.startsWith("http")) {
47
+ // open
48
+ Util.openfs(req.uri, { mode: "open" })
49
+ } else {
50
+ /******************************************************************
51
+ *
52
+ * req.uri is ALWAYS either of the two:
53
+ * 1. ~/...
54
+ * 2. https://github.com/...
55
+ *
56
+ * Need to turn it into absolute file path before subscribing
57
+ *
58
+ ******************************************************************/
59
+
60
+ // req.uri is always http or absolute path
61
+ let id = this.parent.kernel.api.filePath(req.uri)
62
+
63
+ if (req.status) {
64
+ ws.send(JSON.stringify({
65
+ data: this.parent.kernel.api.running[id] ? true : false
66
+ }))
67
+ } else if (req.stop) {
68
+ this.parent.kernel.api.stop({ params: req })
69
+ } else {
70
+ let buf = this.buffer[id]
71
+ let sh = this.active_shell[id]
72
+ this.subscribe(ws, id, buf, sh)
73
+ if (req.mode !== "listen") {
74
+ // Run only if currently not running
75
+ if (!this.parent.kernel.api.running[id]) {
76
+
77
+ // clear the log first
78
+
79
+ await this.parent.kernel.clearLog(id)
80
+
81
+
82
+ this.parent.kernel.api.process(req)
83
+ }
84
+ }
60
85
  }
61
86
  }
62
- }
63
87
 
88
+ }
64
89
  } else if (req.method) {
65
90
  this.subscribe(ws, req.method)
66
91
  if (req.mode !== "listen") {
@@ -68,6 +93,11 @@ class Socket {
68
93
  }
69
94
  } else if (req.emit) {
70
95
  this.parent.kernel.shell.emit(req)
96
+ } else if (req.key && req.id) {
97
+ this.parent.kernel.shell.emit({
98
+ id: req.id,
99
+ emit: req.key
100
+ })
71
101
  }
72
102
  }
73
103
 
@@ -78,11 +108,16 @@ class Socket {
78
108
  headers.push('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
79
109
  });
80
110
  }
81
- subscribe(ws, id) {
111
+ subscribe(ws, id, buf, sh) {
82
112
 
83
113
  if (this.parent.kernel.api.running[id]) {
84
114
  ws.send(JSON.stringify({
85
- type: "connect"
115
+ type: "connect",
116
+ data: {
117
+ id,
118
+ state: buf,
119
+ shell: sh
120
+ }
86
121
  }))
87
122
  }
88
123
 
@@ -120,6 +155,15 @@ class Socket {
120
155
  });
121
156
  }
122
157
 
158
+ if (!this.buffer[id]) {
159
+ this.buffer[id] = ""
160
+ }
161
+ if (e.data && e.data.raw) this.buffer[id] += e.data.raw
162
+
163
+ if (e.data && e.data.shell_id) {
164
+ this.active_shell[id] = e.data.shell_id
165
+ }
166
+
123
167
  // send to caller session
124
168
  if (e.caller) {
125
169
  let caller
@@ -148,6 +192,15 @@ class Socket {
148
192
  }
149
193
  });
150
194
  }
195
+
196
+ if (!this.buffer[caller]) {
197
+ this.buffer[caller] = ""
198
+ }
199
+ if (e.data.raw) this.buffer[caller] += e.data.raw
200
+
201
+ if (e.data && e.data.shell_id) {
202
+ this.active_shell[caller] = e.data.shell_id
203
+ }
151
204
  }
152
205
  }
153
206
  }
@@ -29,7 +29,9 @@
29
29
  */
30
30
  }
31
31
  #menu.margin {
32
+ /*
32
33
  padding: 5px;
34
+ */
33
35
  }
34
36
  #menu.margin i {
35
37
  display: none;
@@ -580,7 +582,7 @@ body.dark .loader-container {
580
582
  <div class='header-top header-item'>
581
583
  <div class='app-info'>
582
584
  <% if (config.icon) { %>
583
- <img src="<%=rawpath%>/<%=config.icon%>?raw=true"/>
585
+ <img src="<%=config.icon%>"/>
584
586
  <% } else { %>
585
587
  <i class="fa-regular fa-circle-dot"></i>
586
588
  <% } %>
@@ -595,6 +597,15 @@ body.dark .loader-container {
595
597
  <a target="<%=src%>" href="<%=src%>" class='btn header-item frame-link' data-index="0">
596
598
  <div class='tab'><i class="fa-regular fa-folder-open"></i> Files <div class='disk-usage'></div></div>
597
599
  </a>
600
+ <div class='shells'>
601
+ <% shells.forEach((shell, index) => { %>
602
+ <a target="SHELL<%=index%>" data-mode="" href="<%=shell%>" class='btn header-item frame-link'>
603
+ <div class='tab'>
604
+ <i class='fa-solid fa-terminal'></i> <%=shell%></i>
605
+ </div>
606
+ </a>
607
+ <% }) %>
608
+ </div>
598
609
  <a target="/share/<%=name%>" href="/share/<%=name%>", class="btn header-item frame-link" data-index="1" data-mode="refresh">
599
610
  <div class='tab'><i class="fa-solid fa-wifi"></i> Share</div>
600
611
  </a>
@@ -653,7 +664,7 @@ body.dark .loader-container {
653
664
  <div class='bar'>
654
665
  <button class='btn2' id='menu-mobile'><i class="fa-solid fa-bars"></i></button>
655
666
  <button class='btn2' id='menu'>
656
- <img src="<%=rawpath%>/<%=config.icon%>?raw=true"/>
667
+ <img src="<%=config.icon%>"/>
657
668
  <i class="fa-solid fa-arrow-right-to-bracket fa-rotate-180"></i>
658
669
  </button>
659
670
  <% if (agent === "electron") { %>
@@ -1510,6 +1521,7 @@ body.dark .loader-container {
1510
1521
  console.log("asideHidden", asideHidden)
1511
1522
  if (!asideHidden) {
1512
1523
  // refresh only if aside
1524
+ console.log("type", event.data.type)
1513
1525
  if (event.data.type === 'disconnect') {
1514
1526
  console.log("Refresh 1")
1515
1527
  refresh()
@@ -113,6 +113,7 @@ body.frozen {
113
113
  }
114
114
  </style>
115
115
  <script>
116
+ let shell_id
116
117
  document.addEventListener("DOMContentLoaded", async () => {
117
118
  <% if (error) { %>
118
119
  document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
@@ -331,8 +332,17 @@ document.addEventListener("DOMContentLoaded", async () => {
331
332
 
332
333
  } else if (packet.type === 'connect') {
333
334
  // document.querySelector(".terminal-container").classList.remove("hidden")
334
- const message = "..........Connected!\r\n"
335
- this.term.write(message)
335
+ if (packet.data.id) {
336
+ shell_id = packet.data.id
337
+ }
338
+ if (packet.data) {
339
+ if (packet.data.shell) {
340
+ shell_id = packet.data.shell
341
+ }
342
+ if (packet.data.state) {
343
+ this.write(packet.data.state)
344
+ }
345
+ }
336
346
  /*
337
347
  for(let i=0; i<message.length; i++) {
338
348
  await new Promise((r, reject) => {
@@ -246,32 +246,6 @@ body.dark .browser-options-row {
246
246
  <div>Serve Pinokio, installed apps, and even external apps (example: Ollama) to any device on the same network.</div>
247
247
  </div>
248
248
  </div>
249
- <!--
250
- <div class='browser-options-row'>
251
- <a href="/proxy" class='flexible'>
252
- <h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
253
- <div>Access Pinokio, Ollama, and other 3rd party apps from any device on the same network. By default it's off.</div>
254
- </a>
255
- <% if (false) { %>
256
- <% if (proxy) { %>
257
- <a id='wifi-stop' data-proxy="<%=proxy.proxy%>" class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></a>
258
- <div class='flexible'>
259
- <h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
260
- <div>Access Pinokio from any device on the same network. By default it's off.</div>
261
- <span class='badge'><i class="fa-solid fa-circle-notch fa-spin"></i> Running at <a href="<%=proxy.proxy%>" target="_blank" features="browser"><%=proxy.proxy%></a></span>
262
- <a id='wifi-qr' class='badge'><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
263
- </div>
264
- <% } else { %>
265
- <a id='wifi' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></a>
266
- <a id='wifi-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></a>
267
- <div class='flexible'>
268
- <h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
269
- <div>Access Pinokio from any device on the same network. By default it's off.</div>
270
- </div>
271
- <% } %>
272
- <% } %>
273
- </div>
274
- -->
275
249
  <div class='browser-options-row hidden'>
276
250
  <% if (cloudflare_pub) { %>
277
251
  <a id='cloudflare-stop' class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></a>
@@ -292,17 +266,10 @@ body.dark .browser-options-row {
292
266
  </div>
293
267
  </div>
294
268
  <% } %>
295
- <!--
296
- <div class='type-tabs'>
297
- <% if (mode === "task") { %>
298
- <a class='type-tab' href="/"><img src='/pinokio-<%=theme=='dark' ? 'white' : 'black'%>.png'> Apps</a>
299
- <a class='type-tab selected' href="/?mode=task"> <img src='/<%=theme=='dark' ? 'term-dark.png' : 'term-white.png'%>'> Tasks</a>
300
- <% } else { %>
301
- <a class='type-tab selected' href="/"><img src='/pinokio-<%=theme=='dark' ? 'white' : 'black'%>.png'> Apps</a>
302
- <a class='type-tab' href="/?mode=task"> <img src='/<%=theme=='dark' ? 'term-dark.png' : 'term-white.png'%>'> Tasks</a>
303
- <% } %>
269
+ <div id='fsmenu'>
270
+ <div class='flexible'></div>
271
+ <button id='newfolder' class='btn'><i class="fa-solid fa-folder-plus"></i> New Folder</button>
304
272
  </div>
305
- -->
306
273
  <% if (running.length > 0) { %>
307
274
  <div class='running-apps'>
308
275
  <div class='header-label'>Running</div>
@@ -1094,6 +1061,30 @@ if (document.querySelector("#genlog")) {
1094
1061
  })
1095
1062
  })
1096
1063
  }
1064
+ document.querySelector("#newfolder").addEventListener("click", async (e) => {
1065
+ let folder = prompt("Enter a folder name for the new folder")
1066
+ if (folder.includes(' ')) {
1067
+ alert("Please use a folder name without a space")
1068
+ return
1069
+ }
1070
+ let res = await fetch("/mkdir", {
1071
+ method: "post",
1072
+ headers: {
1073
+ "Content-Type": "application/json"
1074
+ },
1075
+ body: JSON.stringify({
1076
+ folder
1077
+ })
1078
+ }).then((res) => {
1079
+ return res.json()
1080
+ })
1081
+ if (res.error) {
1082
+ alert(res.error)
1083
+ } else {
1084
+ console.log(res)
1085
+ location.href = res.success
1086
+ }
1087
+ })
1097
1088
 
1098
1089
  </script>
1099
1090
  </body>
@@ -111,6 +111,7 @@ body.frozen {
111
111
  </style>
112
112
  <link href="/terminal.css" rel="stylesheet"/>
113
113
  <script>
114
+ let shell_id
114
115
  document.addEventListener("DOMContentLoaded", async () => {
115
116
  <% if (error) { %>
116
117
  document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
@@ -137,9 +138,22 @@ document.addEventListener("DOMContentLoaded", async () => {
137
138
  class RPC {
138
139
  constructor() {
139
140
  this.socket = new Socket()
141
+ this.buffer = []
140
142
  }
141
143
  write(text) {
142
- this.term.write(text)
144
+ // console.log(text)
145
+ // this.buffer += text;
146
+ // if (!this.timeout) {
147
+ // this.timeout = setTimeout(() => {
148
+ // console.log("write", this.buffer)
149
+ // this.term.write(this.buffer);
150
+ // this.buffer = "";
151
+ // this.timeout = null;
152
+ // }, 50);
153
+ // }
154
+ if (text !== "\u0007") {
155
+ this.term.write(text)
156
+ }
143
157
  this.dirty = true
144
158
  }
145
159
  finished() {
@@ -234,7 +248,12 @@ document.addEventListener("DOMContentLoaded", async () => {
234
248
  // </div>`
235
249
  }
236
250
  } else if (packet.type === "stream") {
251
+ // set the current shell id
252
+ if (packet.data.id) {
253
+ shell_id = packet.data.id
254
+ }
237
255
  if (packet.data.raw) {
256
+ // console.log({ packet })
238
257
  this.write(packet.data.raw)
239
258
  } else if (packet.data.json) {
240
259
  this.write(JSON.stringify(packet.data.json).replace(/\n/g, "\r\n"))
@@ -255,8 +274,14 @@ document.addEventListener("DOMContentLoaded", async () => {
255
274
  document.querySelector(".run .play").classList.remove("hidden")
256
275
  document.querySelector(".run .stop").classList.add("hidden")
257
276
  } else if (packet.type === 'connect') {
258
- const message = "..........Connected!\r\n"
259
- this.write(message)
277
+ if (packet.data) {
278
+ if (packet.data.shell) {
279
+ shell_id = packet.data.shell
280
+ }
281
+ if (packet.data.state) {
282
+ this.write(packet.data.state)
283
+ }
284
+ }
260
285
  /*
261
286
  for(let i=0; i<message.length; i++) {
262
287
  await new Promise((r, reject) => {
@@ -465,7 +490,6 @@ document.addEventListener("DOMContentLoaded", async () => {
465
490
  document.querySelector("#error-screen").classList.add("hidden")
466
491
  })
467
492
  */
468
- console.log("instance", instance)
469
493
  instance.mark(packet.event)
470
494
  let element = document.querySelector("mark")
471
495
  element.scrollIntoView({ behavior: "smooth", block: "center" });
@@ -572,13 +596,19 @@ document.addEventListener("DOMContentLoaded", async () => {
572
596
  }
573
597
  const term = new Terminal(config)
574
598
  term.open(document.querySelector("#terminal"))
575
-
576
599
  term.attachCustomKeyEventHandler(event => {
577
- if (event.ctrlKey && event.key === 'c' && term.hasSelection()) {
578
- return false;
600
+ if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
601
+ const selection = term.getSelection();
602
+ if (selection) {
603
+ navigator.clipboard.writeText(selection);
604
+ return false;
605
+ }
579
606
  }
580
- if (event.ctrlKey && event.key === 'v' && this._options.pasteWithCtrlV) {
581
- return false;
607
+ if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
608
+ navigator.clipboard.readText().then((text) => {
609
+ term.write(text);
610
+ })
611
+ return false
582
612
  }
583
613
  return true;
584
614
  });
@@ -589,6 +619,17 @@ document.addEventListener("DOMContentLoaded", async () => {
589
619
  ////term.resize(cols, rows-5);
590
620
  //term.resize(cols, rows);
591
621
 
622
+ term.onKey(({ key }) => {
623
+ if (this.socket) {
624
+ if (shell_id) {
625
+ this.socket.run({
626
+ key,
627
+ id: shell_id
628
+ })
629
+ }
630
+ }
631
+ });
632
+
592
633
  const fitAddon = new FitAddon.FitAddon();
593
634
  // const searchAddon = new SearchAddon.SearchAddon();
594
635
  // const searchAddonBar = new SearchBarAddon.SearchBarAddon({searchAddon});
@@ -606,6 +647,7 @@ document.addEventListener("DOMContentLoaded", async () => {
606
647
  fitAddon.fit();
607
648
  this.term = term
608
649
  this.fit = fitAddon
650
+
609
651
  }
610
652
  this.term.focus()
611
653
  }
@@ -782,14 +824,16 @@ const reloadMemory = async () => {
782
824
  <span class='starting hidden'><i class="fa-solid fa-circle-notch fa-spin"></i> Starting...</span>
783
825
  <span class='stop hidden'><i class="fa-solid fa-stop"></i> Stop</span>
784
826
  </div>
785
- <button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> View File</button>
827
+ <% if (locals.filepath) { %>
828
+ <button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> View File</button>
829
+ <% } %>
786
830
  <!--
787
831
  <button class='btn' id='open-log' data-logpath="<%=logpath%>"><i class="fa-solid fa-align-left"></i> View Logs</button>
788
832
  -->
789
833
  </div>
790
834
  <% } %>
791
835
  </header>
792
- <% if (requirements_pending) { %>
836
+ <% if (locals.requirements_pending) { %>
793
837
  <div class='requirements'>
794
838
  <div class='content'>
795
839
  <div class='loading'>
@@ -798,7 +842,7 @@ const reloadMemory = async () => {
798
842
  </div>
799
843
  </div>
800
844
  <% } else { %>
801
- <% if (install_required) { %>
845
+ <% if (locals.install_required) { %>
802
846
  <div class='requirements'>
803
847
  <div class='content'>
804
848
  <div class='title'><i class="fa-solid fa-circle-exclamation"></i> Installation required</div>