pinokiod 3.6.28 → 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") {
@@ -69,7 +94,6 @@ class Socket {
69
94
  } else if (req.emit) {
70
95
  this.parent.kernel.shell.emit(req)
71
96
  } else if (req.key && req.id) {
72
- console.log( { req })
73
97
  this.parent.kernel.shell.emit({
74
98
  id: req.id,
75
99
  emit: req.key
@@ -84,11 +108,16 @@ class Socket {
84
108
  headers.push('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
85
109
  });
86
110
  }
87
- subscribe(ws, id) {
111
+ subscribe(ws, id, buf, sh) {
88
112
 
89
113
  if (this.parent.kernel.api.running[id]) {
90
114
  ws.send(JSON.stringify({
91
- type: "connect"
115
+ type: "connect",
116
+ data: {
117
+ id,
118
+ state: buf,
119
+ shell: sh
120
+ }
92
121
  }))
93
122
  }
94
123
 
@@ -126,6 +155,15 @@ class Socket {
126
155
  });
127
156
  }
128
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
+
129
167
  // send to caller session
130
168
  if (e.caller) {
131
169
  let caller
@@ -154,6 +192,15 @@ class Socket {
154
192
  }
155
193
  });
156
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
+ }
157
204
  }
158
205
  }
159
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>
@@ -138,9 +138,22 @@ document.addEventListener("DOMContentLoaded", async () => {
138
138
  class RPC {
139
139
  constructor() {
140
140
  this.socket = new Socket()
141
+ this.buffer = []
141
142
  }
142
143
  write(text) {
143
- 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
+ }
144
157
  this.dirty = true
145
158
  }
146
159
  finished() {
@@ -204,7 +217,6 @@ document.addEventListener("DOMContentLoaded", async () => {
204
217
  rows: this.term.rows,
205
218
  }
206
219
  }, async (packet) => {
207
- console.log({ packet })
208
220
  if (packet.type === 'start') {
209
221
  refreshParent(packet)
210
222
  reloadMemory()
@@ -241,6 +253,7 @@ document.addEventListener("DOMContentLoaded", async () => {
241
253
  shell_id = packet.data.id
242
254
  }
243
255
  if (packet.data.raw) {
256
+ // console.log({ packet })
244
257
  this.write(packet.data.raw)
245
258
  } else if (packet.data.json) {
246
259
  this.write(JSON.stringify(packet.data.json).replace(/\n/g, "\r\n"))
@@ -261,8 +274,14 @@ document.addEventListener("DOMContentLoaded", async () => {
261
274
  document.querySelector(".run .play").classList.remove("hidden")
262
275
  document.querySelector(".run .stop").classList.add("hidden")
263
276
  } else if (packet.type === 'connect') {
264
- const message = "..........Connected!\r\n"
265
- 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
+ }
266
285
  /*
267
286
  for(let i=0; i<message.length; i++) {
268
287
  await new Promise((r, reject) => {
@@ -471,7 +490,6 @@ document.addEventListener("DOMContentLoaded", async () => {
471
490
  document.querySelector("#error-screen").classList.add("hidden")
472
491
  })
473
492
  */
474
- console.log("instance", instance)
475
493
  instance.mark(packet.event)
476
494
  let element = document.querySelector("mark")
477
495
  element.scrollIntoView({ behavior: "smooth", block: "center" });
@@ -578,13 +596,19 @@ document.addEventListener("DOMContentLoaded", async () => {
578
596
  }
579
597
  const term = new Terminal(config)
580
598
  term.open(document.querySelector("#terminal"))
581
-
582
599
  term.attachCustomKeyEventHandler(event => {
583
- if (event.ctrlKey && event.key === 'c' && term.hasSelection()) {
584
- 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
+ }
585
606
  }
586
- if (event.ctrlKey && event.key === 'v' && this._options.pasteWithCtrlV) {
587
- 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
588
612
  }
589
613
  return true;
590
614
  });
@@ -596,7 +620,6 @@ document.addEventListener("DOMContentLoaded", async () => {
596
620
  //term.resize(cols, rows);
597
621
 
598
622
  term.onKey(({ key }) => {
599
- console.log({ key })
600
623
  if (this.socket) {
601
624
  if (shell_id) {
602
625
  this.socket.run({
@@ -801,14 +824,16 @@ const reloadMemory = async () => {
801
824
  <span class='starting hidden'><i class="fa-solid fa-circle-notch fa-spin"></i> Starting...</span>
802
825
  <span class='stop hidden'><i class="fa-solid fa-stop"></i> Stop</span>
803
826
  </div>
804
- <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
+ <% } %>
805
830
  <!--
806
831
  <button class='btn' id='open-log' data-logpath="<%=logpath%>"><i class="fa-solid fa-align-left"></i> View Logs</button>
807
832
  -->
808
833
  </div>
809
834
  <% } %>
810
835
  </header>
811
- <% if (requirements_pending) { %>
836
+ <% if (locals.requirements_pending) { %>
812
837
  <div class='requirements'>
813
838
  <div class='content'>
814
839
  <div class='loading'>
@@ -817,7 +842,7 @@ const reloadMemory = async () => {
817
842
  </div>
818
843
  </div>
819
844
  <% } else { %>
820
- <% if (install_required) { %>
845
+ <% if (locals.install_required) { %>
821
846
  <div class='requirements'>
822
847
  <div class='content'>
823
848
  <div class='title'><i class="fa-solid fa-circle-exclamation"></i> Installation required</div>