From 276ac840aacf01532ef33f0d461775daacb23880 Mon Sep 17 00:00:00 2001 From: Wim Date: Thu, 22 Jun 2017 01:02:05 +0200 Subject: Add initial steam support --- bridge/bridge.go | 4 ++ bridge/config/config.go | 2 + bridge/steam/steam.go | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 bridge/steam/steam.go (limited to 'bridge') diff --git a/bridge/bridge.go b/bridge/bridge.go index fa00ea44..2cf56c0b 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -10,6 +10,7 @@ import ( "github.com/42wim/matterbridge/bridge/mattermost" "github.com/42wim/matterbridge/bridge/rocketchat" "github.com/42wim/matterbridge/bridge/slack" + "github.com/42wim/matterbridge/bridge/steam" "github.com/42wim/matterbridge/bridge/telegram" "github.com/42wim/matterbridge/bridge/xmpp" log "github.com/Sirupsen/logrus" @@ -75,6 +76,9 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid case "matrix": b.Config = cfg.Matrix[name] b.Bridger = bmatrix.New(cfg.Matrix[name], bridge.Account, c) + case "steam": + b.Config = cfg.Steam[name] + b.Bridger = bsteam.New(cfg.Steam[name], bridge.Account, c) case "api": b.Config = cfg.Api[name] b.Bridger = api.New(cfg.Api[name], bridge.Account, c) diff --git a/bridge/config/config.go b/bridge/config/config.go index 79715b53..7f27115b 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -39,6 +39,7 @@ type ChannelInfo struct { } type Protocol struct { + AuthCode string // steam BindAddress string // mattermost, slack Buffer int // api EditSuffix string // mattermost, slack, discord, telegram, gitter @@ -109,6 +110,7 @@ type Config struct { Mattermost map[string]Protocol Matrix map[string]Protocol Slack map[string]Protocol + Steam map[string]Protocol Gitter map[string]Protocol Xmpp map[string]Protocol Discord map[string]Protocol diff --git a/bridge/steam/steam.go b/bridge/steam/steam.go new file mode 100644 index 00000000..491612d1 --- /dev/null +++ b/bridge/steam/steam.go @@ -0,0 +1,158 @@ +package bsteam + +import ( + "fmt" + "github.com/42wim/matterbridge/bridge/config" + "github.com/Philipp15b/go-steam" + "github.com/Philipp15b/go-steam/protocol/steamlang" + "github.com/Philipp15b/go-steam/steamid" + log "github.com/Sirupsen/logrus" + //"io/ioutil" + "strconv" + "sync" + "time" +) + +type Bsteam struct { + c *steam.Client + connected chan struct{} + Config *config.Protocol + Remote chan config.Message + Account string + userMap map[steamid.SteamId]string + sync.RWMutex +} + +var flog *log.Entry +var protocol = "steam" + +func init() { + flog = log.WithFields(log.Fields{"module": protocol}) +} + +func New(cfg config.Protocol, account string, c chan config.Message) *Bsteam { + b := &Bsteam{} + b.Config = &cfg + b.Remote = c + b.Account = account + b.userMap = make(map[steamid.SteamId]string) + b.connected = make(chan struct{}) + return b +} + +func (b *Bsteam) Connect() error { + flog.Info("Connecting") + b.c = steam.NewClient() + go b.handleEvents() + go b.c.Connect() + select { + case <-b.connected: + flog.Info("Connection succeeded") + case <-time.After(time.Second * 30): + return fmt.Errorf("connection timed out") + } + return nil +} + +func (b *Bsteam) Disconnect() error { + b.c.Disconnect() + return nil + +} + +func (b *Bsteam) JoinChannel(channel string) error { + id, err := steamid.NewId(channel) + if err != nil { + return err + } + b.c.Social.JoinChat(id) + return nil +} + +func (b *Bsteam) Send(msg config.Message) error { + id, err := steamid.NewId(msg.Channel) + if err != nil { + return err + } + b.c.Social.SendMessage(id, steamlang.EChatEntryType_ChatMsg, msg.Username+msg.Text) + return nil +} + +func (b *Bsteam) getNick(id steamid.SteamId) string { + b.RLock() + defer b.RUnlock() + if name, ok := b.userMap[id]; ok { + return name + } + return "unknown" +} + +func (b *Bsteam) handleEvents() { + myLoginInfo := new(steam.LogOnDetails) + myLoginInfo.Username = b.Config.Login + myLoginInfo.Password = b.Config.Password + myLoginInfo.AuthCode = b.Config.AuthCode + // Attempt to read existing auth hash to avoid steam guard. + // Maybe works + //myLoginInfo.SentryFileHash, _ = ioutil.ReadFile("sentry") + for event := range b.c.Events() { + //flog.Info(event) + switch e := event.(type) { + case *steam.ChatMsgEvent: + flog.Debugf("Receiving ChatMsgEvent: %#v", e) + flog.Debugf("Sending message from %s on %s to gateway", b.getNick(e.ChatterId), b.Account) + msg := config.Message{Username: b.getNick(e.ChatterId), Text: e.Message, Channel: strconv.FormatInt(int64(e.ChatRoomId), 10), Account: b.Account, UserID: strconv.FormatInt(int64(e.ChatterId), 10)} + b.Remote <- msg + case *steam.PersonaStateEvent: + flog.Debugf("PersonaStateEvent: %#v\n", e) + b.Lock() + b.userMap[e.FriendId] = e.Name + b.Unlock() + case *steam.ConnectedEvent: + b.c.Auth.LogOn(myLoginInfo) + case *steam.MachineAuthUpdateEvent: + /* + flog.Info("authupdate", e) + flog.Info("hash", e.Hash) + ioutil.WriteFile("sentry", e.Hash, 0666) + */ + case *steam.LogOnFailedEvent: + flog.Info("Logon failed", e) + switch e.Result { + case steamlang.EResult_AccountLogonDeniedNeedTwoFactorCode: + { + flog.Info("Steam guard isn't letting me in! Enter 2FA code:") + var code string + fmt.Scanf("%s", &code) + myLoginInfo.TwoFactorCode = code + } + case steamlang.EResult_AccountLogonDenied: + { + flog.Info("Steam guard isn't letting me in! Enter auth code:") + var code string + fmt.Scanf("%s", &code) + myLoginInfo.AuthCode = code + } + default: + log.Errorf("LogOnFailedEvent: ", e.Result) + // TODO: Handle EResult_InvalidLoginAuthCode + return + } + case *steam.LoggedOnEvent: + flog.Debugf("LoggedOnEvent: %#v", e) + b.connected <- struct{}{} + flog.Debugf("setting online") + b.c.Social.SetPersonaState(steamlang.EPersonaState_Online) + case *steam.DisconnectedEvent: + flog.Info("Disconnected") + flog.Info("Attempting to reconnect...") + b.c.Connect() + case steam.FatalErrorEvent: + flog.Error(e) + case error: + flog.Error(e) + default: + flog.Debugf("unknown event %#v", e) + } + } +} -- cgit v1.2.3