Run rustfmt

This commit is contained in:
Dane Johnson 2022-10-12 12:48:23 -05:00
parent bf84433d5b
commit 4c0f571317
5 changed files with 303 additions and 318 deletions

View File

@ -1,98 +1,96 @@
use std::sync::Arc;
use tokio::sync::Mutex;
use futures::{
select,
FutureExt,
};
use hexland_server::{
GlobalState,
Channel,
channel_pair,
GameController,
message::{Message, MessageWebSocket},
msg,
};
pub struct Client {
global_state: Arc<GlobalState>,
ws: MessageWebSocket,
channel: Option<Channel>,
}
impl Client {
pub fn new(ws: MessageWebSocket, global_state: Arc<GlobalState>) -> Self {
Client {
global_state,
ws,
channel: None
}
}
pub async fn run(&mut self) {
loop {
match &mut self.channel {
Some(channel) => {
select! {
msg = channel.rx.recv().fuse() =>
self.handle_server_msg(msg.unwrap()).await,
msg = self.ws.next().fuse() =>
self.handle_client_msg(msg.unwrap()).await,
};
}
None => {
let msg = self.ws.next().await;
self.handle_client_msg(msg.unwrap()).await;
}
}
}
}
async fn handle_client_msg(&mut self, msg: Message) {
match msg.command.as_str() {
"HOST" => {
let room_code = self.global_state.code_generator.lock().await.generate();
let mut game_controller = GameController::default();
let (client_channel, server_channel) = channel_pair();
self.channel = Some(client_channel);
game_controller.channels.push(server_channel);
let game_controller = Arc::new(Mutex::new(game_controller));
self.global_state.rooms.lock().await.insert(room_code.clone(), Arc::clone(&game_controller));
tokio::spawn(async move {game_loop(game_controller)});
self.ws.send(msg!(ROOM_CODE, room_code)).await.unwrap();
}
"JOIN" => {
let room_code = &msg.args[0];
let rooms = self.global_state.rooms.lock().await;
let room = rooms.get(room_code);
match room {
Some(room) => {
let mut room = room.lock().await;
let (client_channel, server_channel) = channel_pair();
self.channel = Some(client_channel);
room.channels.push(server_channel);
self.ws.send(msg!(JOIN_OK)).await.unwrap();
}
None => {
self.ws.send(msg!(JOIN_INVALID)).await.unwrap();
}
}
}
_ => if let Some(channel) = &self.channel {
// Forward message to the server
channel.tx.send(msg).await.unwrap();
}
}
}
async fn handle_server_msg(&mut self, _msg: Message) {
todo!();
}
}
fn game_loop(_gc: Arc<Mutex<GameController>>) {
todo!();
}
use std::sync::Arc;
use futures::{select, FutureExt};
use tokio::sync::Mutex;
use hexland_server::{
channel_pair,
message::{Message, MessageWebSocket},
msg, Channel, GameController, GlobalState,
};
pub struct Client {
global_state: Arc<GlobalState>,
ws: MessageWebSocket,
channel: Option<Channel>,
}
impl Client {
pub fn new(ws: MessageWebSocket, global_state: Arc<GlobalState>) -> Self {
Client {
global_state,
ws,
channel: None,
}
}
pub async fn run(&mut self) {
loop {
match &mut self.channel {
Some(channel) => {
select! {
msg = channel.rx.recv().fuse() =>
self.handle_server_msg(msg.unwrap()).await,
msg = self.ws.next().fuse() =>
self.handle_client_msg(msg.unwrap()).await,
};
}
None => {
let msg = self.ws.next().await;
self.handle_client_msg(msg.unwrap()).await;
}
}
}
}
async fn handle_client_msg(&mut self, msg: Message) {
match msg.command.as_str() {
"HOST" => {
let room_code = self.global_state.code_generator.lock().await.generate();
let mut game_controller = GameController::default();
let (client_channel, server_channel) = channel_pair();
self.channel = Some(client_channel);
game_controller.channels.push(server_channel);
let game_controller = Arc::new(Mutex::new(game_controller));
self.global_state
.rooms
.lock()
.await
.insert(room_code.clone(), Arc::clone(&game_controller));
tokio::spawn(async move { game_loop(game_controller) });
self.ws.send(msg!(ROOM_CODE, room_code)).await.unwrap();
}
"JOIN" => {
let room_code = &msg.args[0];
let rooms = self.global_state.rooms.lock().await;
let room = rooms.get(room_code);
match room {
Some(room) => {
let mut room = room.lock().await;
let (client_channel, server_channel) = channel_pair();
self.channel = Some(client_channel);
room.channels.push(server_channel);
self.ws.send(msg!(JOIN_OK)).await.unwrap();
}
None => {
self.ws.send(msg!(JOIN_INVALID)).await.unwrap();
}
}
}
_ => {
if let Some(channel) = &self.channel {
// Forward message to the server
channel.tx.send(msg).await.unwrap();
}
}
}
}
async fn handle_server_msg(&mut self, _msg: Message) {
todo!();
}
}
fn game_loop(_gc: Arc<Mutex<GameController>>) {
todo!();
}

