Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix rclone hang #74

Merged
merged 1 commit into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/classes/SshConnectionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,13 @@ export class SshConnectionHandler {
): void => {
logger.verbose('SSH request for a new session');
const session = accept();
const sessionHandler = new SshSessionHandler(this.authSession?.authToken ?? '');
const sessionHandler = new SshSessionHandler(
session,
this.authSession?.authToken ?? '',
);
session.on('sftp', sessionHandler.onSftp);
session.on('close', sessionHandler.onClose);
session.on('eof', sessionHandler.onEof);
};

/**
Expand Down
29 changes: 27 additions & 2 deletions src/classes/SshSessionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { logger } from '../logger';
import { SftpSessionHandler } from './SftpSessionHandler';
import type { SFTPWrapper } from 'ssh2';
import type {
Session,
SFTPWrapper,
} from 'ssh2';

export class SshSessionHandler {
private readonly authToken: string;

public constructor(authToken: string) {
private readonly session: Session;

public constructor(
session: Session,
authToken: string,
) {
this.session = session;
this.authToken = authToken;
}

Expand Down Expand Up @@ -50,4 +59,20 @@ export class SshSessionHandler {
public onClose = (): void => {
logger.verbose('SSH session closed');
};

public onEof = (): void => {
// This addresses a bug in the ssh2 library where EOF is not properly
// handled for sftp connections.
// An upstream PR that would fix the behavior: https://github.com/mscdex/ssh2/pull/1111
// And some context from our own debugging: https://github.com/PermanentOrg/sftp-service/issues/45
//
// The solution here is not ideal, as it is accessing an undocumented attribute that
// doesn't exist in TypeScript. As a result I need to disable typescript checks.
//
// Once upstream makes that patch this entire handler should become completely unnecessary
//
// !!BEWARE: THERE BE DRAGONS HERE!!
// @ts-expect-error because `_channel` is private / isn't actually documented.
this.session._channel.end(); // eslint-disable-line max-len, no-underscore-dangle, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
};
}