feat: add IRC wire protocol listener with shared service layer
All checks were successful
check / check (push) Successful in 1m0s

Adds a backward-compatible IRC wire protocol listener (RFC 1459/2812)
with a shared service layer used by both IRC and HTTP transports.

- TCP listener on configurable port (default :6667)
- Full IRC protocol: NICK, USER, JOIN, PART, PRIVMSG, MODE, TOPIC, etc.
- Shared service layer (internal/service/) for consistent code paths
- Tier 2 join restrictions (ban, invite-only, key, limit) in service layer
- Ban check on PRIVMSG in service layer
- SetChannelFlag handles +i and +s modes
- Command dispatch via map[string]cmdHandler pattern
- EXPOSE 6667 in Dockerfile
- Service layer unit tests

closes #89
This commit is contained in:
2026-03-25 18:01:36 -07:00
parent 9a79d92c0d
commit 260f798af4
19 changed files with 4962 additions and 1193 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@ import (
"testing"
"time"
"git.eeqj.de/sneak/neoirc/internal/broker"
"git.eeqj.de/sneak/neoirc/internal/config"
"git.eeqj.de/sneak/neoirc/internal/db"
"git.eeqj.de/sneak/neoirc/internal/globals"
@@ -27,6 +28,7 @@ import (
"git.eeqj.de/sneak/neoirc/internal/logger"
"git.eeqj.de/sneak/neoirc/internal/middleware"
"git.eeqj.de/sneak/neoirc/internal/server"
"git.eeqj.de/sneak/neoirc/internal/service"
"git.eeqj.de/sneak/neoirc/internal/stats"
"go.uber.org/fx"
"go.uber.org/fx/fxtest"
@@ -206,6 +208,14 @@ func newTestHandlers(
hcheck *healthcheck.Healthcheck,
tracker *stats.Tracker,
) (*handlers.Handlers, error) {
brk := broker.New()
svc := service.New(service.Params{ //nolint:exhaustruct
Logger: log,
Config: cfg,
Database: database,
Broker: brk,
})
hdlr, err := handlers.New(lifecycle, handlers.Params{ //nolint:exhaustruct
Logger: log,
Globals: globs,
@@ -213,6 +223,8 @@ func newTestHandlers(
Database: database,
Healthcheck: hcheck,
Stats: tracker,
Broker: brk,
Service: svc,
})
if err != nil {
return nil, fmt.Errorf("test handlers: %w", err)

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),