packet loading

This commit is contained in:
Robin Appelman 2021-07-26 00:27:53 +02:00
commit 57650faeac
15 changed files with 11726 additions and 1662 deletions

View file

@ -1,5 +1,5 @@
[package] [package]
name = "inspector" name = "demo-inspector"
version = "0.1.0" version = "0.1.0"
authors = ["Robin Appelman <robin@icewind.nl>"] authors = ["Robin Appelman <robin@icewind.nl>"]
edition = "2018" edition = "2018"
@ -11,7 +11,10 @@ crate-type = ["cdylib", "rlib"]
default = ["console_error_panic_hook"] default = ["console_error_panic_hook"]
[dependencies] [dependencies]
wasm-bindgen = "0.2.63" bitbuffer = { version = "0.10", path = "../../bitbuffer" }
tf-demo-parser = { version = "0.3", path = "../tf-demo-parser" }
serde_json = "1"
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
# The `console_error_panic_hook` crate provides better debugging of panics by # The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires # logging them with `console.error`. This is great for development, but requires

View file

@ -1,19 +1,52 @@
mod utils; mod utils;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use crate::utils::set_panic_hook;
use tf_demo_parser::demo::parser::{DemoHandler, NullHandler};
use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::parser::RawPacketStream;
use bitbuffer::{BitRead, LittleEndian, BitReadBuffer, BitReadStream};
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")] #[cfg(feature = "wee_alloc")]
#[global_allocator] #[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen] #[wasm_bindgen]
extern { pub struct Parser {
fn alert(s: &str); handler: DemoHandler<'static, NullHandler>,
header: Header,
packets: RawPacketStream<'static>,
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn greet() { impl Parser {
alert("Hello, inspector!"); #[wasm_bindgen(constructor)]
pub fn new(input: Vec<u8>) -> Self {
set_panic_hook();
let buffer = BitReadBuffer::new_owned(input, LittleEndian);
let mut stream = BitReadStream::new(buffer);
let header = Header::read(&mut stream).unwrap();
let packets = RawPacketStream::new(stream);
let mut handler = DemoHandler::default();
handler.handle_header(&header);
Parser {
handler,
header,
packets
}
}
pub fn header(&self) -> JsValue {
JsValue::from_serde(&self.header).unwrap()
}
pub fn next(&mut self) -> JsValue {
self.packets.next(&self.handler.state_handler).unwrap().map(|packet| {
let out = JsValue::from_serde(&packet).unwrap();
self.handler.handle_packet(packet).unwrap();
out
}).unwrap_or(JsValue::NULL)
}
} }

View file

@ -1,5 +0,0 @@
language: node_js
node_js: "10"
script:
- ./node_modules/.bin/webpack

View file

@ -1,67 +0,0 @@
<div align="center">
<h1><code>create-wasm-app</code></h1>
<strong>An <code>npm init</code> template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.</strong>
<p>
<a href="https://travis-ci.org/rustwasm/create-wasm-app"><img src="https://img.shields.io/travis/rustwasm/create-wasm-app.svg?style=flat-square" alt="Build Status" /></a>
</p>
<h3>
<a href="#usage">Usage</a>
<span> | </span>
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
</h3>
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>
## About
This template is designed for depending on NPM packages that contain
Rust-generated WebAssembly and using them to create a Website.
* Want to create an NPM package with Rust and WebAssembly? [Check out
`wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)
* Want to make a monorepo-style Website without publishing to NPM? Check out
[`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)
and/or
[`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).
## 🚴 Usage
```
npm init wasm-app
```
## 🔋 Batteries Included
- `.gitignore`: ignores `node_modules`
- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
- `README.md`: the file you are reading now!
- `index.html`: a bare bones html document that includes the webpack bundle
- `index.js`: example js file with a comment showing how to import and use a wasm pkg
- `package.json` and `package-lock.json`:
- pulls in devDependencies for using webpack:
- [`webpack`](https://www.npmjs.com/package/webpack)
- [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)
- [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)
- defines a `start` script to run `webpack-dev-server`
- `webpack.config.js`: configuration file for bundling your js with webpack
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

4
www/bootstrap.js vendored
View file

@ -1,5 +1,5 @@
// A dependency graph that contains any wasm must all be imported // A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so // asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again. // that no one else needs to worry about it again.
import("./index.js") import("./src")
.catch(e => console.error("Error importing `index.js`:", e)); .catch(e => console.error("Error importing `index.tsx`:", e));

View file

@ -7,5 +7,6 @@
<body> <body>
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript> <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
<script src="./bootstrap.js"></script> <script src="./bootstrap.js"></script>
<div id="root"></div>
</body> </body>
</html> </html>

View file

@ -1,3 +0,0 @@
import * as wasm from "hello-wasm-pack";
wasm.greet();

9628
www/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,35 +2,28 @@
"name": "create-wasm-app", "name": "create-wasm-app",
"version": "0.1.0", "version": "0.1.0",
"description": "create an app to consume rust-generated wasm packages", "description": "create an app to consume rust-generated wasm packages",
"main": "index.js", "main": "src/index.tsx",
"bin": { "bin": {
"create-wasm-app": ".bin/create-wasm-app.js" "create-wasm-app": ".bin/create-wasm-app.js"
}, },
"scripts": { "scripts": {
"build": "webpack --config webpack.config.js", "build": "webpack --config webpack.config.js",
"start": "webpack-dev-server" "start": "webpack serve"
}, },
"repository": { "dependencies": {
"type": "git", "demo-inspector": "file:../pkg",
"url": "git+https://github.com/rustwasm/create-wasm-app.git" "react": "^17.0.2",
"react-dom": "^17.0.2",
"react-dropzone": "^11.3.4"
}, },
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack"
],
"author": "Ashley Williams <ashley666ashley@gmail.com>",
"license": "(MIT OR Apache-2.0)",
"bugs": {
"url": "https://github.com/rustwasm/create-wasm-app/issues"
},
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
"devDependencies": { "devDependencies": {
"hello-wasm-pack": "^0.1.0", "@types/react": "^17.0.15",
"webpack": "^4.29.3", "@types/react-dom": "^17.0.9",
"webpack-cli": "^3.1.0", "copy-webpack-plugin": "^9.0.1",
"webpack-dev-server": "^3.1.5", "ts-loader": "^9.2.4",
"copy-webpack-plugin": "^5.0.0" "typescript": "^4.3.5",
"webpack": "^5.46.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
} }
} }

13
www/src/header.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
export interface Header {
demo_type: string,
version: number,
protocol: number,
server: string,
nick: string,
map: string,
game: string,
duration: number,
ticks: number,
frames: number,
sigon: number
}

103
www/src/index.tsx Normal file
View file

@ -0,0 +1,103 @@
import {Packet} from "./parser";
import React, {useCallback, Component} from 'react'
import {useDropzone} from 'react-dropzone'
import ReactDOM from "react-dom";
import {Header} from "./header";
class App extends Component<{}, {
loading: boolean,
header: Header | null,
packets: Packet[]
}> {
state: {
loading: boolean,
header: Header | null,
packets: Packet[]
} = {
loading: false,
header: null,
packets: []
}
load(data: ArrayBuffer) {
this.setState({loading: true});
const worker = new Worker('./worker.js');
worker.addEventListener("message", (event: MessageEvent<{ type: "header", header: Header } | { type: "packet", packet: Packet } | { type: "done" }>) => {
switch (event.data.type) {
case "header":
let header = event.data.header;
this.setState({header});
break;
case "packet":
let packet = event.data.packet;
let packets = this.state.packets;
packets.push(packet);
this.setState({packets});
break;
case "done":
this.setState({loading: false});
break;
}
});
worker.postMessage(data, [data]);
}
render() {
if (this.state.loading && this.state.header && this.state.packets.length) {
return (
<div>
<h1>Loading</h1>
<p>{this.state.packets.slice(-1)[0].tick}/{this.state.header.ticks}</p>
</div>
)
} else if (this.state.loading) {
return (
<div>
<h1>Loading</h1>
</div>
)
} else if (this.state.packets.length) {
return (
<div>
<h1>{this.state.packets.length}</h1>
</div>
)
} else {
return (
<div>
<DemoDropzone onDrop={(data) => this.load(data)}/>
</div>
)
}
}
}
ReactDOM.render(
<App/>,
document.getElementById("root")
);
function DemoDropzone({onDrop}: { onDrop: (data: ArrayBuffer) => void }) {
const onDropCb = useCallback(acceptedFiles => {
let reader = new FileReader();
reader.readAsArrayBuffer(acceptedFiles[0]);
reader.addEventListener('load', () => {
let result = reader.result as ArrayBuffer;
onDrop(result)
});
}, [])
const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop: onDropCb})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
)
}

3387
www/src/parser.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

23
www/src/worker.ts Normal file
View file

@ -0,0 +1,23 @@
import {Parser} from "demo-inspector";
declare function postMessage(message: any): void;
onmessage = function (event) {
let data = event.data as ArrayBuffer;
import("demo-inspector")
.then(({Parser}) => {
console.log(data);
let parser = new Parser(new Uint8Array(data));
postMessage({type: "header", header: parser.header()})
let packet;
do {
packet = parser.next();
if (packet) {
postMessage({type: "packet", packet})
}
} while (packet);
postMessage({type: "done"})
})
};

12
www/tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es2020",
"target": "es6",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
}
}

View file

@ -1,14 +1,49 @@
const CopyWebpackPlugin = require("copy-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require('path'); const path = require('path');
module.exports = { module.exports = [{
entry: "./bootstrap.js", entry: "./bootstrap.js",
output: { output: {
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "dist"),
filename: "bootstrap.js", filename: "bootstrap.js",
}, },
mode: "development", mode: "development",
plugins: [ module: {
new CopyWebpackPlugin(['index.html']) rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
], ],
}; },
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new CopyWebpackPlugin({patterns: [{from: 'index.html'}]})
],
}, {
entry: "./src/worker.ts",
target: 'webworker',
output: {
path: path.resolve(__dirname, "dist"),
filename: "worker.js"
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
experiments: {
syncWebAssembly: true
},
mode: "development",
}];