Skip to content

Commit ca1a9c4

Browse files
authored
Merge pull request #9 from tilesprivacy/feat/cli-server-commands
Added server commands
2 parents 95f71ca + a75d9a8 commit ca1a9c4

File tree

5 files changed

+126
-17
lines changed

5 files changed

+126
-17
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target
2+
.tiles_dev

scripts/install.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
ENV="dev" # prod is another env, try taking it from github env
4+
ENV="prod" # prod is another env, try taking it from github env
55
REPO="tilesprivacy/tilekit"
66
# VERSION="${TILES_VERSION:-latest}"
77
VERSION="0.1.0"
@@ -39,7 +39,6 @@ fi
3939
log "⬇️ Downloading Tiles (${VERSION}) for ${ARCH}-${OS}..."
4040

4141

42-
4342
if [[ "$ENV" == "prod" ]]; then
4443
TAR_URL="https://github.com/${REPO}/releases/download/${VERSION}/tiles-v${VERSION}-${ARCH}-${OS}.tar.gz"
4544
curl -fsSL -o "${TMPDIR}/tiles.tar.gz" "$TAR_URL"

src/commands/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,11 @@ pub async fn run(modelfile: &str) {
2020
pub fn check_health() {
2121
health::check_health();
2222
}
23+
24+
pub fn start_server() {
25+
let _ = mlx::start_server_daemon();
26+
}
27+
28+
pub fn stop_server() {
29+
let _ = mlx::stop_server_daemon();
30+
}

src/main.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::error::Error;
22

3-
use clap::{Parser, Subcommand};
3+
use clap::{Args, Parser, Subcommand};
44
mod commands;
55
#[derive(Debug, Parser)]
6-
#[command(name = "tilekit")]
6+
#[command(name = "tiles")]
77
#[command(version, about = "Run, fine-tune models locally with Modelfile", long_about = None)]
88
struct Cli {
99
#[command(subcommand)]
@@ -17,8 +17,27 @@ enum Commands {
1717

1818
/// Checks the status of dependencies
1919
Health,
20+
21+
/// start or stop the daemon server
22+
Server(ServerArgs),
23+
}
24+
25+
#[derive(Debug, Args)]
26+
#[command(args_conflicts_with_subcommands = true)]
27+
#[command(flatten_help = true)]
28+
struct ServerArgs {
29+
#[command(subcommand)]
30+
command: Option<ServerCommands>,
2031
}
2132

33+
#[derive(Debug, Subcommand)]
34+
enum ServerCommands {
35+
/// Start the py server as a daemon
36+
Start,
37+
38+
/// Stops the daemon py server
39+
Stop,
40+
}
2241
#[tokio::main]
2342
pub async fn main() -> Result<(), Box<dyn Error>> {
2443
let cli = Cli::parse();
@@ -29,6 +48,11 @@ pub async fn main() -> Result<(), Box<dyn Error>> {
2948
Commands::Health => {
3049
commands::check_health();
3150
}
51+
Commands::Server(server) => match server.command {
52+
Some(ServerCommands::Start) => commands::start_server(),
53+
Some(ServerCommands::Stop) => commands::stop_server(),
54+
_ => println!("Expected start or stop"),
55+
},
3256
}
3357
Ok(())
3458
}

src/runner/mlx.rs

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use reqwest::Client;
33
use serde_json::{Value, json};
44
use std::io::Write;
55
use std::path::PathBuf;
6+
use std::process::Stdio;
67
use std::{env, fs};
78
use std::{io, process::Command};
89

@@ -72,6 +73,52 @@ fn run_model_by_sub_process(modelfile: Modelfile) {
7273
}
7374
}
7475

76+
#[allow(clippy::zombie_processes)]
77+
pub fn start_server_daemon() -> Result<()> {
78+
// check if the server is running
79+
// start server as a child process
80+
// save the pid in a file under ~/.config/tiles/server_pid
81+
let config_dir = get_config_dir()?;
82+
let server_dir = get_server_dir()?;
83+
let pid_file = config_dir.join("server.pid");
84+
if pid_file.exists() {
85+
eprintln!("Server is already running");
86+
return Ok(());
87+
}
88+
89+
let child = Command::new("uv")
90+
.args([
91+
"run",
92+
"--project",
93+
server_dir.to_str().unwrap(),
94+
"python",
95+
"-m",
96+
"server.main",
97+
])
98+
.stdout(Stdio::null())
99+
.stderr(Stdio::null())
100+
.spawn()
101+
.expect("failed to start server");
102+
fs::create_dir_all(&config_dir).context("Failed to create config directory")?;
103+
std::fs::write(pid_file, child.id().to_string()).unwrap();
104+
println!("Server started with PID {}", child.id());
105+
Ok(())
106+
}
107+
108+
pub fn stop_server_daemon() -> Result<()> {
109+
let pid_file = get_config_dir()?.join("server.pid");
110+
111+
if !pid_file.exists() {
112+
eprintln!("Server is not running");
113+
return Ok(());
114+
}
115+
116+
let pid = std::fs::read_to_string(&pid_file).unwrap();
117+
Command::new("kill").arg(pid.trim()).status().unwrap();
118+
std::fs::remove_file(pid_file).unwrap();
119+
println!("Server stopped.");
120+
Ok(())
121+
}
75122
async fn run_model_with_server(modelfile: Modelfile) -> reqwest::Result<()> {
76123
let stdin = io::stdin();
77124
let mut stdout = io::stdout();
@@ -157,19 +204,8 @@ async fn chat(input: &str, model_name: &str) -> Result<String, String> {
157204
}
158205

159206
fn get_memory_path() -> Result<String> {
160-
let home_dir = env::home_dir().context("Failed to fetch $HOME")?;
161-
let config_dir = match env::var("XDG_CONFIG_HOME") {
162-
Ok(val) => PathBuf::from(val),
163-
Err(_err) => home_dir.join(".config"),
164-
};
165-
166-
let data_dir = match env::var("XDG_DATA_HOME") {
167-
Ok(val) => PathBuf::from(val),
168-
Err(_err) => home_dir.join(".local/share"),
169-
};
170-
171-
let tiles_config_dir = config_dir.join("tiles");
172-
let tiles_data_dir = data_dir.join("tiles");
207+
let tiles_config_dir = get_config_dir()?;
208+
let tiles_data_dir = get_data_dir()?;
173209
let mut is_memory_path_found: bool = false;
174210
let mut memory_path: String = String::from("");
175211
if tiles_config_dir.is_dir()
@@ -193,3 +229,44 @@ fn get_memory_path() -> Result<String> {
193229
Ok(memory_path.to_string_lossy().to_string())
194230
}
195231
}
232+
233+
fn get_server_dir() -> Result<PathBuf> {
234+
if cfg!(debug_assertions) {
235+
let base_dir = env::current_dir().context("Failed to fetch CURRENT_DIR")?;
236+
Ok(base_dir.join("server"))
237+
} else {
238+
let home_dir = env::home_dir().context("Failed to fetch $HOME")?;
239+
let data_dir = match env::var("XDG_DATA_HOME") {
240+
Ok(val) => PathBuf::from(val),
241+
Err(_err) => home_dir.join(".local/share"),
242+
};
243+
Ok(data_dir.join("tiles/server"))
244+
}
245+
}
246+
fn get_config_dir() -> Result<PathBuf> {
247+
if cfg!(debug_assertions) {
248+
let base_dir = env::current_dir().context("Failed to fetch CURRENT_DIR")?;
249+
Ok(base_dir.join(".tiles_dev/tiles"))
250+
} else {
251+
let home_dir = env::home_dir().context("Failed to fetch $HOME")?;
252+
let config_dir = match env::var("XDG_CONFIG_HOME") {
253+
Ok(val) => PathBuf::from(val),
254+
Err(_err) => home_dir.join(".config"),
255+
};
256+
Ok(config_dir.join("tiles"))
257+
}
258+
}
259+
260+
fn get_data_dir() -> Result<PathBuf> {
261+
if cfg!(debug_assertions) {
262+
let base_dir = env::current_dir().context("Failed to fetch CURRENT_DIR")?;
263+
Ok(base_dir.join(".tiles_dev/tiles"))
264+
} else {
265+
let home_dir = env::home_dir().context("Failed to fetch $HOME")?;
266+
let data_dir = match env::var("XDG_DATA_HOME") {
267+
Ok(val) => PathBuf::from(val),
268+
Err(_err) => home_dir.join(".local/share"),
269+
};
270+
Ok(data_dir.join("tiles"))
271+
}
272+
}

0 commit comments

Comments
 (0)