Compare commits

...

2 Commits

Author SHA256 Message Date
277d25a820 - add: docker-compose.yml to run the services
- add: .env.example for the config for docker
2024-12-15 01:50:55 -05:00
1b2d6bdac2 - update: code cleanup
- update: reworked how the launch params are parsed
2024-12-15 01:41:42 -05:00
4 changed files with 202 additions and 97 deletions

21
.env.example Executable file
View File

@@ -0,0 +1,21 @@
LOG_LEVEL=info
REDIS_URL=redis://:super_safe_password@127.0.0.1:6379/0
LISTEN_ADDR=0.0.0.0
CONSUL_URL=http://consul:8500
POSTGRES_USER=osirose
POSTGRES_PASSWORD=super_safe_postgres_password
POSTGRES_DB=osirose
# Define service addresses for consul.
# This will set the service address in consul to what ever is placed here.
# This can be a IP address or the container name in docker
AUTH_SERVICE_ADDR=auth-service
API_SERVICE_ADDR=api-service
CHARACTER_SERVICE_ADDR=character-service
DATABASE_SERVICE_ADDR=database-service
PACKET_SERVICE_ADDR=packet-service
WORLD_SERVICE_ADDR=world-service
#<Service Name>_SERVICE_PORT=<PORT> # Replace Service name with the service and port with the port you want to run it on. Ex. AUTH_SERVICE_PORT=30000
#JWT_SECRET=safe_jwt_secret # This is only used for auth-service and is required.
#HEALTH_CHECK_PORT=8080 # This will change the health check port for the services

98
docker-compose.yml Executable file
View File

@@ -0,0 +1,98 @@
services:
auth-service:
build:
context: ./
dockerfile: ./auth-service/Dockerfile
ports:
- "50051:50051"
env_file:
- ./auth-service/.env
- .env
environment:
- HEALTH_CHECK_PORT=8080
depends_on:
- database-service
- consul
api-service:
build:
context: ./
dockerfile: ./api-service/Dockerfile
ports:
- "8080:8080"
env_file:
- ./api-service/.env
- .env
depends_on:
- auth-service
- consul
database-service:
build:
context: ./
dockerfile: ./database-service/Dockerfile
ports:
- "50052:50052"
env_file:
- ./database-service/.env
- .env
depends_on:
- db
- consul
character-service:
build:
context: ./
dockerfile: ./character-service/Dockerfile
ports:
- "50053:50053"
env_file:
- ./character-service/.env
- .env
depends_on:
- auth-service
- consul
world-service:
build:
context: ./
dockerfile: ./world-service/Dockerfile
ports:
- "50054:50054"
env_file:
- ./world-service/.env
- .env
depends_on:
- auth-service
- consul
packet-service:
build:
context: ./
dockerfile: ./packet-service/Dockerfile
ports:
- "4000:4000"
env_file:
- ./packet-service/.env
- .env
depends_on:
- auth-service
- consul
db:
image: postgres:17
env_file:
- .env
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
consul:
image: consul:1.15.4
command: agent -dev -client=0.0.0.0
ports:
- "8500:8500"
volumes:
db_data:

70
launcher/src/launcher.rs Normal file
View File

@@ -0,0 +1,70 @@
use crate::{format_shell_command, wait_for_keypress};
use std::borrow::Cow;
use std::env;
use std::process::{exit, Command, Stdio};
use tracing::{debug, error, info, warn};
use url::Url;
pub(crate) fn launch_game(url: String) {
let exe_dir_path = env::current_exe().unwrap().parent().unwrap().to_path_buf();
// Change the working directory
if let Err(e) = env::set_current_dir(exe_dir_path) {
error!("Failed to set working directory: {}", e);
wait_for_keypress();
exit(1);
}
// Parse the URL
match Url::parse(&url) {
Ok(parsed_url) => {
let params = parsed_url.query_pairs();
let game_executable = "./TRose.exe";
let mut command = Command::new(game_executable);
command.arg("@TRIGGER_SOFT@");
let mut is_direct = false;
for (key, value) in params {
debug!("Query pairs: [{}, {}]", key, value);
match key {
Cow::Borrowed("ip") => {
command.arg("_server").arg(value.to_string());
}
Cow::Borrowed("port") => {
command.arg("_port").arg(value.to_string());
}
Cow::Borrowed("otp") => {
is_direct = true;
command.arg("_direct").arg("_otp").arg(value.to_string());
}
Cow::Borrowed("username") => {
command.arg("_userid").arg(value.to_string());
}
Cow::Borrowed("password") => {
if !is_direct {
command.arg("_pass").arg(value.to_string());
}
}
_ => {
warn!("Unexpected parameter: [{}, {}]", key, value);
}
}
}
command
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
info!("Executing: {:?}", format_shell_command(&command));
// Check if the game launched successfully
match command.spawn() {
Ok(_) => info!("Game launched successfully!"),
Err(e) => error!("Failed to launch the game: {}", e),
}
}
Err(e) => error!("Failed to parse URL: {}", e),
}
}

