feat: add IRC wire protocol listener with shared service layer
Some checks failed
check / check (push) Failing after 46s

Add a traditional IRC wire protocol listener (RFC 1459/2812) on
configurable port (default :6667), sharing business logic with
the HTTP API via a new service layer.

- IRC listener: NICK, USER, PASS, JOIN, PART, PRIVMSG, NOTICE,
  TOPIC, MODE, KICK, QUIT, NAMES, LIST, WHOIS, WHO, AWAY, OPER,
  INVITE, LUSERS, MOTD, PING/PONG, CAP
- Service layer: shared logic for both transports including
  channel join (with Tier 2 checks: ban/invite/key/limit),
  message send (with ban + moderation checks), nick change,
  topic, kick, mode, quit broadcast, away, oper, invite
- BroadcastQuit uses FanOut pattern (one insert, N enqueues)
- HTTP handlers delegate to service for all command logic
- Tier 2 mode operations (+b/+i/+s/+k/+l) use service methods

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 18:01:36 -07:00
parent 9a79d92c0d
commit 92d5145ac6
19 changed files with 4795 additions and 1112 deletions

View File

@@ -17,6 +17,7 @@ import (
"git.eeqj.de/sneak/neoirc/internal/healthcheck"
"git.eeqj.de/sneak/neoirc/internal/logger"
"git.eeqj.de/sneak/neoirc/internal/ratelimit"
"git.eeqj.de/sneak/neoirc/internal/service"
"git.eeqj.de/sneak/neoirc/internal/stats"
"go.uber.org/fx"
)
@@ -33,6 +34,8 @@ type Params struct {
Database *db.Database
Healthcheck *healthcheck.Healthcheck
Stats *stats.Tracker
Broker *broker.Broker
Service *service.Service
}
const defaultIdleTimeout = 30 * 24 * time.Hour
@@ -48,6 +51,7 @@ type Handlers struct {
log *slog.Logger
hc *healthcheck.Healthcheck
broker *broker.Broker
svc *service.Service
hashcashVal *hashcash.Validator
channelHashcash *hashcash.ChannelValidator
loginLimiter *ratelimit.Limiter
@@ -79,7 +83,8 @@ func New(
params: &params,
log: params.Logger.Get(),
hc: params.Healthcheck,
broker: broker.New(),
broker: params.Broker,
svc: params.Service,
hashcashVal: hashcash.NewValidator(resource),
channelHashcash: hashcash.NewChannelValidator(),
loginLimiter: ratelimit.New(loginRate, loginBurst),