View File

@ -1,42 +1,39 @@
use rand::RngCore;
use sha2::{Sha256, Digest};
pub struct CodeGenerator {
counter: u64,
salt: [u8; 32],
}
impl CodeGenerator {
pub fn generate(&mut self) -> String {
let count = self.counter;
self.counter += 1;
let mut hasher = Sha256::new();
hasher.update(self.salt);
hasher.update(count.to_be_bytes());
format!("{:x}", hasher.finalize())[..6].to_string()
}
}
impl Default for CodeGenerator {
fn default() -> Self {
let mut salt = [0; 32];
rand::thread_rng().fill_bytes(&mut salt);
CodeGenerator {
counter: 0,
salt,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_generate() {
let code = CodeGenerator::default().generate();
assert_eq!(code.len(), 6);
}
}
use rand::RngCore;
use sha2::{Digest, Sha256};
pub struct CodeGenerator {
counter: u64,
salt: [u8; 32],
}
impl CodeGenerator {
pub fn generate(&mut self) -> String {
let count = self.counter;
self.counter += 1;
let mut hasher = Sha256::new();
hasher.update(self.salt);
hasher.update(count.to_be_bytes());
format!("{:x}", hasher.finalize())[..6].to_string()
}
}
impl Default for CodeGenerator {
fn default() -> Self {
let mut salt = [0; 32];
rand::thread_rng().fill_bytes(&mut salt);
CodeGenerator { counter: 0, salt }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_generate() {
let code = CodeGenerator::default().generate();
assert_eq!(code.len(), 6);
}
}

View File

@ -1,36 +1,30 @@
use std::{
collections::HashMap,
sync::Arc,
};
use tokio::sync::{Mutex, mpsc};
pub mod message;
use message::{Message};
mod code_generator;
use code_generator::CodeGenerator;
#[derive(Default)]
pub struct GlobalState {
pub code_generator: Arc<Mutex<CodeGenerator>>,
pub rooms: Arc<Mutex<HashMap<String, Arc<Mutex<GameController>>>>>,
}
pub struct Channel {
pub tx: mpsc::Sender<Message>,
pub rx: mpsc::Receiver<Message>,
}
pub fn channel_pair() -> (Channel, Channel) {
let (atx, brx) = mpsc::channel(32);
let (btx, arx) = mpsc::channel(32);
(
Channel { tx: atx, rx: arx },
Channel { tx: btx, rx: brx },
)
}
#[derive(Default)]
pub struct GameController {
pub channels: Vec<Channel>,
}
use std::{collections::HashMap, sync::Arc};
use tokio::sync::{mpsc, Mutex};
pub mod message;
use message::Message;
mod code_generator;
use code_generator::CodeGenerator;
#[derive(Default)]
pub struct GlobalState {
pub code_generator: Arc<Mutex<CodeGenerator>>,
pub rooms: Arc<Mutex<HashMap<String, Arc<Mutex<GameController>>>>>,
}
pub struct Channel {
pub tx: mpsc::Sender<Message>,
pub rx: mpsc::Receiver<Message>,
}
pub fn channel_pair() -> (Channel, Channel) {
let (atx, brx) = mpsc::channel(32);
let (btx, arx) = mpsc::channel(32);
(Channel { tx: atx, rx: arx }, Channel { tx: btx, rx: brx })
}
#[derive(Default)]
pub struct GameController {
pub channels: Vec<Channel>,
}

View File

@ -1,14 +1,9 @@
use std::{
sync::Arc,
io::Error as IoError,
};
use std::{io::Error as IoError, sync::Arc};
use tokio::{
net::{TcpListener},
};
use tokio::net::TcpListener;
use hexland_server::GlobalState;
use hexland_server::message::MessageWebSocket;
use hexland_server::GlobalState;
mod client;
use client::Client;
@ -27,9 +22,11 @@ async fn main() -> Result<(), IoError> {
let global_state = Arc::clone(&global_state);
tokio::spawn(async move {
// Upgrade to a WS connection
let ws = MessageWebSocket(tokio_tungstenite::accept_async(stream)
.await
.expect("Could not establish connection"));
let ws = MessageWebSocket(
tokio_tungstenite::accept_async(stream)
.await
.expect("Could not establish connection"),
);
println!("Connected to {}", addr);
Client::new(ws, global_state).run().await;
});

View File

@ -1,131 +1,130 @@
use std::convert::{From, TryFrom};
use tokio::net::TcpStream;
use tokio_tungstenite::{
WebSocketStream,
tungstenite::Message as WsMessage,
};
use futures::{StreamExt, SinkExt};
use lazy_static::lazy_static;
#[derive(PartialEq, Debug)]
pub struct Message {
pub command: String,
pub args: Vec<String>,
}
pub type Result<T> = std::result::Result<T, Error>;
#[repr(u8)]
#[derive(PartialEq, Debug)]
pub enum Error {
BadParse,
NonText,
Unknown,
}
impl Message {
pub fn parse(text: String) -> Result<Message> {
lazy_static! {
static ref RE: regex::Regex = regex::Regex::new(r"^([A-Z_]+):\s*(.*)").unwrap();
}
match RE.captures(text.as_str()) {
Some(captures) => {
if captures.len() < 3 {
Err(Error::BadParse)
} else {
let command = captures.get(1).unwrap().as_str().to_string();
let args = captures.get(2).unwrap().as_str()
.split(',')
.map(|s| s.trim().to_string())
.collect();
Ok(Message { command, args })
}
}
None => Err(Error::BadParse),
}
}
}
impl TryFrom<WsMessage> for Message {
type Error = Error;
fn try_from(ws_message: WsMessage) -> Result<Self> {
let text = match ws_message {
WsMessage::Text(text) => text,
_ => return Err(Error::NonText)
};
Message::parse(text)
}
}
impl From<Message> for WsMessage {
fn from(message: Message) -> Self {
WsMessage::Text(message.to_string())
}
}
pub struct MessageWebSocket(pub WebSocketStream<TcpStream>);
impl MessageWebSocket {
pub async fn next(&mut self) -> Result<Message> {
if let Some(Ok(msg)) = self.0.next().await {
msg.try_into()
} else {
Err(Error::Unknown)
}
}
pub async fn send(&mut self, msg: Message) -> Result<()> {
if self.0.send(msg.into()).await.is_err() {
Err(Error::Unknown)
} else {
Ok(())
}
}
}
#[macro_export]
macro_rules! msg {
( $command:ident) => {
{
let command = stringify!($command).to_string();
let args = vec![];
Message { command, args }
}
};
( $command:ident, $( $arg:expr ),*) => {
{
let command = stringify!($command).to_string();
let args = vec![$($arg.to_string()),*];
Message { command, args }
}
};
}
impl std::fmt::Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
if self.args.is_empty() {
write!(f, "{}:", self.command)
} else {
write!(f, "{}: {}", self.command, self.args.as_slice().join(", "))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse() -> Result<()> {
let text = "COMMAND: arg1, arg2";
let msg = Message::parse(text.to_string())?;
assert_eq!(msg!(COMMAND, "arg1", "arg2"), msg);
Ok(())
}
#[test]
fn test_to_string() {
let msg = msg!(COMMAND, "arg1", "arg2");
assert_eq!(msg.to_string(), "COMMAND: arg1, arg2".to_string());
}
}
use std::convert::{From, TryFrom};
use futures::{SinkExt, StreamExt};
use lazy_static::lazy_static;
use tokio::net::TcpStream;
use tokio_tungstenite::{tungstenite::Message as WsMessage, WebSocketStream};
#[derive(PartialEq, Debug)]
pub struct Message {
pub command: String,
pub args: Vec<String>,
}
pub type Result<T> = std::result::Result<T, Error>;
#[repr(u8)]
#[derive(PartialEq, Debug)]
pub enum Error {
BadParse,
NonText,
Unknown,
}
impl Message {
pub fn parse(text: String) -> Result<Message> {
lazy_static! {
static ref RE: regex::Regex = regex::Regex::new(r"^([A-Z_]+):\s*(.*)").unwrap();
}
match RE.captures(text.as_str()) {
Some(captures) => {
if captures.len() < 3 {
Err(Error::BadParse)
} else {
let command = captures.get(1).unwrap().as_str().to_string();
let args = captures
.get(2)
.unwrap()
.as_str()
.split(',')
.map(|s| s.trim().to_string())
.collect();
Ok(Message { command, args })
}
}
None => Err(Error::BadParse),
}
}
}
impl TryFrom<WsMessage> for Message {
type Error = Error;
fn try_from(ws_message: WsMessage) -> Result<Self> {
let text = match ws_message {
WsMessage::Text(text) => text,
_ => return Err(Error::NonText),
};
Message::parse(text)
}
}
impl From<Message> for WsMessage {
fn from(message: Message) -> Self {
WsMessage::Text(message.to_string())
}
}
pub struct MessageWebSocket(pub WebSocketStream<TcpStream>);
impl MessageWebSocket {
pub async fn next(&mut self) -> Result<Message> {
if let Some(Ok(msg)) = self.0.next().await {
msg.try_into()
} else {
Err(Error::Unknown)
}
}
pub async fn send(&mut self, msg: Message) -> Result<()> {
if self.0.send(msg.into()).await.is_err() {
Err(Error::Unknown)
} else {
Ok(())
}
}
}
#[macro_export]
macro_rules! msg {
( $command:ident) => {
{
let command = stringify!($command).to_string();
let args = vec![];
Message { command, args }
}
};
( $command:ident, $( $arg:expr ),*) => {
{
let command = stringify!($command).to_string();
let args = vec![$($arg.to_string()),*];
Message { command, args }
}
};
}
impl std::fmt::Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
if self.args.is_empty() {
write!(f, "{}:", self.command)
} else {
write!(f, "{}: {}", self.command, self.args.as_slice().join(", "))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse() -> Result<()> {
let text = "COMMAND: arg1, arg2";
let msg = Message::parse(text.to_string())?;
assert_eq!(msg!(COMMAND, "arg1", "arg2"), msg);
Ok(())
}
#[test]
fn test_to_string() {
let msg = msg!(COMMAND, "arg1", "arg2");
assert_eq!(msg.to_string(), "COMMAND: arg1, arg2".to_string());
}
}