View File

@@ -1,9 +1,9 @@
use std::path::{Path, PathBuf}; mod launcher;
use std::process::{exit, Command, Stdio};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use std::{env, io}; use std::process::{Command};
use std::{io};
use tracing::{debug, error, info, Level}; use tracing::{debug, error, info, Level};
use url::Url;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@@ -12,17 +12,15 @@ struct Args {
action: Commands, action: Commands,
#[arg(short, long, action = clap::ArgAction::Count)] #[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8 verbose: u8,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Commands { enum Commands {
#[command(name = "launch")] #[command(name = "launch")]
Launch { Launch { url: String },
url: String,
},
#[command(name = "update")] #[command(name = "update")]
Update Update,
} }
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -30,18 +28,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let verbose = match args.verbose { let verbose = match args.verbose {
0 => Level::INFO, 0 => Level::INFO,
1 => Level::DEBUG, 1 => Level::DEBUG,
_ => Level::TRACE _ => Level::TRACE,
}; };
// Set our logging level
tracing_subscriber::fmt().with_max_level(verbose).init(); tracing_subscriber::fmt().with_max_level(verbose).init();
let action = args.action; let action = args.action;
match action { match action {
Commands::Launch { url } => { Commands::Launch { url } => {
debug!("launching with URL {}", url); debug!("launching with URL {}", url);
launch_game(url); launcher::launch_game(url);
}, }
Commands::Update => { Commands::Update => {
error!("Update action not implemented"); error!("Update action not implemented");
return Err("Update action not implemented".into()); return Err("Update action not implemented".into());
@@ -51,88 +49,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
fn launch_game(url: String) {
let exe_dir_path = env::current_exe().unwrap().parent().unwrap().to_path_buf();
// let working_directory =
// env::var("GAME_CLIENT_PATH").unwrap_or_else(|_| "D:/rose_osirose-new-x64".to_string());
// Change the working directory
if let Err(e) = env::set_current_dir(exe_dir_path) {
error!("Failed to set working directory: {}", e);
wait_for_keypress();
exit(1);
}
// Parse the URL
match Url::parse(&url) {
Ok(parsed_url) => {
// Extract the "otp" parameter
let otp = parsed_url
.query_pairs()
.find(|(key, _)| key == "otp")
.map(|(_, value)| value.to_string());
let ip = parsed_url
.query_pairs()
.find(|(key, _)| key == "ip")
.map(|(_, value)| value.to_string());
let username = parsed_url
.query_pairs()
.find(|(key, _)| key == "username")
.map(|(_, value)| value.to_string());
let port = parsed_url
.query_pairs()
.find(|(key, _)| key == "port")
.map(|(_, value)| value.to_string())
.unwrap_or("4000".to_string());
// Ensure required parameters are present
if otp.is_none() || ip.is_none() || username.is_none() {
error!("Missing required parameters: otp, ip, or username");
wait_for_keypress();
return;
}
// Unwrap the parameters
let otp = otp.unwrap();
let ip = ip.unwrap();
let username = username.unwrap();
info!("Launching game with:");
info!(" OTP: {}", otp);
info!(" IP: {}", ip);
info!(" Username: {}", username);
// Construct the game client command
let game_executable = "./TRose.exe";
let mut command = Command::new(game_executable);
command
.arg("@TRIGGER_SOFT@")
.arg("_direct")
.arg("_server")
.arg(ip)
.arg("_port")
.arg(port)
.arg("_userid")
.arg(username)
.arg("_otp")
.arg(otp)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
info!("Executing: {:?}", format_shell_command(&command));
// Check if the game launched successfully
match command.spawn() {
Ok(_) => info!("Game launched successfully!"),
Err(e) => error!("Failed to launch the game: {}", e),
}
}
Err(e) => error!("Failed to parse URL: {}", e),
}
}
fn wait_for_keypress() { fn wait_for_keypress() {
// Wait for a keypress // Wait for a keypress
info!("Press Enter to close the launcher..."); info!("Press Enter to close the launcher...");
@@ -147,4 +63,4 @@ fn format_shell_command(command: &Command) -> String {
.collect(); .collect();
format!("{} {}", executable, args.join(" ")) format!("{} {}", executable, args.join(" "))
} }