package core import ( "bufio" "context" "fmt" "log/slog" "net" "github.com/google/uuid" ) type Server struct { l *slog.Logger port string ctx context.Context Sessions chan *Session ln net.Listener } func NewServer(ctx context.Context, l *slog.Logger, port string) *Server { var s Server // TODO: Check for context cancellation and cleanup c := make(chan *Session) s.Sessions = c ln, err := net.Listen("tcp", port) if err != nil { s.l.With( slog.Any("error", err), ).Error("could not start tcp listener") return &s } s.ctx = ctx s.ln = ln s.l = l s.port = port return &s } func (s *Server) Start() { s.l.Debug("starting telnet server") // TODO: Check for context cancellation and cleanup for { conn, err := s.ln.Accept() if err != nil { s.l.With( slog.Any("error", err), ).Error("could not accept tcp connection") } s.Sessions <- NewSession(s.ctx, conn, Printer{}, s.l) } } type Session struct { c net.Conn ctx context.Context p Printer l *slog.Logger userID uint64 } func NewSession(ctx context.Context, c net.Conn, p Printer, l *slog.Logger) *Session { sid := uuid.New() return &Session{ ctx: ctx, l: l.With(slog.String("sid", sid.String())), c: c, } } func (s *Session) bufferInput(commands chan string) { scanner := bufio.NewScanner(s.c) defer close(commands) for scanner.Scan() { err := scanner.Err() switch err { case nil: commands <- scanner.Text() default: s.l.With(slog.Any("error", scanner.Err())).Error("error scanning input") return } } s.l.Debug("session terminated") } func (s *Session) Start() { s.l.Debug("starting telnet session") fmt.Fprint(s.c, "Welcome to Bing Bong.\n") commands := make(chan string) go s.bufferInput(commands) for command := range commands { s.l.With(slog.String("command", command)).Debug("command recieved") _, err := fmt.Fprintf(s.c, "> %q\n", command) if err != nil { s.l.With( slog.Any("error", err), ).Error("connection closed on write") return } } }