group various stream processors into middleware

This commit is contained in:
Eugene Pankov
2021-12-27 20:08:22 +01:00
parent b0c300be43
commit 076b1c7129
12 changed files with 195 additions and 97 deletions

View File

@@ -3,7 +3,7 @@ import colors from 'ansi-colors'
import stripAnsi from 'strip-ansi'
import { Injector } from '@angular/core'
import { Profile, LogService } from 'tabby-core'
import { BaseSession, LoginScriptsOptions, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal'
import { BaseSession, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal'
import { Subject, Observable } from 'rxjs'
@@ -41,6 +41,21 @@ enum TelnetOptions {
NEW_ENVIRON = 0x27,
}
class UnescapeFFMiddleware extends SessionMiddleware {
feedFromSession (data: Buffer): void {
while (data.includes(0xff)) {
const pos = data.indexOf(0xff)
this.outputToTerminal.next(data.slice(0, pos))
this.outputToTerminal.next(Buffer.from([0xff, 0xff]))
data = data.slice(pos + 1)
}
this.outputToTerminal.next(data)
}
}
export class TelnetSession extends BaseSession {
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
@@ -48,7 +63,6 @@ export class TelnetSession extends BaseSession {
private socket: Socket
private streamProcessor: TerminalStreamProcessor
private telnetProtocol = false
private echoEnabled = false
private lastWidth = 0
private lastHeight = 0
private requestedOptions = new Set<number>()
@@ -59,33 +73,10 @@ export class TelnetSession extends BaseSession {
) {
super(injector.get(LogService).create(`telnet-${profile.options.host}-${profile.options.port}`))
this.streamProcessor = new TerminalStreamProcessor(profile.options)
this.streamProcessor.outputToSession$.subscribe(data => {
this.socket.write(this.unescapeFF(data))
})
this.streamProcessor.outputToTerminal$.subscribe(data => {
this.emitOutput(data)
})
this.middleware.push(this.streamProcessor)
this.setLoginScriptsOptions(profile.options)
}
unescapeFF (data: Buffer): Buffer {
if (!this.telnetProtocol) {
return data
}
const result: Buffer[] = []
while (data.includes(0xff)) {
const pos = data.indexOf(0xff)
result.push(data.slice(0, pos))
result.push(Buffer.from([0xff, 0xff]))
data = data.slice(pos + 1)
}
result.push(data)
return Buffer.concat(result)
}
async start (): Promise<void> {
this.socket = new Socket()
this.emitServiceMessage(`Connecting to ${this.profile.options.host}`)
@@ -124,6 +115,7 @@ export class TelnetSession extends BaseSession {
onData (data: Buffer): void {
if (!this.telnetProtocol && data[0] === TelnetCommands.IAC) {
this.telnetProtocol = true
this.middleware.push(new UnescapeFFMiddleware())
this.requestOption(TelnetCommands.DO, TelnetOptions.SUPPRESS_GO_AHEAD)
this.emitTelnet(TelnetCommands.WILL, TelnetOptions.TERMINAL_TYPE)
this.emitTelnet(TelnetCommands.WILL, TelnetOptions.NEGO_WINDOW_SIZE)
@@ -131,7 +123,7 @@ export class TelnetSession extends BaseSession {
if (this.telnetProtocol) {
data = this.processTelnetProtocol(data)
}
this.streamProcessor.feedFromSession(data)
this.emitOutput(data)
}
emitTelnet (command: TelnetCommands, option: TelnetOptions): void {
@@ -190,7 +182,7 @@ export class TelnetSession extends BaseSession {
this.emitTelnet(TelnetCommands.WILL, option)
this.emitSize()
} else if (option === TelnetOptions.ECHO) {
this.echoEnabled = true
this.streamProcessor.forceEcho = true
this.emitTelnet(TelnetCommands.WILL, option)
} else if (option === TelnetOptions.TERMINAL_TYPE) {
this.emitTelnet(TelnetCommands.WILL, option)
@@ -201,7 +193,7 @@ export class TelnetSession extends BaseSession {
}
if (command === TelnetCommands.DONT) {
if (option === TelnetOptions.ECHO) {
this.echoEnabled = false
this.streamProcessor.forceEcho = false
this.emitTelnet(TelnetCommands.WONT, option)
} else {
this.logger.debug('(!) Unhandled option')
@@ -249,10 +241,7 @@ export class TelnetSession extends BaseSession {
}
write (data: Buffer): void {
if (this.echoEnabled) {
this.emitOutput(data)
}
this.streamProcessor.feedFromTerminal(data)
this.socket.write(data)
}
kill (_signal?: string): void {