Add client/server version checking.

This commit is contained in:
yukirij 2024-10-02 12:27:31 -07:00
parent bb1fce886a
commit 64d91c30ff
13 changed files with 146 additions and 49 deletions

12
server/build.rs Normal file
View File

@ -0,0 +1,12 @@
use std::process::Command;
fn main()
{
let output = Command::new("git")
.args(&["rev-parse", "HEAD"])
.output()
.expect("Failed to acquire git HEAD");
let git_hash = String::from_utf8(output.stdout).expect("Invalid UTF-8 output from git HEAD");
let git_hash = git_hash.trim();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}

View File

@ -151,6 +151,12 @@ impl App {
let mut socket = conn.stream.write().await;
match response.data {
QRPacketData::RHello(response) => {
socket.send(Message::Binary(
encode_response(CODE_HELLO, response.encode())
)).await.ok();
}
QRPacketData::RRegister(response) => {
socket.send(Message::Binary(
encode_response(CODE_REGISTER, response.encode())

View File

@ -1 +1,2 @@
pub const VERSION :&str = env!("GIT_HASH");
pub const REGISTER_CODE :&str = "mountain";

View File

@ -77,6 +77,7 @@ async fn service_http(mut request:hyper::Request<hyper::body::Incoming>, args:Ht
match request.uri().path() {
"/.js" => {
output = [
format!("let CONFIG_VERSION = \"{}\";", config::VERSION).as_bytes().to_vec(),
format!("let CONFIG_LANGUAGE = {};", language_code).as_bytes().to_vec(),
output,
].concat();

View File

@ -1,5 +1,6 @@
use bus::Bus;
use crate::{
config,
app::{
authentication::Authentication,
connection::Connection,
@ -58,10 +59,13 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
packet.from,
QRPacket::new(id as u32, QRPacketData::RConn)
).ok();
Some(QRPacket::new(0, QRPacketData::None))
}
QRPacketData::QDisconn => {
println!("Disconnect: {}", qr.id);
// Uninitialize connection
if if let Some(conn) = app.connections.get(qr.id as usize).cloned() {
@ -110,12 +114,17 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
true
} else { false } {
app.connections.remove(qr.id as usize).ok();
println!("Disconnect: {}", qr.id);
}
Some(QRPacket::new(0, QRPacketData::None))
}
QRPacketData::QHello => {
let response = PacketHelloResponse {
version:config::VERSION.to_string(),
};
Some(QRPacket::new(qr.id, QRPacketData::RHello(response)))
}
QRPacketData::QRegister(request) => {
let mut response = PacketRegisterResponse::new();
response.status = STATUS_SERVER_ERROR;

View File

@ -56,6 +56,11 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
println!("MESSAGE {:x}", code);
match code {
CODE_HELLO => {
args.bus.send(
bus_ds, QRPacket::new(conn_id, QRPacketData::QHello)
).ok();
}
CODE_REGISTER => match PacketRegister::decode(&data, &mut index) {
Ok(packet) => {
@ -207,7 +212,10 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
true
}
}
Err(_) => false,
Err(e) => {
println!("WSS error: {}", e.to_string());
false
},
}
None => false,
} { }

View File

@ -22,6 +22,8 @@ pub const STATUS_NOT_IMPL :u16 = 0x00FF;
** Operation Codes
*/
pub const CODE_HELLO :u16 = 0x0001;
pub const CODE_REGISTER :u16 = 0x0010;
pub const CODE_AUTH :u16 = 0x0011;
pub const CODE_AUTH_RESUME :u16 = 0x0012;

View File

@ -12,6 +12,9 @@ pub enum QRPacketData {
QDisconn,
QHello,
RHello(PacketHelloResponse),
QRegister(PacketRegister),
RRegister(PacketRegisterResponse),

View File

@ -0,0 +1,28 @@
use crate::util::pack::pack_u8;
use super::Packet;
#[derive(Clone)]
pub struct PacketHelloResponse {
pub version:String,
}
impl PacketHelloResponse {
pub fn new() -> Self
{
Self {
version:String::new(),
}
}
}
impl Packet for PacketHelloResponse {
type Data = Self;
fn encode(&self) -> Vec<u8>
{
let version_bytes = self.version.as_bytes().to_vec();
[
pack_u8(version_bytes.len() as u8),
version_bytes,
].concat()
}
}

View File

@ -1,3 +1,4 @@
mod hello; pub use hello::*;
mod connect; pub use connect::*;
mod register; pub use register::*;

View File

@ -30,6 +30,8 @@ const Status = {
};
const OpCode = {
Hello :0x0001,
Register :0x0010,
Authenticate :0x0011,
Resume :0x0012,

View File

@ -13,11 +13,23 @@ const SCENES = {
load() {
UI.nav([
UI.button(LANG("reconnect"), () => { RECONNECT(); }),
UI.button(LANG("practice"), () => { LOAD(SCENES.GamePractice); }),
], []);
return true;
}
reconnect() {
LOAD_URL();
message(code, data) {
switch(code) {
case OpCode.Hello: {
console.log("CLIENT VERSION: '" + CONFIG_VERSION + "'");
console.log("SERVER VERSION: '" + data.version + "'");
if(CONFIG_VERSION == data.version) {
RESUME();
} else {
location.reload();
}
} break;
}
}
},
@ -207,36 +219,40 @@ const SCENES = {
this.pages = 1;
}
load() {
UI.mainmenu("browse");
if(SOCKET !== null) {
UI.mainmenu("browse");
let indicator_page = UI.div([]);
indicator_page.setAttribute("id", "indicator-page");
let indicator_page = UI.div([]);
indicator_page.setAttribute("id", "indicator-page");
UI.mainnav(
[ ],
[
indicator_page,
UI.button("◀", () => {
if(SCENE.page < SCENE.pages) { SCENE.page += 1; }
SCENE.refresh();
}),
UI.button("▶", () => {
if(SCENE.page > 1) { SCENE.page -= 1; }
SCENE.refresh();
}),
UI.button(LANG("refresh"), () => { SCENE.referesh(); }),
],
{ auth:true, session:true }
);
let table = document.createElement("table");
table.setAttribute("id", "content");
table.setAttribute("class", "list session");
MAIN.appendChild(table);
UI.mainnav(
[ ],
[
indicator_page,
UI.button("◀", () => {
if(SCENE.page < SCENE.pages) { SCENE.page += 1; }
SCENE.refresh();
}),
UI.button("▶", () => {
if(SCENE.page > 1) { SCENE.page -= 1; }
SCENE.refresh();
}),
UI.button(LANG("refresh"), () => { SCENE.referesh(); }),
],
{ auth:true, session:true }
);
let table = document.createElement("table");
table.setAttribute("id", "content");
table.setAttribute("class", "list session");
MAIN.appendChild(table);
SCENE.refresh();
SCENE.refresh();
history.pushState(null, "Dzura", "/");
history.pushState(null, "Dzura", "/");
} else {
LOAD(SCENES.Offline);
}
return true;
}
refresh() {
@ -1010,7 +1026,6 @@ function LOAD(scene, data=null) {
UI.rebuild();
SCENE = new scene();
if(!SCENE.load(data)) { LOAD(SCENES.Browse); }
UI.update_status();
}
@ -1023,13 +1038,13 @@ function LOAD_URL() {
if(parts.length > 1) {
switch(parts[1]) {
case "continue": LOAD(SCENES.Continue); break;
case "live": LOAD(SCENES.Live); break;
case "history": LOAD(SCENES.History); break;
case "practice": LOAD(SCENES.GamePractice); break;
case "guide": LOAD(SCENES.Guide); break;
case "about": LOAD(SCENES.About); break;
case "challenge": LOAD(SCENES.Challenge); break;
case "continue": LOAD(SCENES.Continue); return;
case "live": LOAD(SCENES.Live); return;
case "history": LOAD(SCENES.History); return;
case "practice": LOAD(SCENES.GamePractice); return;
case "guide": LOAD(SCENES.Guide); return;
case "about": LOAD(SCENES.About); return;
case "challenge": LOAD(SCENES.Challenge); return;
case "game": {
if(parts[2]) {
@ -1038,14 +1053,10 @@ function LOAD_URL() {
token:token,
mode:INTERFACE.Mode.Review,
});
} else {
LOAD(SCENES.Browse);
return;
}
} break;
default: LOAD(SCENES.Browse);
}
} else {
LOAD(SCENES.Browse);
}
LOAD(SCENES.Browse);
}

View File

@ -4,6 +4,7 @@ function RECONNECT() {
SOCKET = new WebSocket("wss://" + location.hostname + ":38612");
SOCKET.binaryType = "arraybuffer";
SOCKET.addEventListener("error", () => {
console.log("Websocket error.");
SOCKET = null;
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
});
@ -20,11 +21,11 @@ function RECONNECT() {
RECONNECT();
});
RESUME();
MESSAGE_COMPOSE([
PACK.u16(OpCode.Hello),
]);
}
});
} else {
RESUME();
}
}
@ -40,7 +41,7 @@ function RESUME() {
secret,
]);
} else {
if(SCENE.reconnect !== undefined) { SCENE.reconnect(); }
LOAD_URL();
}
}
@ -56,6 +57,18 @@ function MESSAGE(event) {
}
switch(code) {
case OpCode.Hello: {
console.log("RECV Hello");
data = {
version:"",
};
result = UNPACK.string(bytes, index, UNPACK.u8);
index = result.index;
data.version = result.data;
} break;
case OpCode.Register: {
console.log("RECV Register");