rewrite
This commit is contained in:
@@ -1,22 +1,28 @@
|
|||||||
# SaturnClient API
|
# SaturnClient API
|
||||||
|
|
||||||
The api for AuraClient which is a Minecraft mod Client
|
The api for AuraClient which is a Minecraft mod Client
|
||||||
|
|
||||||
|
# Handshake
|
||||||
|
In order to communicate with the server, you will have to make a handshake, here is how
|
||||||
|
```
|
||||||
|
<MOJANG-SESSION-TOKEN>
|
||||||
|
```
|
||||||
|
The session token is stored on your minecraft client when it communicates with Mojang servers, as you might understand, this token is a private token used for authentication with Mojang servers, Why do we need it? Because our server needs to understand that whoever logs in with SaturnClient is you and when you make changes in your client, the changes get synced with others, Example: Changing Cloak.
|
||||||
|
|
||||||
# Protocol base
|
# Protocol base
|
||||||
All whitespace is used
|
Every request should be only one line
|
||||||
|
|
||||||
```
|
```
|
||||||
method
|
method@key1=value1@key2=value2
|
||||||
@key=value
|
|
||||||
```
|
|
||||||
For private requests (requires microsoft session tokens)
|
|
||||||
```
|
|
||||||
@SessionToken=<session-token>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# Example method
|
# Error handling
|
||||||
|
request
|
||||||
```
|
```
|
||||||
ping
|
invalid-method
|
||||||
```
|
```
|
||||||
- Response
|
response
|
||||||
```
|
```
|
||||||
pong
|
!Invalid method
|
||||||
```
|
```
|
||||||
|
On a response `!` means it's an error.
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
pub const CLOAKS: &[&str] = &["glitch"];
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
pub struct Player {
|
||||||
|
pub uuid: String,
|
||||||
|
pub cloaks: Vec<String>,
|
||||||
|
pub cloak: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Database {
|
||||||
|
pub players: mongodb::sync::Collection<Player>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Database {
|
||||||
|
pub fn new(client: &mongodb::sync::Client) -> Self {
|
||||||
|
let db = client.database("saturn");
|
||||||
|
Self {
|
||||||
|
players: db.collection("players"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
use mongodb::sync::{Client, Collection};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub enum Response {
|
|
||||||
Pong,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Response {
|
|
||||||
pub fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Response::Pong => "pong".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Player {
|
|
||||||
pub uuid: String,
|
|
||||||
pub cloaks: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Database {
|
|
||||||
pub players: Collection<Player>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Database {
|
|
||||||
pub fn new(client: &Client) -> Self {
|
|
||||||
let db = client.database("saturn");
|
|
||||||
Self {
|
|
||||||
players: db.collection("players"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+31
-55
@@ -1,68 +1,44 @@
|
|||||||
pub mod assets;
|
use std::{
|
||||||
pub mod io;
|
io::{BufRead, BufReader, Write},
|
||||||
|
net::TcpListener,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod database;
|
||||||
pub mod methods;
|
pub mod methods;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod response;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::net::{TcpListener, TcpStream};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use io::Database;
|
|
||||||
use methods::handle_request;
|
|
||||||
use mongodb::sync::Client;
|
|
||||||
|
|
||||||
const MONGO_URI: &str = "mongodb://admin:admin@localhost/";
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let client = Client::with_uri_str(MONGO_URI).unwrap();
|
let client = mongodb::sync::Client::with_uri_str("mongodb://admin:admin@localhost/").unwrap();
|
||||||
let database = Arc::new(Database::new(&client));
|
let database = Arc::new(database::Database::new(&client));
|
||||||
let listener = TcpListener::bind("127.0.0.1:8080")?;
|
|
||||||
|
|
||||||
println!("Server listening on port 8080");
|
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
println!("New connection");
|
||||||
Ok(stream) => {
|
|
||||||
println!("New connection: {}", stream.peer_addr().unwrap());
|
|
||||||
thread::spawn({
|
|
||||||
let database = Arc::clone(&database);
|
let database = Arc::clone(&database);
|
||||||
move || handle_client(stream, database)
|
|
||||||
|
std::thread::spawn({
|
||||||
|
move || {
|
||||||
|
let mut stream = stream.unwrap();
|
||||||
|
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||||
|
let session = methods::Session::new(&mut reader, database).unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut request_string = String::new();
|
||||||
|
match reader.read_line(&mut request_string).unwrap() {
|
||||||
|
0 => break,
|
||||||
|
_ => {
|
||||||
|
let (method, params) = parser::parse(&request_string).unwrap();
|
||||||
|
let response = session.handle_request(&method, ¶ms);
|
||||||
|
stream.write_all(response.to_string().as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => eprintln!("Connection failed: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_client(mut stream: TcpStream, database: Arc<Database>) {
|
|
||||||
let mut buffer = [0; 512];
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match stream.read(&mut buffer) {
|
|
||||||
Ok(0) => break,
|
|
||||||
Ok(n) => {
|
|
||||||
let recv = String::from_utf8_lossy(&buffer[..n]).to_string();
|
|
||||||
match parser::parse(&recv) {
|
|
||||||
Ok((method, params)) => {
|
|
||||||
match handle_request(Arc::clone(&database), method, params) {
|
|
||||||
Ok(response) => {
|
|
||||||
stream.write_all(response.to_string().as_bytes()).unwrap()
|
|
||||||
}
|
|
||||||
Err(e) => eprintln!("Error handling request: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => eprintln!("Error parsing request: {}", e),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error reading from client: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Client disconnected");
|
|
||||||
}
|
|
||||||
|
|||||||
+34
-10
@@ -1,14 +1,38 @@
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{self, BufRead, BufReader},
|
||||||
|
net::TcpStream,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::io::{Database, Response};
|
pub struct Session {
|
||||||
|
pub session_id: String,
|
||||||
|
pub database: Arc<crate::database::Database>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_request(
|
impl Session {
|
||||||
database: Arc<Database>,
|
pub fn new(
|
||||||
method: String,
|
reader: &mut BufReader<TcpStream>,
|
||||||
params: HashMap<String, String>,
|
database: Arc<crate::database::Database>,
|
||||||
) -> Result<Response, String> {
|
) -> io::Result<Self> {
|
||||||
match method.as_str() {
|
let mut session_id = String::new();
|
||||||
"ping" => Ok(Response::Pong),
|
reader.read_line(&mut session_id)?;
|
||||||
_ => Err("Invalid request: ".to_string()),
|
|
||||||
|
Ok(Self {
|
||||||
|
session_id,
|
||||||
|
database,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_request(
|
||||||
|
&self,
|
||||||
|
method: &str,
|
||||||
|
params: &HashMap<String, String>,
|
||||||
|
) -> crate::response::Response {
|
||||||
|
match method {
|
||||||
|
"ping" => crate::response::Response::Pong,
|
||||||
|
|
||||||
|
_ => crate::response::Response::Error(crate::response::Error::InvalidRequest),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ impl ParamMap for HashMap<String, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(s: &str) -> Result<(String, HashMap<String, String>), String> {
|
pub fn parse(s: &str) -> std::io::Result<(String, HashMap<String, String>)> {
|
||||||
let mut parts = s.split("@");
|
let mut parts = s.split("@");
|
||||||
|
|
||||||
let method = parts.next().unwrap().trim().to_lowercase();
|
let method = parts.next().unwrap().trim().to_lowercase();
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Response {
|
||||||
|
Pong,
|
||||||
|
Error(Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Response {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Response::Pong => write!(f, "Pong"),
|
||||||
|
Response::Error(error) => write!(f, "!{}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidRequest,
|
||||||
|
InvalidMethod,
|
||||||
|
InvalidParameter,
|
||||||
|
ParameterNotFound,
|
||||||
|
InvalidSessionToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::InvalidRequest => write!(f, "Invalid request"),
|
||||||
|
Error::InvalidMethod => write!(f, "Invalid method"),
|
||||||
|
Error::InvalidParameter => write!(f, "Invalid parameter"),
|
||||||
|
Error::ParameterNotFound => write!(f, "Parameter not found"),
|
||||||
|
Error::InvalidSessionToken => write!(f, "Invalid session token"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user