aboutsummaryrefslogtreecommitdiff
path: root/forged/internal/ipc/irc
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-08-12 11:01:07 +0800
committerRunxi Yu <me@runxiyu.org>2025-09-13 19:08:22 +0800
commit5717faed659a9eeb86c528ab56822c42eca1ad3f (patch)
tree92e6662628a51c03c52300d2fd98173716a82882 /forged/internal/ipc/irc
parentRemove forge-specific functions from misc (diff)
downloadforge-5717faed659a9eeb86c528ab56822c42eca1ad3f.tar.gz
forge-5717faed659a9eeb86c528ab56822c42eca1ad3f.tar.zst
forge-5717faed659a9eeb86c528ab56822c42eca1ad3f.zip
Refactor
Diffstat (limited to '')
-rw-r--r--forged/internal/ipc/irc/bot.go (renamed from forged/internal/irc/bot.go)38
-rw-r--r--forged/internal/ipc/irc/config.go13
-rw-r--r--forged/internal/ipc/irc/conn.go (renamed from forged/internal/irc/conn.go)15
-rw-r--r--forged/internal/ipc/irc/doc.go2
-rw-r--r--forged/internal/ipc/irc/errors.go (renamed from forged/internal/irc/errors.go)0
-rw-r--r--forged/internal/ipc/irc/message.go (renamed from forged/internal/irc/message.go)20
-rw-r--r--forged/internal/ipc/irc/source.go (renamed from forged/internal/irc/source.go)3
7 files changed, 55 insertions, 36 deletions
diff --git a/forged/internal/irc/bot.go b/forged/internal/ipc/irc/bot.go
index 1c6d32f..07008ae 100644
--- a/forged/internal/irc/bot.go
+++ b/forged/internal/ipc/irc/bot.go
@@ -1,31 +1,21 @@
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
-// Package irc provides basic IRC bot functionality.
package irc
import (
+ "context"
"crypto/tls"
+ "fmt"
"log/slog"
"net"
- "go.lindenii.runxiyu.org/forge/forged/internal/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
)
-// Config contains IRC connection and identity settings for the bot.
-// This should usually be a part of the primary config struct.
-type Config struct {
- Net string `scfg:"net"`
- Addr string `scfg:"addr"`
- TLS bool `scfg:"tls"`
- SendQ uint `scfg:"sendq"`
- Nick string `scfg:"nick"`
- User string `scfg:"user"`
- Gecos string `scfg:"gecos"`
-}
-
// Bot represents an IRC bot client that handles events and allows for sending messages.
type Bot struct {
+ // TODO: Use each config field instead of embedding Config here.
config *Config
ircSendBuffered chan string
ircSendDirectChan chan misc.ErrorBack[string]
@@ -35,24 +25,28 @@ type Bot struct {
func NewBot(c *Config) (b *Bot) {
b = &Bot{
config: c,
- }
+ } //exhaustruct:ignore
return
}
// Connect establishes a new IRC session and starts handling incoming and outgoing messages.
// This method blocks until an error occurs or the connection is closed.
-func (b *Bot) Connect() error {
+func (b *Bot) Connect(ctx context.Context) error {
var err error
var underlyingConn net.Conn
if b.config.TLS {
- underlyingConn, err = tls.Dial(b.config.Net, b.config.Addr, nil)
+ dialer := tls.Dialer{} //exhaustruct:ignore
+ underlyingConn, err = dialer.DialContext(ctx, b.config.Net, b.config.Addr)
} else {
- underlyingConn, err = net.Dial(b.config.Net, b.config.Addr)
+ dialer := net.Dialer{} //exhaustruct:ignore
+ underlyingConn, err = dialer.DialContext(ctx, b.config.Net, b.config.Addr)
}
if err != nil {
- return err
+ return fmt.Errorf("dialing irc: %w", err)
}
- defer underlyingConn.Close()
+ defer func() {
+ _ = underlyingConn.Close()
+ }()
conn := NewConn(underlyingConn)
@@ -165,12 +159,12 @@ func (b *Bot) Send(line string) {
// ConnectLoop continuously attempts to maintain an IRC session.
// If the connection drops, it automatically retries with no delay.
-func (b *Bot) ConnectLoop() {
+func (b *Bot) ConnectLoop(ctx context.Context) {
b.ircSendBuffered = make(chan string, b.config.SendQ)
b.ircSendDirectChan = make(chan misc.ErrorBack[string])
for {
- err := b.Connect()
+ err := b.Connect(ctx)
slog.Error("irc session error", "error", err)
}
}
diff --git a/forged/internal/ipc/irc/config.go b/forged/internal/ipc/irc/config.go
new file mode 100644
index 0000000..b1b5703
--- /dev/null
+++ b/forged/internal/ipc/irc/config.go
@@ -0,0 +1,13 @@
+package irc
+
+// Config contains IRC connection and identity settings for the bot.
+// This should usually be a part of the primary config struct.
+type Config struct {
+ Net string `scfg:"net"`
+ Addr string `scfg:"addr"`
+ TLS bool `scfg:"tls"`
+ SendQ uint `scfg:"sendq"`
+ Nick string `scfg:"nick"`
+ User string `scfg:"user"`
+ Gecos string `scfg:"gecos"`
+}
diff --git a/forged/internal/irc/conn.go b/forged/internal/ipc/irc/conn.go
index b975b72..b9b208c 100644
--- a/forged/internal/irc/conn.go
+++ b/forged/internal/ipc/irc/conn.go
@@ -2,10 +2,11 @@ package irc
import (
"bufio"
+ "fmt"
"net"
"slices"
- "go.lindenii.runxiyu.org/forge/forged/internal/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
)
type Conn struct {
@@ -41,9 +42,17 @@ func (c *Conn) ReadMessage() (msg Message, line string, err error) {
}
func (c *Conn) Write(p []byte) (n int, err error) {
- return c.netConn.Write(p)
+ n, err = c.netConn.Write(p)
+ if err != nil {
+ err = fmt.Errorf("write to connection: %w", err)
+ }
+ return n, err
}
func (c *Conn) WriteString(s string) (n int, err error) {
- return c.netConn.Write(misc.StringToBytes(s))
+ n, err = c.netConn.Write(misc.StringToBytes(s))
+ if err != nil {
+ err = fmt.Errorf("write to connection: %w", err)
+ }
+ return n, err
}
diff --git a/forged/internal/ipc/irc/doc.go b/forged/internal/ipc/irc/doc.go
new file mode 100644
index 0000000..dcfca82
--- /dev/null
+++ b/forged/internal/ipc/irc/doc.go
@@ -0,0 +1,2 @@
+// Package irc provides basic IRC bot functionality.
+package irc
diff --git a/forged/internal/irc/errors.go b/forged/internal/ipc/irc/errors.go
index 3506c70..3506c70 100644
--- a/forged/internal/irc/errors.go
+++ b/forged/internal/ipc/irc/errors.go
diff --git a/forged/internal/irc/message.go b/forged/internal/ipc/irc/message.go
index 84b6867..3387bec 100644
--- a/forged/internal/irc/message.go
+++ b/forged/internal/ipc/irc/message.go
@@ -7,7 +7,7 @@ package irc
import (
"bytes"
- "go.lindenii.runxiyu.org/forge/forged/internal/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
)
type Message struct {
@@ -24,18 +24,18 @@ func Parse(raw []byte) (msg Message, err error) {
if bytes.HasPrefix(sp[0], []byte{'@'}) { // TODO: Check size manually
if len(sp[0]) < 2 {
err = ErrMalformedMsg
- return
+ return msg, err
}
sp[0] = sp[0][1:]
msg.Tags, err = tagsToMap(sp[0])
if err != nil {
- return
+ return msg, err
}
if len(sp) < 2 {
err = ErrMalformedMsg
- return
+ return msg, err
}
sp = sp[1:]
} else {
@@ -45,7 +45,7 @@ func Parse(raw []byte) (msg Message, err error) {
if bytes.HasPrefix(sp[0], []byte{':'}) { // TODO: Check size manually
if len(sp[0]) < 2 {
err = ErrMalformedMsg
- return
+ return msg, err
}
sp[0] = sp[0][1:]
@@ -53,14 +53,14 @@ func Parse(raw []byte) (msg Message, err error) {
if len(sp) < 2 {
err = ErrMalformedMsg
- return
+ return msg, err
}
sp = sp[1:]
}
msg.Command = misc.BytesToString(sp[0])
if len(sp) < 2 {
- return
+ return msg, err
}
sp = sp[1:]
@@ -81,7 +81,7 @@ func Parse(raw []byte) (msg Message, err error) {
msg.Args = append(msg.Args, misc.BytesToString(sp[i]))
}
- return
+ return msg, err
}
var ircv3TagEscapes = map[byte]byte{ //nolint:gochecknoglobals
@@ -97,7 +97,7 @@ func tagsToMap(raw []byte) (tags map[string]string, err error) {
key, value, found := bytes.Cut(rawTag, []byte{'='})
if !found {
err = ErrInvalidIRCv3Tag
- return
+ return tags, err
}
if len(value) == 0 {
tags[misc.BytesToString(key)] = ""
@@ -122,5 +122,5 @@ func tagsToMap(raw []byte) (tags map[string]string, err error) {
}
}
}
- return
+ return tags, err
}
diff --git a/forged/internal/irc/source.go b/forged/internal/ipc/irc/source.go
index d955f45..938751f 100644
--- a/forged/internal/irc/source.go
+++ b/forged/internal/ipc/irc/source.go
@@ -6,13 +6,14 @@ package irc
import (
"bytes"
- "go.lindenii.runxiyu.org/forge/forged/internal/misc"
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
)
type Source interface {
AsSourceString() string
}
+//nolint:ireturn
func parseSource(s []byte) Source {
nick, userhost, found := bytes.Cut(s, []byte{'!'})
if !found {