feat: initial commit — antigravity proxy with MITM, standalone LS, and snapshot tooling
This commit is contained in:
217
src/constants.rs
Normal file
217
src/constants.rs
Normal file
@@ -0,0 +1,217 @@
|
||||
//! Shared constants — auto-detected from the installed Antigravity binary at startup.
|
||||
//!
|
||||
//! On first access, we locate the Antigravity installation (via the running
|
||||
//! language server PID or well-known paths), parse `product.json` for version
|
||||
//! strings, and extract Chrome/Electron versions from the binary. If detection
|
||||
//! fails, we fall back to hardcoded values.
|
||||
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
/// Auto-detected version info from the installed Antigravity app.
|
||||
struct DetectedVersions {
|
||||
antigravity: String,
|
||||
chrome: String,
|
||||
electron: String,
|
||||
client: String,
|
||||
}
|
||||
|
||||
/// Locate the Antigravity install directory by tracing the language server PID
|
||||
/// back to its binary, then walking up to the app root. Falls back to
|
||||
/// well-known install paths.
|
||||
fn find_install_dir() -> Option<String> {
|
||||
// 1. Try tracing the running language server → /usr/share/antigravity/resources/app/extensions/...
|
||||
if let Ok(output) = Command::new("sh")
|
||||
.args(["-c", "pgrep -f language_server_linux | head -1"])
|
||||
.output()
|
||||
{
|
||||
let pid = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if !pid.is_empty() {
|
||||
if let Ok(exe) = fs::read_link(format!("/proc/{pid}/exe")) {
|
||||
let exe_str = exe.to_string_lossy().to_string();
|
||||
// exe is like: /usr/share/antigravity/resources/app/extensions/antigravity/bin/language_server_linux_x64
|
||||
// We want: /usr/share/antigravity
|
||||
if let Some(idx) = exe_str.find("/resources/") {
|
||||
return Some(exe_str[..idx].to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fall back to well-known install paths
|
||||
for path in &["/usr/share/antigravity", "/opt/Antigravity"] {
|
||||
if fs::metadata(format!("{path}/resources/app/product.json")).is_ok() {
|
||||
return Some(path.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Read `product.json` from the install dir and extract version fields.
|
||||
fn read_product_json(install_dir: &str) -> (Option<String>, Option<String>) {
|
||||
let path = format!("{install_dir}/resources/app/product.json");
|
||||
let Ok(contents) = fs::read_to_string(&path) else {
|
||||
return (None, None);
|
||||
};
|
||||
let Ok(json) = serde_json::from_str::<serde_json::Value>(&contents) else {
|
||||
return (None, None);
|
||||
};
|
||||
|
||||
let version = json["version"].as_str().map(|s| s.to_string());
|
||||
let ide_version = json["ideVersion"].as_str().map(|s| s.to_string());
|
||||
(version, ide_version)
|
||||
}
|
||||
|
||||
/// Extract Chrome and Electron versions from the main binary via `strings`.
|
||||
/// Pattern: "Chrome/142.0.7444.175", "Electron/39.2.3".
|
||||
fn extract_binary_versions(install_dir: &str) -> (Option<String>, Option<String>) {
|
||||
let binary = format!("{install_dir}/antigravity");
|
||||
if fs::metadata(&binary).is_err() {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
// Use grep -oP on the binary to avoid loading the whole thing into memory
|
||||
let chrome = Command::new("sh")
|
||||
.args([
|
||||
"-c",
|
||||
&format!(
|
||||
"strings '{}' | grep -oP 'Chrome/[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+' | head -1",
|
||||
binary
|
||||
),
|
||||
])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
let s = String::from_utf8_lossy(&o.stdout).trim().to_string();
|
||||
s.strip_prefix("Chrome/").map(|v| v.to_string())
|
||||
});
|
||||
|
||||
let electron = Command::new("sh")
|
||||
.args([
|
||||
"-c",
|
||||
&format!(
|
||||
"strings '{}' | grep -oP 'Electron/[0-9]+\\.[0-9]+\\.[0-9]+' | head -1",
|
||||
binary
|
||||
),
|
||||
])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
let s = String::from_utf8_lossy(&o.stdout).trim().to_string();
|
||||
s.strip_prefix("Electron/").map(|v| v.to_string())
|
||||
});
|
||||
|
||||
(chrome, electron)
|
||||
}
|
||||
|
||||
/// Detect all versions from the installed Antigravity app.
|
||||
fn detect_versions() -> DetectedVersions {
|
||||
// Hardcoded fallbacks — last known good values
|
||||
const FALLBACK_ANTIGRAVITY: &str = "1.107.0";
|
||||
const FALLBACK_CHROME: &str = "142.0.7444.175";
|
||||
const FALLBACK_ELECTRON: &str = "39.2.3";
|
||||
const FALLBACK_CLIENT: &str = "1.16.5";
|
||||
|
||||
let Some(install_dir) = find_install_dir() else {
|
||||
eprintln!(
|
||||
"[constants] ⚠ Could not find Antigravity install — using fallback versions"
|
||||
);
|
||||
return DetectedVersions {
|
||||
antigravity: FALLBACK_ANTIGRAVITY.to_string(),
|
||||
chrome: FALLBACK_CHROME.to_string(),
|
||||
electron: FALLBACK_ELECTRON.to_string(),
|
||||
client: FALLBACK_CLIENT.to_string(),
|
||||
};
|
||||
};
|
||||
|
||||
// product.json → antigravity version + client/IDE version
|
||||
let (ag_ver, client_ver) = read_product_json(&install_dir);
|
||||
|
||||
// Binary → Chrome + Electron versions
|
||||
let (chrome_ver, electron_ver) = extract_binary_versions(&install_dir);
|
||||
|
||||
let versions = DetectedVersions {
|
||||
antigravity: ag_ver.unwrap_or_else(|| FALLBACK_ANTIGRAVITY.to_string()),
|
||||
chrome: chrome_ver.unwrap_or_else(|| FALLBACK_CHROME.to_string()),
|
||||
electron: electron_ver.unwrap_or_else(|| FALLBACK_ELECTRON.to_string()),
|
||||
client: client_ver.unwrap_or_else(|| FALLBACK_CLIENT.to_string()),
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"[constants] ✓ Detected versions: Antigravity={}, Chrome={}, Electron={}, Client={}",
|
||||
versions.antigravity, versions.chrome, versions.electron, versions.client
|
||||
);
|
||||
|
||||
versions
|
||||
}
|
||||
|
||||
// ─── Public API ──────────────────────────────────────────────────────────────
|
||||
|
||||
/// All detected versions — computed once on first access.
|
||||
static VERSIONS: LazyLock<DetectedVersions> = LazyLock::new(detect_versions);
|
||||
|
||||
/// Antigravity app version (e.g. "1.107.0").
|
||||
pub fn antigravity_version() -> &'static str {
|
||||
&VERSIONS.antigravity
|
||||
}
|
||||
|
||||
/// Chrome version bundled with Electron (e.g. "142.0.7444.175").
|
||||
pub fn chrome_version() -> &'static str {
|
||||
&VERSIONS.chrome
|
||||
}
|
||||
|
||||
/// Electron version (e.g. "39.2.3").
|
||||
pub fn electron_version() -> &'static str {
|
||||
&VERSIONS.electron
|
||||
}
|
||||
|
||||
/// Client/IDE version from product.json (e.g. "1.16.5").
|
||||
pub fn client_version() -> &'static str {
|
||||
&VERSIONS.client
|
||||
}
|
||||
|
||||
pub const CLIENT_NAME: &str = "antigravity";
|
||||
pub const LS_SERVICE: &str = "exa.language_server_pb.LanguageServerService";
|
||||
|
||||
/// Log base directory for Antigravity.
|
||||
pub fn log_base() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
|
||||
format!("{home}/.config/Antigravity/logs")
|
||||
}
|
||||
|
||||
/// Token file path.
|
||||
pub fn token_file_path() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/root".to_string());
|
||||
format!("{home}/.config/antigravity-proxy-token")
|
||||
}
|
||||
|
||||
/// User-Agent string matching the Electron webview — computed once.
|
||||
pub static USER_AGENT: LazyLock<String> = LazyLock::new(|| {
|
||||
format!(
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 \
|
||||
(KHTML, like Gecko) Antigravity/{} \
|
||||
Chrome/{} Electron/{} Safari/537.36",
|
||||
antigravity_version(),
|
||||
chrome_version(),
|
||||
electron_version()
|
||||
)
|
||||
});
|
||||
|
||||
/// Chrome major version for sec-ch-ua header — computed once.
|
||||
pub static CHROME_MAJOR: LazyLock<String> = LazyLock::new(|| {
|
||||
chrome_version()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap_or("142")
|
||||
.to_string()
|
||||
});
|
||||
|
||||
/// Safely truncate a string to at most `max` characters (not bytes).
|
||||
pub fn safe_truncate(s: &str, max: usize) -> String {
|
||||
match s.char_indices().nth(max) {
|
||||
None => s.to_string(),
|
||||
Some((idx, _)) => format!("{}...", &s[..idx]),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user