1pub mod api;
23pub mod bus;
24pub mod exec;
25pub mod fsops;
26pub mod jobs;
27pub mod osops;
28pub mod peer;
29#[cfg(feature = "sysinfo-caps")]
30pub mod procs;
31pub mod proto;
32#[cfg(feature = "pty")]
33pub mod pty;
34pub mod session;
35pub mod store;
36#[cfg(feature = "sysinfo-caps")]
37pub mod sysmon;
38pub mod transport;
39pub mod watch;
40
41pub use proto::{Framing, Out, Peer};
62pub use session::{caps, Session};
63
64use std::io::Read;
65use std::path::PathBuf;
66
67pub const VERSION: &str = env!("CARGO_PKG_VERSION");
69
70pub fn default_socket() -> PathBuf {
78 if let Ok(p) = std::env::var("ZWIRE_HOST_SOCK") {
79 return PathBuf::from(p);
80 }
81 #[cfg(windows)]
82 {
83 let user = std::env::var("USERNAME").unwrap_or_else(|_| "user".into());
84 let safe: String = user
85 .chars()
86 .filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
87 .collect();
88 let name = if safe.is_empty() { "user".into() } else { safe };
89 PathBuf::from(format!("zwire-host-{name}"))
90 }
91 #[cfg(not(windows))]
92 {
93 if let Ok(rt) = std::env::var("XDG_RUNTIME_DIR") {
94 if !rt.is_empty() {
95 return PathBuf::from(rt).join("zwire-host.sock");
96 }
97 }
98 store::app_dir("zwire").join("host.sock")
99 }
100}
101
102const USAGE: &str = "\
103zwire-host — universal local host (system stats · fs · exec · pty · kv · os)
104
105USAGE:
106 zwire-host native-messaging mode on stdio (Chrome default)
107 zwire-host serve run the NDJSON socket daemon
108 zwire-host call '<json>' send one request to the daemon, print reply
109 zwire-host call ...reading the request JSON from stdin
110 zwire-host call --stream '...' keep printing frames (sysinfo/pty streams)
111 zwire-host version | help
112
113OPTIONS:
114 --socket <path> override the socket path (default: $ZWIRE_HOST_SOCK or
115 $XDG_RUNTIME_DIR/zwire-host.sock or ~/.zwire/host.sock)
116 --stream, -f relay every reply frame instead of just the first
117 --tcp <addr> (serve) also listen for peers/remote clients on TCP
118 --token <tok> (serve) shared secret required of inbound TCP ($ZWIRE_HOST_TOKEN)
119 --name <name> (serve) this host's advertised peer name (default: hostname)
120 --peer <addr> (serve) dial a peer and keep it linked; repeatable
121
122Examples:
123 zwire-host serve &
124 zwire-host call '{\"cmd\":\"hostinfo\"}'
125 zwire-host call '{\"cmd\":\"fs_walk\",\"path\":\"~/src\",\"ext\":\"rs\"}'
126 echo '{\"cmd\":\"exec\",\"program\":\"git\",\"args\":[\"status\"]}' | zwire-host call
127 zwire-host call --stream '{\"cmd\":\"sysinfo_start\"}'
128 zwire-host serve --tcp 0.0.0.0:7420 --token SECRET --peer other.local:7420
129";
130
131pub fn run(args: Vec<String>) {
136 let mut socket = default_socket();
138 let mut follow = false;
139 let mut tcp: Option<String> = None;
140 let mut token: Option<String> = None;
141 let mut name: Option<String> = None;
142 let mut peers: Vec<String> = Vec::new();
143 let mut positional: Vec<String> = Vec::new();
144 let mut it = args.into_iter();
145 while let Some(a) = it.next() {
146 match a.as_str() {
147 "--socket" | "-s" => {
148 if let Some(p) = it.next() {
149 socket = PathBuf::from(p);
150 }
151 }
152 "--stream" | "--follow" | "-f" => follow = true,
153 "--tcp" => tcp = it.next(),
154 "--token" => token = it.next(),
155 "--name" => name = it.next(),
156 "--peer" => {
157 if let Some(p) = it.next() {
158 peers.push(p);
159 }
160 }
161 _ => positional.push(a),
162 }
163 }
164
165 match positional.first().map(String::as_str) {
166 Some("serve") => transport::serve(transport::ServeConfig {
167 socket,
168 tcp,
169 token,
170 name,
171 peers,
172 }),
173 Some("call") => {
174 let rest = positional[1..].join(" ");
175 let request = if rest.trim().is_empty() {
176 let mut s = String::new();
177 let _ = std::io::stdin().read_to_string(&mut s);
178 s
179 } else {
180 rest
181 };
182 transport::call(&socket, &request, follow);
183 }
184 Some("version") | Some("--version") | Some("-V") => {
185 println!("zwire-host {VERSION}");
186 }
187 Some("help") | Some("--help") | Some("-h") => {
188 print!("{USAGE}");
189 }
190 _ => transport::stdio(),
192 }
193}