pinokiod 1.3.28 → 1.3.29

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.
@@ -8,8 +8,21 @@ const { DownloaderHelper } = require('node-downloader-helper');
8
8
  const randomUseragent = require('random-useragent');
9
9
  const symlinkDir = require('symlink-dir')
10
10
  const retry = require('async-retry');
11
+ const { createHash } = require('crypto');
11
12
 
12
13
 
14
+ const log = (msgs, ondata) => {
15
+ for(let msg of msgs) {
16
+ if (typeof msg === "object") {
17
+ msg = JSON.stringify(msg, null, 2).replace(/\n/g, "\r\n")
18
+ }
19
+ if (ondata) {
20
+ ondata({ raw: "\r\n" + msg })
21
+ }
22
+ console.log(msg)
23
+ }
24
+ }
25
+
13
26
  class FS {
14
27
  async read(req, ondata, kernel) {
15
28
  /*
@@ -133,6 +146,7 @@ class FS {
133
146
  [p],
134
147
  ondata
135
148
  )
149
+ log([res], ondata)
136
150
  // symlink:
137
151
  // from => :package_path
138
152
  // to => /drives/packages/pip/:package_name/:package_version
@@ -174,19 +188,76 @@ class FS {
174
188
  const copy = res[name].copy
175
189
  const move = res[name].move
176
190
  const version = res[name].version
191
+ const url = res[name].url
177
192
 
178
193
  if (version) {
194
+
195
+ let namespace
196
+ // handle custom install from url
197
+ log(["> Namespace resolution"], ondata)
198
+ if (url) {
199
+ log(["> Custom url exists. Resolve custom namespace..."], ondata)
200
+ if (res[name].archive_info) {
201
+ let info = res[name].archive_info
202
+ log(["> Archive: ", { url, info }], ondata)
203
+ // try to get sha256 first
204
+ if (info.hashes) {
205
+ if (info.hashes.sha256) {
206
+ let hash = info.hashes.sha256
207
+ namespace = `${name}/${version}-f-${hash.slice(0, 4)}`
208
+ } else {
209
+ let keys = Object.keys(info.hashes)
210
+ // just use the first hash
211
+ let key = keys[0]
212
+ let hash = info.hashes[key]
213
+ namespace = `${name}/${version}-${hash.slice(0, 4)}`
214
+ }
215
+ }
216
+ // otherwise get any other hash
217
+ } else if (res[name].vcs_info) {
218
+ let info = res[name].vcs_info
219
+ log(["> VCS: ", { url, info }], ondata)
220
+ namespace = `${name}/${version}-${info.vcs}-${info.commit_id.slice(0, 4)}`
221
+ } else if (res[name].dir_info) {
222
+ let info = res[name].dir_info
223
+ log(["> Directory: ", { url, info }], ondata)
224
+ let hash = createHash('sha256').update(url).digest('hex')
225
+ namespace = `${name}/${version}-d-${hash.slice(0, 4)}`
226
+ }
227
+
228
+ // IMPORTANT: if the namespace doesn't get resolved, do NOT create a drive
229
+ if (!namespace) {
230
+ continue
231
+ }
232
+
233
+ } else {
234
+ namespace = `${name}/${version}`
235
+ }
236
+
237
+ log(["> Resolved namespace", namespace], ondata)
238
+
179
239
  let site_packages_root;
180
240
  if (kernel.platform === "win32") {
181
- site_packages_root = `pip/${name}/${version}/Lib/site-packages`
241
+ site_packages_root = `pip/${namespace}/Lib/site-packages`
182
242
  } else {
183
- site_packages_root = `pip/${name}/${version}/lib/python3.10/site-packages`
243
+ site_packages_root = `pip/${namespace}/lib/python3.10/site-packages`
184
244
  }
185
245
  const d = {
186
246
  copy: {},
187
247
  move: {},
188
- parent: site_packages_root
248
+ parent: site_packages_root,
189
249
  }
250
+
251
+ // if the version is NOT final, overwrite.
252
+ let re = /^\d+(\.\d+)*$/ // regex for testing final versions like 1.2, 1.1.1, 1.2.1.1, etc.
253
+ if (re.test(version)) {
254
+ // final version
255
+ } else {
256
+ d.options = {
257
+ overwrite: true
258
+ }
259
+ }
260
+
190
261
  for(let relpath of copy) {
191
262
  d.copy[relpath] = kernel.path("drive", p, relpath)
192
263
  }
@@ -51,6 +51,31 @@ class Conda {
51
51
  }
52
52
  return base
53
53
  }
54
+ async init() {
55
+ //
56
+ if (this.kernel.homedir) {
57
+ let exists = await this.kernel.exists("condarc")
58
+ if (!exists) {
59
+ await fs.promises.writeFile(this.kernel.path('condarc'), `channels:
60
+ - conda-forge
61
+ - defaults
62
+ create_default_packages:
63
+ - python=3.10`)
64
+ }
65
+ }
66
+ }
67
+ // async init() {
68
+ // let exists = await this.kernel.bin.exists("miniconda/condarc")
69
+ // console.log("condarc exists?", exists)
70
+ // if (!exists) {
71
+ // console.log("write to condarc")
72
+ // await fs.promises.writeFile(this.kernel.bin.path('miniconda/condarc'), `channels:
73
+ // - conda-forge
74
+ // - defaults
75
+ // create_default_packages:
76
+ // - python=3.10`)
77
+ // }
78
+ // }
54
79
  async install(req, ondata) {
55
80
  const installer_url = this.urls[this.kernel.platform][this.kernel.arch]
56
81
  const installer = this.installer[this.kernel.platform]
@@ -73,12 +98,12 @@ class Conda {
73
98
  await this.kernel.bin.exec({ message: cmd, conda: { skip: true } }, (stream) => {
74
99
  ondata(stream)
75
100
  })
76
- // await this.activate()
77
- await fs.promises.writeFile(this.kernel.bin.path('miniconda/condarc'), `channels:
78
- - conda-forge
79
- - defaults
80
- create_default_packages:
81
- - python=3.10`)
101
+ //// await this.activate()
102
+ // await fs.promises.writeFile(this.kernel.bin.path('miniconda/condarc'), `channels:
103
+ // - conda-forge
104
+ // - defaults
105
+ //create_default_packages:
106
+ // - python=3.10`)
82
107
  await this.kernel.bin.exec({
83
108
  message: [
84
109
  // (this.kernel.platform === 'win32' ? 'conda_hook' : `eval "$(conda shell.bash hook)"`),
@@ -91,8 +116,10 @@ create_default_packages:
91
116
  `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --add create_default_packages python=3.10`,
92
117
  */
93
118
  //"conda update -y conda",
119
+ //"conda update -n base -c conda-forge -c defaults conda",
94
120
 
95
121
 
122
+ //"conda install conda=24.5.0",
96
123
  "conda update -y --all",
97
124
 
98
125
 
package/kernel/index.js CHANGED
@@ -102,8 +102,12 @@ class Kernel {
102
102
  return path.resolve(this.homedir, ...args)
103
103
  }
104
104
  exists(...args) {
105
- let abspath = this.path(...args)
106
- return new Promise(r=>fs.access(abspath, fs.constants.F_OK, e => r(!e)))
105
+ if (args) {
106
+ let abspath = this.path(...args)
107
+ return new Promise(r=>fs.access(abspath, fs.constants.F_OK, e => r(!e)))
108
+ } else {
109
+ return false
110
+ }
107
111
  }
108
112
  async load(...filepath) {
109
113
  let p = path.resolve(...filepath)
@@ -171,6 +175,11 @@ class Kernel {
171
175
  async init() {
172
176
  let home = this.store.get("home")
173
177
 
178
+ // reset shells if they exist
179
+ if (this.shell) {
180
+ this.shell.reset()
181
+ }
182
+
174
183
  this.homedir = home
175
184
 
176
185
  // if (home) {
package/kernel/shell.js CHANGED
@@ -125,7 +125,7 @@ class Shell {
125
125
  this.env.XDG_STATE_HOME = path.resolve(this.kernel.homedir, "cache", "XDG_STATE_HOME")
126
126
  this.env.GRADIO_TEMP_DIR = path.resolve(this.kernel.homedir, "cache", "GRADIO_TEMP_DIR")
127
127
  this.env.PIP_CONFIG_FILE = path.resolve(this.kernel.homedir, "pipconfig")
128
- this.env.CONDARC = path.resolve(this.kernel.homedir, "bin", "miniconda", "condarc")
128
+ this.env.CONDARC = path.resolve(this.kernel.homedir, "condarc")
129
129
 
130
130
  this.env.PS1 = "<<PINOKIO SHELL>> "
131
131
  // this.env.PROMPT_COMMAND = "export PS1=\"<<PINOKIO SHELL>> \""
@@ -269,7 +269,6 @@ class Shell {
269
269
  })
270
270
  return response
271
271
  } else {
272
- console.log("SHELL", { params, env: this.env })
273
272
  let response = await this.request(params, async (stream) => {
274
273
  if (stream.prompt) {
275
274
  this.resolve()
@@ -741,14 +740,14 @@ class Shell {
741
740
 
742
741
  */
743
742
  let info = {
744
- id: this.id,
743
+ path: this.path,
744
+ cmd: this.cmd,
745
745
  index: this.index,
746
746
  group: this.group,
747
747
  env: this.env,
748
- path: this.path,
749
- cmd: this.cmd,
750
748
  done: this.done,
751
749
  ready: this.ready,
750
+ id: this.id,
752
751
  ts: Date.now()
753
752
  }
754
753
 
@@ -784,12 +783,8 @@ ${buf}
784
783
 
785
784
  data.cleaned = `######################################################################
786
785
  #
787
- # group: ${this.group}
788
- # id: ${this.id}
789
- # index: ${this.index}
790
- # cmd: ${this.cmd}
791
786
  # timestamp: ${time}
792
- #
787
+ # ${infoYAML.replaceAll("\n", "\n# ")}
793
788
 
794
789
  ${cleaned}
795
790
 
package/kernel/shells.js CHANGED
@@ -197,6 +197,13 @@ class Shells {
197
197
  stop (request, message) {
198
198
  return this.kill(request, message)
199
199
  }
200
+ reset() {
201
+ if (this.shells) {
202
+ for(let shell of this.shells) {
203
+ shell.kill("", true)
204
+ }
205
+ }
206
+ }
200
207
  kill(request, message) {
201
208
  /*
202
209
  * - Kill by ID
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "1.3.28",
3
+ "version": "1.3.29",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -47,7 +47,7 @@
47
47
  "node-gradio-client": "^0.14.6",
48
48
  "node-pty-prebuilt-multiarch-cp": "^0.10.1-pre.48",
49
49
  "open": "8.4.2",
50
- "pdrive": "^0.0.23",
50
+ "pdrive": "^0.0.24",
51
51
  "portfinder": "^1.0.32",
52
52
  "qrcode": "^1.5.3",
53
53
  "random-useragent": "^0.5.0",
package/server/index.js CHANGED
@@ -166,6 +166,63 @@ class Server {
166
166
  }
167
167
  })
168
168
  }
169
+ async chrome(req, res, type) {
170
+ let name = req.params.name
171
+ let app_path = this.kernel.path("api", name, "pinokio.js")
172
+ let rawpath = "/api/" + name
173
+ let config = (await this.kernel.loader.load(app_path)).resolved
174
+ if (config && config.menu) {
175
+ if (typeof config.menu === "function") {
176
+ if (config.menu.constructor.name === "AsyncFunction") {
177
+ config.menu = await config.menu(this.kernel)
178
+ } else {
179
+ config.menu = config.menu(this.kernel)
180
+ }
181
+ }
182
+
183
+ let uri = this.kernel.path("api")
184
+ await this.renderMenu(uri, name, config, [])
185
+
186
+ } else {
187
+ // if there is no menu, display all files
188
+ let p = this.kernel.path("api", name)
189
+ let files = await fs.promises.readdir(p, { withFileTypes: true })
190
+ files = files.filter((file) => {
191
+ return file.name.endsWith(".json") || file.name.endsWith(".js")
192
+ })
193
+ config = {
194
+ title: name,
195
+ menu: files.map((file) => {
196
+ return {
197
+ text: file.name,
198
+ href: file.name
199
+ }
200
+ })
201
+ }
202
+ let uri = this.kernel.path("api")
203
+ await this.renderMenu(uri, name, config, [])
204
+ }
205
+ let platform = os.platform()
206
+ //res.render("browser", {
207
+ res.render("browser-experimental", {
208
+ port: this.port,
209
+ type,
210
+ platform,
211
+ running:this.kernel.api.running,
212
+ memory: this.kernel.memory,
213
+ sidebar: "/pinokio/sidebar/" + name,
214
+ name,
215
+ tabs: (this.tabs[name] || []),
216
+ config,
217
+ // sidebar_url: "/pinokio/sidebar/" + name,
218
+ home: req.originalUrl,
219
+ // paths,
220
+ theme: this.theme,
221
+ agent: this.agent,
222
+ src: "/_api/" + name,
223
+ rawpath,
224
+ })
225
+ }
169
226
  async render(req, res, pathComponents, meta) {
170
227
 
171
228
 
@@ -767,6 +824,7 @@ class Server {
767
824
  execUrl: "~" + req.originalUrl.replace(/^\/_api/, "\/api"),
768
825
  proxies: this.kernel.api.proxies[filepath],
769
826
  }
827
+ console.log("result", result)
770
828
 
771
829
  res.render(template, result)
772
830
  } else {
@@ -928,7 +986,6 @@ class Server {
928
986
 
929
987
 
930
988
  let index = 0
931
- console.log({ items })
932
989
  for(let i=0; i<items.length; i++) {
933
990
  let item = items[i]
934
991
  let p = path.resolve(uri, item.name, "pinokio.js")
@@ -1127,6 +1184,7 @@ class Server {
1127
1184
 
1128
1185
 
1129
1186
  async renderMenu(uri, name, config, pathComponents) {
1187
+ console.log("config.menu =" ,config.menu)
1130
1188
  if (config.menu) {
1131
1189
  for(let i=0; i<config.menu.length; i++) {
1132
1190
  let menuitem = config.menu[i]
@@ -1691,6 +1749,36 @@ class Server {
1691
1749
  // }
1692
1750
  await this.startLogging()
1693
1751
 
1752
+ // check version from this.store
1753
+ let version = this.kernel.store.get("version")
1754
+ // if the version is different from package.json version, run update logic
1755
+ if (this.kernel.homedir) {
1756
+ if (version === this.version.pinokiod) {
1757
+ console.log("version up to date")
1758
+ } else {
1759
+ // update the py module if it's already installed
1760
+ let installed = await this.kernel.bin.mod.py.installed()
1761
+ console.log("py installed", installed)
1762
+ if (installed) {
1763
+ // update
1764
+ console.log("update py")
1765
+ await this.kernel.exec({
1766
+ message: "git pull",
1767
+ path: this.kernel.path("bin/py")
1768
+ }, (e) => {
1769
+ console.log(e)
1770
+ })
1771
+
1772
+ }
1773
+ // after updating, set the version
1774
+ console.log("set the version", this.version.pinokiod)
1775
+ this.kernel.store.set("version", this.version.pinokiod)
1776
+ console.log("RESTART")
1777
+ this.listening = true // set this.listening = true so all http connections get reset when restarting
1778
+ this.start(this.debug)
1779
+ }
1780
+ }
1781
+
1694
1782
 
1695
1783
 
1696
1784
  //await this.configure()
@@ -1836,6 +1924,80 @@ class Server {
1836
1924
  // })
1837
1925
  // }
1838
1926
  })
1927
+
1928
+
1929
+
1930
+ // /*
1931
+ //
1932
+ // Requirements
1933
+ //
1934
+ // 1. When entering /app/:name, it should open the app's page if it's running. If not running, start the app, and open the app's page at the end
1935
+ //
1936
+ // /app/:name
1937
+ //
1938
+ // - check the /api/:name folder
1939
+ // - if it exists:
1940
+ // - check pinokio.js for start attribute
1941
+ // - if start exists,
1942
+ // - if it doesn't exist:
1943
+ //
1944
+ // 2. how about when i want to use the tab view?
1945
+ //
1946
+ //
1947
+ // what if the browser view stays, but just add a "default" attribute for tabs, and select that by default
1948
+ //
1949
+ //
1950
+ // what if every script after starting, checks for local.url, and if it exists,
1951
+ //
1952
+ // */
1953
+ // this.app.get("/app/:name", async (req, res) => {
1954
+ //
1955
+ // // 1. take req.params.name and resolve the folder name
1956
+ // let name = req.params.name
1957
+ // let app_path = this.kernel.path("api", name, "pinokio.js")
1958
+ // // 2. open pinokio.js to check the start attribute
1959
+ // let config = (await this.kernel.loader.load(app_path)).resolved
1960
+ // if (config && config.start) {
1961
+ // if (typeof config.start === "function") {
1962
+ // if (config.start.constructor.name === "AsyncFunction") {
1963
+ // config.start = await config.start(this.kernel)
1964
+ // } else {
1965
+ // config.start = config.start(this.kernel)
1966
+ // }
1967
+ // }
1968
+ // // 3. check if the start script is running
1969
+ // let startScriptPath = this.kernel.path("api", name, config.start)
1970
+ // if (this.kernel.running(startScriptPath)) {
1971
+ // // 4.a. if running, route to the local.url for the start script
1972
+ // let local = this.kernel.local(startScriptPath)
1973
+ // if (local && local.url) {
1974
+ // // if local.url exists, display that
1975
+ // res.redirect(local.url)
1976
+ // } else {
1977
+ // // if local.url doesn't exist, display the app page
1978
+ // res.redirect(`http://localhost:${this.port}/pinokio/browser/${req.params.name}`)
1979
+ // }
1980
+ // } else {
1981
+ // // 4.b. if not running, start the script and render the loading screen
1982
+ // // => the loading screen will automatically reload after the script has started
1983
+ // if (typeof config.start === 'object') {
1984
+ // let url = config.start.url
1985
+ // let params = config.start.params
1986
+ // let queryStr = new URLSearchParams(params).toString()
1987
+ // let u = `http://localhost:${this.port}/pinokio/launch/${req.params.name}/${url}?${queryStr}`
1988
+ // console.log("u1", u)
1989
+ // res.redirect(u)
1990
+ // } else {
1991
+ // let url = config.start
1992
+ // let u = `http://localhost:${this.port}/pinokio/launch/${req.params.name}/${url}`
1993
+ // //let u = `/api/${req.params.name}/${url}`
1994
+ // console.log("u2", u)
1995
+ // res.redirect(u)
1996
+ // }
1997
+ // }
1998
+ // }
1999
+ // })
2000
+
1839
2001
  this.app.get("/script/:name", (req, res) => {
1840
2002
  if (req.params.name === "start") {
1841
2003
  res.json(this.startScripts)
@@ -1995,59 +2157,11 @@ class Server {
1995
2157
  res.redirect("/")
1996
2158
  }
1997
2159
  })
2160
+ this.app.get("/pinokio/launch/:name", async (req, res) => {
2161
+ this.chrome(req, res, "launch")
2162
+ })
1998
2163
  this.app.get("/pinokio/browser/:name", async (req, res) => {
1999
- let name = req.params.name
2000
- let app_path = this.kernel.path("api", name, "pinokio.js")
2001
- let rawpath = "/api/" + name
2002
- let config = (await this.kernel.loader.load(app_path)).resolved
2003
- if (config && config.menu) {
2004
- if (typeof config.menu === "function") {
2005
- if (config.menu.constructor.name === "AsyncFunction") {
2006
- config.menu = await config.menu(this.kernel)
2007
- } else {
2008
- config.menu = config.menu(this.kernel)
2009
- }
2010
- }
2011
-
2012
- let uri = this.kernel.path("api")
2013
- await this.renderMenu(uri, name, config, [])
2014
-
2015
- } else {
2016
- // if there is no menu, display all files
2017
- let p = this.kernel.path("api", name)
2018
- let files = await fs.promises.readdir(p, { withFileTypes: true })
2019
- files = files.filter((file) => {
2020
- return file.name.endsWith(".json") || file.name.endsWith(".js")
2021
- })
2022
- config = {
2023
- title: name,
2024
- menu: files.map((file) => {
2025
- return {
2026
- text: file.name,
2027
- href: file.name
2028
- }
2029
- })
2030
- }
2031
- let uri = this.kernel.path("api")
2032
- await this.renderMenu(uri, name, config, [])
2033
- }
2034
- let platform = os.platform()
2035
- res.render("browser", {
2036
- platform,
2037
- running:this.kernel.api.running,
2038
- memory: this.kernel.memory,
2039
- sidebar: "/pinokio/sidebar/" + name,
2040
- name,
2041
- tabs: (this.tabs[name] || []),
2042
- config,
2043
- // sidebar_url: "/pinokio/sidebar/" + name,
2044
- home: req.originalUrl,
2045
- // paths,
2046
- theme: this.theme,
2047
- agent: this.agent,
2048
- src: "/_api/" + name,
2049
- rawpath,
2050
- })
2164
+ this.chrome(req, res, "browser")
2051
2165
  })
2052
2166
  this.app.post("/pinokio/delete", async (req, res) => {
2053
2167
  try {
@@ -82,7 +82,6 @@ class Socket {
82
82
  this.ws.send(JSON.stringify(rpc))
83
83
  });
84
84
  this.ws.addEventListener('message', (message) => {
85
- // console.log("message", message)
86
85
  const packet = JSON.parse(message.data);
87
86
  ondata(packet)
88
87
  });
@@ -52,7 +52,6 @@
52
52
  }
53
53
  .navheader {
54
54
  padding: 15px 10px;
55
- background: var(--dark-bg);
56
55
  }
57
56
  body.columns footer {
58
57
  }
@@ -1432,10 +1431,8 @@ b {
1432
1431
  }
1433
1432
  body.dark #new-window {
1434
1433
  color: var(--dark-btn-color);
1435
- /*
1436
- color: white;
1437
- */
1438
1434
  }
1435
+ /*
1439
1436
  #new-window {
1440
1437
  cursor: pointer;
1441
1438
  padding: 10px;
@@ -1444,6 +1441,7 @@ body.dark #new-window {
1444
1441
  font-size: 18px;
1445
1442
  color: var(--light-color);
1446
1443
  }
1444
+ */
1447
1445
  body.dark .btn2 {
1448
1446
  color: var(--dark-btn-color);
1449
1447
  /*