Xterm.js: Controle de fluxo usando XON / XOFF

Criado em 10 nov. 2020  ·  3Comentários  ·  Fonte: xtermjs/xterm.js

Olá contribuidores,

Estou usando o xtermjs para criar um aplicativo de terminal em execução no navegador da web e o servidor de destino usa Linux. Percebi que o xtermjs v4.9.0 não responde a ^ C ao executar o comando yes .
Então eu voltei para a v4.0.2 e habilitei a opção useFlowControl , funcionou.

O useFlowControl usando XON / XOFF foi adicionado da v2.3.0 (PR # 447), mas removido da v4.1.0 (PR # 2422).
Não consigo encontrar nenhuma discussão sobre o motivo para removê-lo. A solução XON / XOFF tem alguma armadilha?

Se não, podemos ter um plano para trazer de volta esse recurso para a biblioteca ou devo implementá-lo em meu próprio aplicativo?

O controle de fluxo descrito no documento (https://xtermjs.org/docs/guides/flowcontrol/) não ajuda muito, pois eu uso o websocket para me conectar ao backend.

typquestion

Comentários muito úteis

Removemos o XON / XOFF porque ele não funcionava de maneira confiável em alguns cenários. De trás da minha cabeça, lembro que tivemos problemas com o shell ZSH, que usava as sequências XON / XOFF para algo diferente. Acredito que o Terminal Windows também teve problemas com essas sequências.

De qualquer forma - a forma como resolvi isso (também usando WebSockets - no meu caso, socket.io, mas não importa) é estabelecer manualmente um mecanismo de controle de fluxo sobre o próprio socket.

Portanto - sempre que chegam dados no soquete que devem ser gravados em xterm.js, aumentamos um contador e, uma vez que os dados foram gravados com sucesso em xterm.js (o que significa que foram renderizados por xterm.js), diminuímos esse contador .

Se o contador exceder um certo limite, enviamos uma mensagem pause pelo Websocket, que no lado do servidor irá pausar o stream pty ( terminalStream.pause() ). Assim que atingirmos esse limite, enviaremos uma mensagem resume pelo Websocket, que no lado do servidor retomará o fluxo pty ( terminalStream.resume() ).

Observe que os métodos terminalStream.pause() e terminalStream.resume() são os métodos de fluxo node.js integrados para lidar com a contrapressão. node-pty bem como ssh2 suportam o manuseio da contrapressão por meio desses métodos.

// client
const MAX_PENDING_WRITES = 5;
let pendingWrites = 0;
let paused = false;
socket.on('data', (data) => {
  pendingWrites++;
  xterm.write(data, () => {
    pendingWrites--;
    if (pendingWrites > MAX_PENDING_WRITES && !paused) {
      paused = true;
      socket.emit('pause');
      return;
    }
    if (pendingWrites <= MAX_PENDING_WRITES && paused) {
      paused = false;
      socket.emit('resume');
      return;
    }
  });
});

// server
terminalStream.on('data', (data) => socket.emit('data', data);
socket.on('data', (data) => terminalStream.write(data));
socket.on('pause', () => terminalStream.pause();
socket.on('resume', () => terminalStream.resume();

Este mecanismo está funcionando de forma bastante confiável até agora. O comando yes não inundará mais a conexão. Ainda há um atraso de cerca de 0,5s entre CTRL+C e o término real do comando em cenários de alto rendimento, mas IMO tudo bem.

Espero que ajude.

Todos 3 comentários

Removemos o XON / XOFF porque ele não funcionava de maneira confiável em alguns cenários. De trás da minha cabeça, lembro que tivemos problemas com o shell ZSH, que usava as sequências XON / XOFF para algo diferente. Acredito que o Terminal Windows também teve problemas com essas sequências.

De qualquer forma - a forma como resolvi isso (também usando WebSockets - no meu caso, socket.io, mas não importa) é estabelecer manualmente um mecanismo de controle de fluxo sobre o próprio socket.

Portanto - sempre que chegam dados no soquete que devem ser gravados em xterm.js, aumentamos um contador e, uma vez que os dados foram gravados com sucesso em xterm.js (o que significa que foram renderizados por xterm.js), diminuímos esse contador .

Se o contador exceder um certo limite, enviamos uma mensagem pause pelo Websocket, que no lado do servidor irá pausar o stream pty ( terminalStream.pause() ). Assim que atingirmos esse limite, enviaremos uma mensagem resume pelo Websocket, que no lado do servidor retomará o fluxo pty ( terminalStream.resume() ).

Observe que os métodos terminalStream.pause() e terminalStream.resume() são os métodos de fluxo node.js integrados para lidar com a contrapressão. node-pty bem como ssh2 suportam o manuseio da contrapressão por meio desses métodos.

// client
const MAX_PENDING_WRITES = 5;
let pendingWrites = 0;
let paused = false;
socket.on('data', (data) => {
  pendingWrites++;
  xterm.write(data, () => {
    pendingWrites--;
    if (pendingWrites > MAX_PENDING_WRITES && !paused) {
      paused = true;
      socket.emit('pause');
      return;
    }
    if (pendingWrites <= MAX_PENDING_WRITES && paused) {
      paused = false;
      socket.emit('resume');
      return;
    }
  });
});

// server
terminalStream.on('data', (data) => socket.emit('data', data);
socket.on('data', (data) => terminalStream.write(data));
socket.on('pause', () => terminalStream.pause();
socket.on('resume', () => terminalStream.resume();

Este mecanismo está funcionando de forma bastante confiável até agora. O comando yes não inundará mais a conexão. Ainda há um atraso de cerca de 0,5s entre CTRL+C e o término real do comando em cenários de alto rendimento, mas IMO tudo bem.

Espero que ajude.

@tandatle Veja também a documentação sobre flowcontrol .

Edit: Desculpe, esqueci sua observação de documentos. Importa-se de explicar o que não está claro? Sim, a seção de websocket é apenas um esboço (sem snippet pronto para uso), já que não fiz o que criar toneladas de snippets para diferentes libs de soquete e necessidades personalizadas (isso é difícil de fazer direito com websockets apenas por razões de segurança) . Ainda assim, sinta-se à vontade para adicionar um trecho concreto, que cubra esses aspectos.

@mofux @jerch Obrigado por sua ajuda.
Não estou usando node.js no back-end, mas um processo escrito em C ++, então posso ter que fazer mais algumas investigações para escolher entre usar XON / XOFF e implementar o tratamento de contrapressão em meu processo de back-end.
Muito obrigado.

Esta página foi útil?
0 / 5 - 0 avaliações