package main import ( "bytes" "database/sql" "encoding/json" "fmt" "log" "net/http" "regexp" "strconv" "strings" "time" // https://golang.org/ref/spec#Import_declarations _ "github.com/lib/pq" ) // Faction is a struct that holds data about a faction type Faction struct { webhookGeneral string webhookWar string name string id int } // Event from http://api.orn.com/user type Event struct { id int timestamp time.Time news string } // Events array of Event type Events []Event // Attack struct type Attack struct { id int timestamp time.Time news string } // Attacks array of Attack type Attacks []Attack // News to be broadcast type News struct { Content string `json:"content"` } func main() { duration := time.Duration(10) * time.Second time.Sleep(duration) var err error var e Event timeFormat := "2006-01-02 15:04:05" relentless := Faction{ webhookGeneral: "https://discordapp.com/api/webhooks/330506556820946946/gzReDE9EKFei05twvoFSZgRkAdAG523YTNLy2T_c5NDwagapwgGyhTrjFq_Y2_zu1fOK", webhookWar: "https://discordapp.com/api/webhooks/330163061573025792/m9qS_4FawQwaWN11Y-qDKC2CeBlcR2r7Q9muISiVjW7LVpKrPNcYudNkPf2Y_ZD3sWf6", name: "Relentless", id: 8336} unrelenting := Faction{ webhookGeneral: "https://discordapp.com/api/webhooks/330303142367461376/R9v8SQqZz8J-nyQuDAcU-xA7GNt_DsMzZ30LI6qJmebDJzLOfQoCLvX07YBrjoZTHAVI", webhookWar: "https://discordapp.com/api/webhooks/330303142367461376/R9v8SQqZz8J-nyQuDAcU-xA7GNt_DsMzZ30LI6qJmebDJzLOfQoCLvX07YBrjoZTHAVI", name: "Unrelenting", id: 20747} factions := []Faction{relentless, unrelenting} for _, faction := range factions { e, err = getEventsFromDatabase(faction.name) if err != nil { log.Println("Database error:", err) } if e.id > 0 { fmt.Println("*** Processing: " + faction.name) var code int e.news = strings.Replace(e.news, "[", "\\[", -1) news := replaceLinks(e.news) news = strings.Replace(news, "http:", "https:", -1) news = "`" + e.timestamp.UTC().Format(timeFormat) + "`: " + news fmt.Println(faction.name + ": " + news) code, err = broadcastNews(news, faction.webhookGeneral) // general if err != nil { log.Println("broadcast error:", err) } fmt.Println(faction.name + ": " + strconv.Itoa(code)) if code == 204 { // Assuming sent setBroadcastTrue(e.id) } } // Attacks attacks, err := getAttackFromDatabase(faction.name) if err != nil { log.Println("Database error:", err) } for key, attack := range attacks { fmt.Printf("attacks[%d].id: %d\n", key, attack.id) err = broadcastSingleAttack(attack, faction) if err != nil { log.Println(err) } } //a := attacks[0] } } func getEventsFromDatabase(factionName string) (Event, error) { var err error var e Event db, err := sql.Open("postgres", "user="+pgUser+" dbname="+pgTable+" password="+pgPasswd) if err != nil { return e, err } defer db.Close() rows, err := db.Query(`SELECT id, timestamp, news FROM events WHERE faction = '` + factionName + `' AND broadcast = FALSE ORDER BY id ASC LIMIT 1;`) if err != nil { return e, err } defer rows.Close() for rows.Next() { rows.Scan(&e.id, &e.timestamp, &e.news) if err != nil { return e, err } fmt.Println(e) } if err := rows.Err(); err != nil { return e, err } return e, nil } func getAttackFromDatabase(factionName string) (Attacks, error) { var err error var a Attack var attacks Attacks db, err := sql.Open("postgres", "user="+pgUser+" dbname="+pgTable+" password="+pgPasswd) if err != nil { return attacks, err } defer db.Close() rows, err := db.Query("SELECT id, timestamp, news FROM attacks WHERE faction = '" + factionName + "' AND broadcast = FALSE ORDER BY id ASC;") if err != nil { return attacks, err } defer rows.Close() for rows.Next() { rows.Scan(&a.id, &a.timestamp, &a.news) if err != nil { return attacks, err } attacks = append(attacks, a) fmt.Println(a) } if err := rows.Err(); err != nil { return attacks, err } return attacks, nil } func (e Event) String() string { line := fmt.Sprintf("{\n\t\"id\": %d,", e.id) line += fmt.Sprintf("\n\t\"timestamp\": %s,", e.timestamp) line += fmt.Sprintf("\n\t\"news\": %s", e.news) line += fmt.Sprintf("\n}") return line } func (a Attack) String() string { line := fmt.Sprintf("{\n\t\"id\": %d,", a.id) line += fmt.Sprintf("\n\t\"timestamp\": %s,", a.timestamp) line += fmt.Sprintf("\n\t\"news\": %s", a.news) line += fmt.Sprintf("\n}") return line } func replaceLinks(news string) string { re := regexp.MustCompile(`<[aA].*?href\s?=\s?"?(.*?)[ "]?(?: .*?)?>(.*?)<\/a>`) fmt.Println(re.FindAllStringSubmatch(news, -1)) return re.ReplaceAllString(news, "[${2}](${1})") //return news } func broadcastNews(new string, webhook string) (int, error) { // var err error var news News news.Content = new jsonValue, err := json.Marshal(news) if err != nil { return -1, err } fmt.Println(string(jsonValue)) resp, err := http.Post(webhook, "application/json", bytes.NewBuffer(jsonValue)) if err != nil { return -1, err } return resp.StatusCode, nil } func broadcastSingleAttack(attack Attack, faction Faction) error { timeFormat := "2006-01-02 15:04:05" if attack.id > 0 { members, err := getRelentlessMembers() if err != nil { log.Println("Database error:", err) } news := replaceLinks(attack.news) news = strings.Replace(news, "http:", "https:", -1) for _, val := range members { news = strings.Replace(news, val, "**"+val+"**", -1) } news = strings.Replace(news, "_", "\\_", -1) news = attack.timestamp.UTC().Format(timeFormat) + ": " + news code, err := broadcastNews(news, faction.webhookWar) // war if err != nil { log.Println("broadcast error:", err) } fmt.Println(faction.name + ": " + strconv.Itoa(code)) if code == 204 { // Assuming sent setAttackBroadcastTrue(attack.id) } } return nil } func setBroadcastTrue(id int) error { fmt.Println(id) var err error db, err := sql.Open("postgres", "user="+pgUser+" dbname="+pgTable+" password="+pgPasswd) if err != nil { return err } defer db.Close() tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Rollback() tx.Exec(`SET TIME ZONE 'utc'`) stmt, err := tx.Prepare("UPDATE events SET broadcast = TRUE WHERE id = $1;") if err != nil { return err } _, err = stmt.Exec(fmt.Sprintf("%d", id)) if err != nil { return err } err = tx.Commit() if err != nil { return err } return nil } func setAttackBroadcastTrue(id int) error { fmt.Println(id) var err error db, err := sql.Open("postgres", "user="+pgUser+" dbname="+pgTable+" password="+pgPasswd) if err != nil { return err } defer db.Close() tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Rollback() tx.Exec(`SET TIME ZONE 'utc'`) stmt, err := tx.Prepare("UPDATE attacks SET broadcast = TRUE WHERE id = $1;") if err != nil { return err } _, err = stmt.Exec(fmt.Sprintf("%d", id)) if err != nil { return err } err = tx.Commit() if err != nil { return err } return nil } func getRelentlessMembers() ([]string, error) { var members []string var err error db, err := sql.Open("postgres", "user="+pgUser+" dbname="+pgTable+" password="+pgPasswd) if err != nil { return members, err } defer db.Close() rows, err := db.Query("SELECT member_name FROM members WHERE status = 'joined';") if err != nil { return members, err } defer rows.Close() var name string for rows.Next() { rows.Scan(&name) if err != nil { return members, err } members = append(members, name) } if err := rows.Err(); err != nil { return members, err } return members, nil }