irc/pkg/ircconn/conn.go

74 lines
1.3 KiB
Go
Raw Normal View History

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