irc/plugins/caps/ircmw/cap.go

84 lines
1.9 KiB
Go

package ircmw
import (
"context"
"strings"
"time"
"tuxpa.in/a/irc/pkg/ircv3"
)
type Capabilities struct {
pending int
}
var capabilitiesKey struct{}
func AddPending(ctx context.Context, i int) {
val, ok := ctx.Value(capabilitiesKey).(*Capabilities)
if !ok {
return
}
val.pending += i
}
func (c *Capabilities) Middleware(next ircv3.Handler) ircv3.Handler {
return ircv3.HandlerFunc(func(ctx context.Context, w ircv3.MessageWriter, m *ircv3.Message) {
ctx = context.WithValue(ctx, capabilitiesKey, c)
if m.Command == "" {
c.pending++
w.WriteMessage(ircv3.NewMessage("CAP", "LS", "302"))
}
next.Handle(ctx, w, m)
if m.Command == "CAP" && m.Param(0) == "*" && m.Param(1) == "LS" {
c.pending--
}
if c.pending == 0 {
c.pending = -1
w.WriteMessage(ircv3.NewMessage("CAP", "END"))
}
})
}
func CapabilityExchange(next ircv3.Handler) ircv3.Handler {
return ircv3.HandlerFunc(func(ctx context.Context, w ircv3.MessageWriter, m *ircv3.Message) {
next.Handle(ctx, w, m)
})
}
var keyServerTime struct{}
func ServerTime(ctx context.Context) time.Time {
val, ok := ctx.Value(keyServerTime).(time.Time)
if !ok {
return time.Time{}
}
return val
}
func CapabilityServerTime(next ircv3.Handler) ircv3.Handler {
enabled := false
return ircv3.HandlerFunc(func(ctx context.Context, w ircv3.MessageWriter, m *ircv3.Message) {
if m.Command == "CAP" && m.Param(0) == "*" && m.Param(1) == "LS" {
if strings.Contains(m.Param(2), "server-time") {
AddPending(ctx, 1)
w.WriteMessage(ircv3.NewMessage("CAP", "REQ", "server-time"))
}
}
if m.Command == "CAP" && m.Param(1) == "ACK" && m.Param(2) == "server-time" {
AddPending(ctx, -1)
enabled = true
}
if enabled {
tString := m.Tags.Get("time")
if tString != "" {
parsedTime, err := time.Parse("2006-01-02T15:04:05.000Z", tString)
if err == nil {
ctx = context.WithValue(ctx, keyServerTime, parsedTime)
}
}
}
next.Handle(ctx, w, m)
})
}