1
0
mirror of https://github.com/4yn/slidershim.git synced 2025-02-01 20:18:07 +01:00

brokenithm working

This commit is contained in:
4yn 2022-02-05 04:22:29 +08:00
parent 7f155903ca
commit 786ac83c4c
14 changed files with 777 additions and 72 deletions

9
src-tauri/Cargo.lock generated
View File

@ -2247,6 +2247,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "path-clean"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd"
[[package]]
name = "pathdiff"
version = "0.2.1"
@ -3056,9 +3062,11 @@ dependencies = [
"directories",
"env_logger",
"futures",
"futures-util",
"hyper",
"log",
"palette",
"path-clean",
"rusb",
"serde",
"serde_json",
@ -3067,6 +3075,7 @@ dependencies = [
"tauri-build",
"tokio",
"tokio-tungstenite",
"tokio-util",
"tungstenite",
"vigem-client",
"winapi",

View File

@ -22,6 +22,12 @@ log = "0.4.14"
env_logger = "0.9.0"
tauri = { version = "1.0.0-beta.8", features = ["api-all", "system-tray"] }
futures = "0.3.19"
futures-util = "0.3.19"
async-trait = "0.1.52"
tokio = { version="1.16.1", features=["rt-multi-thread","macros"] }
tokio-util = "0.6.9"
directories = "4.0.1"
rusb = "0.9.0"
serialport = "4.0.1"
@ -29,10 +35,8 @@ vigem-client = "0.1.1"
palette = "0.6.0"
winapi = "0.3.9"
futures = "0.3.19"
async-trait = "0.1.52"
tokio = { version="1.16.1", features=["rt-multi-thread","macros"] }
hyper = { version="0.14.16", features=["server","http1","http2","tcp"] }
hyper = { version="0.14.16", features=["server", "http1", "http2", "tcp", "stream", "runtime"] }
path-clean = "0.1.0"
tungstenite = { version="0.16.0", default-features=false }
tokio-tungstenite = "0.16.1"

1
src-tauri/res/www/app.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
var config = {
// Inverted layout mode.
// Set to "true" to have the "lift" key at the bottom of the screen rather than the top.
invert: false,
// Use a solid background color
bgImage: false,
bgColor: "#000000",
// Use a custom background image
// bgColor is overlayed on the image, so make it semi-transparent
// bgImage:
// "https://raw.githubusercontent.com/gist/4yn/df052666266ce25554110ca1b4f33ce3/raw/1e5e6ab966639bb6786a4690dc49097763b16ba0/subtle-prism.svg",
// bgColor: "rgba(0, 0, 0, 0.5)",
// Key Press Color
keyColor: "#FF00FF",
// Lift key color
lkeyColor: "#00FFFF",
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<title>brokenithm-kb</title>
<meta charset="utf8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" href="favicon.ico" />
<style>
#fullscreen {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: #000000;
color: hotpink;
}
.container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
flex-flow: column nowrap;
touch-action: none;
align-items: stretch;
}
.air-container {
display: flex;
flex-flow: column nowrap;
align-items: stretch;
flex: 1;
}
.touch-container {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
flex: 1;
}
.grow > * {
flex: 1;
}
.key {
flex: 1;
border: 1px solid green;
}
.key[data-active] {
background-color: hotpink;
}
.key.air[data-active] {
background-color: skyblue;
}
canvas {
touch-action: none;
margin: 0px -1.5625vw;
}
</style>
</head>
<body>
<div id="fullscreen">
<!-- Offset for LED display -->
<div class="container">
<div class="air-container grow"></div>
<div class="touch-container grow">
<canvas id="canvas" width="33" height="1"></canvas>
</div>
</div>
<!-- Hitbox Divs -->
<div class="container" id="main">
<div class="air-container grow">
<div class="air key" data-air="1" data-kflag="5"></div>
<div class="air key" data-air="1" data-kflag="4"></div>
<div class="air key" data-air="1" data-kflag="3"></div>
<div class="air key" data-air="1" data-kflag="2"></div>
<div class="air key" data-air="1" data-kflag="1"></div>
<div class="air key" data-air="1" data-kflag="0"></div>
</div>
<div class="touch-container grow">
<div class="key" data-kflag="0"></div>
<div class="key" data-kflag="2"></div>
<div class="key" data-kflag="4"></div>
<div class="key" data-kflag="6"></div>
<div class="key" data-kflag="8"></div>
<div class="key" data-kflag="10"></div>
<div class="key" data-kflag="12"></div>
<div class="key" data-kflag="14"></div>
<div class="key" data-kflag="16"></div>
<div class="key" data-kflag="18"></div>
<div class="key" data-kflag="20"></div>
<div class="key" data-kflag="22"></div>
<div class="key" data-kflag="24"></div>
<div class="key" data-kflag="26"></div>
<div class="key" data-kflag="28"></div>
<div class="key" data-kflag="30"></div>
</div>
</div>
</div>
<script src="/config.js"></script>
<script src="/app.js"></script>
</body>
</html>

344
src-tauri/res/www/src.js Normal file
View File

@ -0,0 +1,344 @@
/*
Post-process with https://babeljs.io/repl and https://javascript-minifier.com/
*/
const throttle = (func, wait) => {
var ready = true;
var args = null;
return function throttled() {
var context = this;
if (ready) {
ready = false;
setTimeout(function () {
ready = true;
if (args) {
throttled.apply(context);
}
}, wait);
if (args) {
func.apply(this, args);
args = null;
} else {
func.apply(this, arguments);
}
} else {
args = arguments;
}
};
};
// Element refs
var keys = document.getElementsByClassName("key");
var airKeys = [];
var midline = 0;
var touchKeys = [];
var allKeys = [];
var topKeys = airKeys;
var bottomKeys = touchKeys;
const compileKey = (key) => {
const prev = key.previousElementSibling;
const next = key.nextElementSibling;
return {
top: key.offsetTop,
bottom: key.offsetTop + key.offsetHeight,
left: key.offsetLeft,
right: key.offsetLeft + key.offsetWidth,
almostLeft: !!prev ? key.offsetLeft + key.offsetWidth / 4 : -99999,
almostRight: !!next ? key.offsetLeft + (key.offsetWidth * 3) / 4 : 99999,
kflag: parseInt(key.dataset.kflag) + (parseInt(key.dataset.air) ? 32 : 0),
isAir: parseInt(key.dataset.air) ? true : false,
prevKeyRef: prev,
prevKeyKflag: prev
? parseInt(prev.dataset.kflag) + (parseInt(prev.dataset.air) ? 32 : 0)
: null,
nextKeyRef: next,
nextKeyKflag: next
? parseInt(next.dataset.kflag) + (parseInt(next.dataset.air) ? 32 : 0)
: null,
ref: key,
};
};
const isInside = (x, y, compiledKey) => {
return (
compiledKey.left <= x &&
x < compiledKey.right &&
compiledKey.top <= y &&
y < compiledKey.bottom
);
};
const compileKeys = () => {
keys = document.getElementsByClassName("key");
airKeys = [];
touchKeys = [];
for (var i = 0, key; i < keys.length; i++) {
const compiledKey = compileKey(keys[i]);
if (!compiledKey.isAir) {
touchKeys.push(compiledKey);
} else {
airKeys.push(compiledKey);
}
allKeys.push(compiledKey);
}
if (!config.invert) {
// Not inverted
topKeys = airKeys;
bottomKeys = touchKeys;
midline = touchKeys[0].top;
} else {
// Inverted
topKeys = touchKeys;
bottomKeys = airKeys;
midline = touchKeys[0].bottom;
}
};
const getKey = (x, y) => {
if (y < midline) {
for (var i = 0; i < topKeys.length; i++) {
if (isInside(x, y, topKeys[i])) return topKeys[i];
}
} else {
for (var i = 0; i < bottomKeys.length; i++) {
if (isInside(x, y, bottomKeys[i])) {
return bottomKeys[i];
}
}
}
return null;
};
// Button State
// prettier-ignore
var lastState = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
function updateTouches(e) {
try {
e.preventDefault();
// prettier-ignore
var keyFlags = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
throttledRequestFullscreen();
for (var i = 0; i < e.touches.length; i++) {
const touch = e.touches[i];
const x = touch.clientX;
const y = touch.clientY;
const key = getKey(x, y);
if (!key) continue;
setKey(keyFlags, key.kflag, key.isAir);
if (key.isAir) continue;
if (x < key.almostLeft) {
setKey(keyFlags, key.prevKeyKflag, false);
}
if (key.almostRight < x) {
setKey(keyFlags, key.nextKeyKflag, false);
}
}
// Render keys
for (var i = 0; i < allKeys.length; i++) {
const key = allKeys[i];
const kflag = key.kflag;
if (keyFlags[kflag] !== lastState[kflag]) {
if (keyFlags[kflag]) {
key.ref.setAttribute("data-active", "");
} else {
key.ref.removeAttribute("data-active");
}
}
}
if (keyFlags !== lastState) {
throttledSendKeys(keyFlags);
}
lastState = keyFlags;
} catch (err) {
alert(err);
}
}
const throttledUpdateTouches = throttle(updateTouches, 10);
const setKey = (keyFlags, kflag, isAir) => {
var idx = kflag;
if (keyFlags[idx] && !isAir) {
idx++;
}
keyFlags[idx] = 1;
};
const sendKeys = (keyFlags) => {
if (wsConnected) {
ws.send("b" + keyFlags.join(""));
}
};
const throttledSendKeys = throttle(sendKeys, 10);
// Websockets
var ws = null;
var wsTimeout = 0;
var wsConnected = false;
const wsConnect = () => {
ws = new WebSocket("ws://" + location.host + "/ws");
ws.binaryType = "arraybuffer";
ws.onopen = () => {
ws.send("alive?");
};
ws.onmessage = (e) => {
if (e.data.byteLength) {
updateLed(e.data);
} else if (e.data == "alive") {
wsTimeout = 0;
wsConnected = true;
}
};
};
const wsWatch = () => {
if (wsTimeout++ > 2) {
wsTimeout = 0;
ws.close();
wsConnected = false;
wsConnect();
return;
}
if (wsConnected) {
ws.send("alive?");
}
};
// Canvas vars
var canvas = document.getElementById("canvas");
var canvasCtx = canvas.getContext("2d");
var canvasData = canvasCtx.getImageData(0, 0, 33, 1);
const setupLed = () => {
for (var i = 0; i < 33; i++) {
canvasData.data[i * 4 + 3] = 255;
}
};
setupLed();
const updateLed = (data) => {
const buf = new Uint8Array(data);
for (var i = 0; i < 32; i++) {
canvasData.data[i * 4] = buf[(31 - i) * 3 + 1]; // r
canvasData.data[i * 4 + 1] = buf[(31 - i) * 3 + 2]; // g
canvasData.data[i * 4 + 2] = buf[(31 - i) * 3 + 0]; // b
}
// Copy from first led
canvasData.data[128] = buf[94];
canvasData.data[129] = buf[95];
canvasData.data[130] = buf[93];
canvasCtx.putImageData(canvasData, 0, 0);
};
// Fullscreener
const fs = document.getElementById("fullscreen");
const requestFullscreen = () => {
if (!document.fullscreenElement && screen.height <= 1024) {
if (fs.requestFullscreen) {
fs.requestFullscreen();
} else if (fs.mozRequestFullScreen) {
fs.mozRequestFullScreen();
} else if (fs.webkitRequestFullScreen) {
fs.webkitRequestFullScreen();
}
}
};
const throttledRequestFullscreen = throttle(requestFullscreen, 3000);
// Do update hooks
const cnt = document.getElementById("main");
cnt.addEventListener("touchstart", updateTouches);
cnt.addEventListener("touchmove", updateTouches);
cnt.addEventListener("touchend", updateTouches);
// cnt.addEventListener("touchstart", throttledUpdateTouches);
// cnt.addEventListener("touchmove", throttledUpdateTouches);
// cnt.addEventListener("touchend", throttledUpdateTouches);
// Load config
const readConfig = (config) => {
var style = "";
if (!!config.invert) {
style += `.container, .air-container {flex-flow: column-reverse nowrap;} `;
}
var bgColor = config.bgColor || "rbga(0, 0, 0, 0.9)";
if (!config.bgImage) {
style += `#fullscreen {background: ${bgColor};} `;
} else {
style += `#fullscreen {background: ${bgColor} url("${config.bgImage}") fixed center / cover!important; background-repeat: no-repeat;} `;
}
if (typeof config.ledOpacity === "number") {
if (config.ledOpacity === 0) {
style += `#canvas {display: none} `;
} else {
style += `#canvas {opacity: ${config.ledOpacity}} `;
}
}
if (typeof config.keyColor === "string") {
style += `.key[data-active] {background-color: ${config.keyColor};} `;
}
if (typeof config.keyColor === "string") {
style += `.key.air[data-active] {background-color: ${config.lkeyColor};} `;
}
if (typeof config.keyBorderColor === "string") {
style += `.key {border: 1px solid ${config.keyBorderColor};} `;
}
if (!!config.keyColorFade && typeof config.keyColorFade === "number") {
style += `.key:not([data-active]) {transition: background ${config.keyColorFade}ms ease-out;} `;
}
if (typeof config.keyHeight === "number") {
if (config.keyHeight === 0) {
style += `.touch-container {display: none;} `;
} else {
style += `.touch-container {flex: ${config.keyHeight};} `;
}
}
if (typeof config.lkeyHeight === "number") {
if (config.lkeyHeight === 0) {
style += `.air-container {display: none;} `;
} else {
style += `.air-container {flex: ${config.keyHeight};} `;
}
}
var styleRef = document.createElement("style");
styleRef.innerHTML = style;
document.head.appendChild(styleRef);
};
// Initialize
const initialize = () => {
readConfig(config);
compileKeys();
wsConnect();
setInterval(wsWatch, 1000);
};
initialize();
// Update keys on resize
window.onresize = compileKeys;

View File

@ -5,41 +5,41 @@ use std::{future::Future, io, time::Duration};
use tokio::{select, time::sleep};
use slidershim::slider_io::worker::{AsyncJob, AsyncWorker};
// use slidershim::slider_io::worker::{AsyncJob, AsyncWorker};
struct CounterJob;
// struct CounterJob;
#[async_trait]
impl AsyncJob for CounterJob {
async fn do_work<F: Future<Output = ()> + Send>(self, stop_signal: F) {
let job_a = async {
println!("Start job A");
let mut x = 0;
loop {
x += 1;
println!("{}", x);
sleep(Duration::from_millis(100)).await;
}
};
let job_b = async move {
println!("Start job B");
stop_signal.await;
println!("Stop signal hit at job B");
};
// #[async_trait]
// impl AsyncJob for CounterJob {
// async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
// let job_a = async {
// println!("Start job A");
// let mut x = 0;
// loop {
// x += 1;
// println!("{}", x);
// sleep(Duration::from_millis(100)).await;
// }
// };
// let job_b = async move {
// println!("Start job B");
// stop_signal.await;
// println!("Stop signal hit at job B");
// };
select! {
_ = job_a => {},
_ = job_b => {},
}
}
}
// select! {
// _ = job_a => {},
// _ = job_b => {},
// }
// }
// }
fn main() {
env_logger::Builder::new()
.filter_level(log::LevelFilter::Debug)
.init();
let worker = AsyncWorker::new("counter", CounterJob);
// let worker = AsyncWorker::new("counter", CounterJob);
let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap();
}

View File

@ -4,14 +4,16 @@ use std::{io, time::Duration};
use tokio::time::sleep;
// use slidershim::slider_io::{brokenithm::BrokenithmJob, worker::AsyncWorker};
use slidershim::slider_io::{
brokenithm::BrokenithmJob, controller_state::FullState, worker::AsyncWorker,
};
fn main() {
env_logger::Builder::new()
.filter_level(log::LevelFilter::Debug)
.init();
// let worker = AsyncWorker::new("brokenithm", BrokenithmJob);
let worker = AsyncWorker::new("brokenithm", BrokenithmJob::new(FullState::new()));
let mut input = String::new();
let string = io::stdin().read_line(&mut input).unwrap();
}

View File

@ -1,3 +1,44 @@
use std::{
env, fs,
path::{Path, PathBuf},
};
const COPY_DIR: &'static str = "res";
fn copy_dir<P, Q>(from: P, to: Q)
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
// https://stackoverflow.com/a/68950006
let to = to.as_ref().to_path_buf();
for path in fs::read_dir(from).unwrap() {
let path = path.unwrap().path();
let to = to.clone().join(path.file_name().unwrap());
if path.is_file() {
fs::copy(&path, to).unwrap();
} else if path.is_dir() {
if !to.exists() {
fs::create_dir(&to).unwrap();
}
copy_dir(&path, to);
} else { /* Skip other content */
}
}
}
fn main() {
let out = env::var("PROFILE").unwrap();
let out = PathBuf::from(format!("target/{}/{}", out, COPY_DIR));
if out.exists() {
fs::remove_dir_all(&out).unwrap()
};
fs::create_dir(&out).unwrap();
copy_dir(COPY_DIR, &out);
tauri_build::build();
}

