Last active
September 15, 2024 00:53
-
-
Save kirkegaard/dfd1dbd481b0a0ef957862e4dd387769 to your computer and use it in GitHub Desktop.
Irc bot written in go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"net" | |
"strings" | |
) | |
// Config holds the configuration for the IRC Client | |
type Config struct { | |
Host string | |
Port int | |
Nick string | |
RealName string | |
Ident string | |
Channels []string | |
} | |
// Client handles the IRC client configuration and connection | |
type Client struct { | |
conn net.Conn | |
reader *bufio.Reader | |
writer *bufio.Writer | |
isConnected bool | |
config Config | |
} | |
type Message struct { | |
Author string | |
Prefix string | |
Command string | |
Content string | |
Params []string | |
} | |
// ParseIRCMessage parses a raw IRC message line and returns an IRCMessage. | |
func parseMessage(line string) (*Message, error) { | |
if len(line) == 0 { | |
return nil, fmt.Errorf("invalid message format") | |
} | |
var author, prefix, command, content string | |
var params []string | |
// Check for prefix | |
if line[0] == ':' { | |
endOfPrefix := strings.Index(line, " ") | |
if endOfPrefix == -1 { | |
return nil, fmt.Errorf("invalid message format") | |
} | |
prefix = line[1:endOfPrefix] | |
author = strings.Split(prefix, "!")[0] | |
line = line[endOfPrefix+1:] | |
} | |
// Check for trailing part | |
if idx := strings.Index(line, " :"); idx != -1 { | |
content = line[idx+2:] | |
line = line[:idx] | |
} | |
// Remaining parts are command and params | |
parts := strings.Fields(line) | |
if len(parts) == 0 { | |
return nil, fmt.Errorf("invalid message format") | |
} | |
command = parts[0] | |
if len(parts) > 1 { | |
params = parts[1:] | |
} | |
return &Message{ | |
Author: author, | |
Prefix: prefix, | |
Command: command, | |
Params: params, | |
Content: content, | |
}, nil | |
} | |
// send a formatted IRC message to the server | |
func (client *Client) send(message string) { | |
if _, err := fmt.Fprintln(client.writer, message); err != nil { | |
fmt.Println("Error sending message:", err) | |
} | |
if err := client.writer.Flush(); err != nil { | |
fmt.Println("Error flushing message:", err) | |
} | |
} | |
// readLine reads a line from the server | |
func (client *Client) readLine() (string, error) { | |
line, err := client.reader.ReadString('\n') | |
if err != nil { | |
return "", err | |
} | |
return strings.TrimSpace(line), nil | |
} | |
// NewClient creates a new Client with the given configuration | |
func NewClient(config Config) *Client { | |
return &Client{ | |
config: config, | |
} | |
} | |
// Connect establishes the connection to the IRC server | |
func (client *Client) Connect() error { | |
address := fmt.Sprintf("%s:%d", client.config.Host, client.config.Port) | |
conn, err := net.Dial("tcp", address) | |
if err != nil { | |
return fmt.Errorf("error connecting to server: %w", err) | |
} | |
client.conn = conn | |
client.reader = bufio.NewReader(conn) | |
client.writer = bufio.NewWriter(conn) | |
// Send NICK and USER commands | |
client.send("NICK " + client.config.Nick) | |
client.send("USER " + client.config.Ident + " 0 * :" + client.config.RealName) | |
return nil | |
} | |
// Disconnect closes the connection to the IRC server | |
func (client *Client) Disconnect() { | |
if client.conn != nil { | |
client.conn.Close() | |
} | |
} | |
// Listen for incomming message | |
func (client *Client) listen() { | |
// Loop forever, reading from the server | |
for { | |
line, err := client.readLine() | |
if err != nil { | |
fmt.Println("Error reading from server:", err) | |
return | |
} | |
msg, err := parseMessage(line) | |
if err != nil { | |
fmt.Println("Error parsing message:", err) | |
continue | |
} | |
if msg.Command == "PING" { | |
client.send("PONG " + strings.TrimPrefix(line, "PING")) | |
} | |
// Listen for MOTD message and join channels | |
if msg.Command == "001" { | |
client.isConnected = true | |
for _, channel := range client.config.Channels { | |
client.send("JOIN " + channel) | |
fmt.Printf("Joined %s\n", channel) | |
} | |
} | |
// Listen for PRIVMSG | |
if msg.Command == "PRIVMSG" { | |
if msg.Content == "hello" { | |
client.send("PRIVMSG " + msg.Params[0] + " :Hello, " + msg.Author) | |
} | |
} | |
} | |
} | |
func main() { | |
client := NewClient(Config{ | |
Host: "irc.quakenet.org", | |
Port: 6667, | |
Nick: "EnGoBot", | |
RealName: "Christian Kirkegaard", | |
Ident: "christian", | |
Channels: []string{"#engobot"}, | |
}) | |
fmt.Println("Connecting to server...") | |
// Connect to the IRC server | |
if err := client.Connect(); err != nil { | |
panic(err) | |
} | |
defer client.Disconnect() | |
client.listen() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment