diff --git a/bot.go b/bot.go index 9fd056e..c822409 100644 --- a/bot.go +++ b/bot.go @@ -1,13 +1,11 @@ package main import ( - "os" "log" "fmt" "net" "time" "bufio" - "bytes" "strings" "database/sql" configo "github.com/distributedio/configo" @@ -39,61 +37,116 @@ func scanline_privmsg (msg string) irc_msg { return irc } -func listenToIRC (foo bot) <-chan []byte { - c := make(chan []byte) - reader := bufio.NewReader(foo.conn) - db, err = sql.Open("sqlite3", foo.Conf.Database) +func bot_connect(bot *bot) { + conn, err := net.Dial("tcp", (*bot).Conf.Server) if err != nil { - LOG_ERR.Printf("opening database failed") - return nil + LOG_ERR.Printf("Error while dialing server.") + (*bot).conn = nil + return } - go func() { + (*bot).conn = conn + fmt.Fprintf((*bot).conn, "USER %s 1 1 1:%s\r\n", (*bot).Conf.Name, (*bot).Conf.Name) +} + +func bot_register(bot *bot) { + /* connect to irc */ + fmt.Fprintf((*bot).conn, "NICK %s\r\n", (*bot).Conf.Name) + for _, channel := range((*bot).Conf.Channels) { + fmt.Fprintf((*bot).conn, "JOIN %s\r\n", channel) + } +} + +func bot_listen(bot *bot) <-chan string { + c := make(chan string) + bot_register(bot) + + go func(timeoutNormal time.Duration, timeoutVersion time.Duration) { + bufReader := bufio.NewReader((*bot).conn) + + timeoutDuration := timeoutNormal + waitversion := false + + defer func() { + fmt.Println("Closing connection...") + close(c) + (*bot).conn.Close() + }() + for { - line, err := reader.ReadString('\n') + (*bot).conn.SetReadDeadline(time.Now().Add(timeoutDuration)) + + line, err := bufReader.ReadString('\n') if err != nil { - LOG_ERR.Printf("Error while reading bytes from connection.\n") - close(c) - return + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + fmt.Printf("Timeout!\n") + if waitversion { + fmt.Println("VERSION command did not return.") + return + } + + n, err := (*bot).conn.Write([]byte("VERSION\n")) + fmt.Printf("n: %d, err: %s\n", n, err) + if err != nil { + fmt.Println("Writing to channel failed.") + return + } + // wait for return value of VERSION + waitversion = true + timeoutDuration = timeoutVersion + } else { + fmt.Println("Some more serious error occured while reading.") + return + } + continue } - c <- []byte(line) + // not waiting for version answer right now + timeoutDuration = timeoutNormal + waitversion = false + c <- line - if bytes.Contains([]byte(line), []byte("PING :")) { - v := []byte(bytes.Replace([]byte(line), []byte("PING"), []byte("PONG"), 1)) - fmt.Printf(string(v[:])) - foo.conn.Write(v) - } else if bytes.Contains([]byte(line), []byte("PRIVMSG")) { - msg := scanline_privmsg(string(line)) - parsemsg(&msg, foo) + if strings.Contains(line, "PING") { + (*bot).conn.Write([]byte(strings.Replace(line, "PING", "PONG", 1))) + } else if strings.Contains(line, "You have not registered") { + // set nickname + time.Sleep(10 * time.Second) + bot_register(bot) + } else if strings.Contains(line, "PRIVMSG") { + msg := scanline_privmsg(line) + parsemsg(&msg, (*bot)) if msg.retmsg != "" { - sendmsg(foo.conn, msg.channel, msg.retmsg) + sendmsg((*bot).conn, msg.channel, msg.retmsg) } } } - } () + } (10 * time.Second, 5 * time.Second) + // } (4 * time.Minute, 1 * time.Minute) + return c } -func connect(boddle *bot) <-chan []byte { - conn, err := net.Dial("tcp", (*boddle).Conf.Server) +func bot_run(bot *bot) { + LOG_INFO.Println("Bot ready to run.") + LOG_INFO.Println("Opening database.") + db, err = sql.Open("sqlite3", (*bot).Conf.Database) if err != nil { - fmt.Fprintf(os.Stderr, "Error while dialing server.") - LOG_ERR.Printf("Error while connecting to server.") - return nil + LOG_ERR.Println("Opening database failed.") + return } - (*boddle).conn = conn - - /* connect to irc */ - fmt.Fprintf((*boddle).conn, "NICK %s\r\n", (*boddle).Conf.Name) - fmt.Fprintf((*boddle).conn, "USER %s 1 1 1:%s\r\n", (*boddle).Conf.Name, (*boddle).Conf.Name) - for _, channel := range((*boddle).Conf.Channels) { - fmt.Fprintf((*boddle).conn, "JOIN %s\r\n", channel) + for { + bot_connect(bot) + if bot.conn == nil { + LOG_INFO.Printf("Bot is nil. Try to connect again.") + time.Sleep(10 * time.Second) + continue + } + for val := range bot_listen(bot) { + LOG_INFO.Printf("%s", val) + } } - - return listenToIRC((*boddle)) } func main() { @@ -104,24 +157,5 @@ func main() { log.Fatal(err) } - LOG_INFO.Println("bot started!") - - var botchan <-chan []byte - - for { - botchan = connect(&boddle) - for { - select { - case res := <-botchan: - fmt.Println(string(res)) - case <-time.After(10 * time.Minute): - fmt.Println("timeout - 10 Minutes no ping received.") - // close channel, close connection - boddle.conn.Close() - goto Reconnect - } - } -Reconnect: - fmt.Println("trying to reconnect...") - } + bot_run(&boddle) } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ef1cee4 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module boddle + +go 1.17 + +require ( + github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816 + github.com/mattn/go-sqlite3 v1.14.12 +) + +require ( + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..eb5290c --- /dev/null +++ b/go.sum @@ -0,0 +1,18 @@ +github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816 h1:V6TyTUY0vUVUOxLnuH6AIOCIOI8psy5h0n4U+qvO4bo= +github.com/distributedio/configo v0.0.0-20200107073829-efd79b027816/go.mod h1:Jwz2omP6W/T/XlSfu+BMGW7NEJX3tf5/Qv5gwaiQ+uU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8= +github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc h1:BrtrZvICmDsYzv7ECoQFwlC5cS+YWDfz/OBpMlMe9HY= +github.com/shafreeck/toml v0.0.0-20190326060449-44ad86712acc/go.mod h1:C9DYu7Ddz1xnXil/kyvydcdaUggQeJvFA7vzYpm+Cw4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190318195719-6c81ef8f67ca/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190319232107-3f1ed9edd1b4/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=