package pjlink import ( "bufio" "crypto/md5" "errors" "fmt" "net" "strings" "time" ) var ( ErrAuthFailed = errors.New("授权验证失败") ErrCommandError = errors.New("命令执行异常") ) type Client struct { Host string Port string Password string ID string conn net.Conn } func NewClient(host, port, password, id string) *Client { return &Client{ Host: host, Port: port, Password: password, ID: id, } } func (c *Client) Connect() error { address := net.JoinHostPort(c.Host, c.Port) conn, err := net.DialTimeout("tcp", address, 5*time.Second) if err != nil { return err } c.conn = conn // Read challenge reader := bufio.NewReader(c.conn) response, err := reader.ReadString('\r') if err != nil { c.Close() return err } // Handle authentication if strings.HasPrefix(response, "PJLINK 1") { if c.Password == "" { c.Close() return ErrAuthFailed } challenge := strings.TrimSpace(strings.Split(response, " ")[2]) authString := fmt.Sprintf("%s%s", challenge, c.Password) hashed := md5.Sum([]byte(authString)) authHash := fmt.Sprintf("%x", hashed) _, err = fmt.Fprintf(c.conn, "%s\r", authHash) if err != nil { c.Close() return err } authResponse, err := reader.ReadString('\r') if err != nil || !strings.Contains(authResponse, "OK") { c.Close() return ErrAuthFailed } } return nil } func (c *Client) sendCommand(command string) (string, error) { if c.conn == nil { return "", errors.New("not connected") } fullCommand := fmt.Sprintf("%%%s%s\r", c.ID, command) _, err := c.conn.Write([]byte(fullCommand)) if err != nil { return "", err } reader := bufio.NewReader(c.conn) response, err := reader.ReadString('\r') if err != nil { return "", err } // Remove prefix and parse response parts := strings.SplitN(response, "=", 2) if len(parts) < 2 { return "", ErrCommandError } result := strings.TrimSpace(parts[1]) if result == "ERR1" { return "", ErrAuthFailed } else if result == "ERR2" { return "", ErrCommandError } return result, nil } func (c *Client) PowerOn() error { response, err := c.sendCommand("POWR 1") if err != nil { return err } if response != "OK" { return fmt.Errorf("unexpected response: %s", response) } return nil } func (c *Client) PowerOff() error { response, err := c.sendCommand("POWR 0") if err != nil { return err } if response != "OK" { return fmt.Errorf("unexpected response: %s", response) } return nil } func (c *Client) Close() { if c.conn != nil { c.conn.Close() c.conn = nil } }