From ba1b37a258f6a0c6a0f6092c9ee5300c75faa300 Mon Sep 17 00:00:00 2001 From: EthanShoeDev <13422990+EthanShoeDev@users.noreply.github.com> Date: Sun, 14 Sep 2025 11:44:45 -0400 Subject: [PATCH] some changes --- apps/mobile/src/app/shell.tsx | 16 +++++++++++----- apps/mobile/src/lib/ssh-connection-manager.ts | 2 ++ .../rust/uniffi-russh/src/lib.rs | 7 +++++++ packages/react-native-uniffi-russh/src/api.ts | 19 +++++++++++++++++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/apps/mobile/src/app/shell.tsx b/apps/mobile/src/app/shell.tsx index 9aa1e5f..c4b6ad8 100644 --- a/apps/mobile/src/app/shell.tsx +++ b/apps/mobile/src/app/shell.tsx @@ -22,11 +22,17 @@ export default function Shell() { const [shellData, setShellData] = useState(''); useEffect(() => { - const channelListenerId = sshConn.client.addChannelListener({ - onData: (data) => { - console.log('Received data (on Shell):', data); - setShellData((prev) => prev + data); - }, + // Decode ArrayBuffer bytes from the SSH channel into text + const decoder = new TextDecoder('utf-8'); + const channelListenerId = sshConn.client.addChannelListener((data) => { + try { + const bytes = new Uint8Array(data); + const chunk = decoder.decode(bytes); + console.log('Received data (on Shell):', chunk.length, 'chars'); + setShellData((prev) => prev + chunk); + } catch (e) { + console.warn('Failed to decode shell data', e); + } }); return () => { sshConn.client.removeChannelListener(channelListenerId); diff --git a/apps/mobile/src/lib/ssh-connection-manager.ts b/apps/mobile/src/lib/ssh-connection-manager.ts index e328aad..6bf23f0 100644 --- a/apps/mobile/src/lib/ssh-connection-manager.ts +++ b/apps/mobile/src/lib/ssh-connection-manager.ts @@ -1,5 +1,7 @@ import { type SshConnection } from '@fressh/react-native-uniffi-russh'; import * as Crypto from 'expo-crypto'; + + export type SSHConn = { client: SshConnection; sessionId: string; diff --git a/packages/react-native-uniffi-russh/rust/uniffi-russh/src/lib.rs b/packages/react-native-uniffi-russh/rust/uniffi-russh/src/lib.rs index c665005..0e4cc44 100644 --- a/packages/react-native-uniffi-russh/rust/uniffi-russh/src/lib.rs +++ b/packages/react-native-uniffi-russh/rust/uniffi-russh/src/lib.rs @@ -1,3 +1,10 @@ +//! This file is used to generate Typescript bindings for the Russh library. +//! +//! For more information on the available data types, see the following links: +//! - https://jhugman.github.io/uniffi-bindgen-react-native/idioms/common-types.html +//! - https://jhugman.github.io/uniffi-bindgen-react-native/idioms/callback-interfaces.html +//! - https://jhugman.github.io/uniffi-bindgen-react-native/idioms/async-callbacks.html + use std::fmt; use std::sync::{Arc, Mutex, Weak}; use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/packages/react-native-uniffi-russh/src/api.ts b/packages/react-native-uniffi-russh/src/api.ts index 96a1a5e..88805ac 100644 --- a/packages/react-native-uniffi-russh/src/api.ts +++ b/packages/react-native-uniffi-russh/src/api.ts @@ -68,7 +68,9 @@ async function connect(options: ConnectOptions) { security, onStatusChange: options.onStatusChange ? { onChange: (statusEnum) => { - options.onStatusChange?.(sshConnStatusEnumToLiteral[statusEnum]!); + const tsLiteral = sshConnStatusEnumToLiteral[statusEnum]; + if (!tsLiteral) throw new Error(`Invalid status enum: ${statusEnum}`); + options.onStatusChange?.(tsLiteral); }, } : undefined, }, @@ -99,7 +101,20 @@ async function connect(options: ConnectOptions) { } type BetterStartShellFn = typeof betterStartShell; (sshConnectionInterface as any).startShell = betterStartShell - return sshConnectionInterface as GeneratedRussh.SshConnectionInterface & { startShell: BetterStartShellFn }; + + + const originalAddChannelListener = sshConnectionInterface.addChannelListener.bind(sshConnectionInterface); + const betterAddChannelListener = (listener: GeneratedRussh.ChannelListener['onData']) => { + return originalAddChannelListener({ + onData: (data) => { + listener(data); + }, + }); + } + type BetterAddChannelListenerFn = typeof betterAddChannelListener; + (sshConnectionInterface as any).addChannelListener = betterAddChannelListener; + + return sshConnectionInterface as GeneratedRussh.SshConnectionInterface & { startShell: BetterStartShellFn; addChannelListener: BetterAddChannelListenerFn }; } export type SshConnection = Awaited>;