No mundo da modernização de sistemas, nem sempre é possível reescrever o código legado. Muitas das maiores instituições financeiras e seguradoras do mundo ainda rodam seus núcleos em mainframes IBM. O desafio surge quando precisamos conectar uma aplicação web moderna ou um script de automação a essas telas verdes antigas.

É aqui que entra o s3270.

O que é o s3270? Link para o cabeçalho

O s3270 é um emulador de terminal scriptável e headless (sem monitor/interface gráfica) para sessões IBM 3270. Ele faz parte da suíte open-source x3270.

Enquanto um emulador tradicional (como o PCOMM ou o próprio x3270) desenha a tela para um humano ler e teclar, o s3270 roda em segundo plano. Ele abre a conexão, mantém o estado da sessão na memória e permite que outros programas “digitem” e “leiam” a tela através de comandos.

Por que ele é essencial?

  1. RPA (Robotic Process Automation): Permite criar robôs que navegam no mainframe para extrair dados ou cadastrar informações sem intervenção humana.
  2. Modernização de Interface: Você pode criar uma página Web bonita em React ou Vue.js onde, quando o usuário clica em “Consultar Saldo”, o backend (PHP, Python, Java) aciona o s3270 para buscar esse dado na tela verde e devolvê-lo formatado.
  3. Testes Automatizados: Equipes de QA utilizam o s3270 para validar se as alterações no COBOL não quebraram o fluxo das telas.

A Arquitetura da Automação

O fluxo de funcionamento geralmente segue esta lógica:

  1. O Gatilho: Um script (Python, PHP, Shell) inicia o processo s3270.
  2. O Comando: O script envia comandos de ação (ex: Connect, String, Enter).
  3. O Feedback: O s3270 processa o comando no host IBM e retorna o output (o texto da tela) para o script.

Exemplos Práticos Link para o cabeçalho

Para interagir com o s3270, a melhor prática não é chamar o executável cru e tentar parsear o texto manualmente, mas sim usar bibliotecas (wrappers) que gerenciam a conexão e o tempo de resposta (timing) do mainframe.

1 - Exemplo em Python

Em Python, a biblioteca mais robusta é a py3270. Ela abstrai a complexidade de gerenciar o processo.

Cenário: Conectar, fazer login e extrair um texto da tela.

Instalação: pip install py3270

from py3270 import Emulator

# Inicializa o emulador (certifique-se que o s3270 está instalado no OS)
em = Emulator(visible=False) 

try:
    # 1. Conectar ao host
    em.connect('mainframe.exemplo.com')
    
    # 2. Esperar a tela carregar (espera o campo 'Userid' aparecer)
    # Mainframes são assíncronos, esperar é crucial!
    em.wait_for_field()
    
    # 3. Preencher Login
    em.send_string('MEU_USUARIO')
    em.send_enter()
    
    # Esperar o próximo campo (Password) e preencher
    em.wait_for_field()
    em.send_string('MINHA_SENHA')
    em.send_enter()
    
    # 4. Navegar e Extrair Dados
    # Supondo que após o login, queremos ler o saldo na linha 5, coluna 20
    em.wait_for_field()
    
    # Lê 15 caracteres a partir da linha 5, coluna 20
    saldo = em.string_get(5, 20, 15)
    
    print(f"O saldo extraído do mainframe é: {saldo.strip()}")

    # 5. Fazer Logoff (Boa prática)
    em.send_string('logoff')
    em.send_enter()

except Exception as e:
    print(f"Erro na automação: {e}")

finally:
    # Fecha o processo s3270
    em.terminate()

2 - Exemplo em PHP

No PHP, é comum usar o s3270 para criar APIs que expõem funcionalidades do mainframe. Como não há uma biblioteca padrão tão onipresente quanto a py3270, muitas vezes usamos proc_open para interagir diretamente com o processo ou bibliotecas específicas da comunidade (como gomoob/php3270).

Abaixo, um exemplo usando uma abordagem direta com uma classe wrapper simplificada para ilustração.

Cenário: Rodar um script s3270 pré-definido para buscar um status.

<?php

class MainframeAutomator {
    private $host;

    public function __construct($host) {
        $this->host = $host;
    }

    public function consultarStatus($usuario) {
        // Montamos um script de ações para o s3270
        // O s3270 aceita comandos via stdin ou arquivo
        $comandos = [
            "Connect({$this->host})",
            "Wait(Unlock)",
            "String($usuario)",
            "Enter()",
            "Wait(Unlock)",
            // O comando Ascii lê a tela inteira para podermos processar
            "Ascii()" 
        ];

        // Convertemos o array em uma string única
        $inputScript = implode("\n", $comandos) . "\nquit\n";

        // Executamos o s3270 passando os comandos
        // 2>&1 garante que pegamos erros também
        // s3270 -model 3278-2 define o tamanho da tela (80x24 padrão)
        $process = proc_open('s3270 -model 3278-2', [
            0 => ['pipe', 'r'], // stdin (nós escrevemos aqui)
            1 => ['pipe', 'w'], // stdout (nós lemos daqui)
            2 => ['pipe', 'w']  // stderr
        ], $pipes);

        if (is_resource($process)) {
            // Envia os comandos para o s3270
            fwrite($pipes[0], $inputScript);
            fclose($pipes[0]);

            // Lê a resposta (a tela do mainframe)
            $output = stream_get_contents($pipes[1]);
            fclose($pipes[1]);
            proc_close($process);

            return $this->parseOutput($output);
        }

        return false;
    }

    private function parseOutput($tela) {
        // Lógica simples de regex para achar um padrão na tela capturada
        // Exemplo: Procurar "STATUS: ATIVO"
        if (preg_match('/STATUS:\s+(\w+)/', $tela, $matches)) {
            return $matches[1];
        }
        return "Status não encontrado";
    }
}

// Uso
$mf = new MainframeAutomator('mainframe.interno.com');
$resultado = $mf->consultarStatus('USER123');
echo "O status do usuário é: " . $resultado;

?>

Dicas de Ouro para Automação com s3270

  1. Respeite o “Unlock”: O erro mais comum é o script enviar comandos mais rápido do que o mainframe consegue processar. Sempre use comandos de espera (Wait(Unlock) ou wait_for_field) antes de enviar a próxima string.
  2. Mapeamento de Tela: Mainframes têm tamanho fixo (normalmente 24 linhas por 80 colunas). Mapear exatamente onde os dados aparecem (coordenadas X, Y) é vital.
  3. Segurança: Evite hardcode de senhas nos scripts. Use variáveis de ambiente ou cofres de senha para injetar as credenciais no momento da execução.