123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857 |
- use crate::{
- instance_manager::{InstanceInfo, InstanceManager},
- types::*,
- };
- use futures_util::StreamExt;
- use helix_db::{
- helix_engine::graph_core::config::Config,
- helixc::{
- analyzer::analyzer::analyze,
- generator::{generator_types::Source as GeneratedSource, tsdisplay::ToTypeScript},
- parser::helix_parser::{Content, HelixParser, HxFile, Source},
- },
- utils::styled_string::StyledString,
- };
- use reqwest::Client;
- use serde::Deserialize;
- use serde_json::{Value as JsonValue, json};
- use spinners::{Spinner, Spinners};
- use std::{
- error::Error,
- fmt::Write,
- fs::{self, DirEntry, File},
- io::{ErrorKind, Write as iWrite},
- net::{SocketAddr, TcpListener},
- path::{Path, PathBuf},
- process::{Command, Stdio},
- };
- use tokio_tungstenite::{
- connect_async,
- tungstenite::{
- Message,
- protocol::{CloseFrame, frame::coding::CloseCode},
- },
- };
- use toml::Value;
- pub const DB_DIR: &str = "helixdb-cfg/";
- pub const DEFAULT_SCHEMA: &str = r#"// Start building your schema here.
- //
- // The schema is used to to ensure a level of type safety in your queries.
- //
- // The schema is made up of Node types, denoted by N::,
- // and Edge types, denoted by E::
- //
- // Under the Node types you can define fields that
- // will be stored in the database.
- //
- // Under the Edge types you can define what type of node
- // the edge will connect to and from, and also the
- // properties that you want to store on the edge.
- //
- // Example:
- //
- // N::User {
- // Name: String,
- // Label: String,
- // Age: Integer,
- // IsAdmin: Boolean,
- // }
- //
- // E::Knows {
- // From: User,
- // To: User,
- // Properties: {
- // Since: Integer,
- // }
- // }
- //
- // For more information on how to write queries,
- // see the documentation at https://docs.helix-db.com
- // or checkout our GitHub at https://github.com/HelixDB/helix-db
- "#;
- pub const DEFAULT_QUERIES: &str = r#"// Start writing your queries here.
- //
- // You can use the schema to help you write your queries.
- //
- // Queries take the form:
- // QUERY {query name}({input name}: {input type}) =>
- // {variable} <- {traversal}
- // RETURN {variable}
- //
- // Example:
- // QUERY GetUserFriends(user_id: String) =>
- // friends <- N<User>(user_id)::Out<Knows>
- // RETURN friends
- //
- //
- // For more information on how to write queries,
- // see the documentation at https://docs.helix-db.com
- // or checkout our GitHub at https://github.com/HelixDB/helix-db
- "#;
- pub fn check_helix_installation() -> Option<PathBuf> {
- let home_dir = dirs::home_dir()?;
- let repo_path = home_dir.join(".helix/repo/helix-db");
- let container_path = repo_path.join("helix-container");
- let cargo_path = container_path.join("Cargo.toml");
- if !repo_path.exists()
- || !repo_path.is_dir()
- || !container_path.exists()
- || !container_path.is_dir()
- || !cargo_path.exists()
- {
- return None;
- }
- Some(container_path)
- }
- pub fn print_instance(instance: &InstanceInfo) {
- let rg: bool = instance.running;
- println!(
- "{} {} {}{}",
- if rg {
- format!(
- "{}{}{}",
- "(".green().bold(),
- instance.short_id.to_string().green().bold(),
- ")".green().bold(),
- )
- } else {
- format!(
- "{}{}{}",
- "(".yellow().bold(),
- instance.short_id.to_string().green().bold(),
- ")".yellow().bold(),
- )
- },
- if rg {
- "Instance ID:".green().bold()
- } else {
- "Instance ID:".yellow().bold()
- },
- if rg {
- instance.id.green().bold()
- } else {
- instance.id.yellow().bold()
- },
- if rg {
- " (running)".to_string().green().bold()
- } else {
- " (not running)".to_string().yellow().bold()
- },
- );
- println!(
- "└── Short ID: {}",
- instance.short_id.to_string().underline()
- );
- println!("└── Port: {}", instance.port);
- println!("└── Available endpoints:");
- instance
- .available_endpoints
- .iter()
- .for_each(|ep| println!(" └── /{ep}"));
- }
- pub fn get_cli_version() -> Result<Version, String> {
- Version::parse(&format!("v{}", env!("CARGO_PKG_VERSION")))
- }
- pub fn get_crate_version<P: AsRef<Path>>(path: P) -> Result<Version, String> {
- let cargo_toml_path = path.as_ref().join("Cargo.toml");
- if !cargo_toml_path.exists() {
- return Err("Not a Rust crate: Cargo.toml not found".to_string());
- }
- let contents = fs::read_to_string(&cargo_toml_path)
- .map_err(|e| format!("Failed to read Cargo.toml: {e}"))?;
- let parsed_toml = contents
- .parse::<Value>()
- .map_err(|e| format!("Failed to parse Cargo.toml: {e}"))?;
- let version = parsed_toml
- .get("package")
- .and_then(|pkg| pkg.get("version"))
- .and_then(|v| v.as_str())
- .ok_or("Version field not found in [package] section")?;
- let vers = Version::parse(version)?;
- Ok(vers)
- }
- pub async fn get_remote_helix_version() -> Result<Version, Box<dyn Error>> {
- let client = Client::new();
- let url = "https://api.github.com/repos/HelixDB/helix-db/releases/latest";
- let response = client
- .get(url)
- .header("User-Agent", "rust")
- .header("Accept", "application/vnd.github+json")
- .send()
- .await?
- .text()
- .await?;
- let json: JsonValue = serde_json::from_str(&response)?;
- let tag_name = json
- .get("tag_name")
- .and_then(|v| v.as_str())
- .ok_or("Failed to find tag_name in response")?
- .to_string();
- Ok(Version::parse(&tag_name)?)
- }
- pub async fn github_login() -> Result<(String, String), Box<dyn Error>> {
- let url = "ws://ec2-184-72-27-116.us-west-1.compute.amazonaws.com:3000/login";
- let (mut ws_stream, _) = connect_async(url).await?;
- let init_msg: UserCodeMsg = match ws_stream.next().await {
- Some(Ok(Message::Text(payload))) => sonic_rs::from_str(&payload)?,
- Some(Ok(m)) => return Err(format!("Unexpected message: {m:?}").into()),
- Some(Err(e)) => return Err(e.into()),
- None => return Err("Connection Closed Unexpectedly".into()),
- };
- println!(
- "To Login please go \x1b]8;;{}\x1b\\here\x1b]8;;\x1b\\({}),\nand enter the code: {}",
- init_msg.verification_uri,
- init_msg.verification_uri,
- init_msg.user_code.bold()
- );
- let msg: ApiKeyMsg = match ws_stream.next().await {
- Some(Ok(Message::Text(payload))) => sonic_rs::from_str(&payload)?,
- Some(Ok(Message::Close(Some(CloseFrame {
- code: CloseCode::Error,
- reason,
- })))) => return Err(format!("Error: {reason}").into()),
- Some(Ok(m)) => return Err(format!("Unexpected message: {m:?}").into()),
- Some(Err(e)) => return Err(e.into()),
- None => return Err("Connection Closed Unexpectedly".into()),
- };
- Ok((msg.key, msg.user_id))
- }
- #[derive(Deserialize)]
- struct UserCodeMsg {
- user_code: String,
- verification_uri: String,
- }
- #[derive(Deserialize)]
- struct ApiKeyMsg {
- user_id: String,
- key: String,
- }
- /// tries to parse a credential file, returning the key, if any
- pub fn parse_credentials(creds: &str) -> Option<&str> {
- for line in creds.lines() {
- if let Some((key, value)) = line.split_once("=")
- && key.to_lowercase() == "helix_user_key"
- {
- return Some(value);
- }
- }
- None
- }
- pub async fn check_helix_version() {
- match check_helix_installation() {
- Some(_) => {}
- None => return,
- }
- let repo_path = {
- let home_dir = match dirs::home_dir() {
- Some(dir) => dir,
- None => return,
- };
- home_dir.join(".helix/repo/helix-db/helix-db")
- };
- let local_cli_version = match Version::parse(&format!("v{}", env!("CARGO_PKG_VERSION"))) {
- Ok(value) => value,
- Err(_) => return,
- };
- let crate_version = match get_crate_version(&repo_path) {
- Ok(value) => value,
- Err(_) => return,
- };
- let local_db_version = match Version::parse(&format!("v{crate_version}")) {
- Ok(value) => value,
- Err(_) => return,
- };
- let remote_helix_version = match get_remote_helix_version().await {
- Ok(value) => value,
- Err(_) => return,
- };
- if local_db_version < remote_helix_version || local_cli_version < remote_helix_version {
- println!(
- "{} {} {} {}",
- "New HelixDB version is available!".yellow().bold(),
- "Run".yellow().bold(),
- "helix update".white().bold(),
- "to install the newest version!".yellow().bold(),
- );
- }
- }
- pub fn check_cargo_version() -> bool {
- match Command::new("cargo").arg("--version").output() {
- Ok(output) => {
- let version_str = String::from_utf8_lossy(&output.stdout);
- let version = version_str
- .split_whitespace()
- .nth(1)
- .unwrap_or("0.0.0")
- .split('-')
- .next()
- .unwrap_or("0.0.0");
- let parts: Vec<u32> = version.split('.').filter_map(|s| s.parse().ok()).collect();
- if parts.len() >= 2 {
- parts[0] >= 1 && parts[1] >= 88
- } else {
- false
- }
- }
- Err(_) => false,
- }
- }
- pub fn get_n_helix_cli() -> Result<(), Box<dyn Error>> {
- // TODO: running this through rust doesn't identify GLIBC so has to compile from source
- let status = Command::new("sh")
- .arg("-c")
- .arg("curl -sSL 'https://install.helix-db.com' | bash")
- .env(
- "PATH",
- format!(
- "{}:{}",
- std::env::var("HOME")
- .map(|h| format!("{h}/.cargo/bin"))
- .unwrap_or_default(),
- std::env::var("PATH").unwrap_or_default()
- ),
- )
- .stdout(Stdio::inherit())
- .stderr(Stdio::inherit())
- .status()?;
- if !status.success() {
- return Err(format!("Command failed with status: {status}").into());
- }
- Ok(())
- }
- /// Checks if the path contains a schema.hx and config.hx.json file
- /// Returns a vector of DirEntry objects for all .hx files in the path
- pub fn check_and_read_files(path: &str) -> Result<Vec<DirEntry>, String> {
- if !fs::read_dir(path)
- .map_err(|e| format!("IO Error: {e}"))?
- .any(|file| file.ok().is_some_and(|f| f.file_name() == "schema.hx"))
- {
- return Err("No schema file found".to_string());
- }
- if !fs::read_dir(path)
- .map_err(|e| format!("IO Error: {e}"))?
- .any(|file| file.ok().is_some_and(|f| f.file_name() == "config.hx.json"))
- {
- return Err("No config.hx.json file found".to_string());
- }
- let files: Vec<DirEntry> = fs::read_dir(path)
- .unwrap()
- .filter_map(|entry| entry.ok())
- .filter(|file| file.file_name().to_string_lossy().ends_with(".hx"))
- .collect();
- let has_queries = files.iter().any(|file| file.file_name() != "schema.hx");
- if !has_queries {
- return Err("No query files (.hx) found".to_string());
- }
- Ok(files)
- }
- /// Generates a Content object from a vector of DirEntry objects
- /// Returns a Content object with the files and source
- ///
- /// This essentially makes a full string of all of the files while having a separate vector of the individual files
- ///
- /// This could be changed in the future but keeps the option open for being able to access the files separately or all at once
- pub fn generate_content(files: &[DirEntry]) -> Result<Content, String> {
- let files: Vec<HxFile> = files
- .iter()
- .map(|file| {
- let name = file.path().to_string_lossy().into_owned();
- let content = fs::read_to_string(file.path()).unwrap();
- HxFile { name, content }
- })
- .collect();
- let content = files
- .clone()
- .iter()
- .map(|file| file.content.clone())
- .collect::<Vec<String>>()
- .join("\n");
- Ok(Content {
- content,
- files,
- source: Source::default(),
- })
- }
- /// Uses the helix parser to parse the content into a Source object
- fn parse_content(content: &Content) -> Result<Source, String> {
- let source = match HelixParser::parse_source(content) {
- Ok(source) => source,
- Err(e) => {
- return Err(e.to_string());
- }
- };
- Ok(source)
- }
- /// Runs the static analyzer on the parsed source to catch errors and generate diagnostics if any.
- /// Otherwise returns the generated source object which is an IR used to transpile the queries to rust.
- fn analyze_source(source: Source) -> Result<GeneratedSource, String> {
- let (diagnostics, source) = analyze(&source);
- if !diagnostics.is_empty() {
- for diag in diagnostics {
- let filepath = diag.filepath.clone().unwrap_or("queries.hx".to_string());
- println!("{}", diag.render(&source.src, &filepath));
- }
- return Err("compilation failed!".to_string());
- }
- Ok(source)
- }
- pub fn generate(files: &[DirEntry], path: &str) -> Result<(Content, GeneratedSource), String> {
- let mut content = generate_content(files)?;
- content.source = parse_content(&content)?;
- let mut analyzed_source = analyze_source(content.source.clone())?;
- analyzed_source.config = read_config(path)?;
- Ok((content, analyzed_source))
- }
- pub fn read_config(path: &str) -> Result<Config, String> {
- let config_path = PathBuf::from(path).join("config.hx.json");
- let schema_path = PathBuf::from(path).join("schema.hx");
- let config = Config::from_files(config_path, schema_path).map_err(|e| e.to_string())?;
- Ok(config)
- }
- pub fn gen_typescript(source: &GeneratedSource, output_path: &str) -> Result<(), String> {
- let mut file = match File::create(PathBuf::from(output_path).join("interface.d.ts")) {
- Ok(file) => file,
- Err(e) => return Err(e.to_string()),
- };
- for node in &source.nodes {
- match write!(file, "{}", node.to_typescript()) {
- Ok(_) => {}
- Err(e) => return Err(e.to_string()),
- }
- }
- for edge in &source.edges {
- match write!(file, "{}", edge.to_typescript()) {
- Ok(_) => {}
- Err(e) => return Err(e.to_string()),
- }
- }
- for vector in &source.vectors {
- match write!(file, "{}", vector.to_typescript()) {
- Ok(_) => {}
- Err(e) => return Err(e.to_string()),
- }
- }
- Ok(())
- }
- pub fn find_available_port(start_port: u16) -> Option<u16> {
- let mut port = start_port;
- while port < 65535 {
- let addr = format!("0.0.0.0:{port}").parse::<SocketAddr>().unwrap();
- match TcpListener::bind(addr) {
- Ok(listener) => {
- drop(listener);
- let localhost = format!("127.0.0.1:{port}").parse::<SocketAddr>().unwrap();
- match TcpListener::bind(localhost) {
- Ok(local_listener) => {
- drop(local_listener);
- return Some(port);
- }
- Err(e) => {
- if e.kind() != ErrorKind::AddrInUse {
- return None;
- }
- port += 1;
- continue;
- }
- }
- }
- Err(e) => {
- if e.kind() != ErrorKind::AddrInUse {
- return None;
- }
- port += 1;
- continue;
- }
- }
- }
- None
- }
- pub fn get_cfg_deploy_path(cmd_path: Option<String>) -> String {
- if let Some(path) = cmd_path {
- return path;
- }
- let cwd = ".";
- let files = match check_and_read_files(cwd) {
- Ok(files) => files,
- Err(_) => {
- return DB_DIR.to_string();
- }
- };
- if !files.is_empty() {
- return cwd.to_string();
- }
- DB_DIR.to_string()
- }
- pub fn compile_and_build_helix(
- path: String,
- output: &PathBuf,
- files: Vec<DirEntry>,
- ) -> Result<Content, String> {
- let mut sp = Spinner::new(Spinners::Dots9, "Compiling Helix queries".into());
- let num_files = files.len();
- let (code, analyzed_source) = match generate(&files, &path) {
- Ok((code, analyzer_source)) => (code, analyzer_source),
- Err(e) => {
- sp.stop_with_message("Error compiling queries".red().bold().to_string());
- println!("└── {e}");
- return Err("Error compiling queries".to_string());
- }
- };
- sp.stop_with_message(format!(
- "{} {} {}",
- "Successfully compiled".green().bold(),
- num_files,
- "query files".green().bold()
- ));
- let cache_dir = PathBuf::from(&output);
- fs::create_dir_all(&cache_dir).unwrap();
- let file_path = PathBuf::from(&output).join("src/queries.rs");
- let mut generated_rust_code = String::new();
- match write!(&mut generated_rust_code, "{analyzed_source}") {
- Ok(_) => println!("{}", "Successfully transpiled queries".green().bold()),
- Err(e) => {
- println!("{}", "Failed to transpile queries".red().bold());
- println!("└── {} {}", "Error:".red().bold(), e);
- return Err("Failed to transpile queries".to_string());
- }
- }
- match fs::write(file_path, generated_rust_code) {
- Ok(_) => println!("{}", "Successfully wrote queries file".green().bold()),
- Err(e) => {
- println!("{}", "Failed to write queries file".red().bold());
- println!("└── {} {}", "Error:".red().bold(), e);
- return Err("Failed to write queries file".to_string());
- }
- }
- let mut sp = Spinner::new(Spinners::Dots9, "Building Helix".into());
- let config_path = PathBuf::from(&output).join("src/config.hx.json");
- fs::copy(
- PathBuf::from(path.to_string() + "/config.hx.json"),
- config_path,
- )
- .unwrap();
- let schema_path = PathBuf::from(&output).join("src/schema.hx");
- fs::copy(PathBuf::from(path.to_string() + "/schema.hx"), schema_path).unwrap();
- let mut runner = Command::new("cargo");
- runner
- .arg("check")
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .current_dir(PathBuf::from(&output));
- match runner.output() {
- Ok(_) => {}
- Err(e) => {
- sp.stop_with_message("Failed to check Rust code".red().bold().to_string());
- println!("└── {} {}", "Error:".red().bold(), e);
- return Err("Error checking rust code".to_string());
- }
- }
- let mut runner = Command::new("cargo");
- runner
- .arg("build")
- .arg("--release")
- .current_dir(PathBuf::from(&output))
- .env("RUSTFLAGS", "-Awarnings");
- match runner.output() {
- Ok(output) => {
- if output.status.success() {
- sp.stop_with_message("Successfully built Helix".green().bold().to_string());
- Ok(code)
- } else {
- sp.stop_with_message("Failed to build Helix".red().bold().to_string());
- let stderr = String::from_utf8_lossy(&output.stderr);
- if !stderr.is_empty() {
- println!("└── {} {}", "Error:\n".red().bold(), stderr);
- }
- Err("Error building helix".to_string())
- }
- }
- Err(e) => {
- sp.stop_with_message("Failed to build Helix".red().bold().to_string());
- println!("└── {} {}", "Error:".red().bold(), e);
- Err("Error building helix".to_string())
- }
- }
- }
- pub fn deploy_helix(port: u16, code: Content, instance_id: Option<String>) -> Result<(), String> {
- let mut sp = Spinner::new(Spinners::Dots9, "Starting Helix instance".into());
- let instance_manager = InstanceManager::new().unwrap();
- let binary_path = dirs::home_dir()
- .map(|path| path.join(".helix/repo/helix-db/target/release/helix-container"))
- .unwrap();
- let endpoints: Vec<String> = code.source.queries.iter().map(|q| q.name.clone()).collect();
- if let Some(iid) = instance_id {
- let cached_binary = instance_manager.cache_dir.join(&iid);
- match fs::copy(binary_path, &cached_binary) {
- Ok(_) => {}
- Err(e) => {
- println!("{} {}", "Error while copying binary:".red().bold(), e);
- return Err("".to_string());
- }
- }
- match instance_manager.start_instance(&iid, Some(endpoints)) {
- Ok(instance) => {
- sp.stop_with_message(
- "Successfully started Helix instance"
- .green()
- .bold()
- .to_string(),
- );
- print_instance(&instance);
- Ok(())
- }
- Err(e) => {
- sp.stop_with_message("Failed to start Helix instance".red().bold().to_string());
- println!("└── {} {}", "Error:".red().bold(), e);
- Err("".to_string())
- }
- }
- } else {
- match instance_manager.init_start_instance(&binary_path, port, endpoints) {
- Ok(instance) => {
- sp.stop_with_message(
- "Successfully started Helix instance"
- .green()
- .bold()
- .to_string(),
- );
- print_instance(&instance);
- Ok(())
- }
- Err(e) => {
- sp.stop_with_message("Failed to start Helix instance".red().bold().to_string());
- println!("└── {} {}", "Error:".red().bold(), e);
- Err("Failed to start Helix instance".to_string())
- }
- }
- }
- }
- pub fn redeploy_helix(instance: String, code: Content) -> Result<(), String> {
- let instance_manager = InstanceManager::new().unwrap();
- let iid = instance;
- match instance_manager.get_instance(&iid) {
- Ok(Some(_)) => println!("{}", "Helix instance found!".green().bold()),
- Ok(None) => {
- println!(
- "{} {}",
- "No Helix instance found with id".red().bold(),
- iid.red().bold()
- );
- return Err("Error".to_string());
- }
- Err(e) => {
- println!("{} {}", "Error:".red().bold(), e);
- return Err("".to_string());
- }
- };
- match instance_manager.stop_instance(&iid) {
- Ok(_) => {}
- Err(e) => {
- println!("{} {}", "Error while stopping instance:".red().bold(), e);
- return Err("".to_string());
- }
- }
- match deploy_helix(0, code, Some(iid)) {
- Ok(_) => Ok(()),
- Err(e) => Err(e.to_string()),
- }
- }
- pub async fn redeploy_helix_remote(
- cluster: String,
- path: String,
- files: Vec<DirEntry>,
- ) -> Result<(), String> {
- let mut sp = Spinner::new(Spinners::Dots9, "Uploading queries to remote db".into());
- let content = match generate_content(&files) {
- Ok(content) => content,
- Err(e) => {
- sp.stop_with_message("Error generating content".red().bold().to_string());
- println!("└── {e}");
- return Err("".to_string());
- }
- };
- // get config from ~/.helix/credentials
- let home_dir = std::env::var("HOME").unwrap_or("~/".to_string());
- let config_path = &format!("{home_dir}/.helix");
- let config_path = Path::new(config_path);
- let config_path = config_path.join("credentials");
- if !config_path.exists() {
- sp.stop_with_message("No credentials found".yellow().bold().to_string());
- println!(
- "{}",
- "Please run `helix config` to set your credentials"
- .yellow()
- .bold()
- );
- return Err("".to_string());
- }
- // TODO: probable could make this more secure
- // reads credentials from ~/.helix/credentials
- let config = fs::read_to_string(config_path).unwrap();
- let user_id = config
- .split("helix_user_id=")
- .nth(1)
- .unwrap()
- .split("\n")
- .next()
- .unwrap();
- let user_key = config
- .split("helix_user_key=")
- .nth(1)
- .unwrap()
- .split("\n")
- .next()
- .unwrap();
- // read config.hx.json
- let config = match Config::from_files(
- PathBuf::from(path.clone()).join("config.hx.json"),
- PathBuf::from(path.clone()).join("schema.hx"),
- ) {
- Ok(config) => config,
- Err(e) => {
- println!("Error loading config: {e}");
- sp.stop_with_message("Error loading config".red().bold().to_string());
- return Err("".to_string());
- }
- };
- // upload queries to central server
- let payload = json!({
- "user_id": user_id,
- "queries": content.files,
- "cluster_id": cluster,
- "version": "0.1.0",
- "helix_config": config.to_json()
- });
- println!("{payload:#?}");
- let client = reqwest::Client::new();
- println!("{user_key}");
- println!("{}", &cluster);
- match client
- .post(
- "http://ec2-184-72-27-116.us-west-1.compute.amazonaws.com:3000/clusters/deploy-queries",
- )
- .header("x-api-key", user_key) // used to verify user
- .header("x-cluster-id", &cluster) // used to verify instance with user
- .header("Content-Type", "application/json")
- .body(sonic_rs::to_string(&payload).unwrap())
- .send()
- .await
- {
- Ok(response) => {
- if response.status().is_success() {
- sp.stop_with_message("Queries uploaded to remote db".green().bold().to_string());
- } else {
- sp.stop_with_message(
- "Error uploading queries to remote db"
- .red()
- .bold()
- .to_string(),
- );
- println!("└── {}", response.text().await.unwrap());
- return Err("".to_string());
- }
- }
- Err(e) => {
- sp.stop_with_message(
- "Error uploading queries to remote db"
- .red()
- .bold()
- .to_string(),
- );
- println!("└── {e}");
- return Err("".to_string());
- }
- };
- Ok(())
- }
|