Example #1
0
// 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
}
Example #2
0
// 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
}
Example #3
0
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
}
Example #4
0
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)
				}
			}

		}
	}

}