rust changes

This commit is contained in:
EthanShoeDev
2025-09-19 16:52:50 -04:00
parent 519de821e2
commit b053cb9945
6 changed files with 479 additions and 352 deletions

View File

@@ -29,7 +29,10 @@ export default function TabsShellDetail() {
useFocusEffect(
React.useCallback(() => {
startTransition(() => {
setReady(true);
setTimeout(() => {
// TODO: This is gross
setReady(true);
}, 50);
}); // React 19: non-urgent
return () => {
@@ -78,6 +81,7 @@ function ShellDetail() {
useEffect(() => {
if (!sess) return;
if (sess.status === 'disconnected') {
console.log('shell disconnected, replacing route with /shell');
// Replace so the detail screen isn't on the stack anymore
router.replace('/shell');
}
@@ -119,6 +123,7 @@ function ShellDetail() {
}}
style={{
flex: 1,
justifyContent: 'flex-start',
backgroundColor: theme.colors.background,
padding: 0,
paddingBottom:
@@ -142,7 +147,6 @@ function ShellDetail() {
} catch (e) {
console.warn('Failed to disconnect', e);
}
router.replace('/shell');
}}
>
<Ionicons name="power" size={20} color={theme.colors.primary} />
@@ -162,7 +166,7 @@ function ShellDetail() {
// xterm options
xtermOptions={{
theme: {
background: theme.colors.background,
background: 'red',
foreground: theme.colors.textPrimary,
},
}}

View File

@@ -1,86 +1,125 @@
import {
RnRussh,
type SshConnection,
type SshShell,
type SshConnectionStatus,
} from '@fressh/react-native-uniffi-russh';
import { create } from 'zustand';
export type SessionKey = string;
export const makeSessionKey = (connectionId: string, channelId: number) =>
`${connectionId}:${channelId}` as const;
// export type SessionKey = string;
// export const makeSessionKey = (connectionId: string, channelId: number) =>
// `${connectionId}:${channelId}` as const;
export type SessionStatus = 'connecting' | 'connected' | 'disconnected';
// export type SessionStatus = 'connecting' | 'connected' | 'disconnected';
export interface StoredSession {
connection: SshConnection;
shell: SshShell;
status: SessionStatus;
// export interface StoredSession {
// connection: SshConnection;
// shell: SshShell;
// status: SessionStatus;
// }
// interface SshStoreState {
// sessions: Record<SessionKey, StoredSession>;
// addSession: (conn: SshConnection, shell: SshShell) => SessionKey;
// removeSession: (key: SessionKey) => void;
// setStatus: (key: SessionKey, status: SessionStatus) => void;
// getByKey: (key: SessionKey) => StoredSession | undefined;
// listConnectionsWithShells: () => (SshConnection & { shells: SshShell[] })[];
// }
// export const useSshStore = create<SshStoreState>((set, get) => ({
// sessions: {},
// addSession: (conn, shell) => {
// const key = makeSessionKey(conn.connectionId, shell.channelId);
// set((s) => ({
// sessions: {
// ...s.sessions,
// [key]: { connection: conn, shell, status: 'connected' },
// },
// }));
// return key;
// },
// removeSession: (key) => {
// set((s) => {
// const { [key]: _omit, ...rest } = s.sessions;
// return { sessions: rest };
// });
// },
// setStatus: (key, status) => {
// set((s) =>
// s.sessions[key]
// ? { sessions: { ...s.sessions, [key]: { ...s.sessions[key], status } } }
// : s,
// );
// },
// getByKey: (key) => get().sessions[key],
// listConnectionsWithShells: () => {
// const byConn = new Map<
// string,
// { conn: SshConnection; shells: SshShell[] }
// >();
// for (const { connection, shell } of Object.values(get().sessions)) {
// const g = byConn.get(connection.connectionId) ?? {
// conn: connection,
// shells: [],
// };
// g.shells.push(shell);
// byConn.set(connection.connectionId, g);
// }
// return Array.from(byConn.values()).map(({ conn, shells }) => ({
// ...conn,
// shells,
// }));
// },
// }));
// export function toSessionStatus(status: SshConnectionStatus): SessionStatus {
// switch (status) {
// case 'shellConnecting':
// return 'connecting';
// case 'shellConnected':
// return 'connected';
// case 'shellDisconnected':
// return 'disconnected';
// default:
// return 'connected';
// }
// }
type SshRegistryStore = {
connections: Record<string, {
connection: SshConnection,
shells: Record<number, SshShell>,
status:
}>,
shells: Record<`${string}-${number}`, SshShell>,
addConnection: typeof RnRussh.connect,
}
interface SshStoreState {
sessions: Record<SessionKey, StoredSession>;
addSession: (conn: SshConnection, shell: SshShell) => SessionKey;
removeSession: (key: SessionKey) => void;
setStatus: (key: SessionKey, status: SessionStatus) => void;
getByKey: (key: SessionKey) => StoredSession | undefined;
listConnectionsWithShells: () => (SshConnection & { shells: SshShell[] })[];
type SshRegistryService = {
connect: typeof RnRussh.connect,
}
export const useSshStore = create<SshStoreState>((set, get) => ({
sessions: {},
addSession: (conn, shell) => {
const key = makeSessionKey(conn.connectionId, shell.channelId);
set((s) => ({
sessions: {
...s.sessions,
[key]: { connection: conn, shell, status: 'connected' },
},
}));
return key;
},
removeSession: (key) => {
set((s) => {
const { [key]: _omit, ...rest } = s.sessions;
return { sessions: rest };
const useSshRegistryStore = create<SshRegistryStore>((set) => ({
connections: {},
shells: {},
addConnection: async (args) => {
const connection = await RnRussh.connect({
...args,
onStatusChange: (status) => {
args.onStatusChange?.(status);
if (status === 'tcpDisconnected') {
// remove all shell
}
}
});
},
setStatus: (key, status) => {
set((s) =>
s.sessions[key]
? { sessions: { ...s.sessions, [key]: { ...s.sessions[key], status } } }
: s,
);
},
getByKey: (key) => get().sessions[key],
listConnectionsWithShells: () => {
const byConn = new Map<
string,
{ conn: SshConnection; shells: SshShell[] }
>();
for (const { connection, shell } of Object.values(get().sessions)) {
const g = byConn.get(connection.connectionId) ?? {
conn: connection,
shells: [],
};
g.shells.push(shell);
byConn.set(connection.connectionId, g);
}
return Array.from(byConn.values()).map(({ conn, shells }) => ({
...conn,
shells,
}));
},
}));
export function toSessionStatus(status: SshConnectionStatus): SessionStatus {
switch (status) {
case 'shellConnecting':
return 'connecting';
case 'shellConnected':
return 'connected';
case 'shellDisconnected':
return 'disconnected';
default:
return 'connected';
}
}
}))
const sshRegistryService = {
connect
}