debug: comprehensive SFTP channel + readdir diagnostic logging

This commit is contained in:
Vantz Stockwell 2026-03-14 02:22:42 -04:00
parent 711ef73786
commit e39d8fbdda
2 changed files with 38 additions and 5 deletions

View File

@ -39,11 +39,30 @@ export class SftpGateway {
return this.send(client, { type: 'error', message: 'sessionId required' });
}
const sftp = await this.ssh.getSftpChannel(sessionId);
this.logger.log(`[SFTP] Getting SFTP channel for session ${sessionId}...`);
let sftp: any;
try {
sftp = await this.ssh.getSftpChannel(sessionId);
this.logger.log(`[SFTP] Got SFTP channel OK — type: ${typeof sftp}, constructor: ${sftp?.constructor?.name}`);
} catch (err: any) {
this.logger.error(`[SFTP] Failed to get SFTP channel: ${err.message}`);
return this.send(client, { type: 'error', message: `SFTP channel failed: ${err.message}` });
}
// Listen for SFTP channel errors
sftp.on('error', (err: any) => {
this.logger.error(`[SFTP] Channel error event: ${err.message}`);
});
sftp.on('close', () => {
this.logger.warn(`[SFTP] Channel closed`);
});
switch (msg.type) {
case 'list': {
this.logger.log(`[SFTP] readdir starting for path: "${msg.path}"`);
try {
sftp.readdir(msg.path, (err: any, list: any[]) => {
this.logger.log(`[SFTP] readdir callback fired, err=${err?.message || 'null'}, entries=${list?.length || 0}`);
if (err) return this.send(client, { type: 'error', message: err.message });
const entries = list.map((f: any) => ({
name: f.filename,
@ -53,8 +72,13 @@ export class SftpGateway {
permissions: (f.attrs.mode & 0o7777).toString(8),
modified: new Date(f.attrs.mtime * 1000).toISOString(),
}));
this.logger.log(`[SFTP] Sending list response with ${entries.length} entries, client.readyState=${client.readyState}`);
this.send(client, { type: 'list', path: msg.path, entries });
});
} catch (syncErr: any) {
this.logger.error(`[SFTP] readdir threw synchronously: ${syncErr.message}`);
this.send(client, { type: 'error', message: syncErr.message });
}
break;
}
case 'read': {

View File

@ -171,11 +171,20 @@ export class SshConnectionService {
}
getSftpChannel(sessionId: string): Promise<any> {
const logger = this.logger;
return new Promise((resolve, reject) => {
const session = this.sessions.get(sessionId);
if (!session) return reject(new Error('Session not found'));
if (!session) {
logger.error(`[SFTP] Session ${sessionId} not found in sessions map (${this.sessions.size} active sessions)`);
return reject(new Error('Session not found'));
}
logger.log(`[SFTP] Requesting SFTP subsystem on session ${sessionId}, client connected: ${(session.client as any)._sock?.readable ?? 'unknown'}`);
session.client.sftp((err, sftp) => {
if (err) return reject(err);
if (err) {
logger.error(`[SFTP] client.sftp() callback error: ${err.message}`);
return reject(err);
}
logger.log(`[SFTP] SFTP subsystem opened successfully for session ${sessionId}`);
resolve(sftp);
});
});