package appservice import ( "fmt" "maunium.net/go/gomatrix" ) type IntentAPI struct { *gomatrix.Client bot *gomatrix.Client as *AppService Localpart string UserID string } func (as *AppService) NewIntentAPI(localpart string) *IntentAPI { userID := fmt.Sprintf("@%s:%s", localpart, as.HomeserverDomain) bot := as.BotClient() if userID == bot.UserID { bot = nil } return &IntentAPI{ Client: as.Client(userID), bot: bot, as: as, Localpart: localpart, UserID: userID, } } func (intent *IntentAPI) Register() error { _, _, err := intent.Client.Register(&gomatrix.ReqRegister{ Username: intent.Localpart, }) if err != nil { return err } return nil } func (intent *IntentAPI) EnsureRegistered() error { if intent.as.StateStore.IsRegistered(intent.UserID) { return nil } err := intent.Register() httpErr, ok := err.(gomatrix.HTTPError) if !ok || httpErr.RespError.ErrCode != "M_USER_IN_USE" { return err } intent.as.StateStore.MarkRegistered(intent.UserID) return nil } func (intent *IntentAPI) EnsureJoined(roomID string) error { if intent.as.StateStore.IsInRoom(roomID, intent.UserID) { return nil } if err := intent.EnsureRegistered(); err != nil { return err } resp, err := intent.JoinRoom(roomID, "", nil) if err != nil { httpErr, ok := err.(gomatrix.HTTPError) if !ok || httpErr.RespError.ErrCode != "M_FORBIDDEN" || intent.bot == nil { return httpErr } _, inviteErr := intent.bot.InviteUser(roomID, &gomatrix.ReqInviteUser{ UserID: intent.UserID, }) if inviteErr != nil { return err } resp, err = intent.JoinRoom(roomID, "", nil) if err != nil { return err } } intent.as.StateStore.SetMembership(resp.RoomID, intent.UserID, "join") return nil } func (intent *IntentAPI) SendMessageEvent(roomID string, eventType gomatrix.EventType, contentJSON interface{}) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendMessageEvent(roomID, eventType, contentJSON) } func (intent *IntentAPI) SendMassagedMessageEvent(roomID string, eventType gomatrix.EventType, contentJSON interface{}, ts int64) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendMassagedMessageEvent(roomID, eventType, contentJSON, ts) } func (intent *IntentAPI) SendStateEvent(roomID string, eventType gomatrix.EventType, stateKey string, contentJSON interface{}) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendStateEvent(roomID, eventType, stateKey, contentJSON) } func (intent *IntentAPI) SendMassagedStateEvent(roomID string, eventType gomatrix.EventType, stateKey string, contentJSON interface{}, ts int64) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendMassagedStateEvent(roomID, eventType, stateKey, contentJSON, ts) } func (intent *IntentAPI) StateEvent(roomID string, eventType gomatrix.EventType, stateKey string, outContent interface{}) (err error) { if err := intent.EnsureJoined(roomID); err != nil { return err } return intent.Client.StateEvent(roomID, eventType, stateKey, outContent) } func (intent *IntentAPI) PowerLevels(roomID string) (pl *gomatrix.PowerLevels, err error) { pl = intent.as.StateStore.GetPowerLevels(roomID) if pl == nil { pl = &gomatrix.PowerLevels{} err = intent.StateEvent(roomID, gomatrix.StatePowerLevels, "", pl) if err == nil { intent.as.StateStore.SetPowerLevels(roomID, pl) } } return } func (intent *IntentAPI) SetPowerLevels(roomID string, levels *gomatrix.PowerLevels) (resp *gomatrix.RespSendEvent, err error) { resp, err = intent.SendStateEvent(roomID, gomatrix.StatePowerLevels, "", &levels) if err == nil { intent.as.StateStore.SetPowerLevels(roomID, levels) } return } func (intent *IntentAPI) SetPowerLevel(roomID, userID string, level int) (*gomatrix.RespSendEvent, error) { pl, err := intent.PowerLevels(roomID) if err != nil { return nil, err } if pl.GetUserLevel(userID) != level { pl.SetUserLevel(userID, level) return intent.SendStateEvent(roomID, gomatrix.StatePowerLevels, "", &pl) } return nil, nil } func (intent *IntentAPI) UserTyping(roomID string, typing bool, timeout int64) (resp *gomatrix.RespTyping, err error) { if intent.as.StateStore.IsTyping(roomID, intent.UserID) == typing { return } resp, err = intent.Client.UserTyping(roomID, typing, timeout) if err != nil { return } if !typing { timeout = -1 } intent.as.StateStore.SetTyping(roomID, intent.UserID, timeout) return } func (intent *IntentAPI) SendText(roomID, text string) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendText(roomID, text) } func (intent *IntentAPI) SendImage(roomID, body, url string) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendImage(roomID, body, url) } func (intent *IntentAPI) SendVideo(roomID, body, url string) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendVideo(roomID, body, url) } func (intent *IntentAPI) SendNotice(roomID, text string) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.SendNotice(roomID, text) } func (intent *IntentAPI) RedactEvent(roomID, eventID string, req *gomatrix.ReqRedact) (*gomatrix.RespSendEvent, error) { if err := intent.EnsureJoined(roomID); err != nil { return nil, err } return intent.Client.RedactEvent(roomID, eventID, req) } func (intent *IntentAPI) SetRoomName(roomID, roomName string) (*gomatrix.RespSendEvent, error) { return intent.SendStateEvent(roomID, gomatrix.StateRoomName, "", map[string]interface{}{ "name": roomName, }) } func (intent *IntentAPI) SetRoomAvatar(roomID, avatarURL string) (*gomatrix.RespSendEvent, error) { return intent.SendStateEvent(roomID, gomatrix.StateRoomAvatar, "", map[string]interface{}{ "url": avatarURL, }) } func (intent *IntentAPI) SetRoomTopic(roomID, topic string) (*gomatrix.RespSendEvent, error) { return intent.SendStateEvent(roomID, gomatrix.StateTopic, "", map[string]interface{}{ "topic": topic, }) } func (intent *IntentAPI) SetDisplayName(displayName string) error { if err := intent.EnsureRegistered(); err != nil { return err } return intent.Client.SetDisplayName(displayName) } func (intent *IntentAPI) SetAvatarURL(avatarURL string) error { if err := intent.EnsureRegistered(); err != nil { return err } return intent.Client.SetAvatarURL(avatarURL) } func (intent *IntentAPI) EnsureInvited(roomID, userID string) error { if !intent.as.StateStore.IsInvited(roomID, userID) { _, err := intent.Client.InviteUser(roomID, &gomatrix.ReqInviteUser{ UserID: userID, }) return err } return nil }