GET /api/v1/messages read the client output queue and only then
registered with the broker. Notify wakes only the channels registered
at that moment, so a message queued between the empty read and the
registration waited out the whole long-poll timeout. The handler now
registers first and removes its channel on every exit path; the IRC
relay loop registers before each drain in the same way.
The handlers read the queue through a function field that defaults to
Database.PollMessages, so tests can act just after a read: one checks
that a message queued there comes back at once, others that no wait
channel stays registered however a request ends.
Model: opus-5-5
The IRC relay registers a broker wait channel on each pass of its
loop, and when the 100 ms ticker fired instead of a notification it
looped without removing that channel. An idle IRC listener connection
added ten channels a second to the broker, and all but the last stayed
after the connection closed. The ticker case now removes its channel,
as the HTTP long-poll does after its timer.
Broker.ListenerCount returns how many wait channels a user holds, so
the test can check that an idle connection holds at most one, and
none after it closes.
Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
README.md rules that nicks are case-sensitive, but the IRC listener's
relay and user MODE on both transports compared nicks ignoring case:
an IRC listener user alice never saw a PRIVMSG, NOTICE, JOIN, PART,
NICK or QUIT from Alice, and MODE Alice from alice was taken as her
own nick. These checks now use ==.
Tests cover alice receiving each of these from Alice, MODE Alice from
alice getting 502 on both transports, and Alice registering while
alice exists. README.md drops the text that described the old
behaviour.
Model: opus-5-5
The IRC listener relayed only the first line of a PRIVMSG or NOTICE
body; it now sends one line per body line. A relayed MODE change now
carries its key, limit or mask, each value its own parameter, also in
the echo to the user who made it. CR, LF and NUL are removed from each
parameter and from each whole line sent to an IRC listener connection,
so no stored value can start a line of its own. The channel name check
moved into service.JoinChannel, so the IRC listener's JOIN refuses the
same names with 403.
Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
USERHOST, VERSION, ADMIN, INFO, TIME, KILL and WALLOPS work on the
HTTP API and on the IRC listener. The USERHOST reply, the VERSION,
ADMIN and INFO text, KILL and WALLOPS are each one service function
that both transports call. User mode +w selects who receives WALLOPS.
MODE on your own nick queries or changes your user modes through one
parser on both transports: the whole mode string is checked before
anything is stored, and both flags are stored in one transaction. KILL
closes the victim's IRC connection after sending it KILL and ERROR,
without the operator waiting on it. The sessions table gains
is_wallops in 001_initial.sql, as the pre-1.0 rule in REPO_POLICIES.md
asks.
Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
The HTTP server built its router inside the goroutine that starts
serving, so the start hook returned before the router existed, and
the internal/handlers tests raced with it or hit a nil router. The
start hook now runs configure, enableSentry and SetupRoutes, in that
order, then serves in the background.
The goroutine that sends queued messages to an IRC client read c.nick
without c.mu while NICK changed it. Every such read now takes the lock.
Under -race in the Docker build, internal/handlers takes over 30s on
database work, not clock waits, so both go test runs in make test use
-timeout 120s. The || retry stays
(#101).
Model: opus-5-5
Changes the Go module path from `git.eeqj.de/sneak/neoirc` to `sneak.berlin/go/neoirc`.
All occurrences updated:
- `go.mod` module directive
- All Go import paths across 35 `.go` files (107 import statements)
- All JSON schema `$id` URIs across 30 `.json` files in `schema/`
No functional changes — this is a pure rename of the module path.
`docker build .` passes clean (formatting, linting, all tests, binary build).
closes#98
Co-authored-by: clawbot <clawbot@users.noreply.git.eeqj.de>
Reviewed-on: #99
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>