package ircconn import ( "bufio" "context" "io" "log/slog" "sync" "github.com/valyala/bytebufferpool" "tuxpa.in/a/irc/pkg/ircdecoder" "tuxpa.in/a/irc/pkg/ircv3" ) type Conn struct { w io.Writer r io.Reader log *slog.Logger muWrite sync.Mutex } func New(log *slog.Logger, w io.Writer, r io.Reader) *Conn { return &Conn{ log: log, w: w, r: r, } } // while serve is running, the conn owns the reader. func (c *Conn) Serve(ctx context.Context, h ircv3.Handler) error { // once serve is called, we call with an empty message. h.Handle(ctx, c, &ircv3.Message{}) dec := &ircdecoder.Decoder{} r := c.r r = bufio.NewReaderSize(c.r, 10240) for { select { case <-ctx.Done(): return ctx.Err() default: } msg := &ircv3.Message{} r = io.LimitReader(r, 8191+512) err := dec.Decode(r, msg) if err != nil { return err } h.Handle(ctx, c, msg) } } func (c *Conn) WriteMessage(msg *ircv3.Message) error { b := bytebufferpool.Get() defer bytebufferpool.Put(b) err := msg.Encode(b) if err != nil { return err } b.WriteString("\r\n") c.muWrite.Lock() defer c.muWrite.Unlock() c.log.Info("out >", "msg", msg.String()) _, err = b.WriteTo(c.w) if err != nil { return err } return nil }