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 muWrite sync.Mutex } func New(w io.Writer, r io.Reader) *Conn { return &Conn{ w: w, r: r, } } // while serve is running, the conn owns the reader. func Serve(ctx context.Context, r io.Reader, wr ircv3.MessageWriter, h ircv3.Handler) error { h.Handle(wr, ircv3.NewEvent(ctx, ircv3.EventTypeCONTROL, ircv3.NewMessage("/EVENT_ON_SERVE"))) dec := &ircdecoder.Decoder{} r = bufio.NewReaderSize(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(wr, ircv3.NewEvent(ctx, ircv3.EventTypeIRC, msg)) } } type MessageWriter struct { R io.Writer Log *slog.Logger mu sync.Mutex } func (r *MessageWriter) WriteMessage(msg *ircv3.Message) error { b := bytebufferpool.Get() defer bytebufferpool.Put(b) err := msg.Encode(b) if err != nil { return err } if r.Log != nil { r.Log.Info("out >", "msg", msg.String()) } b.WriteString("\r\n") r.mu.Lock() defer r.mu.Unlock() _, err = r.R.Write(b.B) if err != nil { return err } return nil }