irc/pkg/ircconn/conn.go

74 lines
1.3 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
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
}