View File

@ -32,8 +32,12 @@ fn main() {
env_logger::init();
let config = Arc::new(Mutex::new(Some(slider_io::Config::default())));
let manager: slider_io::Manager;
{
config.lock().unwrap().as_ref().unwrap().save();
let c = config.lock().unwrap();
let cr = c.as_ref().unwrap();
cr.save();
manager = slider_io::Manager::new(cr.clone());
}
tauri::Builder::default()

View File

@ -1,50 +1,213 @@
use std::{convert::Infallible, net::SocketAddr};
use log::info;
use tokio::time::sleep;
use async_trait::async_trait;
use futures::{SinkExt, StreamExt};
use hyper::{
header,
server::conn::AddrStream,
service::{make_service_fn, service_fn},
Body, Request, Response, Server,
upgrade::{self, Upgraded},
Body, Method, Request, Response, Server, StatusCode,
};
use log::{error, info};
use path_clean::PathClean;
use std::{convert::Infallible, future::Future, net::SocketAddr, path::PathBuf};
use tokio::{fs::File, select};
use tokio_tungstenite::WebSocketStream;
use tokio_util::codec::{BytesCodec, FramedRead};
use tungstenite::{handshake, Error, Message};
// use crate::slider_io::worker::{AsyncJob, AsyncJobFut, AsyncJobRecvStop};
use crate::slider_io::{controller_state::FullState, worker::AsyncJob};
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
async fn error_response() -> Result<Response<Body>, Infallible> {
Ok(
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from(format!("Not found")))
.unwrap(),
)
}
async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
let mut pb = PathBuf::from("res/www/");
pb.push(path);
pb.clean();
// println!("CWD {:?}", std::env::current_dir());
// println!("Serving file {:?}", pb);
match File::open(pb).await {
Ok(f) => {
let stream = FramedRead::new(f, BytesCodec::new());
let body = Body::wrap_stream(stream);
Ok(Response::new(body))
}
Err(_) => error_response().await,
}
}
async fn handle_brokenithm(ws_stream: WebSocketStream<Upgraded>, state: FullState) {
let (mut ws_write, mut ws_read) = ws_stream.split();
loop {
match ws_read.next().await {
Some(msg) => match msg {
Ok(msg) => match msg {
Message::Text(msg) => {
let mut chars = msg.chars();
let head = chars.next().unwrap();
match head {
'a' => {
ws_write.send(Message::Text("alive".to_string())).await;
}
'b' => {
let flat_state: Vec<bool> = chars
.map(|x| match x {
'0' => false,
'1' => true,
_ => unreachable!(),
})
.collect();
let mut controller_state_handle = state.controller_state.lock().unwrap();
for (idx, c) in flat_state[0..32].iter().enumerate() {
controller_state_handle.ground_state[idx] = match c {
false => 0,
true => 255,
}
}
for (idx, c) in flat_state[32..38].iter().enumerate() {
controller_state_handle.air_state[idx] = match c {
false => 0,
true => 1,
}
}
// println!(
// "{:?} {:?}",
// controller_state_handle.ground_state, controller_state_handle.air_state
// );
}
_ => {
break;
}
}
}
Message::Close(_) => {
info!("Websocket connection closed");
break;
}
_ => {}
},
Err(e) => {
error!("Websocket connection error: {}", e);
break;
}
},
None => {
break;
}
}
}
}
async fn handle_websocket(
mut request: Request<Body>,
state: FullState,
) -> Result<Response<Body>, Infallible> {
let res = match handshake::server::create_response_with_body(&request, || Body::empty()) {
Ok(res) => {
tokio::spawn(async move {
match upgrade::on(&mut request).await {
Ok(upgraded) => {
let ws_stream = WebSocketStream::from_raw_socket(
upgraded,
tokio_tungstenite::tungstenite::protocol::Role::Server,
None,
)
.await;
handle_brokenithm(ws_stream, state).await;
}
Err(e) => {
error!("Websocket upgrade error: {}", e);
}
}
});
res
}
Err(e) => {
error!("Websocket creation error: {}", e);
Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from(format!("Failed to create websocket: {}", e)))
.unwrap()
}
};
Ok(res)
}
async fn handle_request(
request: Request<Body>,
remote_addr: SocketAddr,
state: FullState,
) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from(format!(
"Hello there connection {}\n",
remote_addr
))))
}
let method = request.method();
let path = request.uri().path();
if method != Method::GET {
error!("Server unknown method {} {}", method, path);
return error_response().await;
}
info!("Server {} {}", method, path);
async fn brokenithm_server() {
let addr = SocketAddr::from(([0, 0, 0, 0], 1666));
info!("Brokenithm opening on {:?}", addr);
let make_svc = make_service_fn(|conn: &AddrStream| {
let remote_addr = conn.remote_addr();
async move {
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
handle_request(request, remote_addr)
}))
}
});
let server = Server::bind(&addr).serve(make_svc);
if let Err(e) = server.await {
eprintln!("Server error: {}", e);
match (
request.uri().path(),
request.headers().contains_key(header::UPGRADE),
) {
("/", false) | ("/index.html", false) => serve_file("index.html").await,
(filename, false) => serve_file(&filename[1..]).await,
("/ws", true) => handle_websocket(request, state).await,
_ => error_response().await,
}
}
// struct BrokenithmJob;
pub struct BrokenithmJob {
state: FullState,
}
// impl AsyncJob {
// fn job(self, mut recv_stop: AsyncJobRecvStop) -> AsyncJobFut {
// return Box::pin()
// }
// }
impl BrokenithmJob {
pub fn new(state: FullState) -> Self {
Self { state }
}
}
#[async_trait]
impl AsyncJob for BrokenithmJob {
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
let state = self.state.clone();
let make_svc = make_service_fn(|conn: &AddrStream| {
let remote_addr = conn.remote_addr();
let make_svc_state = state.clone();
async move {
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
let svc_state = make_svc_state.clone();
handle_request(request, remote_addr, svc_state)
}))
}
});
let addr = SocketAddr::from(([0, 0, 0, 0], 1606));
info!("Brokenithm server listening on {}", addr);
let server = Server::bind(&addr)
// .http1_keepalive(false)
// .http2_keep_alive_interval(None)
// .tcp_keepalive(None)
.serve(make_svc)
.with_graceful_shutdown(stop_signal);
if let Err(e) = server.await {
info!("Brokenithm server stopped: {}", e);
}
}
}

View File

@ -2,10 +2,10 @@ mod config;
mod utils;
pub mod worker;
mod controller_state;
pub mod controller_state;
mod voltex;
mod brokenithm;
pub mod brokenithm;
mod gamepad;
mod keyboard;

View File

@ -68,7 +68,7 @@ impl Drop for ThreadWorker {
#[async_trait]
pub trait AsyncJob: Send + 'static {
async fn do_work<F: Future<Output = ()> + Send>(self, stop_signal: F);
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F);
}
pub struct AsyncWorker {
@ -94,7 +94,7 @@ impl AsyncWorker {
let task = runtime.spawn(async move {
job
.do_work(async move {
.run(async move {
recv_stop.await;
})
.await;