Compare commits
3 Commits
75134b6fac
...
179744d8b3
| Author | SHA1 | Date | |
|---|---|---|---|
|
179744d8b3
|
|||
|
e15146af60
|
|||
|
0a26e77899
|
@@ -19,8 +19,8 @@ REPO ?= spacesh
|
|||||||
|
|
||||||
# ---- Prod deploy (SSH) ----
|
# ---- Prod deploy (SSH) ----
|
||||||
SSH_HOST ?= 192.168.8.5
|
SSH_HOST ?= 192.168.8.5
|
||||||
SSH_USER ?= deploy
|
SSH_USER ?= root
|
||||||
SSH_REMOTE_DIR ?= /opt/spacesh
|
SSH_REMOTE_DIR ?= /srv/spaceshell
|
||||||
SSH_KEY ?= $(HOME)/.ssh/id_rsa
|
SSH_KEY ?= $(HOME)/.ssh/id_rsa
|
||||||
SSH_OPTS := -i $(SSH_KEY) -o StrictHostKeyChecking=accept-new
|
SSH_OPTS := -i $(SSH_KEY) -o StrictHostKeyChecking=accept-new
|
||||||
|
|
||||||
@@ -44,14 +44,18 @@ targets: ## add rust targets for the universal build
|
|||||||
|
|
||||||
.PHONY: dmg
|
.PHONY: dmg
|
||||||
dmg: targets ## build the universal (Intel + Apple Silicon) .dmg — UNSIGNED
|
dmg: targets ## build the universal (Intel + Apple Silicon) .dmg — UNSIGNED
|
||||||
# Tauri's universal build compiles each arch separately and expects a sidecar
|
# Tauri's universal build needs BOTH the per-arch sidecars (resolved during each
|
||||||
# named with THAT arch's triple; it lipo's them into the universal bundle and
|
# arch sub-build) AND a fat spaceshd-universal-apple-darwin (copied into the final
|
||||||
# ships spaceshd inside spacesh.app/Contents/MacOS (else the GUI is offline).
|
# bundle — Tauri does not lipo sidecars itself). spaceshd ships inside
|
||||||
|
# spacesh.app/Contents/MacOS else the GUI is offline.
|
||||||
cargo build --release -p spaceshd --target aarch64-apple-darwin
|
cargo build --release -p spaceshd --target aarch64-apple-darwin
|
||||||
cargo build --release -p spaceshd --target x86_64-apple-darwin
|
cargo build --release -p spaceshd --target x86_64-apple-darwin
|
||||||
rm -rf $(SIDECAR_DIR) && mkdir -p $(SIDECAR_DIR) # avoid stale sidecars poisoning the bundle
|
rm -rf $(SIDECAR_DIR) && mkdir -p $(SIDECAR_DIR) # avoid stale sidecars poisoning the bundle
|
||||||
cp target/aarch64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-aarch64-apple-darwin
|
cp target/aarch64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-aarch64-apple-darwin
|
||||||
cp target/x86_64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-x86_64-apple-darwin
|
cp target/x86_64-apple-darwin/release/spaceshd $(SIDECAR_DIR)/spaceshd-x86_64-apple-darwin
|
||||||
|
lipo -create -output $(SIDECAR_DIR)/spaceshd-universal-apple-darwin \
|
||||||
|
target/aarch64-apple-darwin/release/spaceshd \
|
||||||
|
target/x86_64-apple-darwin/release/spaceshd
|
||||||
cd $(APP_DIR) && npm run tauri build -- --target $(TAURI_TARGET) --config $(BUNDLE_CONFIG)
|
cd $(APP_DIR) && npm run tauri build -- --target $(TAURI_TARGET) --config $(BUNDLE_CONFIG)
|
||||||
@echo "→ $(DMG_DIR)" && ls -lh $(DMG_DIR)/*.dmg
|
@echo "→ $(DMG_DIR)" && ls -lh $(DMG_DIR)/*.dmg
|
||||||
|
|
||||||
@@ -63,6 +67,13 @@ dmg-native: ## build a .dmg for the current arch only (faster)
|
|||||||
cd $(APP_DIR) && npm run tauri build -- --config $(BUNDLE_CONFIG)
|
cd $(APP_DIR) && npm run tauri build -- --config $(BUNDLE_CONFIG)
|
||||||
@ls -lh $(NATIVE_DMG_DIR)/*.dmg
|
@ls -lh $(NATIVE_DMG_DIR)/*.dmg
|
||||||
|
|
||||||
|
.PHONY: app-bundle
|
||||||
|
app-bundle: ## build just the native .app (no .dmg/hdiutil — fast, for self-install)
|
||||||
|
cargo build --release -p spaceshd
|
||||||
|
rm -rf $(SIDECAR_DIR) && mkdir -p $(SIDECAR_DIR)
|
||||||
|
cp target/release/spaceshd $(SIDECAR_DIR)/spaceshd-$(NATIVE_TRIPLE)
|
||||||
|
cd $(APP_DIR) && npm run tauri build -- --bundles app --config $(BUNDLE_CONFIG)
|
||||||
|
|
||||||
.PHONY: dev
|
.PHONY: dev
|
||||||
dev: ## run the app in dev mode (tauri dev)
|
dev: ## run the app in dev mode (tauri dev)
|
||||||
cd $(APP_DIR) && npm run tauri dev
|
cd $(APP_DIR) && npm run tauri dev
|
||||||
@@ -90,7 +101,7 @@ install-universal: kill-daemon ## install the universal .app to /Applications
|
|||||||
xattr -dr com.apple.quarantine /Applications/spacesh.app
|
xattr -dr com.apple.quarantine /Applications/spacesh.app
|
||||||
|
|
||||||
.PHONY: reinstall
|
.PHONY: reinstall
|
||||||
reinstall: dmg-native install ## native rebuild + reinstall + restart daemon (fast self-update)
|
reinstall: app-bundle install ## fast self-update: build .app (no dmg), reinstall, restart daemon
|
||||||
|
|
||||||
# ---- Tests ----
|
# ---- Tests ----
|
||||||
|
|
||||||
|
|||||||
+13
-28
@@ -120,7 +120,7 @@ impl Bridge {
|
|||||||
let pending: Arc<Mutex<HashMap<u64, oneshot::Sender<Envelope>>>> = Arc::default();
|
let pending: Arc<Mutex<HashMap<u64, oneshot::Sender<Envelope>>>> = Arc::default();
|
||||||
let out_channels: Arc<Mutex<HashMap<String, Channel<Vec<u8>>>>> = Arc::default();
|
let out_channels: Arc<Mutex<HashMap<String, Channel<Vec<u8>>>>> = Arc::default();
|
||||||
let (tx, reader) = spawn_connection(&sock, &app, pending.clone(), out_channels.clone()).await?;
|
let (tx, reader) = spawn_connection(&sock, &app, pending.clone(), out_channels.clone()).await?;
|
||||||
let bridge = Self {
|
Ok(Self {
|
||||||
next_id: AtomicU64::new(1),
|
next_id: AtomicU64::new(1),
|
||||||
app,
|
app,
|
||||||
sock,
|
sock,
|
||||||
@@ -130,34 +130,16 @@ impl Bridge {
|
|||||||
reader: Mutex::new(reader),
|
reader: Mutex::new(reader),
|
||||||
pending,
|
pending,
|
||||||
out_channels,
|
out_channels,
|
||||||
};
|
})
|
||||||
bridge.ensure_matching_daemon().await;
|
|
||||||
Ok(bridge)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If a previously-running daemon is a different build than the one bundled
|
/// Send a command without awaiting a reply or retrying. Used for Shutdown:
|
||||||
/// with this GUI (the daemon outlives the GUI, so an old one can still be
|
/// the daemon exits before its reply is flushed, so a normal request() would
|
||||||
/// serving the socket), restart it so our matching daemon takes over. No-op
|
/// time out and the reconnect-retry would respawn-and-reshutdown in a loop.
|
||||||
/// for unstamped dev builds or when the daemon is too old to report a build.
|
async fn fire(&self, cmd: Cmd) {
|
||||||
async fn ensure_matching_daemon(&self) {
|
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||||
let want = option_env!("SPACESH_BUILD").unwrap_or("dev");
|
let tx = self.tx.lock().await.clone();
|
||||||
if want == "dev" {
|
let _ = tx.send(Envelope::Req { id, cmd }).await;
|
||||||
return;
|
|
||||||
}
|
|
||||||
let got = match self.request(Cmd::Health).await {
|
|
||||||
Ok(env) => data_of(env)
|
|
||||||
.ok()
|
|
||||||
.and_then(|v| v.get("build").and_then(|b| b.as_str()).map(str::to_string))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
if got.is_empty() || got == want {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Stale daemon — stop it and respawn our bundled one (matching code).
|
|
||||||
let seen = self.gen.load(Ordering::Acquire);
|
|
||||||
let _ = self.request(Cmd::Shutdown).await; // daemon exits; reply may not arrive
|
|
||||||
let _ = self.reconnect(seen).await; // ensure_daemon respawns the bundled daemon
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-establish the daemon connection. Single-flight: callers pass the `gen`
|
/// Re-establish the daemon connection. Single-flight: callers pass the `gen`
|
||||||
@@ -461,5 +443,8 @@ pub async fn set_config(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn shutdown_daemon(state: BridgeState<'_>) -> Result<Value, String> {
|
pub async fn shutdown_daemon(state: BridgeState<'_>) -> Result<Value, String> {
|
||||||
data_of(state.request(Cmd::Shutdown).await.map_err(|e| e.to_string())?)
|
// Fire-and-forget: the daemon exits without a flushed reply, so awaiting one
|
||||||
|
// would time out and trigger a respawn-then-reshutdown loop.
|
||||||
|
state.fire(Cmd::Shutdown).await;
|
||||||
|
Ok(Value::Null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- landing
|
- landing
|
||||||
ports:
|
expose:
|
||||||
- "80:80"
|
- "80"
|
||||||
volumes:
|
volumes:
|
||||||
- ./proxy.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./proxy.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
- ./download:/srv/download:ro
|
- ./download:/srv/download:ro
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
0.1.1
|
0.1.2
|
||||||
+3
-3
@@ -820,7 +820,7 @@
|
|||||||
<a href="#cli">CLI</a>
|
<a href="#cli">CLI</a>
|
||||||
<a href="https://github.com/spacesh" target="_blank" rel="noopener">GitHub</a>
|
<a href="https://github.com/spacesh" target="_blank" rel="noopener">GitHub</a>
|
||||||
</nav>
|
</nav>
|
||||||
<a href="#download" class="btn btn-primary">Скачать для macOS</a>
|
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary">Скачать для macOS</a>
|
||||||
<button class="mobile-nav-toggle" aria-label="Меню">☰</button>
|
<button class="mobile-nav-toggle" aria-label="Меню">☰</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -840,7 +840,7 @@
|
|||||||
Закрыл окно, обновил приложение, словил краш — агенты продолжают работать.
|
Закрыл окно, обновил приложение, словил краш — агенты продолжают работать.
|
||||||
</p>
|
</p>
|
||||||
<div class="hero-buttons">
|
<div class="hero-buttons">
|
||||||
<a href="#download" class="btn btn-primary btn-large">
|
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary btn-large">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -1098,7 +1098,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="cta-title reveal">Готов гонять агентов пачками?</h2>
|
<h2 class="cta-title reveal">Готов гонять агентов пачками?</h2>
|
||||||
<div class="cta-buttons reveal">
|
<div class="cta-buttons reveal">
|
||||||
<a href="/download/spacesh.dmg" class="btn btn-primary btn-large">
|
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary btn-large">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
Reference in New Issue
Block a user