package irclogs import ( "database/sql" "fmt" "log" "slices" "strings" ) type IRCMessage struct { Tags map[string]string Nick string Command string Params []string } func ParseIRCMessage(message string) IRCMessage { message = strings.TrimRight(message, "\r\n") msg := IRCMessage{ Tags: make(map[string]string), } if strings.HasPrefix(message, "@") { end := strings.IndexByte(message, ' ') rawTags := message[1:end] for _, tag := range strings.Split(rawTags, ";") { parts := strings.SplitN(tag, "=", 2) if len(parts) == 2 { msg.Tags[parts[0]] = parts[1] } else { msg.Tags[parts[0]] = "true" } } message = message[end+1:] } if strings.HasPrefix(message, ":") { end := strings.IndexByte(message, ' ') prefix := message[1:end] if bang := strings.IndexByte(prefix, '!'); bang != -1 { msg.Nick = prefix[:bang] } message = message[end+1:] } parts := strings.Split(message, " ") if len(parts) == 0 { return msg } msg.Command = parts[0] parts = parts[1:] for i := 0; i < len(parts); i++ { if len(parts[i]) == 0 { continue } if parts[i][0] == ':' { param := strings.Join(parts[i:], " ")[1:] msg.Params = append(msg.Params, param) break } msg.Params = append(msg.Params, parts[i]) } return msg } func (m *IRCMessage) Save(db *sql.DB, serverId int) { var roomId int var roomDepart sql.NullTime err := db.QueryRow( "SELECT id, departed_at FROM rooms WHERE name = ? AND server_id = ?", m.Params[0], serverId, ).Scan(&roomId, &roomDepart) if err != nil || roomDepart.Valid { return } var userId int64 var userDepart sql.NullTime err = db.QueryRow( "SELECT id, departed_at FROM users WHERE server_id = ? AND nick = ?", serverId, m.Nick, ).Scan(&userId, &userDepart) if err == sql.ErrNoRows { res, err := db.Exec("INSERT INTO users(server_id, nick) VALUES (?, ?)", serverId, m.Nick) if err != nil { log.Panicf("Failed to create a new user: %v\n", err) } userId, _ = res.LastInsertId() } else if err != nil { log.Panicf("Failed to get a user: %v\n", err) } else if userDepart.Valid { return } tags := sql.NullString{ String: "", Valid: len(m.Tags) > 0, } for k, v := range m.Tags { tags.String += fmt.Sprintf("%s=%s;", k, v) } if len(tags.String) > 0 { tags.String = tags.String[:len(tags.String)-1] } if len(m.Params) > 0 && m.Params[0][0] == '#' { m.Params = slices.Delete(m.Params, 0, 1) } params := sql.NullString{ String: strings.Join(m.Params, " "), Valid: len(m.Params) > 0, } _, err = db.Exec("INSERT INTO messages(room_id, user_id, command, params, tags) VALUES (?, ?, ?, ?, ?)", roomId, userId, m.Command, params, tags) if err != nil { log.Panicf("Failed to add a message: %v\n", err) } }