Files
public/myssh/myssh.go
xxjwxc eb574b852a new
2020-05-26 02:04:46 +08:00

189 lines
3.8 KiB
Go

package myssh
import (
"fmt"
"io"
"net"
"os"
"time"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
)
// Cli ...
type Cli struct {
IP string //IP地址
Username string //用户名
Password string //密码
Port int //端口号
client *ssh.Client //ssh客户端
}
// New 创建命令行对象
// ip IP地址
// username 用户名
// password 密码
// port 端口号,默认22
func New(ip string, username string, password string, port ...int) (*Cli, error) {
cli := new(Cli)
cli.IP = ip
cli.Username = username
cli.Password = password
if len(port) <= 0 {
cli.Port = 22
} else {
cli.Port = port[0]
}
return cli, cli.connect()
}
// NewSession new session
func (c Cli) newSession() (*ssh.Session, error) {
if c.client == nil {
if err := c.connect(); err != nil {
return nil, err
}
}
session, err := c.client.NewSession()
if err != nil {
return nil, err
}
return session, nil
}
// Run 执行 shell脚本命令
func (c Cli) Run(shell string) (string, error) {
session, err := c.newSession()
if err != nil {
return "", err
}
defer session.Close()
buf, err := session.CombinedOutput(shell)
return string(buf), err
}
// RunTerminal 执行带交互的命令
func (c *Cli) RunTerminal(shell string) error {
session, err := c.newSession()
if err != nil {
return err
}
defer session.Close()
return c.runTerminalSession(session, shell)
}
// runTerminalSession 执行带交互的命令
func (c *Cli) runTerminalSession(session *ssh.Session, shell string) error {
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
panic(err)
}
defer terminal.Restore(fd, oldState)
session.Stdout = os.Stdout
session.Stderr = os.Stdin
session.Stdin = os.Stdin
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
panic(err)
}
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
return err
}
session.Run(shell)
return nil
}
// EnterTerminal 完全进入终端
func (c Cli) EnterTerminal() error {
session, err := c.newSession()
if err != nil {
return err
}
defer session.Close()
return c.enterTerminalSession(session, os.Stdout, os.Stdin)
}
// Enter 完全进入终端
func (c Cli) Enter(w io.Writer, r io.Reader) error {
session, err := c.newSession()
if err != nil {
return err
}
defer session.Close()
return c.enterTerminalSession(session, w, r)
}
// EnterTerminalSession 进入终端
func (c Cli) enterTerminalSession(session *ssh.Session, w io.Writer, r io.Reader) error {
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
return err
}
defer terminal.Restore(fd, oldState)
session.Stdout = w
session.Stderr = os.Stdin
session.Stdin = r
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
return err
}
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
err = session.RequestPty("xterm-256color", termHeight, termWidth, modes)
if err != nil {
return err
}
err = session.Shell()
if err != nil {
return err
}
return session.Wait()
}
// 连接
func (c *Cli) connect() error {
config := ssh.ClientConfig{
User: c.Username,
Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
Timeout: 10 * time.Second,
}
addr := fmt.Sprintf("%s:%d", c.IP, c.Port)
sshClient, err := ssh.Dial("tcp", addr, &config)
if err != nil {
return err
}
c.client = sshClient
return nil
}