package main import ( "bytes" "encoding/json" "log" "mime/multipart" "net" "net/http" "net/textproto" "time" ) const ( AnnounceStart = "start" AnnounceUpdate = "update" AnnounceDelete = "delete" ) const verString = "multiserver v1.13.3" func Announce(action string) error { listsrv, ok := ConfKey("serverlist_url").(string) if !ok { return nil } log.Print("Updating server list announcement") host, ok := ConfKey("host").(string) if !ok { host = "0.0.0.0:33000" } addr, err := net.ResolveUDPAddr("udp", host) if err != nil { return err } conns := Conns() mods, ok := ConfKey("serverlist_mods").([]string) if !ok { mods = make([]string, 0) } clients_list := make([]string, 0) for _, conn := range conns { clients_list = append(clients_list, conn.Username()) } maxPeers, ok := ConfKey("player_limit").(int) if !ok { maxPeers = int(^uint(0) >> 1) } conf := func(key string) interface{} { value, ok := ConfKey(key).(string) if !ok { return "" } return value } confBool := func(key string) interface{} { value, ok := ConfKey(key).(bool) if !ok { return false } return value } data := make(map[string]interface{}) data["action"] = action data["port"] = addr.Port data["address"] = conf("serverlist_address") if action != AnnounceDelete { data["name"] = conf("serverlist_name") data["description"] = conf("serverlist_desc") data["version"] = verString data["proto_min"] = ProtoMin data["proto_max"] = ProtoLatest data["url"] = conf("serverlist_display_url") data["creative"] = confBool("serverlist_creative") data["damage"] = confBool("serverlist_damage") data["password"] = confBool("disallow_empty_passwords") data["pvp"] = confBool("serverlist_pvp") data["uptime"] = Uptime() data["game_time"] = 0 data["clients"] = ConnCount() data["clients_max"] = maxPeers data["clients_list"] = clients_list data["gameid"] = conf("serverlist_game") } if action == AnnounceStart { data["can_see_far_names"] = confBool("serverlist_can_see_far_names") data["mods"] = mods } s, err := json.Marshal(data) if err != nil { return err } rqBody := &bytes.Buffer{} writer := multipart.NewWriter(rqBody) mimeHeader := textproto.MIMEHeader{} mimeHeader.Set("Content-Disposition", "form-data; name=\"json\"") part, _ := writer.CreatePart(mimeHeader) part.Write(s) writer.Close() _, err = http.Post(listsrv+"/announce", "multipart/form-data; boundary="+writer.Boundary(), rqBody) if err != nil { return err } return nil } func init() { reannounce, ok := ConfKey("serverlist_announce_interval").(int) if !ok { reannounce = 300 } go func() { announce := time.NewTicker(time.Duration(reannounce) * time.Second) for { select { case <-announce.C: Announce(AnnounceUpdate) } } }() }