P1: typed RPC bridge + FileSystemProvider + dual-panel local browsing
- shared/types + shared/rpc: full wire contract (Result envelope, no exceptions cross the bridge) - FileSystemProvider interface, LocalProvider, SessionRegistry with built-in 'local' - walk.ts: provider-generic recursive walk + removeRecursive - rpc-handlers wired into BrowserWindow; 10min request timeout for slow SFTP ops - Angular: RpcService (Electroview bridge + plain-browser guard), PanelsService with signals-based PanelState (sort/cursor/selection), FilePanel component with keyboard nav (arrows/Space/Enter/Backspace/Tab), path bar, toasts - verified: both panels listDir home over the bridge in the running app Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { LocalProvider } from "./local";
|
||||
import type { FileSystemProvider } from "./provider";
|
||||
|
||||
export const LOCAL_SESSION_ID = "local";
|
||||
|
||||
/**
|
||||
* Maps sessionId -> provider. "local" is always available; each SFTP connect
|
||||
* adds a new session (one SSH connection per panel-connect, no refcounting).
|
||||
*/
|
||||
export class SessionRegistry {
|
||||
private sessions = new Map<string, FileSystemProvider>([
|
||||
[LOCAL_SESSION_ID, new LocalProvider()],
|
||||
]);
|
||||
private counter = 0;
|
||||
|
||||
get(sessionId: string): FileSystemProvider {
|
||||
const provider = this.sessions.get(sessionId);
|
||||
if (!provider) throw new Error(`Session "${sessionId}" is not connected`);
|
||||
return provider;
|
||||
}
|
||||
|
||||
add(provider: FileSystemProvider): string {
|
||||
const id = `sftp-${++this.counter}`;
|
||||
this.sessions.set(id, provider);
|
||||
return id;
|
||||
}
|
||||
|
||||
async remove(sessionId: string): Promise<void> {
|
||||
if (sessionId === LOCAL_SESSION_ID)
|
||||
throw new Error("The local session cannot be disconnected");
|
||||
const provider = this.sessions.get(sessionId);
|
||||
if (!provider) return;
|
||||
this.sessions.delete(sessionId);
|
||||
await provider.dispose();
|
||||
}
|
||||
|
||||
/** Remove without dispose — for sessions that died on their own. */
|
||||
drop(sessionId: string): void {
|
||||
if (sessionId === LOCAL_SESSION_ID) return;
|
||||
this.sessions.delete(sessionId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user