WIP on reimplementing edit character script with typescript

This commit is contained in:
projectmoon 2021-01-04 22:36:21 +00:00
parent b4981dfc78
commit 63571d9711
8 changed files with 142 additions and 74 deletions

View File

@ -6,15 +6,6 @@ use std::ops::Deref;
pub mod cofd;
const CRATE_NAME: &'static str = env!("CARGO_BIN_NAME");
/// Convert an incoming protobuf content-type to the equivalent type
/// name produced by std::any::type_name(). Currently does NOT work
/// with nested types due to how prost generates the module names.
fn convert_to_rust_name(proto_type: &str) -> String {
format!("{}::{}", CRATE_NAME, proto_type.replace(".", "::"))
}
/// A struct wrapping a protobuf that allows it to be used as binary
/// data submitted via POST using fetch API. Can automatically be
/// dereferenced into its wrapped type.
@ -40,21 +31,10 @@ where
.map(|ct| ct.top() == "application" && ct.sub() == "x-protobuf")
.unwrap_or(false);
let message_type: Option<String> = content_type.and_then(|ct| {
ct.params()
.find(|&(name, _)| name == "messageType")
.map(|(_, message_type)| convert_to_rust_name(message_type))
});
if !is_protobuf {
return Outcome::Failure((Status::new(422, "invalid protobuf"), Error::InvalidInput));
}
if message_type.as_ref().map(String::as_str) != Some(std::any::type_name::<T>()) {
println!("message type is {:?}", message_type);
return Outcome::Forward(data);
}
let bytes: Vec<u8> = match data.open(2.mebibytes()).stream_to_vec().await {
Ok(read_bytes) => read_bytes,
Err(e) => return Outcome::Failure((Status::new(422, "invalid protobuf"), e.into())),

View File

@ -85,8 +85,11 @@
</style>
<script src="https://cdn.jsdelivr.net/npm/protobufjs@6.10.2/dist/protobuf.min.js"></script>
<script defer type="text/javascript" src="/scripts/api.js"></script>
<script defer type="text/javascript" src="/scripts/characters/edit.js"></script>
{# <script defer type="text/javascript" src="/scripts/api.js"></script> #}
{# <script defer type="text/javascript" src="/scripts/characters/edit.js"></script> #}
{# Webpack Templating for API script #}
<%= htmlWebpackPlugin.tags.bodyTags %>
<h1>Core Sheet</h1>
<div>
<h1>Name: <input type="text" value="{{name}}" /></h1>

View File

@ -2,12 +2,12 @@
//TODO start refactoring these into a separate script, and make API calls
//take all necessary info (e.g. username and character ID, plus other stuff)
//as object params.
const root = await protobuf.load("/protos/cofd_api.proto");
//const root = await protobuf.load("/protos/cofd_api.proto");
const [, , USERNAME, CHARACTER_ID] = window.location.pathname.split('/');
const api = makeAPI(root);
console.log("api is", api);
//const api = makeAPI(root);
//console.log("api is", api);
function setupAttributes() {
const attributeInputs = document.querySelectorAll('#attributes input[type="number"]');

15
static/scripts/src/api.ts Normal file
View File

@ -0,0 +1,15 @@
import { UpdateSkillValueRequest } from "../_proto/cofd_api_pb";
const PROTOBUF_CONTENT_TYPE = { 'Content-Type': 'application/x-protobuf' };
export async function updateSkillValue(params: UpdateSkillValueRequest) {
let resp = await fetch('/api/rpc/cofd/update_skill_value', {
method: 'POST',
headers: { ...PROTOBUF_CONTENT_TYPE },
body: params.serializeBinary()
}).then(async resp => {
console.log("resp is", await resp.text());
}).catch(async err => {
console.log("err is", err.text());
});
}

View File

@ -0,0 +1,63 @@
import { UpdateSkillValueRequest } from "../../_proto/cofd_api_pb";
import * as api from "../api";
(async () => {
//TODO start refactoring these into a separate script, and make API calls
//take all necessary info (e.g. username and character ID, plus other stuff)
//as object params.
//const root = await protobuf.load("/protos/cofd_api.proto");
const [, , USERNAME, CHARACTER_ID] = window.location.pathname.split('/');
//const api = makeAPI(root);
//console.log("api is", api);
function setupAttributes() {
// const attributeInputs = document.querySelectorAll('#skills input[type="number"]');
// async function skillValueHandler(event: Event) {
// const input = event.target as HTMLInputElement;
// console.log("updating attr");
// const attribute = input.id;
// const newValue = parseInt(input.value);
// const params = new UpdateSkillValueRequest();
// params.setCharacterUsername(USERNAME);
// params.setCharacterId(parseInt(CHARACTER_ID));
// params.setSkillName(attribute);
// params.setSkillValue(newValue);
// await api.updateSkillValue(params);
// }
// Array.from(attributeInputs).forEach(input => {
// input.addEventListener('change', skillValueHandler);
// });
}
function setupSkills() {
const skillInputs = document.querySelectorAll('#skills input[type="number"]');
async function skillValueHandler(event: Event) {
const input = event.target as HTMLInputElement;
console.log("updating attr");
const attribute = input.id;
const newValue = parseInt(input.value);
const params = new UpdateSkillValueRequest();
params.setCharacterUsername(USERNAME);
params.setCharacterId(parseInt(CHARACTER_ID));
params.setSkillName(attribute);
params.setSkillValue(newValue);
await api.updateSkillValue(params);
}
Array.from(skillInputs).forEach(input => {
input.addEventListener('change', skillValueHandler);
});
}
setupAttributes();
setupSkills();
})().catch(e => {
alert(e);
});

View File

@ -1,8 +1,10 @@
import * as api from "./api";
import { grpc } from "@improbable-eng/grpc-web";
import { CofdApi } from "../_proto/cofd_api_pb_service";
import { UpdateSkillValueRequest } from "../_proto/cofd_api_pb";
import { CofdSheet } from "../_proto/cofd_pb";
console.log(api.updateSkillValue);
let x = new UpdateSkillValueRequest();
x.setCharacterId(1);
x.setCharacterUsername("guy");

View File

@ -9,7 +9,9 @@
"strictNullChecks": true,
"stripInternal": true,
"noFallthroughCasesInSwitch": true,
"noEmitOnError": true
"noEmitOnError": true,
"lib": [
"dom"
]
}
}

View File

@ -6,56 +6,59 @@ const path = require('path');
const root = path.resolve(__dirname, '..', '..');
function packPage(page, chunks) {
if (!chunks) chunks = [];
return new HtmlWebpackPlugin({
template: `${root}/src/templates/${page}`,
filename: `${root}/static/templates/${page}`,
chunks: chunks,
inject: false,
minify: false
});
if (!chunks) chunks = [];
return new HtmlWebpackPlugin({
template: `${root}/src/templates/${page}`,
filename: `${root}/static/templates/${page}`,
publicPath: '/scripts/dist',
scriptLoading: 'defer',
chunks: chunks,
inject: false,
minify: false
});
}
module.exports = {
entry: {
index: "./src/index.ts",
blah: "./src/blah.ts",
entry: {
index: "./src/index.ts",
edit_character: "./src/characters/edit.ts",
blah: "./src/blah.ts",
},
optimization: {
runtimeChunk: "single",
splitChunks: {
chunks: 'all',
},
optimization: {
runtimeChunk: "single",
splitChunks: {
chunks: 'all',
},
},
mode: "development",
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.ts$/,
include: /src|_proto/,
exclude: /node_modules/,
loader: "ts-loader"
}
]
},
resolve: {
extensions: [".ts", ".js"]
},
plugins: [
new CleanWebpackPlugin(),
packPage('login.html.tera', ['index']),
packPage('base.html.tera'),
packPage('error.html.tera'),
packPage('index.html.tera'),
packPage('registration.html.tera'),
packPage('characters/edit_character.html.tera'),
packPage('characters/edit_character_macros.html.tera'),
packPage('characters/new_character.html.tera'),
packPage('characters/view_character.html.tera')
},
mode: "development",
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.ts$/,
include: /src|_proto/,
exclude: /node_modules/,
loader: "ts-loader"
}
]
},
resolve: {
extensions: [".ts", ".js"]
},
plugins: [
new CleanWebpackPlugin(),
packPage('login.html.tera', ['index']),
packPage('base.html.tera'),
packPage('error.html.tera'),
packPage('index.html.tera'),
packPage('registration.html.tera'),
packPage('characters/edit_character.html.tera', ['edit_character']),
packPage('characters/edit_character_macros.html.tera'),
packPage('characters/new_character.html.tera'),
packPage('characters/view_character.html.tera')
]
};