Compare commits
3 Commits
4046f56191
...
launcher_v
| Author | SHA256 | Date | |
|---|---|---|---|
|
50cc39c6a2
|
|||
|
d47d5f44b1
|
|||
|
9e984d2aa8
|
@@ -7,7 +7,7 @@ use crate::auth::{
|
||||
use crate::common::Empty;
|
||||
use crate::database_client::{DatabaseClient, DatabaseClientTrait};
|
||||
use crate::session::session_service_client::SessionServiceClient;
|
||||
use crate::session::{GetSessionRequest};
|
||||
use crate::session::{GetSessionRequest, RefreshSessionRequest};
|
||||
use crate::users::{hash_password, verify_user};
|
||||
use chrono::{Duration, Utc};
|
||||
use rand::Rng;
|
||||
@@ -78,7 +78,7 @@ impl AuthService for MyAuthService {
|
||||
.session_client
|
||||
.as_ref()
|
||||
.clone()
|
||||
.get_session(GetSessionRequest {
|
||||
.refresh_session(RefreshSessionRequest {
|
||||
session_id: req.session_id,
|
||||
})
|
||||
.await;
|
||||
@@ -87,7 +87,7 @@ impl AuthService for MyAuthService {
|
||||
Ok(res) => {
|
||||
let res = res.into_inner();
|
||||
debug!("Session valid: {:?}", res);
|
||||
Ok(Response::new(RefreshSessionResponse { valid: true }))
|
||||
Ok(Response::new(RefreshSessionResponse { valid: res.valid }))
|
||||
}
|
||||
Err(_) => {
|
||||
debug!("Unable to refresh session");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::session::{session_service_client::SessionServiceClient, GetSessionRequest, GetSessionResponse};
|
||||
use crate::session::{session_service_client::SessionServiceClient, GetSessionRequest, GetSessionResponse, RefreshSessionRequest, RefreshSessionResponse};
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::error::Error;
|
||||
@@ -11,6 +11,10 @@ pub trait SessionClientTrait: Sized {
|
||||
&mut self,
|
||||
session_id: String,
|
||||
) -> Result<GetSessionResponse, Box<dyn std::error::Error>>;
|
||||
async fn refresh_session(
|
||||
&mut self,
|
||||
session_id: String,
|
||||
) -> Result<RefreshSessionResponse, Box<dyn std::error::Error>>;
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct SessionClient {
|
||||
@@ -31,4 +35,11 @@ impl SessionClientTrait for SessionClient {
|
||||
let response = self.client.get_session(request).await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
async fn refresh_session(&mut self, session_id: String) -> Result<RefreshSessionResponse, Box<dyn Error>> {
|
||||
let request = tonic::Request::new(RefreshSessionRequest {
|
||||
session_id,
|
||||
});
|
||||
let response = self.client.refresh_session(request).await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::grpc::database_service::MyDatabaseService;
|
||||
use crate::grpc::session_service_server::SessionService;
|
||||
use tonic::{Request, Response, Status};
|
||||
use tracing::debug;
|
||||
use crate::grpc::{GetSessionRequest, GetSessionResponse};
|
||||
use crate::grpc::{GetSessionRequest, GetSessionResponse, RefreshSessionRequest, RefreshSessionResponse};
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl SessionService for MyDatabaseService {
|
||||
@@ -22,4 +22,19 @@ impl SessionService for MyDatabaseService {
|
||||
user_id: session.user_id,
|
||||
}))
|
||||
}
|
||||
|
||||
async fn refresh_session(&self, request: Request<RefreshSessionRequest>) -> Result<Response<RefreshSessionResponse>, Status> {
|
||||
let req = request.into_inner();
|
||||
debug!("get_session: {:?}", req);
|
||||
|
||||
let session = self.db.session_repo.refresh_session(&req.session_id).await
|
||||
.map_err(|_| Status::not_found("Session not found"))?;
|
||||
|
||||
let valid = true;
|
||||
|
||||
debug!("session: {:?}", session);
|
||||
Ok(Response::new(RefreshSessionResponse {
|
||||
valid
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,34 @@ impl SessionRepository {
|
||||
debug!("session: {:?}", session);
|
||||
|
||||
self.cache.lock().await
|
||||
.set(&cache_key, &session, 0).await
|
||||
.set(&cache_key, &session, 300).await
|
||||
.map_err(|_| sqlx::Error::RowNotFound)?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub async fn refresh_session(&self, session_id: &str) -> Result<Session, sqlx::Error> {
|
||||
let cache_key = format!("session:{}", session_id);
|
||||
|
||||
if let Some(session) = self.cache.lock().await
|
||||
.get::<Session>(&cache_key).await
|
||||
.map_err(|_| sqlx::Error::RowNotFound)?
|
||||
{
|
||||
self.cache.lock().await
|
||||
.refresh(&cache_key, 300).await
|
||||
.map_err(|_| sqlx::Error::RowNotFound)?;
|
||||
return Ok(session);
|
||||
}
|
||||
|
||||
// Check to make sure the session is still valid
|
||||
let session = sqlx::query_as::<_, Session>(
|
||||
"SELECT id, \"userId\" as user_id FROM session WHERE id = $1",
|
||||
)
|
||||
.bind(session_id)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
|
||||
self.cache.lock().await
|
||||
.set(&cache_key, &session, 300).await
|
||||
.map_err(|_| sqlx::Error::RowNotFound)?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
[package]
|
||||
name = "launcher"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
shell-escape = "0.1.5"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "chrono"] }
|
||||
url = "2.5.4"
|
||||
clap = { version = "4.5.23", features = ["derive"] }
|
||||
reqwest = { version = "0.12.15", features = ["json"] }
|
||||
serde_json = "1.0.140"
|
||||
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros"] }
|
||||
@@ -1,17 +1,22 @@
|
||||
mod launcher;
|
||||
mod version;
|
||||
|
||||
use crate::version::version_check;
|
||||
use std::process::Command;
|
||||
use std::{env, io};
|
||||
use tracing::{debug, error, info, Level};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Commands {
|
||||
Launch,
|
||||
Update,
|
||||
Check,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let verbose = 0;
|
||||
let verbose = match verbose {
|
||||
0 => Level::INFO,
|
||||
@@ -20,7 +25,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
};
|
||||
|
||||
// Set our logging level
|
||||
tracing_subscriber::fmt().with_max_level(verbose).init();
|
||||
let filter = EnvFilter::try_new(format!("launcher=debug"))
|
||||
.unwrap_or_else(|_| EnvFilter::new(format!("launcher=info")));
|
||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() < 2 {
|
||||
@@ -42,6 +49,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let action = match method {
|
||||
"launch" => Commands::Launch,
|
||||
"update" => Commands::Update,
|
||||
"version" => Commands::Check,
|
||||
other => return Err(format!("Unknown method: {}", other).into()),
|
||||
};
|
||||
|
||||
@@ -54,6 +62,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
error!("Update action not implemented");
|
||||
return Err("Update action not implemented".into());
|
||||
}
|
||||
Commands::Check => {
|
||||
version_check(uri.to_string()).await;
|
||||
wait_for_keypress();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
87
launcher/src/version.rs
Normal file
87
launcher/src/version.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use crate::format_shell_command;
|
||||
use crate::wait_for_keypress;
|
||||
use reqwest::Client;
|
||||
use serde_json::json;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
use std::process::{Command, Stdio};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use url::Url;
|
||||
|
||||
static APP_USER_AGENT: &str = concat!(
|
||||
"osirose-",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
);
|
||||
|
||||
async fn send_version_to_browser(callback_url: Option<String>, client_version: &str) {
|
||||
if let Some(url) = callback_url {
|
||||
let payload = json!({
|
||||
"version": client_version,
|
||||
});
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.user_agent(APP_USER_AGENT)
|
||||
.build();
|
||||
|
||||
if (client.is_err()) {
|
||||
error!("Unable to build info client");
|
||||
return;
|
||||
}
|
||||
|
||||
match client.unwrap().post(url.clone()).json(&payload).send().await {
|
||||
Ok(response) => {
|
||||
if response.status().is_success() {
|
||||
info!("Successfully sent version info to {url} URL!");
|
||||
} else {
|
||||
error!("Failed to send data. Status: {}", response.status());
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error sending POST request: {}", err);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
error!("Missing callback URL");
|
||||
}
|
||||
|
||||
fn parse_url(url: &str) -> Option<String> {
|
||||
if let parsed_url = Url::parse(url).ok()? {
|
||||
return Some(parsed_url.to_string());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn check_client_version() -> String {
|
||||
// This is temp until I can get an actual version check
|
||||
"1.0.0".to_string()
|
||||
}
|
||||
|
||||
pub(crate) async fn version_check(url: String) {
|
||||
match Url::parse(&url) {
|
||||
Ok(parsed_url) => {
|
||||
let params = parsed_url.query_pairs();
|
||||
|
||||
let mut callback_url = None;
|
||||
for (key, value) in params {
|
||||
debug!("Query pairs: [{}, {}]", key, value);
|
||||
|
||||
match key {
|
||||
Cow::Borrowed("callback") => {
|
||||
callback_url = parse_url(&value);
|
||||
}
|
||||
_ => {
|
||||
warn!("Unexpected parameter: [{}, {}]", key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_version_to_browser(callback_url, &check_client_version()).await;
|
||||
}
|
||||
Err(e) => error!("Failed to parse URL: {}", e),
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ use crate::enums::ItemType;
|
||||
use crate::packet::{send_packet, Packet, PacketPayload};
|
||||
use crate::packet_type::PacketType;
|
||||
use crate::packets::*;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpStream;
|
||||
@@ -16,6 +14,17 @@ use tokio::sync::Mutex;
|
||||
use tonic::{Code, Status};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use utils::null_string::NullTerminatedString;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
|
||||
fn string_to_u32(s: &str) -> u32 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
s.hash(&mut hasher);
|
||||
// Convert the 64-bit hash to a 32-bit number.
|
||||
// Note: This cast might lead to collisions if there are a lot of objects,
|
||||
hasher.finish() as u32
|
||||
}
|
||||
|
||||
pub(crate) fn convert_slot_to_equip_slot(slot: i32) -> srv_char_list_reply::EquippedPosition {
|
||||
match enums::EquippedPosition::from_i32(slot) {
|
||||
@@ -368,10 +377,9 @@ pub(crate) async fn handle_select_char_req(
|
||||
pat_cooldown_time: stats.pat_cooldown_time as u32,
|
||||
skills: skill_list,
|
||||
hotbar: hotbar_list,
|
||||
tag: 100,
|
||||
tag: string_to_u32(&user_id),
|
||||
name,
|
||||
};
|
||||
debug!("{:?}", data);
|
||||
let response_packet = Packet::new(PacketType::PakwcSelectCharReply, &data)?;
|
||||
send_packet(stream, &response_packet).await?;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ package session_db_api;
|
||||
|
||||
service SessionService {
|
||||
rpc GetSession(GetSessionRequest) returns (GetSessionResponse);
|
||||
rpc RefreshSession(RefreshSessionRequest) returns (RefreshSessionResponse);
|
||||
}
|
||||
|
||||
message GetSessionRequest {
|
||||
@@ -13,4 +14,12 @@ message GetSessionRequest {
|
||||
message GetSessionResponse {
|
||||
string session_id = 1;
|
||||
string user_id = 2;
|
||||
}
|
||||
|
||||
message RefreshSessionRequest {
|
||||
string session_id = 1;
|
||||
}
|
||||
|
||||
message RefreshSessionResponse {
|
||||
bool valid = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user