irc/pkg/ircconn/conn.go

70 lines
1.2 KiB
Go

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
}