Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.dev
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
POSTGRES_USER=finwar
POSTGRES_PASSWORD=password
POSTGRES_DB=finwar
DATABASE_URL=postgresql://finwar:password@localhost:5432/finwar
FINWAR_MARKET_DATABASE_URL=postgresql://finwar:password@localhost:5432/finwar
RUST_LOG=info
15 changes: 10 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ services:
context: ./servers/rust-server
dockerfile: docker/Dockerfile
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
RUST_LOG: info
FINWAR_MARKET_DB_USER: ${POSTGRES_USER:-finwar}
FINWAR_MARKET_DB_PASSWORD: ${POSTGRES_PASSWORD:-password}
FINWAR_MARKET_DB_HOST: timescaledb
FINWAR_MARKET_DB_NAME: ${POSTGRES_DB:-finwar}
command: migrate
depends_on:
timescaledb:
Expand All @@ -40,8 +42,11 @@ services:
ports:
- "4444:4444"
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-finwar}:${POSTGRES_PASSWORD:-password}@timescaledb:5432/${POSTGRES_DB:-finwar}
RUST_LOG: info
FINWAR_MARKET_DB_USER: ${POSTGRES_USER:-finwar}
FINWAR_MARKET_DB_PASSWORD: ${POSTGRES_PASSWORD:-password}
FINWAR_MARKET_DB_HOST: timescaledb
FINWAR_MARKET_DB_NAME: ${POSTGRES_DB:-finwar}
FINWAR_MARKET_TRACKED_TICKER: AAPL
command: serve
depends_on:
migration:
Expand All @@ -51,7 +56,7 @@ services:
image: docker.io/library/busybox:stable-uclibc
command: ["sh", "-c", "tail -f /dev/null"]
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --tries=1 http://rust-server:4444/api/time || exit 1"]
test: ["CMD-SHELL", "wget -q --spider --tries=1 http://rust-server:4444/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
Expand Down
10 changes: 5 additions & 5 deletions servers/rust-server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion servers/rust-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "finwar-market"
version = "0.2.0"
version = "0.4.0"
authors = ["Coding Kelps <contact@kelps.org>"]
autotests = true
categories = ["finance", "simulation"]
Expand Down
21 changes: 19 additions & 2 deletions servers/rust-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ sea-orm-cli migrate reset

### Environment Setup

- Set `DATABASE_URL=postgres://finwar:password@localhost/finwar` as an env variable or in a .env
- Set `FINWAR_MARKET_DB_USER=finwar`, `FINWAR_MARKET_DB_PASSWORD=password`, and `FINWAR_MARKET_DB_NAME=finwar` as an env variable or in a .env
- Default server runs on `0.0.0.0:4444`
- Stock data loaded from `./local/data/Stocks/` directory

Expand All @@ -68,7 +68,7 @@ docker build -t finwar-rust-server -f ./docker/Dockerfile .
**Run only the server container:**

```bash
docker run -p 4444:4444 -e DATABASE_URL=postgresql://finwar:password@host.docker.internal:5432/finwar finwar-rust-server
docker run -p 4444:4444 -e FINWAR_MARKET_DB_USER=finwar FINWAR_MARKET_DB_PASSWORD=password FINWAR_MARKET_DB_NAME=finwar finwar-rust-server
```

**Or use docker-compose (recommended):**
Expand All @@ -89,3 +89,20 @@ or in powershell:
```powershell
Invoke-RestMethod -Uri http://localhost:4444/api/enroll -Method POST -ContentType "application/json" -Body '{"name":"bot0"}'
```

## Configuration

| Environment Variable | Command Line. | Description | Default |
| :------------------------------------ | :------------------ | :--------------------------------------------------------------------------- | :---------------------: |
| `FINWAR_MARKET_LOG_LEVEL` | `--log-level` | The log level of the application. | `info` |
| `FINWAR_MARKET_HOST` | `--host` | The HTTP server address. | `0.0.0.0` |
| `FINWAR_MARKET_PORT` | `--port` | The HTTP server port | `4444` |
| `FINWAR_MARKET_INTERVAL_SECONDS` | `--interval-seconds` | The internal time passed (in seconds) in the Market each real second. | `60` |
| `FINWAR_MARKET_TRACKED_SYMBOL` | `--tracked-symbols` | The tracked stock ticker symbol on which the Market simulation is based on. | `AAPL` |
| `FINWAR_MARKET_DB_USER` | `--db-user` | The username used for the database authentication. | |
| `FINWAR_MARKET_DB_USER_FILE` | `--db-user-file` | The path of the file containing the database auth username. | |
| `FINWAR_MARKET_DB_PASSWORD` | `--db-password` | The password used for the database authentication. | |
| `FINWAR_MARKET_DB_PASSWORD_FILE` | `--db-password-file` | The path of the file containing the database auth password. | |
| `FINWAR_MARKET_DB_HOST` | `--db-host` | The host or address of the database to connect to. | `localhost` |
| `FINWAR_MARKET_DB_PORT` | `--db-port` | The port of the database to connect to. | `5432` |
| `FINWAR_MARKET_DB_NAME` | `--db-name` | The name of the database to connect to. | `postgres` |
117 changes: 83 additions & 34 deletions servers/rust-server/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,97 @@
use clap::{Parser, Subcommand};
use migration::{Migrator, MigratorTrait};
use std::path::PathBuf;

/// Simple CLI for the market server. Defaults to `serve` when no subcommand
/// is provided.
#[derive(Debug, Parser)]
#[command(author, version, about = "Finwar market server CLI")]
pub struct Opts {
#[command(subcommand)]
pub command: Command,
macro_rules! env_prefix {
($name:expr) => {
concat!("FINWAR_MARKET_", $name)
};
}

#[derive(Debug, Subcommand)]
pub enum Command {
/// Start the HTTP server (default)
Serve,
/// Run database migrations using the workspace `migration` member
Migrate,
/// Simple CLI for the market server.
#[derive(Debug, Parser, Clone)]
#[command(author, version, about = "Finwar market server CLI")]
pub struct Args {
/// Log level (trace, debug, info, warn, error)
#[arg(long, env = env_prefix!("LOG_LEVEL"), default_value = "info")]
pub log_level: String,

#[command(subcommand)]
pub command: Commands,
}

pub async fn run() -> Result<(), crate::error::Error> {
let opts = Opts::parse();
#[derive(Subcommand, Debug, Clone)]
pub enum Commands {
Serve {
/// Host to bind to
#[arg(long, env = env_prefix!("HOST"), default_value = "0.0.0.0")]
host: String,

/// Port to bind to
#[arg(short, long, env = env_prefix!("PORT"), default_value = "4444")]
port: u16,

/// Database user
#[arg(long, env = env_prefix!("DB_USER"), required_unless_present = "db_user_file")]
db_user: Option<String>,

/// Database user file path
#[arg(long, env = env_prefix!("DB_USER_FILE"), required_unless_present = "db_user")]
db_user_file: Option<PathBuf>,

/// Database password
#[arg(long, env = env_prefix!("DB_PASSWORD"), required_unless_present = "db_password_file")]
db_password: Option<String>,

/// Database password file path
#[arg(long, env = env_prefix!("DB_PASSWORD_FILE"), required_unless_present = "db_password")]
db_password_file: Option<PathBuf>,

/// Database host
#[arg(long, env = env_prefix!("DB_HOST"), default_value = "localhost")]
db_host: String,

/// Database port
#[arg(long, env = env_prefix!("DB_PORT"), default_value = "5432")]
db_port: u16,

/// Database name
#[arg(long, env = env_prefix!("DB_NAME"), default_value = "postgres")]
db_name: String,

#[arg(long, env = env_prefix!("TRACKED_SYMBOL"), default_value = "AAPL")]
tracked_symbol: String,

#[arg(long, env = env_prefix!("INTERVAL_SECONDS"), default_value = "60")]
interval_seconds: u64
},

match opts.command {
Command::Serve => {
let database_url =
std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
Migrate {
/// Database user
#[arg(long, env = env_prefix!("DB_USER"), required_unless_present = "db_user_file")]
db_user: Option<String>,

let db_connection = sea_orm::Database::connect(&database_url)
.await
.map_err(crate::error::Error::InitDb)?;
/// Database user file path
#[arg(long, env = env_prefix!("DB_USER_FILE"), required_unless_present = "db_user")]
db_user_file: Option<PathBuf>,

crate::run_server(db_connection).await
},
Command::Migrate => {
let database_url =
std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
/// Database password
#[arg(long, env = env_prefix!("DB_PASSWORD"), required_unless_present = "db_password_file")]
db_password: Option<String>,

let db_connection = sea_orm::Database::connect(&database_url)
.await
.map_err(crate::error::Error::InitDb)?;
/// Database password file path
#[arg(long, env = env_prefix!("DB_PASSWORD_FILE"), required_unless_present = "db_password")]
db_password_file: Option<PathBuf>,

Migrator::up(&db_connection, None).await?;
/// Database host
#[arg(long, env = env_prefix!("DB_HOST"), default_value = "localhost")]
db_host: String,

/// Database port
#[arg(long, env = env_prefix!("DB_PORT"), default_value = "5432")]
db_port: u16,

Ok(())
},
/// Database name
#[arg(long, env = env_prefix!("DB_NAME"), default_value = "postgres")]
db_name: String,
}
}
4 changes: 2 additions & 2 deletions servers/rust-server/src/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl MarketClock {
}

pub fn advance(&mut self, seconds: u64) {
self.current_time = self.current_time + Duration::from_secs(seconds * 60);
self.current_time = self.current_time + Duration::from_secs(seconds);
}
}

Expand All @@ -50,4 +50,4 @@ pub async fn time(State(state): State<AppState>) -> Result<impl IntoResponse, Ap
let clock = state.clock.read().await;
let time_str = clock.current_time().format("%Y-%m-%d %H:%M:%S").to_string();
Ok(time_str)
}
}
Loading