diff --git a/.gitignore b/.gitignore index 52d6e16a..f8ef8c07 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ command/.cargo command/repos command/target + +config.toml diff --git a/README.md b/README.md index 9f12614c..f0395981 100644 --- a/README.md +++ b/README.md @@ -176,16 +176,13 @@ docker compose run --rm -w /scalachess --entrypoint="sbt package" lila ```bash ## run formatter -docker run --rm -v $(pwd)/repos/dartchess:/mnt --workdir /mnt dart:3.1.5-sdk \ - dart format . +docker compose run --rm -w /dartchess mobile dart format . ## analyze -docker run --rm -v $(pwd)/repos/dartchess:/mnt --workdir /mnt dart:3.1.5-sdk \ - bash -c "dart pub get && dart analyze" +docker compose run --rm -w /dartchess mobile bash -c "dart pub get && dart analyze" ## run tests -docker run --rm -v $(pwd)/repos/dartchess:/mnt --workdir /mnt dart:3.1.5-sdk \ - bash -c "dart pub get && dart test -x full_perft" +docker compose run --rm -w /dartchess mobile bash -c "dart pub get && dart test -x full_perft" ``` ### bbpPairings: @@ -247,3 +244,48 @@ curl --get http://localhost:8086/query \ --data-urlencode "db=kamon" \ --data-urlencode "q=show measurements;" ``` + +### Mobile + +1. On your host machine: + 1. Have the lila-docker services running, with the `Mobile` optional service started + 2. Configure lila to run with your host's IP address or hostname instead of localhost + ```bash + ./lila-docker hostname + ``` + 3. Configure the mobile settings + ```bash + ./lila-docker mobile + ``` + 4. Enter the IP address, port, and pairing code from the steps below +2. On your Android phone: + 1. Connect your phone to the same wifi network as your host machine + 2. Ensure your phone and can access lila in your browser app using the host value you set above + ``` + http://[your-selection]:8080 + ``` + 3. Enable Developer Mode + 4. In Developer Options + 1. enable wireless debugging + 2. Tap into the wireless debugging settings + 1. Use the "IP address & Port" value in the prompt on your host + 2. Tap "Pair device with pairing code" + 1. Enter the pairing port and code in the prompt on your host +3. On your host machine: + 1. Get a shell on the container: + ```bash + docker compose exec -it mobile bash + + # see your phone + adb devices + ``` + 2. Install the app dependencies: + ```bash + flutter pub get + dart run build_runner build + ``` + 3. Run the app: + ```bash + flutter run -v --dart-define=LICHESS_HOST=$LICHESS_URL --dart-define=LICHESS_WS_HOST=$LICHESS_URL + ``` + - No substitutions necessary. The `$LICHESS_URL` environment variable will already be set on the container. diff --git a/command/Cargo.lock b/command/Cargo.lock index a48c924b..7b024a55 100644 --- a/command/Cargo.lock +++ b/command/Cargo.lock @@ -8,6 +8,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cfg-if" version = "1.0.0" @@ -44,6 +50,10 @@ version = "0.1.0" dependencies = [ "cliclack", "colored", + "local-ip-address", + "serde", + "struct_iterable", + "toml", ] [[package]] @@ -59,12 +69,33 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + [[package]] name = "errno" version = "0.3.8" @@ -75,12 +106,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "indicatif" version = "0.17.7" @@ -132,6 +179,55 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "local-ip-address" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66357e687a569abca487dc399a9c9ac19beb3f13991ed49f00c144e02cbd42ab" +dependencies = [ + "libc", + "neli", + "thiserror", + "windows-sys 0.48.0", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -181,12 +277,81 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "smawk" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "struct_iterable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "849a064c6470a650b72e41fa6c057879b68f804d113af92900f27574828e7712" +dependencies = [ + "struct_iterable_derive", + "struct_iterable_internal", +] + +[[package]] +name = "struct_iterable_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb939ce88a43ea4e9d012f2f6b4cc789deb2db9d47bad697952a85d6978662c" +dependencies = [ + "erased-serde", + "proc-macro2", + "quote", + "struct_iterable_internal", + "syn 2.0.39", +] + +[[package]] +name = "struct_iterable_internal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9426b2a0c03e6cc2ea8dbc0168dbbf943f88755e409fb91bcb8f6a268305f4a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.39" @@ -209,6 +374,60 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -425,6 +644,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + [[package]] name = "zeroize" version = "1.7.0" @@ -442,5 +670,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] diff --git a/command/Cargo.toml b/command/Cargo.toml index 263d9b27..070abd5c 100644 --- a/command/Cargo.toml +++ b/command/Cargo.toml @@ -8,3 +8,7 @@ edition = "2021" [dependencies] cliclack = "0.1.6" colored = "2.0.4" +local-ip-address = "0.5.6" +serde = { version = "1.0.193", features = ["derive"] } +struct_iterable = "0.1.1" +toml = "0.8.8" diff --git a/command/src/main.rs b/command/src/main.rs index 985aab56..278876f3 100644 --- a/command/src/main.rs +++ b/command/src/main.rs @@ -1,9 +1,13 @@ -use cliclack::{confirm, input, intro, log, multiselect, spinner}; +use cliclack::{confirm, input, intro, multiselect, select, spinner}; use colored::Colorize; +use local_ip_address::local_ip; +use serde::{Deserialize, Serialize}; use std::{ + env, io::Error, path::{Path, PathBuf}, }; +use struct_iterable::Iterable; const BANNER: &str = r" |\_ _ _ _ @@ -14,25 +18,78 @@ const BANNER: &str = r" |___/ "; +#[derive(Serialize, Deserialize, Iterable, Debug)] struct Config { - profiles: Vec, - setup_database: bool, - su_password: String, - password: String, - enable_monitoring: bool, + compose_profile: Option>, + setup_database: Option, + enable_monitoring: Option, + su_password: Option, + password: Option, + hostname: Option, + phone_ip: Option, + connection_port: Option, + pairing_port: Option, + pairing_code: Option, } impl Config { - fn to_env(&self) -> String { - let mut env = String::new(); + fn default() -> Self { + Self { + compose_profile: None, + setup_database: None, + enable_monitoring: None, + su_password: None, + password: None, + hostname: None, + phone_ip: None, + connection_port: None, + pairing_port: None, + pairing_code: None, + } + } - env.push_str(&format!("COMPOSE_PROFILES={}\n", self.profiles.join(","))); - env.push_str(&format!("SETUP_DATABASE={}\n", self.setup_database)); - env.push_str(&format!("SU_PASSWORD={}\n", self.su_password)); - env.push_str(&format!("PASSWORD={}\n", self.password)); - env.push_str(&format!("ENABLE_MONITORING={}\n", self.enable_monitoring)); + fn load() -> Self { + if !Path::new("config.toml").exists() { + return Self::default(); + } - env + let toml = std::fs::read_to_string("config.toml").unwrap(); + toml::from_str(&toml).unwrap() + } + + fn save(&self) { + let toml = toml::to_string(&self).unwrap(); + std::fs::write("config.toml", toml).unwrap(); + + self.to_env(); + } + + fn to_env(&self) { + for (key, value) in self.iter() { + if let Some(string_opt) = value.downcast_ref::>() { + if let Some(string_opt) = string_opt { + env::set_var(key.to_uppercase(), string_opt); + } + } else if let Some(bool_opt) = value.downcast_ref::>() { + if let Some(bool_opt) = bool_opt { + env::set_var(key.to_uppercase(), bool_opt.to_string()); + } + } else if let Some(u16_opt) = value.downcast_ref::>() { + if let Some(u16_opt) = u16_opt { + env::set_var(key.to_uppercase(), u16_opt.to_string()); + } + } else if let Some(u32_opt) = value.downcast_ref::>() { + if let Some(u32_opt) = u32_opt { + env::set_var(key.to_uppercase(), u32_opt.to_string()); + } + } else if let Some(vec_string) = value.downcast_ref::>>() { + if let Some(vec_string) = vec_string { + env::set_var(key.to_uppercase(), vec_string.join(",")); + } + } else { + panic!("Unsupported Config type for: {key}"); + } + } } } @@ -63,21 +120,6 @@ impl Repository { } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_repository() { - let repo = Repository::new("lichess-org", "lila"); - assert_eq!(repo.org, "lichess-org"); - assert_eq!(repo.project, "lila"); - assert_eq!(repo.full_name(), "lichess-org/lila"); - assert_eq!(repo.url(), "https://github.com/lichess-org/lila"); - assert_eq!(repo.clone_path(), Path::new("repos/lila")); - } -} - #[derive(Default, Clone, Eq, PartialEq, Debug)] struct OptionalService<'a> { compose_profile: Option>, @@ -86,11 +128,14 @@ struct OptionalService<'a> { fn main() -> std::io::Result<()> { let args: Vec = std::env::args().collect(); - assert!(args.len() > 1, "Missing command"); + let config = Config::load(); + match args[1].as_str() { - "setup" => setup(), + "setup" => setup(config), + "hostname" => hostname(config), + "mobile" => mobile_setup(config), "gitpod-welcome" => { gitpod_welcome(); Ok(()) @@ -99,7 +144,7 @@ fn main() -> std::io::Result<()> { } } -fn setup() -> std::io::Result<()> { +fn setup(mut config: Config) -> std::io::Result<()> { intro(BANNER)?; let services = prompt_for_optional_services()?; @@ -126,20 +171,23 @@ fn setup() -> std::io::Result<()> { (String::new(), String::new()) }; - let config = Config { - profiles: services + config.compose_profile = Some( + services .iter() .filter_map(|service| service.compose_profile.clone()) .flatten() .map(std::string::ToString::to_string) .collect(), - setup_database, - su_password, - password, - enable_monitoring: services + ); + config.setup_database = Some(setup_database); + config.enable_monitoring = Some( + services .iter() .any(|service| service.compose_profile == Some(vec!["monitoring"])), - }; + ); + config.su_password = Some(su_password); + config.password = Some(password); + config.save(); create_placeholder_dirs(); @@ -190,8 +238,7 @@ fn setup() -> std::io::Result<()> { progress.stop(format!("Clone {} ✓", repo.full_name())); } - std::fs::write(".env", config.to_env())?; - log::success("Wrote .env") + Ok(()) } fn create_placeholder_dirs() { @@ -211,6 +258,7 @@ fn create_placeholder_dirs() { Repository::new("lichess-org", "chessground"), Repository::new("lichess-org", "pgn-viewer"), Repository::new("lichess-org", "scalachess"), + Repository::new("lichess-org", "mobile"), Repository::new("lichess-org", "dartchess"), Repository::new("lichess-org", "berserk"), Repository::new("cyanfish", "bbpPairings"), @@ -316,6 +364,14 @@ fn prompt_for_optional_services() -> Result>, Error "Scalachess", "standalone chess logic library", ) + .item( + OptionalService { + compose_profile: vec!["mobile"].into(), + repositories: vec![Repository::new("lichess-org", "mobile")].into(), + }, + "Mobile app", + "Flutter-based mobile app", + ) .item( OptionalService { compose_profile: None, @@ -351,6 +407,68 @@ fn prompt_for_optional_services() -> Result>, Error .interact() } +fn hostname(mut config: Config) -> std::io::Result<()> { + let local_ip = match local_ip() { + Ok(ip) => ip.to_string(), + _ => "127.0.0.1".to_string(), + }; + + let hostname: String = match select("Select a hostname to access your local Lichess instance:") + .initial_value("localhost") + .item("localhost", "localhost", "default") + .item( + local_ip.as_str(), + local_ip.as_str(), + "Your private IP address, for accessing from other devices on your local network", + ) + .item( + "10.0.2.2", + "10.0.2.2", + "For accessing from an Android emulator running on this machine", + ) + .item("other", "Other", "Enter a custom hostname") + .interact()? + { + "other" => input("Enter a custom hostname: (It must be resolvable)").interact()?, + selection => selection.to_string(), + }; + + config.hostname = Some(hostname); + config.save(); + + Ok(()) +} + +fn mobile_setup(mut config: Config) -> std::io::Result<()> { + let phone_ip: String = input("Your phone's private IP address") + .placeholder("192.168.x.x or 10.x.x.x") + .interact()?; + let connection_port: u16 = input("Wireless debugging port") + .validate(|input: &String| validate_string_length(input, 5)) + .interact()?; + let pairing_port: u16 = input("Pairing port") + .validate(|input: &String| validate_string_length(input, 5)) + .interact()?; + let pairing_code: u32 = input("Pairing code") + .validate(|input: &String| validate_string_length(input, 6)) + .interact()?; + + config.phone_ip = Some(phone_ip); + config.connection_port = Some(connection_port); + config.pairing_port = Some(pairing_port); + config.pairing_code = Some(pairing_code); + config.save(); + + Ok(()) +} + +fn validate_string_length(input: &String, length: usize) -> Result<(), String> { + match input.len() { + len if len == length => Ok(()), + _ => Err(format!("Value should be {length} digits in length")), + } +} + fn gitpod_welcome() { println!("{}", "################".green()); println!( @@ -367,3 +485,46 @@ fn gitpod_welcome() { "For full documentation, see: https://lichess-org.github.io/lila-gitpod/".green() ); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_repository() { + let repo = Repository::new("lichess-org", "lila"); + assert_eq!(repo.org, "lichess-org"); + assert_eq!(repo.project, "lila"); + assert_eq!(repo.full_name(), "lichess-org/lila"); + assert_eq!(repo.url(), "https://github.com/lichess-org/lila"); + assert_eq!(repo.clone_path(), Path::new("repos/lila")); + } + + #[test] + fn test_set_env_vars_from_struct() { + Config { + compose_profile: Some(vec!["foo".to_string(), "bar".to_string()]), + setup_database: Some(true), + enable_monitoring: Some(false), + su_password: Some("foo".to_string()), + password: Some("bar".to_string()), + hostname: Some("baz".to_string()), + phone_ip: Some("1.2.3.4".to_string()), + connection_port: Some(1234), + pairing_port: Some(5678), + pairing_code: Some(901234), + } + .to_env(); + + assert_eq!(env::var("COMPOSE_PROFILE").unwrap(), "foo,bar"); + assert_eq!(env::var("SETUP_DATABASE").unwrap(), "true"); + assert_eq!(env::var("ENABLE_MONITORING").unwrap(), "false"); + assert_eq!(env::var("SU_PASSWORD").unwrap(), "foo"); + assert_eq!(env::var("PASSWORD").unwrap(), "bar"); + assert_eq!(env::var("HOSTNAME").unwrap(), "baz"); + assert_eq!(env::var("PHONE_IP").unwrap(), "1.2.3.4"); + assert_eq!(env::var("CONNECTION_PORT").unwrap(), "1234"); + assert_eq!(env::var("PAIRING_PORT").unwrap(), "5678"); + assert_eq!(env::var("PAIRING_CODE").unwrap(), "901234"); + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 686052a6..439aa770 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,8 +23,8 @@ services: - lila-network environment: - SCHEME=${SCHEME:-http} - - LILA_DOMAIN=${LILA_DOMAIN:-localhost:8080} - - PICFIT_DOMAIN=${PICFIT_DOMAIN:-localhost:3001} + - LILA_DOMAIN=${LILA_DOMAIN:-${LILA_HOSTNAME:-localhost}:8080} + - PICFIT_DOMAIN=${PICFIT_DOMAIN:-${LILA_HOSTNAME:-localhost}:3001} - ENABLE_MONITORING=${ENABLE_MONITORING} volumes: - ./repos/lila:/lila @@ -43,7 +43,7 @@ services: - lila-network environment: - SCHEME=${SCHEME:-http} - - LILA_DOMAIN=${LILA_DOMAIN:-localhost:8080} + - LILA_DOMAIN=${LILA_DOMAIN:-${LILA_HOSTNAME:-localhost}:8080} volumes: - ./repos/lila-ws:/lila-ws - ./conf/lila-ws.conf:/lila-ws.conf @@ -63,6 +63,19 @@ services: - lila - lila_ws + mobile: + build: + context: docker + dockerfile: mobile.Dockerfile + environment: + - LICHESS_URL=${LICHESS_URL:-http://${LILA_HOSTNAME:-localhost}:8080} + tty: true + volumes: + - ./repos/dartchess:/dartchess + - ./repos/mobile:/app + profiles: + - mobile + api_docs: build: context: docker diff --git a/docker/mobile.Dockerfile b/docker/mobile.Dockerfile new file mode 100644 index 00000000..c3e6053a --- /dev/null +++ b/docker/mobile.Dockerfile @@ -0,0 +1,28 @@ +FROM ghcr.io/cirruslabs/flutter:3.16.0 + +RUN apt-get update +RUN apt install --yes \ + clang \ + cmake \ + libgtk-3-dev \ + ninja-build \ + pkg-config + +RUN dart --disable-analytics +RUN flutter precache +RUN sdkmanager \ + "build-tools;30.0.3" \ + "emulator" \ + "ndk;23.1.7779620" \ + "platforms;android-29" \ + "platforms;android-30" \ + "platforms;android-31" +RUN flutter doctor -v + +# Pre-install mobile app + Flutter dependencies +RUN git clone --depth 1 https://github.com/lichess-org/mobile.git /opt/mobile && \ + cd /opt/mobile && \ + flutter pub get && \ + dart run build_runner build + +WORKDIR /app diff --git a/lila-docker b/lila-docker index 61f22a5e..2850ff1b 100755 --- a/lila-docker +++ b/lila-docker @@ -3,13 +3,13 @@ if [ ! -z "$GITPOD_WORKSPACE_ID" ]; then export IS_GITPOD=true export SCHEME=https + export LICHESS_URL=$(gp url 8080) export LILA_DOMAIN=$(gp url 8080 | cut -c9-) export PICFIT_DOMAIN=$(gp url 3001 | cut -c9-) fi run_setup() { rust_cmd setup - export $(cat .env | xargs) docker compose build docker compose --profile utils build @@ -79,6 +79,27 @@ run_formatter() { docker compose exec lila sbt scalafmtAll || docker compose run --rm --entrypoint "sbt scalafmtAll" lila } +run_hostname() { + if [ "$IS_GITPOD" = "true" ]; then + echo "Setting of hostname not available on Gitpod" + echo "Use $(gp url 8080)" + exit 1 + fi + + rust_cmd hostname + + if [ ! -z "$(docker compose ps -a --services | xargs)" ]; then + docker compose down lila lila_ws nginx + docker compose up -d lila lila_ws nginx + fi +} + +run_mobile() { + rust_cmd mobile + docker compose exec mobile adb pair $PHONE_IP:$PAIRING_PORT $PAIRING_CODE + docker compose exec mobile adb connect $PHONE_IP:$CONNECTION_PORT +} + rust_cmd() { if command -v rustup &> /dev/null; then # if the host has Rust installed, use it directly @@ -122,6 +143,12 @@ case $1 in format) run_formatter ;; + hostname) + run_hostname + ;; + mobile) + run_mobile "${@:2}" + ;; *) show_help exit 1 diff --git a/nginx/errors/5xx.html b/nginx/errors/5xx.html index b36ac566..ebe23118 100644 --- a/nginx/errors/5xx.html +++ b/nginx/errors/5xx.html @@ -63,6 +63,9 @@

To Fix:

window.location.reload(); } }; + xhr.onerror = function() { + window.location.reload(); + }; xhr.send(); }, 5*1000);