Compare commits

..

No commits in common. "f828384dbadb764f723b9d56fc698a50f5719176" and "15a8ff29e62f75e7953b36fa45fcfd6b7bfaf241" have entirely different histories.

9 changed files with 13 additions and 65 deletions

View File

@ -52,10 +52,10 @@ https://wakamaifondue.com/
## Pluto Goals: Phase 2 ## Pluto Goals: Phase 2
- [x] public tunnel for your NOSE webapps - [ ] public tunnel for your NOSE webapps
- [x] public tunnel lives through reboots - [ ] public tunnel lives through reboots
- [x] self updating NOSE server - [ ] self updating NOSE server
- [x] `pub/` static hosting in webapps - [ ] `pub/` static hosting in webapps
- [ ] game/bin/www cartridges - [ ] game/bin/www cartridges
- [ ] upload files to projects - [ ] upload files to projects
- [ ] pico8-style games - [ ] pico8-style games

View File

@ -4,7 +4,7 @@
export const game = true export const game = true
import type { GameContext, InputState } from "@/shared/game" import type { GameContext, InputState } from "@/shared/game"
import { rng } from "@/shared/utils" import { rng } from "@/shared/utils.ts"
const WIDTH = 960 const WIDTH = 960
const HEIGHT = 540 const HEIGHT = 540

View File

@ -1,20 +0,0 @@
// List all the games installed on the system.
import { readdirSync } from "fs"
import { join } from "path"
import { NOSE_SYS_BIN } from "@/config"
export default async function () {
let games = await Promise.all(readdirSync(NOSE_SYS_BIN, { withFileTypes: true }).map(async file => {
if (!file.isFile()) return
const code = await Bun.file(join(NOSE_SYS_BIN, file.name)).text()
if (/^export const game\s*=\s*true\s*;?\s*$/m.test(code))
return file.name.replace(".tsx", "").replace(".ts", "")
})).then(games => games.filter(file => file))
return <>
{games.map(game => <a href={`#${game}`}>{game}</a>)}
</>
}

View File

@ -2,7 +2,7 @@
export const game = true export const game = true
import type { GameContext, InputState } from "@/shared/game" import type { GameContext, InputState } from "@/shared/game"
import { rng } from "@/shared/utils" import { rng } from "@/shared/utils.ts"
const CELL = 20 const CELL = 20
const WIDTH = 30 const WIDTH = 30

View File

@ -7,7 +7,7 @@
export const game = true export const game = true
import type { GameContext, InputState } from "@/shared/game" import type { GameContext, InputState } from "@/shared/game"
import { randomElement, randomIndex } from "@/shared/utils" import { randomElement, randomIndex } from "@/shared/utils.ts"
const COLS = 10 const COLS = 10
const ROWS = 20 const ROWS = 20

View File

@ -7,7 +7,6 @@ import { initHistory } from "./history.js"
import { initHyperlink } from "./hyperlink.js" import { initHyperlink } from "./hyperlink.js"
import { initInput } from "./input.js" import { initInput } from "./input.js"
import { initResize } from "./resize.js" import { initResize } from "./resize.js"
import { initScrollback } from "./scrollback.js"
import { startVramCounter } from "./vram.js" import { startVramCounter } from "./vram.js"
import { startConnection } from "./websocket.js" import { startConnection } from "./websocket.js"
@ -20,7 +19,6 @@ initHistory()
initHyperlink() initHyperlink()
initInput() initInput()
initResize() initResize()
initScrollback()
startConnection() startConnection()
startVramCounter() startVramCounter()

View File

@ -2,16 +2,12 @@
// The scrollback shows your history of interacting with the shell. // The scrollback shows your history of interacting with the shell.
// input, output, etc // input, output, etc
import type { CommandOutput } from "../shared/types.js" import { scrollback, $$ } from "./dom.js"
import { scrollback, cmdInput, $$ } from "./dom.js"
import { randomId } from "../shared/utils.js" import { randomId } from "../shared/utils.js"
import type { CommandOutput } from "../shared/types.js"
type InputStatus = "waiting" | "streaming" | "ok" | "error" type InputStatus = "waiting" | "streaming" | "ok" | "error"
export function initScrollback() {
window.addEventListener("click", handleInputClick)
}
export function autoScroll() { export function autoScroll() {
// requestAnimationFrame(() => scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight) // requestAnimationFrame(() => scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight)
// scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight // scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight
@ -67,11 +63,10 @@ export function addOutput(id: string, output: CommandOutput) {
item.textContent = content item.textContent = content
const input = document.querySelector(`[data-id="${id}"].input`) const input = document.querySelector(`[data-id="${id}"].input`)
if (input instanceof HTMLLIElement) { if (input instanceof HTMLLIElement)
input.parentNode!.insertBefore(item, input.nextSibling) input.parentNode!.insertBefore(item, input.nextSibling)
} else { else
insert(item) insert(item)
}
autoScroll() autoScroll()
} }
@ -140,13 +135,3 @@ function processOutput(output: CommandOutput): ["html" | "text", string] {
return [html ? "html" : "text", content] return [html ? "html" : "text", content]
} }
function handleInputClick(e: MouseEvent) {
const target = e.target
if (!(target instanceof HTMLElement)) return
if (target.matches(".input .content")) {
cmdInput.value = target.textContent
}
}

View File

@ -8,8 +8,6 @@ import { addErrorMessage } from "./scrollback.js"
const MAX_RETRIES = 5 const MAX_RETRIES = 5
let retries = 0 let retries = 0
let connected = false
let msgQueue: Message[] = []
let ws: WebSocket | null = null let ws: WebSocket | null = null
@ -22,21 +20,10 @@ export function startConnection() {
ws.onmessage = receive ws.onmessage = receive
ws.onclose = retryConnection ws.onclose = retryConnection
ws.onerror = () => ws?.close() ws.onerror = () => ws?.close()
ws.onopen = () => {
connected = true
msgQueue.forEach(msg => send(msg))
msgQueue.length = 0
}
} }
// send any message // send any message
export function send(msg: Message) { export function send(msg: Message) {
if (!connected) {
msgQueue.push(msg)
startConnection()
return
}
if (!msg.session) msg.session = sessionID if (!msg.session) msg.session = sessionID
ws?.readyState === 1 && ws.send(JSON.stringify(msg)) ws?.readyState === 1 && ws.send(JSON.stringify(msg))
console.log("-> send", msg) console.log("-> send", msg)
@ -54,8 +41,6 @@ export function close() {
} }
function retryConnection() { function retryConnection() {
connected = false
if (retries >= MAX_RETRIES) { if (retries >= MAX_RETRIES) {
addErrorMessage(`!! Failed to reconnect ${retries} times. Server is down.`) addErrorMessage(`!! Failed to reconnect ${retries} times. Server is down.`)
if (ws) ws.onclose = () => { } if (ws) ws.onclose = () => { }

View File

@ -42,10 +42,10 @@ app.use("*", async (c, next) => {
}) })
app.on("GET", ["/js/:path{.+}", "/shared/:path{.+}"], async c => { app.on("GET", ["/js/:path{.+}", "/shared/:path{.+}"], async c => {
let path = "./src/" + c.req.path.replace("..", ".") const path = "./src/" + c.req.path.replace("..", ".")
// path must end in .js or .ts // path must end in .js or .ts
if (!path.endsWith(".js") && !path.endsWith(".ts")) path += ".ts" if (!path.endsWith(".js") && !path.endsWith(".ts")) return c.text("File not found", 404)
const ts = path.replace(".js", ".ts") const ts = path.replace(".js", ".ts")
if (isFile(ts)) { if (isFile(ts)) {