diff --git a/src/config.rs b/src/config.rs index 5e4cff6e..5b1a39a8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -292,6 +292,8 @@ impl Stack { Node::Internal(Image::Whisker(w)) } Image::Runner(r) => Node::Internal(Image::Runner(r)), + Image::Mongo(m) => Node::Internal(Image::Mongo(m)), + Image::Chat(c) => Node::Internal(Image::Chat(c)), }, }); Stack { diff --git a/src/images/chat.rs b/src/images/chat.rs new file mode 100644 index 00000000..4e5bd13e --- /dev/null +++ b/src/images/chat.rs @@ -0,0 +1,90 @@ +use super::*; +use crate::config::Node; +use crate::images::mongo::MongoImage; +use crate::utils::{domain, exposed_ports, host_config}; +use anyhow::{Context, Result}; +use async_trait::async_trait; +use bollard::{container::Config, Docker}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct ChatImage { + pub name: String, + pub version: String, + pub http_port: String, + pub links: Links, + pub host: Option, +} + +impl ChatImage { + pub fn new(name: &str, version: &str) -> Self { + // ports are hardcoded + Self { + name: name.to_string(), + version: version.to_string(), + http_port: "8282".to_string(), + links: vec![], + host: None, + } + } + pub fn host(&mut self, eh: Option) { + if let Some(h) = eh { + self.host = Some(format!("chat.{}", h)); + } + } + pub fn links(&mut self, links: Vec<&str>) { + self.links = strarr(links) + } +} + +#[async_trait] +impl DockerConfig for ChatImage { + async fn make_config(&self, nodes: &Vec, _docker: &Docker) -> Result> { + let li = LinkedImages::from_nodes(self.links.clone(), nodes); + let mongo = li.find_mongo().context("Chat: No Mongo")?; + Ok(chat(self, &mongo)) + } +} + +impl DockerHubImage for ChatImage { + fn repo(&self) -> Repository { + Repository { + org: "huggingface".to_string(), + repo: "chat-ui".to_string(), + root_volume: "/data".to_string(), + } + } +} + +fn chat(node: &ChatImage, mongo: &MongoImage) -> Config { + let name = node.name.clone(); + let repo = node.repo(); + let image_end = format!("{}/{}", repo.org, repo.repo); + let image = format!("ghcr.io/{}", image_end); + + let root_vol = &repo.root_volume; + let ports = vec![node.http_port.clone()]; + + let env = vec![format!( + "MONGODB_URL=mongodb://{}:{}", + domain(&mongo.name), + mongo.http_port + )]; + // let env = vec![format!( + // "MONGODB_URL=mongodb://{}:{}@{}:{}", + // mongo.user, + // mongo.pass, + // domain(&mongo.name), + // mongo.http_port + // )]; + + let c = Config { + image: Some(format!("{}:{}", image, node.version)), + hostname: Some(domain(&name)), + exposed_ports: exposed_ports(ports.clone()), + env: Some(env), + host_config: host_config(&name, ports, root_vol, None, None), + ..Default::default() + }; + c +} diff --git a/src/images/mod.rs b/src/images/mod.rs index 89120f88..30a63cf8 100644 --- a/src/images/mod.rs +++ b/src/images/mod.rs @@ -4,6 +4,7 @@ pub mod broker; pub mod btc; pub mod builtin; pub mod cache; +pub mod chat; pub mod cln; pub mod config_server; pub mod dufs; @@ -13,6 +14,7 @@ pub mod llama; pub mod lnd; pub mod lss; pub mod mixer; +pub mod mongo; pub mod navfiber; pub mod neo4j; pub mod postgres; @@ -61,6 +63,8 @@ pub enum Image { Whisper(whisper::WhisperImage), Whisker(whisker::WhiskerImage), Runner(runner::RunnerImage), + Mongo(mongo::MongoImage), + Chat(chat::ChatImage), } pub struct Repository { @@ -112,6 +116,8 @@ impl Image { Image::Whisper(n) => n.name.clone(), Image::Whisker(n) => n.name.clone(), Image::Runner(n) => n.name.clone(), + Image::Mongo(n) => n.name.clone(), + Image::Chat(n) => n.name.clone(), } } pub fn typ(&self) -> String { @@ -141,6 +147,8 @@ impl Image { Image::Whisper(_n) => "Whisper", Image::Whisker(_n) => "Whisker", Image::Runner(_n) => "Runner", + Image::Mongo(_n) => "Mongo", + Image::Chat(_n) => "Chat", } .to_string() } @@ -171,6 +179,8 @@ impl Image { Image::Whisper(_n) => (), Image::Whisker(_n) => (), Image::Runner(n) => n.version = version.to_string(), + Image::Mongo(n) => n.version = version.to_string(), + Image::Chat(n) => n.version = version.to_string(), }; } pub async fn pre_startup(&self, docker: &Docker) -> Result<()> { @@ -260,6 +270,8 @@ impl DockerConfig for Image { Image::Whisper(n) => n.make_config(nodes, docker).await, Image::Whisker(n) => n.make_config(nodes, docker).await, Image::Runner(n) => n.make_config(nodes, docker).await, + Image::Mongo(n) => n.make_config(nodes, docker).await, + Image::Chat(n) => n.make_config(nodes, docker).await, } } } @@ -292,6 +304,8 @@ impl DockerHubImage for Image { Image::Whisper(n) => n.repo(), Image::Whisker(n) => n.repo(), Image::Runner(n) => n.repo(), + Image::Mongo(n) => n.repo(), + Image::Chat(n) => n.repo(), } } } @@ -431,6 +445,14 @@ impl LinkedImages { } None } + pub fn find_mongo(&self) -> Option { + for img in self.0.iter() { + if let Ok(i) = img.as_mongo() { + return Some(i); + } + } + None + } } impl Image { @@ -542,6 +564,12 @@ impl Image { _ => Err(anyhow::anyhow!("Not Whisper".to_string())), } } + pub fn as_mongo(&self) -> anyhow::Result { + match self { + Image::Mongo(i) => Ok(i.clone()), + _ => Err(anyhow::anyhow!("Not Mongo".to_string())), + } + } } fn strarr(i: Vec<&str>) -> Vec { diff --git a/src/images/mongo.rs b/src/images/mongo.rs new file mode 100644 index 00000000..152c0b39 --- /dev/null +++ b/src/images/mongo.rs @@ -0,0 +1,110 @@ +use super::*; +use crate::config::Node; +use crate::utils::{domain, exposed_ports, host_config}; +use anyhow::Result; +use async_trait::async_trait; +use bollard::{container::Config, Docker}; +use serde::{Deserialize, Serialize}; + +// docker run --name mongodb -p 27017:27017 -d mongodb/mongodb-community-server:latest + +/* + +// ssh into the running container +// Change container name if necessary +$ docker exec -it mongo.sphinx /bin/bash + +// Enter into mongo shell +$ mongosh + +// Caret will change when you enter successfully +// Switch to admin database +$> use admin +$> db.auth("admin", passwordPrompt()) + +// Show available databases +$> show dbs + +*/ + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +pub struct MongoImage { + pub name: String, + pub version: String, + pub http_port: String, + pub user: String, + pub pass: String, + pub links: Links, + pub host: Option, +} + +impl MongoImage { + pub fn new(name: &str, version: &str) -> Self { + // ports are hardcoded + Self { + name: name.to_string(), + version: version.to_string(), + http_port: "27017".to_string(), + user: "root".to_string(), + pass: "password".to_string(), + links: vec![], + host: None, + } + } + pub fn host(&mut self, eh: Option) { + if let Some(h) = eh { + self.host = Some(format!("mongo.{}", h)); + } + } + pub fn links(&mut self, links: Vec<&str>) { + self.links = strarr(links) + } +} + +#[async_trait] +impl DockerConfig for MongoImage { + async fn make_config(&self, _nodes: &Vec, _docker: &Docker) -> Result> { + Ok(mongo(self)) + } +} + +impl DockerHubImage for MongoImage { + fn repo(&self) -> Repository { + Repository { + org: "library".to_string(), + repo: "mongo".to_string(), + root_volume: "/data".to_string(), + } + } +} + +fn mongo(node: &MongoImage) -> Config { + let name = node.name.clone(); + let repo = node.repo(); + let img = format!("{}/{}", repo.org, repo.repo); + let root_vol = &repo.root_volume; + let ports = vec![node.http_port.clone()]; + + let env = Vec::new(); + // let env = vec![ + // "MONGO_INITDB_ROOT_USERNAME=root".to_string(), + // "MONGO_INITDB_ROOT_PASSWORD=password".to_string(), + // ]; + + let c = Config { + image: Some(format!("{}:{}", img, node.version)), + hostname: Some(domain(&name)), + exposed_ports: exposed_ports(ports.clone()), + host_config: host_config(&name, ports, root_vol, None, None), + env: Some(env), + entrypoint: Some(vec![ + "mongod".to_string(), + // "--auth".to_string(), + "--bind_ip_all".to_string(), + "--dbpath".to_string(), + "/data/db".to_string(), + ]), + ..Default::default() + }; + c +} diff --git a/src/secondbrain.rs b/src/secondbrain.rs index ebdae454..e3a9c179 100644 --- a/src/secondbrain.rs +++ b/src/secondbrain.rs @@ -94,3 +94,19 @@ pub fn external_lnd() -> Option { } None } + +pub fn only_chat_ui() -> Stack { + let mongo = crate::images::mongo::MongoImage::new("mongo", "latest"); + let mut chat = crate::images::chat::ChatImage::new("chat-ui", "sha-165b40b"); + chat.links(vec!["mongo"]); + let nodes = vec![ + Node::Internal(Image::Mongo(mongo)), + Node::Internal(Image::Chat(chat)), + ]; + return Stack { + network: "regtest".to_string(), + nodes, + jwt_key: secrets::random_word(16), + ..Default::default() + }; +}