package main import ( "bufio" "net" "os" "regexp" "strings" "time" log "github.com/sirupsen/logrus" ) var spotRe *regexp.Regexp = regexp.MustCompile(`DX\sde\s([\w\d]+).*:\s+(\d+.\d)\s+([\w\d\/]+)\s+(CW|SSB|FT8|FT4|RTTY|USB|LSB)?\s+(.*)\s\s\s+([\d]+\w{1})`) var defaultLoginRe *regexp.Regexp = regexp.MustCompile("[\\w\\d-_]+ login:") var defaultPasswordRe *regexp.Regexp = regexp.MustCompile("Password:") type TCPClient struct { Login string Password string Address string Port string LoggedIn bool Timeout time.Duration LogWriter *bufio.Writer Reader *bufio.Reader Writer *bufio.Writer Scanner *bufio.Scanner Conn net.Conn TCPServer TCPServer MsgChan chan string CmdChan chan string SpotChanToFlex chan TelnetSpot SpotChanToHTTPServer chan TelnetSpot Log *log.Logger Config *Config Countries Countries LoginRe *regexp.Regexp PasswordRe *regexp.Regexp } func NewTCPClient(TCPServer *TCPServer, Countries Countries) *TCPClient { return &TCPClient{ Address: Cfg.Cluster.Server, Port: Cfg.Cluster.Port, Login: Cfg.Cluster.Login, Password: Cfg.Cluster.Password, MsgChan: TCPServer.MsgChan, CmdChan: TCPServer.CmdChan, SpotChanToFlex: make(chan TelnetSpot, 100), TCPServer: *TCPServer, SpotChanToHTTPServer: make(chan TelnetSpot, 100), Countries: Countries, } } func (c *TCPClient) setDefaultParams() { if c.Timeout == 0 { c.Timeout = 600 * time.Second } if c.LogWriter == nil { c.LogWriter = bufio.NewWriter(os.Stdout) } c.LoggedIn = false if c.LoginRe == nil { c.LoginRe = defaultLoginRe } if c.PasswordRe == nil { c.PasswordRe = defaultPasswordRe } } func (c *TCPClient) StartClient() { var err error c.setDefaultParams() c.Conn, err = net.Dial("tcp", c.Address+":"+c.Port) if err != nil { Log.Error("Cannot connect to Telnet Client:", err) } c.Reader = bufio.NewReader(c.Conn) c.Writer = bufio.NewWriter(c.Conn) go func() { for message := range c.TCPServer.CmdChan { Log.Infof("Received Command: %s", message) c.Write([]byte(message + "\r\n")) } }() go c.ReadLine() } func (c *TCPClient) Close() { c.Writer.WriteString("bye") time.Sleep(time.Second * 2) } func (c *TCPClient) SetFilters() { if Cfg.Cluster.FT8 { c.Write([]byte("set/ft8\r\n")) Log.Info("FT8: On") } if Cfg.Cluster.Skimmer { c.Write([]byte("set/skimmer\r\n")) Log.Info("Skimmer: On") } if Cfg.Cluster.FT4 { c.Write([]byte("set/ft4\r\n")) Log.Info("FT4: On") } if !Cfg.Cluster.FT8 { c.Write([]byte("set/noft8\r\n")) Log.Info("FT8: Off") } if !Cfg.Cluster.FT4 { c.Write([]byte("set/noft4\r\n")) Log.Info("FT4: Off") } if !Cfg.Cluster.Skimmer { c.Write([]byte("set/noskimmer\r\n")) Log.Info("Skimmer: Off") } } func (c *TCPClient) ReadLine() { for { // Need to check data with space first to find login and then use \n if !c.LoggedIn { message, err := c.Reader.ReadBytes(':') if err != nil { Log.Errorf("Error reading message: %s", err) c.Conn.Close() c.StartClient() } // message, _ = strings.CutSuffix(message, "\n") // message, _ = strings.CutSuffix(message, "\r") if strings.Contains(string(message), Cfg.Cluster.LoginPrompt) || strings.Contains(string(message), "login:") { time.Sleep(time.Second * 1) Log.Debug("Found login prompt...sending callsign") c.Write([]byte(c.Login + "\n\r")) c.LoggedIn = true Log.Infof("Connected to DX cluster %s:%s", Cfg.Cluster.Server, Cfg.Cluster.Port) continue } } if c.LoggedIn { message, err := c.Reader.ReadBytes('\n') messageString := string(message) // Log.Println(messageString) if messageString != "" { if err != nil { Log.Errorf("Error reading message: %s", err) c.Conn.Close() c.StartClient() } if strings.Contains(messageString, "password") { Log.Debug("Found password prompt...sending password...") c.Write([]byte(c.Password + "\r\n")) } if strings.Contains(messageString, "Hello") || strings.Contains(messageString, "Welcome") { go c.SetFilters() if Cfg.Cluster.Command != "" { c.WriteString(Cfg.Cluster.Command + "\n\r") Log.Debugf("Sending Command: %s", Cfg.Cluster.Command) } } if strings.Contains(messageString, "Error reading from server: read tcp") { Log.Error("Disconnected from Telnet Server, reconnecting") c.Close() c.StartClient() } if strings.Contains(messageString, "DX") { ProcessTelnetSpot(spotRe, messageString, c.SpotChanToFlex, c.SpotChanToHTTPServer, c.Countries) } // Send the spot message to TCP server c.MsgChan <- messageString } } } } // Write sends raw data to remove telnet server func (tc *TCPClient) Write(data []byte) (n int, err error) { n, err = tc.Writer.Write(data) if err == nil { err = tc.Writer.Flush() } return } func (tc *TCPClient) WriteString(data string) (n int, err error) { n, err = tc.Writer.Write([]byte(data)) if err == nil { err = tc.Writer.Flush() } return }