feat: support for watching jacscript file in devtools

This commit is contained in:
Peli de Halleux 2022-11-08 00:15:31 +00:00
Родитель 23b8fd2de5
Коммит 339a296dc3
5 изменённых файлов: 72 добавлений и 15 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -102,3 +102,4 @@ dist
# TernJS port file # TernJS port file
.tern-port .tern-port
test.js

Просмотреть файл

@ -50,6 +50,10 @@ This command will work in [GitHub codespaces](https://github.com/features/codesp
jacdac devtools jacdac devtools
``` ```
#### `jacscript devtools --jacscript <file>`
Starts the devtools web site and also watches/uploads the source of a given jacscript to the development web site. The dev web site will automatically compile and potentially deploy the jacscript program to a connected device.
## Contributing ## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a This project welcomes contributions and suggestions. Most contributions require you to agree to a

Просмотреть файл

@ -39,7 +39,8 @@
"dependencies": { "dependencies": {
"commander": "^9.0.0", "commander": "^9.0.0",
"faye-websocket": "^0.11.4", "faye-websocket": "^0.11.4",
"jacdac-ts": "^1.27.0" "jacdac-ts": "^1.27.0",
"node-watch": "^0.7.3"
}, },
"devDependencies": { "devDependencies": {
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",
@ -59,8 +60,8 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"rpio": "^2.4.2", "rpio": "^2.4.2",
"spi-device": "^3.1.2",
"serialport": "^9.2.8", "serialport": "^9.2.8",
"spi-device": "^3.1.2",
"usb": "^2.1.2" "usb": "^2.1.2"
}, },
"files": [ "files": [

Просмотреть файл

@ -12,6 +12,8 @@ import {
Flags, Flags,
JDFrameBuffer, JDFrameBuffer,
FRAME_PROCESS, FRAME_PROCESS,
JSONTryParse,
prettySize,
} from "jacdac-ts" } from "jacdac-ts"
import { enableLogging } from "./jdlogging" import { enableLogging } from "./jdlogging"
import { createTransports, TransportsOptions } from "./transports" import { createTransports, TransportsOptions } from "./transports"
@ -29,10 +31,14 @@ const log = console.log
const debug = console.debug const debug = console.debug
const error = console.error const error = console.error
function fetchProxy(): Promise<string> { function fetchProxy(localhost: boolean): Promise<string> {
const url = "https://microsoft.github.io/jacdac-docs/devtools/proxy" const protocol = localhost ? http : https
const url = localhost
? "http://localhost:8000/devtools/proxy.html"
: "https://microsoft.github.io/jacdac-docs/devtools/proxy"
console.debug(`fetch devtools proxy at ${url}`)
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
https protocol
.get(url, res => { .get(url, res => {
if (res.statusCode != 200) if (res.statusCode != 200)
reject( reject(
@ -41,7 +47,15 @@ function fetchProxy(): Promise<string> {
res.setEncoding("utf8") res.setEncoding("utf8")
let body = "" let body = ""
res.on("data", data => (body += data)) res.on("data", data => (body += data))
res.on("end", () => resolve(body)) res.on("end", () => {
if (localhost) {
body = body.replace(
/https:\/\/microsoft.github.io\/jacdac-docs\/dashboard/g,
"http://localhost:8000/dashboard"
)
}
resolve(body)
})
res.on("error", reject) res.on("error", reject)
}) })
.on("error", reject) .on("error", reject)
@ -56,10 +70,18 @@ export async function devToolsCommand(
trace?: string trace?: string
diagnostics?: boolean diagnostics?: boolean
localhost?: boolean localhost?: boolean
jacscript?: string
} & TransportsOptions } & TransportsOptions
) { ) {
const { packets, internet, trace, logging, diagnostics, localhost } = const {
options || {} packets,
internet,
trace,
logging,
diagnostics,
localhost,
jacscript: jacscriptFile,
} = options || {}
const port = 8081 const port = 8081
const tcpPort = 8082 const tcpPort = 8082
const listenHost = internet ? undefined : "127.0.0.1" const listenHost = internet ? undefined : "127.0.0.1"
@ -73,16 +95,27 @@ export async function devToolsCommand(
log(` raw socket: tcp://localhost:${tcpPort}`) log(` raw socket: tcp://localhost:${tcpPort}`)
// download proxy sources // download proxy sources
let proxyHtml = await fetchProxy() const proxyHtml = await fetchProxy(localhost)
if (localhost)
proxyHtml = proxyHtml.replace(
/https:\/\/microsoft.github.io\/jacdac-docs\/dashboard/g,
"http://localhost:8000/dashboard"
)
// start http server // start http server
const clients: WebSocket[] = [] const clients: WebSocket[] = []
// upload jacscript file is needed
const sendJacscript = jacscriptFile
? () => {
const source = fs.readFileSync(jacscriptFile, {
encoding: "utf-8",
})
console.debug(`refresh jacscript (${prettySize(source.length)})`)
const msg = JSON.stringify({
type: "source",
channel: "jacscript",
source,
})
clients.forEach(c => c.send(msg))
}
: undefined
const server = http.createServer(function (req, res) { const server = http.createServer(function (req, res) {
const parsedUrl = url.parse(req.url) const parsedUrl = url.parse(req.url)
const pathname = parsedUrl.pathname const pathname = parsedUrl.pathname
@ -118,6 +151,11 @@ export async function devToolsCommand(
}) })
bridge.on(FRAME_PROCESS, forwardFrame) bridge.on(FRAME_PROCESS, forwardFrame)
bus.addBridge(bridge) bus.addBridge(bridge)
const processMessage = (message: string, sender: string) => {
const msg = JSONTryParse(message)
if (!msg) return
console.debug(msg)
}
const processPacket = (message: Buffer | Uint8Array, sender: string) => { const processPacket = (message: Buffer | Uint8Array, sender: string) => {
const data = new Uint8Array(message) const data = new Uint8Array(message)
bridge.receiveFrameOrPacket(data, sender) bridge.receiveFrameOrPacket(data, sender)
@ -140,10 +178,12 @@ export async function devToolsCommand(
log(`client: connected (${sender}, ${clients.length} clients)`) log(`client: connected (${sender}, ${clients.length} clients)`)
client.on("message", (event: any) => { client.on("message", (event: any) => {
const { data } = event const { data } = event
processPacket(data, sender) if (typeof data === "string") processMessage(data, sender)
else processPacket(data, sender)
}) })
client.on("close", () => removeClient(client)) client.on("close", () => removeClient(client))
client.on("error", (ev: Error) => error(ev)) client.on("error", (ev: Error) => error(ev))
if (sendJacscript) sendJacscript()
} }
}) })
@ -207,4 +247,11 @@ export async function devToolsCommand(
bus.connect(true) bus.connect(true)
server.listen(port, listenHost) server.listen(port, listenHost)
tcpServer.listen(tcpPort, listenHost) tcpServer.listen(tcpPort, listenHost)
if (sendJacscript) {
console.debug(`watch ${jacscriptFile}`)
fs.watch(jacscriptFile, async (eventType, filename) => {
sendJacscript()
})
}
} }

Просмотреть файл

@ -58,6 +58,10 @@ async function mainCli() {
"--localhost", "--localhost",
"use localhost:8000 instead of the internet dashboard" "use localhost:8000 instead of the internet dashboard"
) )
.option(
"-j, --jacscript <string>",
"upload and watch source of local jacscript file"
)
.action(devToolsCommand) .action(devToolsCommand)
await program.parseAsync(process.argv) await program.parseAsync(process.argv)