Add user options to disable battery and certain connected messages
Some checks failed
Go / Lint ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} (1.21) (push) Has been cancelled
Go / Lint ${{ matrix.go-version == '1.22' && '(latest)' || '(old)' }} (1.22) (push) Has been cancelled

This commit is contained in:
Sean Greenawalt 2024-06-18 23:44:53 -04:00
parent 5cfc7b0de4
commit cf4484f123
6 changed files with 100 additions and 7 deletions

View file

@ -52,6 +52,8 @@ func (br *GMBridge) RegisterCommands() {
cmdDisconnect, cmdDisconnect,
cmdSetActive, cmdSetActive,
cmdPing, cmdPing,
cmdToggleBatteryNotifications,
cmdToggleVerboseNotifications,
cmdPM, cmdPM,
cmdDeletePortal, cmdDeletePortal,
cmdDeleteAllPortals, cmdDeleteAllPortals,
@ -402,6 +404,44 @@ func fnPing(ce *WrappedCommandEvent) {
} }
} }
var cmdToggleBatteryNotifications = &commands.FullHandler{
Func: wrapCommand(fnToggleBatteryNotifications),
Name: "toggle-battery-notifications",
Help: commands.HelpMeta{
Section: HelpSectionConnectionManagement,
Description: "Silence Battery statuses.",
},
}
func fnToggleBatteryNotifications(ce *WrappedCommandEvent) {
ce.User.toggleNotifyBattery()
if ce.User.DisableNotifyBattery {
ce.Reply("Disabled battery notifications")
} else {
ce.Reply("Enabled battery notifications")
}
ce.ZLog.Trace().Msg("ToggleBatteryNotifications command finished")
}
var cmdToggleVerboseNotifications = &commands.FullHandler{
Func: wrapCommand(fnToggleVerboseNotifications),
Name: "toggle-verbose-notifications",
Help: commands.HelpMeta{
Section: HelpSectionConnectionManagement,
Description: "Silence Connected statuses when session changes and no data received recently.",
},
}
func fnToggleVerboseNotifications(ce *WrappedCommandEvent) {
ce.User.toggleNotifyVerbose()
if ce.User.DisableNotifyVerbose {
ce.Reply("Disabled verbose notifications")
} else {
ce.Reply("Enabled verbose notifications")
}
ce.ZLog.Trace().Msg("ToggleVerboseNotifications command finished")
}
var cmdPM = &commands.FullHandler{ var cmdPM = &commands.FullHandler{
Func: wrapCommand(fnPM), Func: wrapCommand(fnPM),
Name: "pm", Name: "pm",

View file

@ -0,0 +1,3 @@
-- v11 (compatible with v10+): User settings
ALTER TABLE "user" ADD COLUMN disable_notify_battery BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "user" ADD COLUMN disable_notify_verbose BOOLEAN NOT NULL DEFAULT false;

View file

@ -40,7 +40,7 @@ func newUser(qh *dbutil.QueryHelper[*User]) *User {
} }
const ( const (
getUserBaseQuery = `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token FROM "user"` getUserBaseQuery = `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token, disable_notify_battery, disable_notify_verbose FROM "user"`
getAllUsersWithSessionQuery = getUserBaseQuery + " WHERE session IS NOT NULL" getAllUsersWithSessionQuery = getUserBaseQuery + " WHERE session IS NOT NULL"
getAllUsersWithDoublePuppetQuery = getUserBaseQuery + " WHERE access_token<>''" getAllUsersWithDoublePuppetQuery = getUserBaseQuery + " WHERE access_token<>''"
getUserByRowIDQuery = getUserBaseQuery + " WHERE rowid=$1" getUserByRowIDQuery = getUserBaseQuery + " WHERE rowid=$1"
@ -53,7 +53,8 @@ const (
updateUserQuery = ` updateUserQuery = `
UPDATE "user" UPDATE "user"
SET phone_id=$2, session=$3, self_participant_ids=$4, sim_metadata=$5, settings=$6, SET phone_id=$2, session=$3, self_participant_ids=$4, sim_metadata=$5, settings=$6,
management_room=$7, space_room=$8, access_token=$9 management_room=$7, space_room=$8, access_token=$9,
disable_notify_battery=$10, disable_notify_verbose=$11
WHERE mxid=$1 WHERE mxid=$1
` `
updateuserParticipantIDsQuery = `UPDATE "user" SET self_participant_ids=$2 WHERE mxid=$1` updateuserParticipantIDsQuery = `UPDATE "user" SET self_participant_ids=$2 WHERE mxid=$1`
@ -103,6 +104,9 @@ type User struct {
Settings Settings Settings Settings
AccessToken string AccessToken string
DisableNotifyBattery bool
DisableNotifyVerbose bool
} }
func (user *User) Scan(row dbutil.Scannable) (*User, error) { func (user *User) Scan(row dbutil.Scannable) (*User, error) {
@ -111,6 +115,7 @@ func (user *User) Scan(row dbutil.Scannable) (*User, error) {
err := row.Scan( err := row.Scan(
&user.RowID, &user.MXID, &phoneID, &session, &selfParticipantIDs, &simMetadata, &user.RowID, &user.MXID, &phoneID, &session, &selfParticipantIDs, &simMetadata,
&settings, &managementRoom, &spaceRoom, &accessToken, &settings, &managementRoom, &spaceRoom, &accessToken,
&user.DisableNotifyBattery, &user.DisableNotifyVerbose,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -169,6 +174,7 @@ func (user *User) sqlVariables() []any {
return []any{ return []any{
user.MXID, dbutil.StrPtr(user.PhoneID), session, string(selfParticipantIDs), string(simMetadata), user.MXID, dbutil.StrPtr(user.PhoneID), session, string(selfParticipantIDs), string(simMetadata),
string(settings), dbutil.StrPtr(user.ManagementRoom), dbutil.StrPtr(user.SpaceRoom), dbutil.StrPtr(user.AccessToken), string(settings), dbutil.StrPtr(user.ManagementRoom), dbutil.StrPtr(user.SpaceRoom), dbutil.StrPtr(user.AccessToken),
user.DisableNotifyBattery, user.DisableNotifyVerbose,
} }
} }

View file

@ -19,6 +19,8 @@ type GaiaLoggedOut struct{}
type NoDataReceived struct{} type NoDataReceived struct{}
type RecentlyDisconnected struct{}
type AccountChange struct { type AccountChange struct {
*gmproto.AccountChangeOrSomethingEvent *gmproto.AccountChangeOrSomethingEvent
IsFake bool IsFake bool

View file

@ -240,7 +240,7 @@ func (dp *dittoPinger) Loop() {
go dp.HandleNoRecentUpdates() go dp.HandleNoRecentUpdates()
} else if time.Since(pingStart) > 5*time.Minute { } else if time.Since(pingStart) > 5*time.Minute {
dp.log.Warn().Msg("Was disconnected for over 5 minutes, sending extra GET_UPDATES call") dp.log.Warn().Msg("Was disconnected for over 5 minutes, sending extra GET_UPDATES call")
go dp.HandleNoRecentUpdates() go dp.HandleRecentlyDisconnected()
} }
} }
} }
@ -259,6 +259,20 @@ func (dp *dittoPinger) HandleNoRecentUpdates() {
} }
} }
func (dp *dittoPinger) HandleRecentlyDisconnected() {
dp.client.triggerEvent(&events.RecentlyDisconnected{})
err := dp.client.sessionHandler.sendMessageNoResponse(SendMessageParams{
Action: gmproto.ActionType_GET_UPDATES,
OmitTTL: true,
RequestID: dp.client.sessionHandler.sessionID,
})
if err != nil {
dp.log.Err(err).Msg("Failed to send extra GET_UPDATES call")
} else {
dp.log.Debug().Msg("Sent extra GET_UPDATES call")
}
}
func (c *Client) shouldDoDataReceiveCheck() bool { func (c *Client) shouldDoDataReceiveCheck() bool {
c.nextDataReceiveCheckLock.Lock() c.nextDataReceiveCheckLock.Lock()
defer c.nextDataReceiveCheckLock.Unlock() defer c.nextDataReceiveCheckLock.Unlock()

30
user.go
View file

@ -79,6 +79,7 @@ type User struct {
phoneNotRespondingAlertSent bool phoneNotRespondingAlertSent bool
didHackySetActive bool didHackySetActive bool
noDataReceivedRecently bool noDataReceivedRecently bool
recentlyDisconnected bool
lastDataReceived time.Time lastDataReceived time.Time
gaiaHackyDeviceSwitcher int gaiaHackyDeviceSwitcher int
@ -660,6 +661,7 @@ func (user *User) DeleteSession() {
user.SelfParticipantIDs = []string{} user.SelfParticipantIDs = []string{}
user.didHackySetActive = false user.didHackySetActive = false
user.noDataReceivedRecently = false user.noDataReceivedRecently = false
user.recentlyDisconnected = false
user.lastDataReceived = time.Time{} user.lastDataReceived = time.Time{}
err := user.Update(context.TODO()) err := user.Update(context.TODO())
if err != nil { if err != nil {
@ -849,6 +851,8 @@ func (user *User) syncHandleEvent(event any) {
user.handleSettings(v) user.handleSettings(v)
case *events.AccountChange: case *events.AccountChange:
user.handleAccountChange(v) user.handleAccountChange(v)
case *events.RecentlyDisconnected:
user.recentlyDisconnected = true
case *events.NoDataReceived: case *events.NoDataReceived:
user.noDataReceivedRecently = true user.noDataReceivedRecently = true
default: default:
@ -970,17 +974,20 @@ func (user *User) handleUserAlert(v *gmproto.UserAlertEvent) {
user.ready = true user.ready = true
newSessionID := user.Client.CurrentSessionID() newSessionID := user.Client.CurrentSessionID()
sessionIDChanged := user.sessionID != newSessionID sessionIDChanged := user.sessionID != newSessionID
if sessionIDChanged || wasInactive || user.noDataReceivedRecently { if sessionIDChanged || wasInactive || user.noDataReceivedRecently || user.recentlyDisconnected {
user.zlog.Debug(). user.zlog.Debug().
Str("old_session_id", user.sessionID). Str("old_session_id", user.sessionID).
Str("new_session_id", newSessionID). Str("new_session_id", newSessionID).
Bool("was_inactive", wasInactive). Bool("was_inactive", wasInactive).
Bool("had_no_data_received", user.noDataReceivedRecently). Bool("had_no_data_received", user.noDataReceivedRecently).
Bool("recently_disconeccted", user.recentlyDisconnected).
Time("last_data_received", user.lastDataReceived). Time("last_data_received", user.lastDataReceived).
Msg("Session ID changed for browser active event, resyncing") Msg("Session ID changed for browser active event, resyncing")
user.sessionID = newSessionID user.sessionID = newSessionID
go user.fetchAndSyncConversations(user.lastDataReceived, !sessionIDChanged && !wasInactive) go user.fetchAndSyncConversations(user.lastDataReceived, !sessionIDChanged && !wasInactive)
if (!user.DisableNotifyVerbose || wasInactive || user.recentlyDisconnected) {
go user.sendMarkdownBridgeAlert(ctx, false, "Connected to Google Messages") go user.sendMarkdownBridgeAlert(ctx, false, "Connected to Google Messages")
}
} else { } else {
user.zlog.Debug(). user.zlog.Debug().
Str("session_id", user.sessionID). Str("session_id", user.sessionID).
@ -990,6 +997,7 @@ func (user *User) handleUserAlert(v *gmproto.UserAlertEvent) {
Msg("Session ID didn't change for browser active event, not resyncing") Msg("Session ID didn't change for browser active event, not resyncing")
} }
user.noDataReceivedRecently = false user.noDataReceivedRecently = false
user.recentlyDisconnected = false
user.lastDataReceived = time.Now() user.lastDataReceived = time.Now()
case gmproto.AlertType_BROWSER_INACTIVE_FROM_TIMEOUT: case gmproto.AlertType_BROWSER_INACTIVE_FROM_TIMEOUT:
user.browserInactiveType = GMBrowserInactiveTimeout user.browserInactiveType = GMBrowserInactiveTimeout
@ -1004,13 +1012,17 @@ func (user *User) handleUserAlert(v *gmproto.UserAlertEvent) {
case gmproto.AlertType_MOBILE_BATTERY_LOW: case gmproto.AlertType_MOBILE_BATTERY_LOW:
user.batteryLow = true user.batteryLow = true
if time.Since(user.batteryLowAlertSent) > 30*time.Minute { if time.Since(user.batteryLowAlertSent) > 30*time.Minute {
if (!user.DisableNotifyBattery) {
go user.sendMarkdownBridgeAlert(ctx, true, "Your phone's battery is low") go user.sendMarkdownBridgeAlert(ctx, true, "Your phone's battery is low")
}
user.batteryLowAlertSent = time.Now() user.batteryLowAlertSent = time.Now()
} }
case gmproto.AlertType_MOBILE_BATTERY_RESTORED: case gmproto.AlertType_MOBILE_BATTERY_RESTORED:
user.batteryLow = false user.batteryLow = false
if !user.batteryLowAlertSent.IsZero() { if !user.batteryLowAlertSent.IsZero() {
if (!user.DisableNotifyBattery) {
go user.sendMarkdownBridgeAlert(ctx, false, "Phone battery restored") go user.sendMarkdownBridgeAlert(ctx, false, "Phone battery restored")
}
user.batteryLowAlertSent = time.Time{} user.batteryLowAlertSent = time.Time{}
} }
default: default:
@ -1026,6 +1038,22 @@ func (user *User) handleUserAlert(v *gmproto.UserAlertEvent) {
user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected})
} }
func (user *User) toggleNotifyBattery() {
user.DisableNotifyBattery = !user.DisableNotifyBattery
err := user.Update(context.TODO())
if err != nil {
user.zlog.Err(err).Msg("Failed to save notify battery preference")
}
}
func (user *User) toggleNotifyVerbose() {
user.DisableNotifyVerbose = !user.DisableNotifyVerbose
err := user.Update(context.TODO())
if err != nil {
user.zlog.Err(err).Msg("Failed to save notify verbose preference")
}
}
func (user *User) handleSettings(settings *gmproto.Settings) { func (user *User) handleSettings(settings *gmproto.Settings) {
if settings.SIMCards == nil { if settings.SIMCards == nil {
return return