Documentation
¶
Index ¶
- Variables
- func SendContactJoinedFlipcashPush(ctx context.Context, pusher Pusher, joinedPhone *commonpb.PhoneNumber, ...) error
- func SendFlipcashCurrencyBoughtPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendFlipcashCurrencyDepositedPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendFlipcashCurrencyGainPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendFlipcashCurrencySoldPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendLobbyAdmittedPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendLobbyEnteredPush(ctx context.Context, pusher Pusher, creator *commonpb.UserId, ...) error
- func SendUsdfDepositProcessingPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- func SendUsdfDepositedPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, ...) error
- type BadgeCounts
- type BadgeResolver
- type ChatMessagePush
- func BuildContactDmPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, ...) (*ChatMessagePush, error)
- func BuildDmPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, ...) (*ChatMessagePush, error)
- func BuildGroupChatPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, ...) (*ChatMessagePush, error)
- type ChatRecipients
- type CurrencyState
- type CurrencyStateStore
- type FCMClient
- type FCMPusher
- type NoOpPusher
- type Pusher
- type ReceiverPush
- type Server
- type Store
- type Token
- type TokenStore
Constants ¶
This section is empty.
Variables ¶
var ErrCurrencyStateNotFound = errors.New("currency state not found")
ErrCurrencyStateNotFound is returned when no push state exists for a mint.
Functions ¶
func SendContactJoinedFlipcashPush ¶ added in v1.11.0
func SendFlipcashCurrencyBoughtPush ¶ added in v0.4.0
func SendFlipcashCurrencyDepositedPush ¶ added in v0.4.0
func SendFlipcashCurrencyGainPush ¶ added in v1.1.0
func SendFlipcashCurrencySoldPush ¶ added in v0.4.0
func SendLobbyAdmittedPush ¶ added in v1.36.0
func SendLobbyAdmittedPush(ctx context.Context, pusher Pusher, user *commonpb.UserId, chatId *commonpb.ChatId, chatTitle string) error
SendLobbyAdmittedPush tells a user that a private group's creator let them in from its lobby, titled by the group. Like SendLobbyEnteredPush it is a chat push that is not for a message, and moves no badge.
func SendLobbyEnteredPush ¶ added in v1.36.0
func SendLobbyEnteredPush(ctx context.Context, pusher Pusher, creator *commonpb.UserId, chatId *commonpb.ChatId, chatTitle, requesterDisplayName string) error
SendLobbyEnteredPush tells a private group's creator that a user is waiting in its lobby to be let in ("Alice requested to join", titled by the group). The requester is named by display name, or as "Someone" when they have none. It is a chat push that is not for a message: it navigates to the group and carries its type, but no message and no sender (see pushpb.ChatMetadata), and it moves no badge, like every push that is not a message's.
func SendUsdfDepositProcessingPush ¶ added in v1.9.0
Types ¶
type BadgeCounts ¶ added in v1.30.0
BadgeCounts maps a user (keyed by string(userID.Value)) to the app-icon badge to display alongside a push. A user absent from the map gets no badge.
type BadgeResolver ¶ added in v1.30.0
BadgeResolver produces the badge count to display for each of the given users. A pusher invokes it with only the users who own at least one iOS device — APNs is the only platform with a server-settable numeric badge — so any per-user work behind it (e.g. bumping a stored count) is skipped for users who could never display the result.
A resolver may return a partial map alongside an error: the counts it did produce are still carried on the push, and the error is reported after the push is sent.
type ChatMessagePush ¶ added in v1.32.0
type ChatMessagePush struct {
// contains filtered or unexported fields
}
ChatMessagePush is a chat message's notification, rendered once and sent to any number of recipient pages (see Send). Rendering is the part of a push that is the same for every recipient — the title, the body, the payload, and for cash content a currency-name lookup — so a fan-out that walks a large group's roster in pages builds it once per message rather than once per page. A nil *ChatMessagePush from a builder means the message's content earns no push (an unsupported content type, or a sender missing what the title needs), which is not an error.
func BuildContactDmPush ¶ added in v1.32.0
func BuildContactDmPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, message *messagingpb.Message, senderID *commonpb.UserId, senderContact *commonpb.PhoneNumber) (*ChatMessagePush, error)
BuildContactDmPush renders a new message in a contact DM. The title is a contact substitution on the sender's phone number, which the recipient's client resolves against their address book.
func BuildDmPush ¶ added in v1.33.0
func BuildDmPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, message *messagingpb.Message, senderID *commonpb.UserId, senderDisplayName string) (*ChatMessagePush, error)
BuildDmPush renders a new message in a DM (ChatType_DM). The sender is typically not in the recipient's contacts, so the title carries the sender's display name directly rather than a contact substitution — and never the sender's phone number, which is private outside contact DMs.
func BuildGroupChatPush ¶ added in v1.32.0
func BuildGroupChatPush(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, message *messagingpb.Message, senderID *commonpb.UserId, senderDisplayName, receiverDisplayName, chatTitle string) (*ChatMessagePush, error)
BuildGroupChatPush renders a new message in a group chat. The notification is titled by the group ("Untitled Group" when it has none), with the sender identified by display name in the body ("Alice: hello"; "Alice sent a message" for encrypted content, see renderGroupChatMessagePushBody). A cash message paying one member also names its receiver, by receiverDisplayName ("Alice sent Bob $5 of USDF"), which is ignored for any other content; one paying several names no one and counts them instead ("Alice sent $20 of USDF to 4 people"). Receivers are meant to get BuildGroupChatReceiverPushes instead. Like a DM, a group push never carries the sender's phone number, which is private outside contact DMs.
func (*ChatMessagePush) Send ¶ added in v1.32.0
func (p *ChatMessagePush) Send(ctx context.Context, pusher Pusher, badges badge.Store, recipients ChatRecipients) error
Send delivers the push to both halves of one page of its audience: the unmuted half with each recipient's badge bumped and the new total carried on the notification, so a recipient's icon updates with the same push that announces the message rather than a second, badge-only push per recipient; the muted half flagged, unbadged, as a copy of the same payload, to Android devices only. Either half may be empty and costs nothing then. The two sends are independent, and a failure in one is reported alongside the other's. Send may be called once per page of a large audience; each call is its own token lookup, badge batch and FCM send, so what a call holds is bounded by its page.
type ChatRecipients ¶ added in v1.32.0
ChatRecipients is a chat push's audience, split by whether each recipient has the chat muted. The unmuted half receives the alert with a badge bump. The muted half receives the same payload flagged (ChatMetadata.muted) and without a badge bump, since a muted chat must not move the app icon's count — and only on Android, where the client can deliver the message quietly; the FCMPusher drops a muted recipient's iOS devices, which could not suppress the alert, so an iOS user hears nothing from a chat they muted. Which half a recipient lands in is the sender's best-effort call at send time; the client's own copy of its mute is the last word.
type CurrencyState ¶ added in v1.19.0
type CurrencyState struct {
Mint *commonpb.PublicKey
AllTimeHighSupply uint64
AllTimeHighSlot uint64
LastGainPushAt *time.Time // nil if a gain push has never been granted for the mint
}
CurrencyState captures per-currency state used to gate push notifications.
AllTimeHighSupply tracks the circulating supply (in quarks) observed at the last granted gain push, NOT a true high-water mark: it only advances when a gain push is actually granted (see CurrencyStateStore.ClaimGainPush).
type CurrencyStateStore ¶ added in v1.19.0
type CurrencyStateStore interface {
// ClaimGainPush atomically gates a "currency gain" push wave for a mint.
//
// granted is true only when both conditions hold against the currently stored
// state: (1) supply is strictly greater than the stored all-time high, and
// (2) at least cooldown has elapsed since the last granted gain push (or none
// has ever been granted). When granted, the stored all-time high (supply,
// slot) and last-gain-push timestamp are advanced to the provided values / now.
// When not granted, the stored state is left unchanged — in particular a new
// high observed during cooldown is NOT recorded.
//
// Whenever err is nil, the returned CurrencyState reflects the resulting stored
// state — the freshly written values when granted, or the existing values when
// not — so callers can populate a local cache regardless of the outcome.
ClaimGainPush(ctx context.Context, mint *commonpb.PublicKey, supply, slot uint64, cooldown time.Duration) (granted bool, state *CurrencyState, err error)
// GetCurrencyState returns the stored push state for a mint, or
// ErrCurrencyStateNotFound if none has been recorded yet.
GetCurrencyState(ctx context.Context, mint *commonpb.PublicKey) (*CurrencyState, error)
}
type FCMClient ¶
type FCMClient interface {
SendEach(ctx context.Context, messages []*messaging.Message) (*messaging.BatchResponse, error)
}
FCMClient is the subset of *messaging.Client the pusher depends on. SendEach takes one fully independent message per device, which is what lets each recipient carry its own badge; the SDK fans it out one request per message over a worker pool, exactly as it does for a multicast.
type FCMPusher ¶
type FCMPusher struct {
// contains filtered or unexported fields
}
func NewFCMPusher ¶
func NewFCMPusher(log *zap.Logger, tokens TokenStore, client FCMClient) *FCMPusher
func (*FCMPusher) SendPushes ¶ added in v0.7.0
type NoOpPusher ¶
type NoOpPusher struct{}
func (*NoOpPusher) SendPushes ¶ added in v0.7.0
func (*NoOpPusher) SendPushesWithBadges ¶ added in v1.30.0
func (n *NoOpPusher) SendPushesWithBadges(_ context.Context, _, _ string, _ *pushpb.Payload, _ BadgeResolver, _ ...*commonpb.UserId) error
type Pusher ¶
type Pusher interface {
// SendPushes sends the same notification to every device of the given users.
SendPushes(ctx context.Context, title, body string, customPayload *pushpb.Payload, users ...*commonpb.UserId) error
// SendPushesWithBadges is SendPushes with a per-user app-icon badge carried
// on the notification itself, resolved on demand for the recipients whose
// devices can display one (see BadgeResolver).
SendPushesWithBadges(ctx context.Context, title, body string, customPayload *pushpb.Payload, resolveBadges BadgeResolver, users ...*commonpb.UserId) error
}
func NewNoOpPusher ¶
func NewNoOpPusher() Pusher
type ReceiverPush ¶ added in v1.36.0
type ReceiverPush struct {
Receivers []*commonpb.UserId
Push *ChatMessagePush
}
ReceiverPush is a group cash message's notification for some of its receivers, and who they are: every receiver whose own push reads the same, so they can be sent it together.
func BuildGroupChatReceiverPushes ¶ added in v1.36.0
func BuildGroupChatReceiverPushes(ctx context.Context, ocpData ocp_data.Provider, chatId *commonpb.ChatId, message *messagingpb.Message, senderID *commonpb.UserId, senderDisplayName, chatTitle string) ([]ReceiverPush, error)
BuildGroupChatReceiverPushes renders a cash message in a group chat for its receivers alone, each addressed with their own part ("Alice sent you $5 of USDF"), with the title and payload every other member's push has (see BuildGroupChatPush). A payment to one member has one receiver, paid the whole; one to several has one per entry of its multi receiver, each paid their part. Receivers whose push reads the same share one ReceiverPush, in the order the first of them appears in the message. It is empty for any message that is not cash naming a receiver.
type Server ¶
type Server struct {
pushpb.UnimplementedPushServer
// contains filtered or unexported fields
}
func NewServer ¶
func NewServer(log *zap.Logger, authz auth.Authorizer, tokens TokenStore) *Server
func (*Server) AddToken ¶
func (s *Server) AddToken(ctx context.Context, req *pushpb.AddTokenRequest) (*pushpb.AddTokenResponse, error)
func (*Server) DeleteTokens ¶
func (s *Server) DeleteTokens(ctx context.Context, req *pushpb.DeleteTokensRequest) (*pushpb.DeleteTokensResponse, error)
type Store ¶ added in v1.19.0
type Store interface {
TokenStore
CurrencyStateStore
}
Store is the combined push persistence surface, implemented by each backend.
type Token ¶
type Token struct {
UserID *commonpb.UserId
Type pushpb.TokenType
Token string
AppInstallID string
}
Token represents a push notification token.
Tokens are bound to a (user, device) pair, identified by the AppInstallID.
type TokenStore ¶
type TokenStore interface {
// GetTokens returns all tokens for a user.
GetTokens(ctx context.Context, userID *commonpb.UserId) ([]Token, error)
// GetTokensBatch returns all tokens for a batch of users.
GetTokensBatch(ctx context.Context, userIDs ...*commonpb.UserId) ([]Token, error)
// AddToken adds a token for a user.
//
// If the token already exists for the same user and device, it will be updated.
AddToken(ctx context.Context, userID *commonpb.UserId, appInstallID *commonpb.AppInstallId, tokenType pushpb.TokenType, token string) error
// DeleteToken deletes a token for a user.
DeleteToken(ctx context.Context, tokenType pushpb.TokenType, token string) error
// DeleteTokens deletes every given (type, token) pair in one operation. It
// exists for the pusher's cleanup of tokens FCM reports as unregistered,
// which a large send can surface many of at once. A pair that no longer
// exists is skipped, not an error.
DeleteTokens(ctx context.Context, tokens ...Token) error
// FilterUsersWithTokens returns the subset of user IDs that have at least one push token.
FilterUsersWithTokens(ctx context.Context, userIDs ...*commonpb.UserId) ([]*commonpb.UserId, error)
}