104 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
// ssh -L 8080:localhost:80 -L 9090:localhost:90 user@remote-server
 | 
						|
import { ChildProcess, spawn } from 'child_process';
 | 
						|
type Options = {
 | 
						|
  name: string;
 | 
						|
  values: SSHValue[];
 | 
						|
};
 | 
						|
export type SSHValue = {
 | 
						|
  localPort: number;
 | 
						|
  remoteHost: string; // localhost
 | 
						|
  remotePort: number;
 | 
						|
  remote?: string; //sky config配置
 | 
						|
  status?: 'active' | 'inactive';
 | 
						|
};
 | 
						|
export const demos: SSHValue[] = [
 | 
						|
  {
 | 
						|
    localPort: 3000,
 | 
						|
    remoteHost: 'localhost',
 | 
						|
    remotePort: 3000,
 | 
						|
    remote: 'diana',
 | 
						|
  },
 | 
						|
  {
 | 
						|
    localPort: 5244,
 | 
						|
    remoteHost: 'localhost',
 | 
						|
    remotePort: 5244,
 | 
						|
    remote: 'diana',
 | 
						|
  },
 | 
						|
];
 | 
						|
export class SSHServer {
 | 
						|
  name = 'diana';
 | 
						|
  values: SSHValue[] = [];
 | 
						|
  childProcess: ChildProcess | null = null;
 | 
						|
  isRunning = false;
 | 
						|
  constructor(opts?: Options) {
 | 
						|
    this.name = opts?.name || this.name;
 | 
						|
    this.values = opts?.values || demos;
 | 
						|
  }
 | 
						|
  start(options?: Options) {
 | 
						|
    try {
 | 
						|
      const remote = options?.name || this.name;
 | 
						|
      const demos = options?.values || this.values;
 | 
						|
      const _port = demos.filter((item) => item.status === 'active');
 | 
						|
      if (_port.length === 0) {
 | 
						|
        this.isRunning = false;
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      const params = _port
 | 
						|
        .map((item) => {
 | 
						|
          return ['-L', `${item.localPort}:${item.remoteHost}:${item.remotePort}`];
 | 
						|
        })
 | 
						|
        .flat();
 | 
						|
      const childProcess = spawn(
 | 
						|
        'ssh',
 | 
						|
        [
 | 
						|
          '-N', // 不执行远程命令
 | 
						|
          // '-f', // 后台运行
 | 
						|
          '-o',
 | 
						|
          'ServerAliveInterval=60', // 每60秒发送一次心跳包
 | 
						|
          '-o',
 | 
						|
          'ServerAliveCountMax=3', // 尝试3次心跳失败后断开连接
 | 
						|
          '-T',
 | 
						|
          ...params,
 | 
						|
          remote,
 | 
						|
        ],
 | 
						|
        {
 | 
						|
          // stdio: 'ignore',
 | 
						|
          stdio: 'inherit',
 | 
						|
          killSignal: 'SIGINT',
 | 
						|
        },
 | 
						|
      );
 | 
						|
      this.childProcess = childProcess;
 | 
						|
      childProcess.stdout?.on('data', (data) => {
 | 
						|
        console.log('childProcess', data.toString());
 | 
						|
      });
 | 
						|
      childProcess.on('error', (err: any) => {
 | 
						|
        if (err.code === 'EADDRINUSE') {
 | 
						|
          console.error('端口被占用:', err);
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        console.error('Failed to start SSH process:', err);
 | 
						|
      });
 | 
						|
      childProcess.on('exit', (code, signal) => {
 | 
						|
        console.log('SSH process exited:', code, signal);
 | 
						|
        this.isRunning = false;
 | 
						|
      });
 | 
						|
      this.isRunning = true;
 | 
						|
      console.log('当前ssh -L 服务启动', this.name);
 | 
						|
      // 监听的端口是
 | 
						|
      // console.log('监听的端口是:', _port.map((item) => `[${item.localPort},${item.remotePort}]`).join(','));
 | 
						|
      console.log('监听的端口是:', _port.map((item) => item.localPort).join(','));
 | 
						|
    } catch (error) {
 | 
						|
      console.error('启动失败:', error);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  stop() {
 | 
						|
    if (this.childProcess) {
 | 
						|
      console.log('正在停止 ssh -L 服务:', this.name);
 | 
						|
      this.childProcess.kill(); // 发送默认信号 SIGTERM
 | 
						|
      this.childProcess = undefined;
 | 
						|
    } else {
 | 
						|
      console.log('没有正在运行的 ssh -L 服务.');
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |