diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7ed82ac --- /dev/null +++ b/flake.lock @@ -0,0 +1,95 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1780930886, + "narHash": "sha256-rppURzHviaQN131F+nLiLdGfcb0uCd9gGP0E5+iw9MI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c3cede7ddc26bd659d2d383b5610efbd2c7a16e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1770107345, + "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs", + "systems": "systems", + "treefmt-nix": "treefmt-nix" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1780220602, + "narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "db947814a175b7ca6ded66e21383d938df01c227", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..043bd8a --- /dev/null +++ b/flake.nix @@ -0,0 +1,76 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + systems.url = "github:nix-systems/default"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + flake-compat = { + url = "github:NixOS/flake-compat"; + flake = false; + }; + }; + + outputs = + { + nixpkgs, + ... + }@inputs: + with builtins; + with nixpkgs.lib; + + let + doubles = import inputs.systems; + forAllSystems = genAttrs doubles; + + pkgs_gen = + { ... }@args: + import nixpkgs args; + + dmm_gen = + { + pkgs, + tools ? [ ], + specialArgs ? { }, + }: + pkgs.rustPlatform.buildRustPackage ( + let + src = cleanSource ./.; + in + final: + { + pname = "dockermcmgr"; + version = "0.0.1"; + + inherit src; + cargoLock.lockFile = src + "/Cargo.lock"; + nativeBuildInputs = tools; + + buildInputs = + with pkgs; [ sqlite ]; + + } + // specialArgs + ); + in + { + packages = forAllSystems ( + system: + let + pkgs = pkgs_gen { inherit system; }; + iloader = dmm_gen { inherit pkgs; }; + in + { + inherit iloader; + default = iloader; + } + ); + formatter = forAllSystems ( + system: + let + pkgs = pkgs_gen { inherit system; }; + in + inputs.treefmt-nix.lib.mkWrapper pkgs { + programs.nixfmt.enable = true; + } + ); + }; +} diff --git a/migrations/2026-05-28-142613-0000_servers/up.sql b/migrations/2026-05-28-142613-0000_servers/up.sql index edfa6df..b679e0b 100644 --- a/migrations/2026-05-28-142613-0000_servers/up.sql +++ b/migrations/2026-05-28-142613-0000_servers/up.sql @@ -3,7 +3,8 @@ CREATE TABLE "servers" ( "last_login" timestamp, "status" INT2 NOT NULL DEFAULT 0, "is_default" bool NOT NULL DEFAULT false, - "redirect_ip" varchar(50) + "redirect_ip" varchar(50), + "simple_redirect" bool NOT NULL DEFAULT false ); -insert into servers (name, last_login, status, is_default, redirect_ip) values ('potato', datetime(), 4, false, 'play.hypixel.net:25565'); +insert into servers (name, last_login, status, is_default, redirect_ip, simple_redirect) values ('potato', datetime(), 4, false, 'play.hypixel.net:25565', true); diff --git a/src/minecraft/manager_loop.rs b/src/minecraft/manager_loop.rs new file mode 100644 index 0000000..ef1e28c --- /dev/null +++ b/src/minecraft/manager_loop.rs @@ -0,0 +1,55 @@ +use bollard::{Docker, query_parameters::{ListContainersOptionsBuilder, StopContainerOptionsBuilder}}; + +use crate::{ DbPool, dockermgr, models, schema, status::ServerStatus }; + +use async_std::task; + +use std::{collections::HashMap, time::Duration}; + +use diesel::prelude::*; + + +async fn server_init(pool: &DbPool, docker: &Docker) -> Result<(), String> { + use schema::servers::dsl::*; + let conn = &mut pool.get().unwrap(); + + println!("init start"); + + let _ = diesel::update(servers).filter(simple_redirect.eq(false)).set(status.eq(ServerStatus::Stopped)).execute(conn); + + let mut filters = HashMap::new(); + filters.insert("name", vec!["minecraft-"]); + let container_list_options = ListContainersOptionsBuilder::new() + .all(true) + .filters(&filters) + .build(); + let containers = docker.list_containers(Some(container_list_options)).await.map_err(|e| format!("Failed get current containers : {}", e))?; + + if containers.len() != 0 { + println!("stopping {} stray container(s)", containers.len()) + } + + for container in containers { + let container_name = &container.names.unwrap()[0][1..]; + println!("stopping {}", container_name); + let stop_options = StopContainerOptionsBuilder::new() + .t(60) + .build(); + docker.stop_container(container_name, Some(stop_options)).await.map_err(|e| format!("Failed to stop container {}, : {}", container_name, e))?; + println!("{} stopped", container_name); + } + println!("init done"); + Ok(()) +} + +pub async fn server_manager_loop(pool: DbPool, docker: Docker) +{ + match server_init(&pool, &docker).await { + Err(e) => { eprintln!("init failed , ignoring because idgaf : {}", e); }, + Ok(_) => {}, + }; + + loop { + task::sleep(Duration::from_mins(5)).await; + } +} diff --git a/src/minecraft/mod.rs b/src/minecraft/mod.rs index 1fdd8f1..68a14b8 100644 --- a/src/minecraft/mod.rs +++ b/src/minecraft/mod.rs @@ -5,3 +5,6 @@ mod client; mod socket; pub use socket::mc_socket_listen; + +mod manager_loop; +pub use manager_loop::server_manager_loop; diff --git a/src/minecraft/socket.rs b/src/minecraft/socket.rs index 101c30f..4844e28 100644 --- a/src/minecraft/socket.rs +++ b/src/minecraft/socket.rs @@ -1,4 +1,4 @@ -use crate::minecraft::client::client::Client; +use crate::minecraft::{client::client::Client, manager_loop}; use bollard::Docker; use tokio::net::TcpStream; @@ -8,8 +8,20 @@ use tokio::net::TcpListener; use std::io; +use crate::minecraft::server_manager_loop; + pub async fn mc_socket_listen(pool: DbPool, docker: Docker) -> io::Result<()> { let mc_listener = TcpListener::bind("0.0.0.0:25565").await?; + + { + let cloned_pool = pool.clone(); + let cloned_docker = docker.clone(); + + tokio::spawn(async move { + server_manager_loop(cloned_pool, cloned_docker).await; + }); + } + loop { if let Ok((socket, _)) = mc_listener.accept().await { let cloned_pool = pool.clone();