package main import ( "bytes" "errors" "fmt" "net" "os" "time" ) type Client struct { server *Server conn net.Conn Ip string Line string Prompt string PromptWLine bool } func NewClient(server *Server, conn net.Conn) *Client { ip := conn.RemoteAddr().String() c := &Client{ server: server, conn: conn, Ip: ip, Line: "", Prompt: "Login: ", PromptWLine: true, } c.Write("\xff\xfb\x01\xff\xfb\x03\xff\xfd\x10") Drain(c.conn, 3) go c.reader() c.Write("Login: ") c.InsertWrite("Trade Trek\r\n") c.InsertWrite("v1.0 Apollo@21:1/236\r\n\r\n") return c } func (c *Client) Write(text string) { c.conn.Write([]byte(text)) } var clearLine = bytes.Repeat([]byte("\b \b"), 1000) func (c *Client) InsertWrite(text string) { c.conn.Write(clearLine) c.Write(text) if len(c.Prompt) != 0 { c.Write(c.Prompt) if c.PromptWLine { c.Write(c.Line) } } } func (c *Client) reader() { var ( buf []byte = make([]byte, 1024) // 1kb read int err error ) for { c.conn.SetReadDeadline(time.Now().Add(time.Duration(200) * time.Millisecond)) read, err = c.conn.Read(buf) if err != nil { if errors.Is(err, net.ErrClosed) || errors.Is(err, os.ErrClosed) { return } else if errors.Is(err, os.ErrDeadlineExceeded) { if read != 0 { c.process(string(buf[0:read])) } continue } else { fmt.Printf("%s ERR> %v", c.Ip, err) continue } } if read != 0 { c.process(string(buf[0:read])) } } } func (c *Client) process(input string) { // Process the input as far as ENTER/RETURN and keys being pressed // This will require a state machine to track where the client is (Login, Password, Sitting in their ship, Accessing computer, etc) // For now we'll just echo it back c.Write(input) }