online system
This commit is contained in:
@@ -7,6 +7,7 @@ pub struct Player {
|
||||
pub cloak: String,
|
||||
pub hats: Vec<String>,
|
||||
pub hat: String,
|
||||
pub online: bool,
|
||||
}
|
||||
|
||||
pub struct Database {
|
||||
|
||||
+4
-1
@@ -32,7 +32,10 @@ fn main() -> std::io::Result<()> {
|
||||
loop {
|
||||
let mut request_string = String::new();
|
||||
match reader.read_line(&mut request_string).unwrap() {
|
||||
0 => break,
|
||||
0 => {
|
||||
methods::player::logout(&session).unwrap();
|
||||
println!("[MOJANG] {} went offline", session.local_player.name);
|
||||
}
|
||||
_ => {
|
||||
let (method, params) = parser::parse(&request_string).unwrap();
|
||||
let response = session.handle_request(&method, ¶ms);
|
||||
|
||||
+51
-37
@@ -1,4 +1,4 @@
|
||||
mod player;
|
||||
pub mod player;
|
||||
mod set_cloak;
|
||||
mod set_hat;
|
||||
|
||||
@@ -6,10 +6,9 @@ use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, BufReader},
|
||||
net::TcpStream,
|
||||
sync::Arc,
|
||||
sync::{mpsc, Arc},
|
||||
};
|
||||
|
||||
use player::create;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@@ -34,42 +33,57 @@ impl Session {
|
||||
reader: &mut BufReader<TcpStream>,
|
||||
database: Arc<crate::database::Database>,
|
||||
) -> Result<(Self, Response)> {
|
||||
// Read the session token
|
||||
let mut session_token = String::new();
|
||||
reader
|
||||
.read_line(&mut session_token)
|
||||
let (token_send, token_recv) =
|
||||
mpsc::channel::<std::result::Result<String, crate::response::Error>>();
|
||||
|
||||
let reader_clone = reader
|
||||
.get_ref()
|
||||
.try_clone()
|
||||
.map_err(|_| crate::response::Error::InvalidHandshake)?;
|
||||
|
||||
// Validate session id
|
||||
let response = minreq::get("https://api.minecraftservices.com/minecraft/profile")
|
||||
.with_header("Authorization", &format!("Bearer {session_token}"))
|
||||
.send()
|
||||
.map_err(|_| crate::response::Error::InvalidSession)?;
|
||||
|
||||
// If the session is invalid, return an error
|
||||
if response.status_code != 200 {
|
||||
return Err(crate::response::Error::InvalidSession);
|
||||
}
|
||||
|
||||
// Parse the player data
|
||||
let local_player: LocalPlayer = response
|
||||
.json()
|
||||
.map_err(|_| crate::response::Error::InvalidSession)?;
|
||||
|
||||
let session = Self {
|
||||
session_token,
|
||||
database,
|
||||
local_player,
|
||||
};
|
||||
|
||||
// Capture the player
|
||||
match player::login(&session) {
|
||||
Ok(player) => Ok((session, player)),
|
||||
Err(crate::response::Error::DatabaseError) => {
|
||||
let player = create(&session)?;
|
||||
Ok((session, player))
|
||||
std::thread::spawn(move || {
|
||||
let mut reader = BufReader::new(reader_clone);
|
||||
let mut session_token = String::new();
|
||||
if reader.read_line(&mut session_token).is_ok() {
|
||||
token_send.send(Ok(session_token))
|
||||
} else {
|
||||
token_send.send(Err(crate::response::Error::InvalidHandshake))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
});
|
||||
|
||||
match token_recv.recv_timeout(std::time::Duration::from_secs(20)) {
|
||||
Ok(Ok(session_token)) => {
|
||||
// Validate session id
|
||||
let response = minreq::get("https://api.minecraftservices.com/minecraft/profile")
|
||||
.with_header("Authorization", &format!("Bearer {session_token}"))
|
||||
.send()
|
||||
.map_err(|_| crate::response::Error::InvalidSession)?;
|
||||
|
||||
// If the session is invalid, return an error
|
||||
if response.status_code != 200 {
|
||||
return Err(crate::response::Error::InvalidSession);
|
||||
}
|
||||
|
||||
// Parse the player data
|
||||
let local_player: LocalPlayer = response
|
||||
.json()
|
||||
.map_err(|_| crate::response::Error::InvalidSession)?;
|
||||
|
||||
println!("[MOJANG] {} successfully logged on", &local_player.name);
|
||||
|
||||
let session = Self {
|
||||
session_token,
|
||||
database,
|
||||
local_player,
|
||||
};
|
||||
|
||||
// Capture the player
|
||||
match player::login(&session) {
|
||||
Ok(player) => Ok((session, player)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
Err(mpsc::RecvTimeoutError::Timeout) => Err(crate::response::Error::Timeout),
|
||||
_ => Err(crate::response::Error::InvalidHandshake),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+49
-34
@@ -16,22 +16,27 @@ pub fn player(session: &Session, uuid: String) -> Result {
|
||||
.run()?;
|
||||
|
||||
// Check if there's a document in the cursor
|
||||
match cursor.next() {
|
||||
Ok(match cursor.next() {
|
||||
Some(Ok(player)) => {
|
||||
// Player exists, deserialize and return their data
|
||||
Ok(Response::Player(crate::response::PlayerResponse::Player {
|
||||
cloak: player.cloak,
|
||||
uuid,
|
||||
cloaks: player.cloaks,
|
||||
hats: player.hats,
|
||||
hat: player.hat,
|
||||
}))
|
||||
if player.online {
|
||||
Response::Player(crate::response::PlayerResponse::Player {
|
||||
cloak: player.cloak,
|
||||
uuid,
|
||||
cloaks: player.cloaks,
|
||||
hats: player.hats,
|
||||
hat: player.hat,
|
||||
})
|
||||
} else {
|
||||
crate::response::Response::Player(crate::response::PlayerResponse::NonSaturnPlayer(
|
||||
uuid,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
_ => Ok(crate::response::Response::Player(
|
||||
crate::response::PlayerResponse::NonSaturnPlayer(uuid),
|
||||
_ => crate::response::Response::Player(crate::response::PlayerResponse::NonSaturnPlayer(
|
||||
uuid,
|
||||
)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(session: &Session) -> Result {
|
||||
@@ -43,6 +48,7 @@ pub fn create(session: &Session) -> Result {
|
||||
cloak: "".to_string(),
|
||||
hats: Vec::new(),
|
||||
hat: String::new(),
|
||||
online: true,
|
||||
};
|
||||
|
||||
session.database.players.insert_one(player.clone()).run()?;
|
||||
@@ -68,7 +74,18 @@ pub fn login(session: &Session) -> Result {
|
||||
|
||||
// Check if there's a document in the cursor
|
||||
match cursor.next() {
|
||||
Some(Ok(player)) => {
|
||||
Some(Ok(mut player)) => {
|
||||
// Update player's online status
|
||||
player.online = true;
|
||||
session
|
||||
.database
|
||||
.players
|
||||
.update_one(
|
||||
doc! { "uuid": uuid.clone() },
|
||||
doc! { "$set": { "online": true } },
|
||||
)
|
||||
.run()?;
|
||||
|
||||
// Player exists, deserialize and return their data
|
||||
Ok(Response::Player(crate::response::PlayerResponse::Player {
|
||||
cloak: player.cloak,
|
||||
@@ -80,26 +97,24 @@ pub fn login(session: &Session) -> Result {
|
||||
}
|
||||
|
||||
// No document found or deserialization error
|
||||
_ => {
|
||||
let player = Player {
|
||||
uuid: uuid.clone(),
|
||||
cloaks: Vec::new(),
|
||||
cloak: "".to_string(),
|
||||
hats: Vec::new(),
|
||||
hat: String::new(),
|
||||
};
|
||||
|
||||
// Insert the new player
|
||||
session.database.players.insert_one(player.clone()).run()?;
|
||||
|
||||
// Return the newly created player's data
|
||||
Ok(Response::Player(crate::response::PlayerResponse::Player {
|
||||
cloak: player.cloak,
|
||||
uuid,
|
||||
cloaks: player.cloaks,
|
||||
hats: player.hats,
|
||||
hat: player.hat,
|
||||
}))
|
||||
}
|
||||
_ => create(session),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn logout(session: &Session) -> Result {
|
||||
let uuid = session.local_player.id.clone();
|
||||
|
||||
// Update player's online status to false
|
||||
session
|
||||
.database
|
||||
.players
|
||||
.update_one(
|
||||
doc! { "uuid": uuid.clone() },
|
||||
doc! { "$set": { "online": false } },
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(Response::Player(
|
||||
crate::response::PlayerResponse::NonSaturnPlayer(uuid),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ pub enum Error {
|
||||
InvalidHandshake,
|
||||
DatabaseError,
|
||||
SomethingWentWrong,
|
||||
Timeout,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
@@ -83,6 +84,7 @@ impl std::fmt::Display for Error {
|
||||
Error::InvalidHandshake => write!(f, "Invalid handshake"),
|
||||
Error::DatabaseError => write!(f, "Database error"),
|
||||
Error::SomethingWentWrong => write!(f, "Something went wrong"),
|
||||
Error::Timeout => write!(f, "Timeout"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user