// GetRandomEuropeCM returns back a random server in europe func GetRandomEuropeCM() *netutil.PortAddr { rng := rand.New(rand.NewSource(time.Now().UnixNano())) addr := netutil.ParsePortAddr(CMServers[1][rng.Int31n(int32(len(CMServers[1])))]) if addr == nil { panic("invalid address in CMServers slice") } return addr }
// GetRandomCM returns back a random server anywhere func GetRandomCM() *netutil.PortAddr { rng := rand.New(rand.NewSource(time.Now().UnixNano())) servers := append(CMServers[0], CMServers[1]...) addr := netutil.ParsePortAddr(servers[rng.Int31n(int32(len(servers)))]) if addr == nil { panic("invalid address in CMServers slice") } return addr }
func (sd *steamDirectory) GetRandomCM() *netutil.PortAddr { sd.RLock() defer sd.RUnlock() if !sd.isInitialized { panic("steam directory is not initialized") } rng := rand.New(rand.NewSource(time.Now().UnixNano())) addr := netutil.ParsePortAddr(sd.servers[rng.Int31n(int32(len(sd.servers)))]) return addr }
func main() { // Init seed rand.Seed(time.Now().UTC().UnixNano()) // Steam details var chatId steamid.SteamId loginInfo := new(steam.LogOnDetails) loginInfo.Username, loginInfo.Password, chatId = GetSteamInfo() loginInfo.SentryFileHash, errCatch = ioutil.ReadFile("sentry.conf") // Setup IRC and connect // IRC takes longer to connect than Steam so we do this first ircUsers := []string{} ircNick, ircServer, ircChan := GetIRCInfo() irco := irc.IRC(ircNick, "bot") irco.Connect(ircServer) // Create maps of steamId:Name var steamUsers map[steamid.SteamId]string var steamUserStatus map[steamid.SteamId]string var userGames map[steamid.SteamId]string steamUsers = make(map[steamid.SteamId]string) steamUserStatus = make(map[steamid.SteamId]string) userGames = make(map[steamid.SteamId]string) // Create steam client and connect client := steam.NewClient() // If we don't have a local list of Steam servers, connect using built in list if _, err := os.Stat("steamservers.conf"); os.IsNotExist(err) { log.Print("Connecting to Steam using built-in server list.") log.Print("You may need to ^C and try again multiple times.") log.Print("This should only happen the first time you run the program.") client.Connect() } else { // Once we have the list connect to a random server steamServer := netutil.ParsePortAddr(GetRandomServer()) client.ConnectTo(steamServer) } // Enumerate ircUsers on an RPL_NAMEREPLY irco.AddCallback("353", func(e *irc.Event) { ircUsers = strings.Split(e.Message(), " ") }) // When connected to IRC, join channel and tell Steam about it irco.AddCallback("001", func(e *irc.Event) { irco.Join(ircChan) inIRC = true if inSteam { client.Social.SendMessage(chatId, 1, "Joined IRC") } }) // Poll for Steam events for event := range client.Events() { switch e := event.(type) { // Once connected, log on case *steam.ConnectedEvent: client.Auth.LogOn(loginInfo) // If using new Steam Guard string, generate sentry case *steam.MachineAuthUpdateEvent: ioutil.WriteFile("sentry.conf", e.Hash, 0666) // Once logged on, appear as online and join chat case *steam.LoggedOnEvent: log.Print("Logged on to Steam") client.Social.SetPersonaState(steamlang.EPersonaState_Online) client.Social.JoinChat(chatId) // Write server list to file // We want to do this even if we already have it so it's up-to-date case *steam.ClientCMListEvent: steamIPs := []string{} for i := 0; i < len(e.Addresses); i++ { steamIPs = append(steamIPs, e.Addresses[i].String()) } ioutil.WriteFile("steamservers.conf", []byte(strings.Join(steamIPs, "\n")), 0666) // Something broke! Report to terminal and carry on case *steam.DisconnectedEvent: //log.Print("foo | Disconnected") case *steam.FatalErrorEvent: inSteam = false log.Print(e) log.Print("bar | Disconnected/Fatal") time.Sleep(time.Second * time.Duration(waitSeconds)) client.Connect() //To(steamServer) case error: /*if strings.Contains(string(e), "EOF") { inSteam = false client.ConnectTo(steamServer) }*/ log.Print(e) log.Print("baz | Generic") // Once joined chat case *steam.ChatEnterEvent: log.Print("Joined Steam chat") inSteam = true // Tell IRC if inIRC { irco.Privmsg(ircChan, "Joined Steam") } // Init IRC event callbacks (only first time) if callbackSet == false { callbackSet = true // Received message irco.AddCallback("PRIVMSG", func(ie *irc.Event) { // Don't parse PMs if ie.Arguments[0] == ircChan { // Format for Steam then send steamMsg := ie.Nick + ": " + ie.Message() client.Social.SendMessage(chatId, 1, steamMsg) // IRC-side commands switch ie.Message() { // Reconnect to Steam /*case ".restart": client.Disconnect() time.Sleep(time.Second*time.Duration(waitSeconds)) client.ConnectTo(steamServer) */ // Don't completely disconnect from Steam but rejoin chat case ".reset": go ResetSteam(client, chatId) // Get steam steamUsers. We have a map of steamUsers in chat to iterate over case ".online": msg := GetSteamUsers(steamUserStatus, steamUsers) irco.Privmsg(ircChan, msg) client.Social.SendMessage(chatId, 1, msg) case ".playing": msg := GetUsersPlaying(userGames, steamUsers) for i := range msg { irco.Privmsg(ircChan, msg[i]) client.Social.SendMessage(chatId, 1, msg[i]) } } } }) // Nick change irco.AddCallback("NICK", func(ie *irc.Event) { irco.SendRaw("NAMES " + ircChan) steamMsg := ie.Nick + " is now known as " + ie.Message() client.Social.SendMessage(chatId, 1, steamMsg) }) // /me irco.AddCallback("CTCP_ACTION", func(ie *irc.Event) { steamMsg := "* " + ie.Nick + " " + ie.Message() client.Social.SendMessage(chatId, 1, steamMsg) }) irco.AddCallback("JOIN", func(ie *irc.Event) { irco.SendRaw("NAMES " + ircChan) if ie.Nick != string('`') { steamMsg := ie.Nick + " has joined." client.Social.SendMessage(chatId, 1, steamMsg) } }) irco.AddCallback("PART", func(ie *irc.Event) { irco.SendRaw("NAMES " + ircChan) steamMsg := ie.Nick + " has left." client.Social.SendMessage(chatId, 1, steamMsg) }) irco.AddCallback("QUIT", func(ie *irc.Event) { irco.SendRaw("NAMES " + ircChan) steamMsg := ie.Nick + " has quit. (" + ie.Message() + ")" client.Social.SendMessage(chatId, 1, steamMsg) }) irco.AddCallback("TOPIC", func(ie *irc.Event) { steamMsg := ie.Nick + " has changed the topic to " + ie.Message() client.Social.SendMessage(chatId, 1, steamMsg) }) irco.AddCallback("KICK", func(ie *irc.Event) { irco.SendRaw("NAMES " + ircChan) steamMsg := ie.Nick + " was kicked. (" + ie.Message() + ")" client.Social.SendMessage(chatId, 1, steamMsg) }) } // Populate steamId:name map initChat, errCatch := client.Social.Chats.ById(chatId) for userId := range initChat.ChatMembers { client.Social.RequestFriendInfo(userId, steamlang.EClientPersonaStateFlag_Status) } if errCatch != nil { log.Print(errCatch) } // We get a Steam message case *steam.ChatMsgEvent: // Only parse PMs to reset if e.ChatRoomId != chatId { if e.Message == ".reset" { go ResetSteam(client, chatId) client.Social.SendMessage(chatId, 1, steamUsers[e.ChatterId]+": "+e.Message) e.Message += " \x0304(PM)\x0f" } else { break } } messages := strings.Split(e.Message, "\n") // Get username from steamId msgUser := steamUsers[e.ChatterId] // Format for IRC then send for i := range messages { concat := "\x0307" + msgUser + "\x0f: " + messages[i] if len(concat) > 300 { concat = concat[:300] } irco.Privmsg(ircChan, concat) } // Steam-side commands switch e.Message { // Reconnect to IRC case ".reset": irco.Quit() inIRC = false irco.Connect(ircServer) case ".online": msg := GetIRCUsers(ircUsers) irco.Privmsg(ircChan, msg) client.Social.SendMessage(chatId, 1, msg) case ".playing": msg := GetUsersPlaying(userGames, steamUsers) for i := range msg { irco.Privmsg(ircChan, msg[i]) client.Social.SendMessage(chatId, 1, msg[i]) } } // Something happened in Steam chat case *steam.ChatMemberInfoEvent: // Don't parse PMs if e.ChatRoomId != chatId { break } onId := e.StateChangeInfo.ChatterActedOn byId := e.StateChangeInfo.ChatterActedBy // Get the user affected on := steamUsers[onId] // Get the user performing an action (i.e. kick/ban) by := steamUsers[byId] // Send the state's message to IRC switch e.StateChangeInfo.StateChange { case steamlang.EChatMemberStateChange_Entered: msg := on + " joined chat." irco.Privmsg(ircChan, msg) client.Social.RequestFriendInfo(onId, steamlang.EClientPersonaStateFlag_Status) case steamlang.EChatMemberStateChange_Left: msg := on + " left chat." irco.Privmsg(ircChan, msg) delete(steamUserStatus, onId) delete(userGames, onId) case steamlang.EChatMemberStateChange_Disconnected: msg := on + " disconnected." irco.Privmsg(ircChan, msg) delete(steamUserStatus, onId) delete(userGames, onId) case steamlang.EChatMemberStateChange_Kicked: msg := on + " was kicked from chat by " + by + "." irco.Privmsg(ircChan, msg) delete(steamUserStatus, onId) delete(userGames, onId) case steamlang.EChatMemberStateChange_Banned: msg := on + " was banned from chat by " + by + "." irco.Privmsg(ircChan, msg) delete(steamUserStatus, onId) delete(userGames, onId) } // Got Steam user info case *steam.PersonaStateEvent: if e.Name == "AusGaf" || e.Name == string("`") { break } // Keep old name for comparison later oldName := steamUsers[e.FriendId] // Store name in map steamUsers[e.FriendId] = e.Name steamUserStatus[e.FriendId] = steamlang.EPersonaState.String(e.State) // Only output to IRC if we're in IRC // If person's playing a game, make sure we haven't just told people about it if userGames[e.FriendId] != e.GameName { puncSelect := rand.Intn(3) punc := "" switch puncSelect { case 0: punc = "." case 1: punc = "!" case 2: punc = "" } userGame = e.Name + " is now playing " + e.GameName + punc // Don't send exiting a game if len(e.GameName) > 0 { userGames[e.FriendId] = e.GameName if inIRC { irco.Privmsg(ircChan, userGame) client.Social.SendMessage(chatId, 1, userGame) } } else { delete(userGames, e.FriendId) } } // Name change. Hopefully this won't go off during initialisation if oldName != e.Name && oldName != "" { msg := steamUsers[e.FriendId] + " is now known as " + e.Name + "." if inIRC { irco.Privmsg(ircChan, msg) } } } } }