aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.go10
-rw-r--r--forge.scfg10
-rw-r--r--irc.go111
3 files changed, 111 insertions, 20 deletions
diff --git a/config.go b/config.go
index 9a5647f..5382bbe 100644
--- a/config.go
+++ b/config.go
@@ -36,9 +36,13 @@ var config struct {
Root string `scfg:"root"`
} `scfg:"ssh"`
IRC struct {
- Net string `scfg:"net"`
- Addr string `scfg:"addr"`
- TLS bool `scfg:"tls"`
+ 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"`
} `scfg:"irc"`
General struct {
Title string `scfg:"title"`
diff --git a/forge.scfg b/forge.scfg
index cf77a4b..42a4b57 100644
--- a/forge.scfg
+++ b/forge.scfg
@@ -15,6 +15,16 @@ http {
root https://forge.example.org
}
+irc {
+ tls true
+ net tcp
+ addr irc.runxiyu.org:6697
+ sendq 6000
+ nick forge-test
+ user forge
+ gecos "Lindenii Forge Test"
+}
+
git {
repo_dir /var/lib/lindenii/forge/repos
}
diff --git a/irc.go b/irc.go
index fc9e0af..afc9f96 100644
--- a/irc.go
+++ b/irc.go
@@ -4,9 +4,20 @@ import (
"crypto/tls"
"net"
+ "go.lindenii.runxiyu.org/lindenii-common/clog"
"go.lindenii.runxiyu.org/lindenii-irc"
)
+var (
+ ircSendBuffered chan string
+ ircSendDirectChan chan errorBack[string]
+)
+
+type errorBack[T any] struct {
+ content T
+ errorBack chan error
+}
+
func ircBotSession() error {
var err error
var underlyingConn net.Conn
@@ -16,31 +27,97 @@ func ircBotSession() error {
underlyingConn, err = net.Dial(config.IRC.Net, config.IRC.Addr)
}
if err != nil {
- return (err)
+ return err
}
+ defer underlyingConn.Close()
+
conn := irc.NewConn(underlyingConn)
- conn.WriteString("NICK forge\r\nUSER forge 0 * :Forge\r\n")
- for {
- msg, err := conn.ReadMessage()
- if err != nil {
- return (err)
+ conn.WriteString(
+ "NICK " + config.IRC.Nick + "\r\n" +
+ "USER " + config.IRC.User + " 0 * :" + config.IRC.Gecos + "\r\n",
+ )
+
+ readLoopError := make(chan error)
+ writeLoopAbort := make(chan struct{})
+ go func() {
+ for {
+ select {
+ case <-writeLoopAbort:
+ return
+ default:
+ }
+ msg, err := conn.ReadMessage()
+ if err != nil {
+ readLoopError <- err
+ return
+ }
+ switch msg.Command {
+ case "001":
+ _, err = conn.WriteString("JOIN #chat\r\n")
+ if err != nil {
+ readLoopError <- err
+ return
+ }
+ case "PING":
+ _, err = conn.WriteString("PONG :" + msg.Args[0] + "\r\n")
+ if err != nil {
+ readLoopError <- err
+ return
+ }
+ case "JOIN":
+ _, err = conn.WriteString("PRIVMSG #chat :test\r\n")
+ if err != nil {
+ readLoopError <- err
+ return
+ }
+ default:
+ }
}
- switch msg.Command {
- case "001":
- conn.WriteString("JOIN #chat\r\n")
- case "PING":
- conn.WriteString("PONG :")
- conn.WriteString(msg.Args[0])
- conn.WriteString("\r\n")
- case "JOIN":
- conn.WriteString("PRIVMSG #chat :test\r\n")
- default:
+ }()
+
+ for {
+ select {
+ case err = <-readLoopError:
+ return err
+ case s := <-ircSendBuffered:
+ _, err = conn.WriteString(s)
+ if err != nil {
+ select {
+ case ircSendBuffered <- s:
+ default:
+ clog.Error("unable to requeue IRC message: " + s)
+ }
+ writeLoopAbort <- struct{}{}
+ return err
+ }
+ case se := <-ircSendDirectChan:
+ _, err = conn.WriteString(se.content)
+ se.errorBack <- err
+ if err != nil {
+ writeLoopAbort <- struct{}{}
+ return err
+ }
}
}
}
+func ircSendDirect(s string) error {
+ ech := make(chan error, 1)
+
+ ircSendDirectChan <- errorBack[string]{
+ content: s,
+ errorBack: ech,
+ }
+
+ return <-ech
+}
+
func ircBotLoop() {
+ ircSendBuffered = make(chan string, config.IRC.SendQ)
+ ircSendDirectChan = make(chan errorBack[string])
+
for {
- _ = ircBotSession()
+ err := ircBotSession()
+ clog.Error("IRC error: " + err.Error())
}
}