direct

package
v0.0.0-...-3bed8bd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2024 License: AGPL-3.0 Imports: 47 Imported by: 0

Documentation

Index

Constants

View Source
const ArbitraryRegisterCheckBuffer = 2 * time.Minute
View Source
const CurrentGroupVersion = "8"
View Source
const CurrentProtocolVersion = "1"
View Source
const DefaultRegisterCheckInterval = 1 * day
View Source
const MaxReregisterInterval = 45 * day
View Source
const MinRegisterCheckInterval = 30 * time.Minute

Variables

View Source
var ErrHandlesReroutedTooRecently = errors.New("handle rerouted too recently")
View Source
var ErrNoRerouteURLConfigured = errors.New("no reroute URL configured")
View Source
var ErrNoSMSForwarding = errors.New("SMS forwarding not enabled")
View Source
var ErrNotOnIMessage = errors.New("requested user is not on iMessage")
View Source
var ErrRerouteRatelimit = errors.New("reroute cancelled due to ratelimit")

Functions

func ParseEditXML

func ParseEditXML(editXML string) (string, error)

func TextLen

func TextLen(text string) int

Types

type AMContentType

type AMContentType int
const (
	AMContentTypeAttachment   AMContentType = 0
	AMContentTypeText         AMContentType = 1
	AMContentTypeAudioMessage AMContentType = 2
	AMContentTypeImage        AMContentType = 3
	AMContentTypeContact      AMContentType = 4
	AMContentTypeEvent        AMContentType = 5
	AMContentTypeLocation     AMContentType = 6
	AMContentTypeMovie        AMContentType = 7
	AMContentTypeWalletPass   AMContentType = 8
	AMContentTypeCustom       AMContentType = 9
)

type AMSummaryInfo

type AMSummaryInfo struct {
	ContentType AMContentType `plist:"amc"`
	// When type is text, the quoted text. When type is custom, the type of message.
	SourceText string `plist:"ams,omitempty"`
	// Balloon type when type is custom and target is a balloon provider thing
	BalloonType string `plist:"amb,omitempty"`
}

func (*AMSummaryInfo) String

func (ams *AMSummaryInfo) String() string

type APNSConnected

type APNSConnected struct{}

type AsyncMessage

type AsyncMessage struct {
	ObjectID     string `plist:"mmcs-owner"`
	SignatureHex string `plist:"mmcs-signature-hex"`
	DownloadURL  string `plist:"mmcs-url"`
}

type AttachmentMessageXML

type AttachmentMessageXML struct {
	XMLName     xml.Name                  `xml:"html"`
	Attachments []*ids.UploadedAttachment `xml:"body>FILE"`
	Text        []*imessage.MessagePart   `xml:"body>span"`
	Objects     []*MessageObject          `xml:"body>object"`
}

TODO move this to a more sensible place

type BalloonID

type BalloonID string
const (
	BalloonURL     BalloonID = "com.apple.messages.URLBalloonProvider"
	BalloonYouTube BalloonID = "com.apple.messages.MSMessageExtensionBalloonPlugin:EQHXZ8M8AV:com.google.ios.youtube.MessagesExtension"
)

type BalloonPayload

type BalloonPayload struct {
	Attachments [][]byte `plist:"__attachments__"`
	Payload     []byte   `plist:"__payload__"`
}

type BaloonPayloadDownloadInfo

type BaloonPayloadDownloadInfo struct {
	DecryptionKey []byte `plist:"e"`
	FileSize      int    `plist:"f"`
	MMCSOwner     string `plist:"o"`
	MMCSURL       string `plist:"r"`
	MMCSSignature []byte `plist:"s"`
}

type BridgeInfoUpdated

type BridgeInfoUpdated struct{}

type ConfigUpdated

type ConfigUpdated struct{}

type Connector

type Connector struct {
	User *ids.User

	IDSCache       ids.LookupCache
	RerouteHistory ids.RerouteHistory

	OutgoingCounterStore ids.OutgoingCounterStore

	NACServ *nacserv.Client

	LoginTestConfig config.IMessageLoginTestConfig

	PushKeyRegenAttempted bool
	OwnHandleChecked      atomic.Bool
	// contains filtered or unexported fields
}

func NewConnector

func NewConnector(
	nacservClient *nacserv.Client,
	eventHandler func(any),
	idsCache ids.LookupCache,
	rerouteHistory ids.RerouteHistory,
	enablePairECSending bool,
	outgoingCounterStore ids.OutgoingCounterStore,
	manualLookupRatelimit *rate.Limiter,
) *Connector

func (*Connector) BroadcastHandleTo

func (dc *Connector) BroadcastHandleTo(ctx context.Context, identities []uri.ParsedURI, senderHandle uri.ParsedURI, onlyIfNotBroadcasted bool) error

func (*Connector) Configure

func (dc *Connector) Configure(ctx context.Context, cfg *ids.Config, dontPublishKeys bool) error

func (*Connector) DeRegisterIDS

func (dc *Connector) DeRegisterIDS(ctx context.Context) error

func (*Connector) DoPhoneRegistrationLookupTest

func (dc *Connector) DoPhoneRegistrationLookupTest(ctx context.Context, handle uri.ParsedURI) (bool, error)

func (*Connector) EventHandler

func (dc *Connector) EventHandler(evt any)

func (*Connector) FetchValidationData

func (dc *Connector) FetchValidationData(ctx context.Context) ([]byte, error)

func (*Connector) FetchValidationVersions

func (dc *Connector) FetchValidationVersions(ctx context.Context) (*ids.Versions, error)

func (*Connector) FinishAuth

func (dc *Connector) FinishAuth(ctx context.Context, response *ids.AuthResponse) error

func (*Connector) HasAnyAuthCerts

func (dc *Connector) HasAnyAuthCerts() bool

func (*Connector) HasValidAuthCerts

func (dc *Connector) HasValidAuthCerts() bool

func (*Connector) HasValidIDCerts

func (dc *Connector) HasValidIDCerts() bool

func (*Connector) IDSReregisterLoop

func (dc *Connector) IDSReregisterLoop(ctx context.Context)

func (*Connector) Login

func (dc *Connector) Login(ctx context.Context, username string, password string, code string) error

func (*Connector) Logout

func (dc *Connector) Logout(ctx context.Context) error

func (*Connector) NextReregisterCheck

func (dc *Connector) NextReregisterCheck() time.Time

func (*Connector) RegisterIDS

func (dc *Connector) RegisterIDS(ctx context.Context, forceRegister bool) error

func (*Connector) RerouteAndReregister

func (dc *Connector) RerouteAndReregister(ctx context.Context, missingHandles []uri.ParsedURI) error

func (*Connector) ResolveIdentifiers

func (dc *Connector) ResolveIdentifiers(ctx context.Context, force bool, handle *uri.ParsedURI, identifiers ...string) (found, notFound []uri.ParsedURI, err error)

func (*Connector) Run

func (dc *Connector) Run(log zerolog.Logger, onConnect func(), onRegister func())

func (*Connector) RunWithoutConn

func (dc *Connector) RunWithoutConn(ctx context.Context) error

func (*Connector) SendDelivered

func (dc *Connector) SendDelivered(ctx context.Context, input *apns.SendMessagePayload, sessionToken []byte) error

func (*Connector) SendEdit

func (dc *Connector) SendEdit(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID string, messageUUID uuid.UUID, part int, xhtml string) (*SendResponse, error)

func (*Connector) SendMarkUnread

func (dc *Connector) SendMarkUnread(ctx context.Context, sendFromHandle uri.ParsedURI, messageGUID uuid.UUID) error

func (*Connector) SendMessage

func (dc *Connector) SendMessage(ctx context.Context, sendFromHandle uri.ParsedURI, msg *IMessage, id uuid.UUID) (*SendResponse, error)

func (*Connector) SendReadReceipt

func (dc *Connector) SendReadReceipt(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, readUpTo uuid.UUID, service imessage.Service) error

func (*Connector) SendSMS

func (dc *Connector) SendSMS(ctx context.Context, msg *ReflectedSMS) (*SendResponse, error)

func (*Connector) SendTypingNotification

func (dc *Connector) SendTypingNotification(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID string, typing bool) (*SendResponse, error)

func (*Connector) SendUnsend

func (dc *Connector) SendUnsend(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID string, messageUUID uuid.UUID, partIndex int) (*SendResponse, error)

func (*Connector) Stop

func (dc *Connector) Stop(ctx context.Context)

func (*Connector) TryResolveOwnHandle

func (dc *Connector) TryResolveOwnHandle(ctx context.Context, force bool) (bool, error)

func (*Connector) UpdateChatAvatar

func (dc *Connector) UpdateChatAvatar(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID, groupName string, propertiesVersion int, avatar []byte) (string, error)

func (*Connector) UpdateChatName

func (dc *Connector) UpdateChatName(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID, newName string) (*SendResponse, error)

func (*Connector) UpdateParticipants

func (dc *Connector) UpdateParticipants(ctx context.Context, sendFromHandle uri.ParsedURI, participants []uri.ParsedURI, groupID string, newParticipants []uri.ParsedURI) (*SendResponse, error)

type DeleteSync

type DeleteSync struct {
	IsPermanentDelete     bool             `plist:"isPermanentDelete,omitempty"`
	RecoverableDeleteDate time.Time        `plist:"recoverableDeleteDate,omitempty"`
	Message               []plistuuid.UUID `plist:"message,omitempty"`
	Chat                  []DeletedChat    `plist:"chat,omitempty"`

	PermanentChatMeta []DeletedChat `plist:"permanentDeleteChatMetadataArray,omitempty"`

	KeepMessages *KeepMessagesConfig `plist:"KeepMessages,omitempty"`
}

type DeletedChat

type DeletedChat struct {
	GroupID plistuuid.UUID `plist:"groupID"`
	GUID    string         `plist:"guid"` // This is a legacy style iMessage;-; identifier

	WasReportedAsJunk bool `plist:"wasReportedAsJunk,omitempty"`
}

type EditType

type EditType int
const (
	EditTypeEdit   EditType = 1
	EditTypeUnsend EditType = 2
)

func (EditType) String

func (et EditType) String() string

type EffectID

type EffectID string
const (
	EffectEcho          EffectID = "com.apple.messages.effect.CKEchoEffect"
	EffectSpotlight     EffectID = "com.apple.messages.effect.CKSpotlightEffect"
	EffectBalloons      EffectID = "com.apple.messages.effect.CKHappyBirthdayEffect"
	EffectConfetti      EffectID = "com.apple.messages.effect.CKConfettiEffect"
	EffectLove          EffectID = "com.apple.messages.effect.CKHeartEffect"
	EffectLasers        EffectID = "com.apple.messages.effect.CKLasersEffect"
	EffectFireworks     EffectID = "com.apple.messages.effect.CKFireworksEffect"
	EffectCelebration   EffectID = "com.apple.messages.effect.CKSparklesEffect"
	EffectShootingStars EffectID = "com.apple.messages.effect.CKShootingStarEffect"
)

Screen effects

const (
	EffectSlam         EffectID = "com.apple.MobileSMS.expressivesend.impact"
	EffectLoud         EffectID = "com.apple.MobileSMS.expressivesend.loud"
	EffectGentle       EffectID = "com.apple.MobileSMS.expressivesend.gentle"
	EffectInvisibleInk EffectID = "com.apple.MobileSMS.expressivesend.invisibleink"
)

Bubble effects

func (EffectID) IsValid

func (ei EffectID) IsValid() bool

type GroupMetaChangeType

type GroupMetaChangeType string
const (
	GroupMetaChangeName         GroupMetaChangeType = "n"
	GroupMetaChangeAvatar       GroupMetaChangeType = "v"
	GroupMetaChangeParticipants GroupMetaChangeType = "p"
	GroupMetaChangeVR           GroupMetaChangeType = "vr" // ???
)

type HandlesUpdated

type HandlesUpdated struct {
	OldHandles []uri.ParsedURI
	NewHandles []uri.ParsedURI
}

type IDSActuallyReregistered

type IDSActuallyReregistered struct{}

type IDSRegisterFail

type IDSRegisterFail struct {
	Error error
}

type IDSRegisterSuccess

type IDSRegisterSuccess struct{}

type IMFileTransfer

type IMFileTransfer struct {
	IMFileTransferCreatedDate float64 `plist:"IMFileTransferCreatedDate"`
	IMFileTransferFilenameKey string  `plist:"IMFileTransferFilenameKey"`
	// at_0_GUID
	IMFileTransferGUID             string                         `plist:"IMFileTransferGUID"`
	IMFileTransferLocalUserInfoKey IMFileTransferLocalUserInfoKey `plist:"IMFileTransferLocalUserInfoKey"`
	IMFileTransferMessageGUID      *plistuuid.UUID                `plist:"IMFileTransferMessageGUID"`
}

type IMFileTransferLocalUserInfoKey

type IMFileTransferLocalUserInfoKey struct {
	DecryptionKey    string `plist:"decryption-key"`
	FileSize         string `plist:"file-size"`
	MMCSOwner        string `plist:"mmcs-owner"`
	MMCSSignatureHex string `plist:"mmcs-signature-hex"`
	MMCSURL          string `plist:"mmcs-url"`
}

type IMessage

type IMessage struct {
	AttachmentCount int `plist:"-" json:"-"`

	Subject      string          `plist:"s,omitempty" json:",omitempty"`
	Text         string          `plist:"t"`
	XML          string          `plist:"x,omitempty" json:",omitempty"`
	Participants []uri.ParsedURI `plist:"p"`

	// Message ID, this should be the same as MessageUUID in the apns.SendMessagePayload
	// (but that one is encoded as a big endian integer)
	PreviousMessageID *plistuuid.UUID `plist:"r,omitempty"`

	GroupID  string   `plist:"gid,omitempty"`
	EffectID EffectID `plist:"iid,omitempty" json:",omitempty"`

	// This seems to be a base64-encoded gzipped NSKeyedArchiver plist (related to attachments?)
	ATI []byte `plist:"ati,omitempty" json:",omitempty"`

	// Tapback type as per imessage/tapback.go
	TapbackType int `plist:"amt,omitempty" json:",omitempty"`
	// This is formatted as p:0/UUID where 0 is the same as amrlc and UUID is the message ID (tapbacks don't have their own ids)
	TapbackTargetFullID     string `plist:"amk,omitempty" json:",omitempty"`
	TapbackTargetStartIndex *int   `plist:"amrlc,omitempty" json:",omitempty"`
	TapbackTargetLength     int    `plist:"amrln,omitempty" json:",omitempty"`
	// base64-encoded plist that contains "ams" with the original message that was tapbacked? (also amc: 1)
	// but sometimes not base64-encoded, maybe when sending from mac?
	TapbackMessageSummaryInfo []byte `plist:"msi,omitempty" json:",omitempty"`

	// See ParsedThreadRoot for the format
	ThreadRoot string `plist:"tg,omitempty" json:",omitempty"`

	GroupName string `plist:"n,omitempty" json:",omitempty"`

	BalloonID      BalloonID                  `plist:"bid,omitempty" json:",omitempty"`
	BalloonPayload []byte                     `plist:"bp,omitempty" json:",omitempty"`
	BalloonInfo    *BaloonPayloadDownloadInfo `plist:"bpdi,omitempty" json:",omitempty"`

	// Inline Attachments
	InlineAttachment0 []byte `plist:"ia-0,omitempty" json:",omitempty"`

	GroupVersion      string `plist:"gv,omitempty" json:",omitempty"` // always "8"?
	PropertiesVersion int    `plist:"pv" json:",omitempty"`           // 0 for DM, 1 for group?
	ProtocolVersion   string `plist:"v,omitempty" json:",omitempty"`  // always "1"?
	Arc               string `plist:"arc,omitempty" json:",omitempty"`
	Are               string `plist:"are,omitempty" json:",omitempty"`

	IsAudioMessage      bool `plist:"a,omitempty" json:",omitempty"`
	AudioMessageExpires bool `plist:"e,omitempty" json:",omitempty"`

	GPRU *plisttime.UnixNano `plist:"gpru,omitempty" json:",omitempty"`
}

func (*IMessage) GetInlineAttachment

func (im *IMessage) GetInlineAttachment(name string) []byte

type IMessageEdit

type IMessageEdit struct {
	EditMessageID   plistuuid.UUID `plist:"emg"`
	EditXML         string         `plist:"epb,omitempty"`
	EditPartIndex   int            `plist:"epi"`          // Part being edited or unsent. Can be -1 if unsending the subject part.
	EditType        EditType       `plist:"et"`           // 1 for edit, 2 for unsend?
	RS              bool           `plist:"rs,omitempty"` // true for unsend, omit for edit?
	ProtocolVersion string         `plist:"v"`            // "1"
}

type IMessageEditDetails

type IMessageEditDetails struct {
	XMLName xml.Name               `xml:"html"`
	Edits   []imessage.MessagePart `xml:"body>span"`
}

IMessageEditDetails should only be used for encoding edit XML.

type IMessageGroupMetaChange

type IMessageGroupMetaChange struct {
	GroupID           string              `plist:"gid,omitempty"`
	GroupVersion      string              `plist:"gv,omitempty" json:",omitempty"`
	PropertiesVersion int                 `plist:"pv" json:",omitempty"` // 1 for pictures, not there for group names?
	Type              GroupMetaChangeType `plist:"type,omitempty" json:",omitempty"`

	NewGroupAvatar *IMFileTransfer `plist:"tv,omitempty" json:",omitempty"`

	Participants       []string `plist:"sp"`
	TargetParticipants []string `plist:"tp,omitempty" json:",omitempty"`

	GroupName    string `plist:"n,omitempty" json:",omitempty"`
	NewGroupName string `plist:"nn,omitempty" json:",omitempty"`
	OldGroupName string `plist:"old,omitempty" json:",omitempty"`
}

type IncomingMMS

type IncomingMMS struct {
	EncryptionKey []byte `plist:"eK"`
	OFS           int    `plist:"oFS"`
	ObjectID      string `plist:"oID"`
	DownloadURL   string `plist:"rUS"`
	Signature     []byte `plist:"sg"`
}

type InvalidSignature

type InvalidSignature struct {
	Payload *apns.SendMessagePayload
	Error   error
}

type KeepMessagesConfig

type KeepMessagesConfig struct {
	ID              int  `plist:"ID"`
	Days            int  `plist:"days"`
	ResetPreference bool `plist:"resetPreference"`
}

type MarkUnread

type MarkUnread struct {
	MessageID plistuuid.UUID `plist:"uG"`
}

type MessageDelivered

type MessageDelivered struct {
	ID uuid.UUID
	To map[uri.ParsedURI][]pushToken
}

type MessageObject

type MessageObject struct {
	BreadcrumbText string `xml:"breadcrumbText,attr"`
}

type NACServFail

type NACServFail IDSRegisterFail

type ReflectedSMS

type ReflectedSMS struct {
	ChatStyle  string           `plist:"chat-style"` // "im" for DMs and "chat" for group chats?
	Recipients []SMSRecipient   `plist:"re"`
	Data       ReflectedSMSData `plist:"mD"`

	FR bool `plist:"fR,omitempty"` // true
	IC int  `plist:"ic"`           // 0
}

func (*ReflectedSMS) GetInlineAttachment

func (im *ReflectedSMS) GetInlineAttachment(name string) []byte

type ReflectedSMSData

type ReflectedSMSData struct {
	GUID plistuuid.UUID `plist:"guid"`
	// International phone number
	Handle              string          `plist:"handle"`
	PlainBody           string          `plist:"plain-body"`
	Subject             string          `plist:"subject,omitempty"`
	XHTML               string          `plist:"xhtml,omitempty"`
	PreviousMessageGUID *plistuuid.UUID `plist:"replyToGUID,omitempty"`
	Service             string          `plist:"service"` // "SMS"
	SV                  string          `plist:"sV"`      // "1"
}

type RefreshCredentialsRequired

type RefreshCredentialsRequired struct {
	UserID string
	Old    bool
}

type SMS

type SMS struct {
	Receiver    string         `plist:"co"`
	Sender      string         `plist:"h"`
	MessageUUID plistuuid.UUID `plist:"g"`
	Timestamp   time.Time      `plist:"w"`
	Content     []SMSChunk     `plist:"k"`

	// Only for MMS
	Subject     string   `plist:"a"`
	ContentType string   `plist:"b"`
	Recipients  []string `plist:"re"` // list of recipient phone numbers for MMS

	SC  int            `plist:"_sc"`  // 0
	SSC int            `plist:"_ssc"` // 0
	CS  plistuuid.UUID `plist:"cs"`   // not present?
	IC  int            `plist:"ic"`   // not present?
	L   int            `plist:"l"`    // 0
	M   string         `plist:"m"`    // "sms" or "mms"
	N   string         `plist:"n"`    // always "244"?
	R   bool           `plist:"r"`    // true
	SV  string         `plist:"sV"`   // 1
}

type SMSChunk

type SMSChunk struct {
	Data []byte `plist:"data"`
	Type string `plist:"type"`

	// Only for MMS
	ContentLocation string `plist:"content-location,omitempty"`
	// Same as ContentLocation, but wrapped in < >?
	ContentID string `plist:"content-id,omitempty"`
}

type SMSForwardingEnableRequestCode

type SMSForwardingEnableRequestCode struct {
	Code int `plist:"ak"`
}

type SMSForwardingToggled

type SMSForwardingToggled struct {
	AR bool `plist:"ar"`
	WC bool `plist:"wc"`

	UE bool `plist:"ue"`

	UD bool            `plist:"ud"`
	G  *plistuuid.UUID `plist:"g"`
}

type SMSOutgoingStatus

type SMSOutgoingStatus struct {
	GUID plistuuid.UUID `plist:"g"`
}

type SMSRecipient

type SMSRecipient struct {
	IntlPhone string `plist:"id"`
	// Local phone number, relative to own country code
	// If the phone is not in the same country, this is the same as IntlPhone
	LocalPhone string `plist:"uID,omitempty"`
	// Own country code
	CountryCode string `plist:"n,omitempty"`
}

type SendMessageError

type SendMessageError struct {
	DestinationTokenCount int
	DestinationUserCount  int
	SuccessCount          int
	MissingCount          int
	ErrorCount            int

	StatusByUser     UserErrorCountsMap
	CountByErrorType map[types.IDSStatus]int
	UniqueErrorTypes []types.IDSStatus
	MissingUsers     []uri.ParsedURI
}

func (*SendMessageError) Error

func (sme *SendMessageError) Error() string

type SendResponse

type SendResponse struct {
	ID      uuid.UUID        `json:"id"`
	Service imessage.Service `json:"service"`
	Time    time.Time        `json:"time"`
}

type SettingValue

type SettingValue struct {
	ReadReceipts       bool `plist:"gR,omitempty" json:",omitempty"` // true -> send read receipts, false -> don't
	ReadReceiptVersion int  `plist:"gV,omitempty" json:",omitempty"` // number of times the setting has been toggled

	ChatReadReceipts       bool `plist:"eR,omitempty" json:",omitempty"`
	ChatReadReceiptVersion int  `plist:"vR,omitempty" json:",omitempty"`

	ProfileSharedVersion   int      `plist:"nBWV,omitempty" json:",omitempty"`
	ProfileSharedWhitelist []string `plist:"nWL,omitempty" json:",omitempty"`
	ProfileSharedBlacklist []string `plist:"nBL,omitempty" json:",omitempty"` // uncertain
}

type Settings

type Settings struct {
	SettingID SettingsCode `plist:"gC"`
	Value     SettingValue `plist:"pID"`

	// When toggling per-chat settings, like read receipts, this is the chat GUID
	ChatGUID string `plist:"cID"` // This is a legacy style iMessage;-; identifier
}

type SettingsCode

type SettingsCode int
const (
	SettingsCodeReadReceiptsEnabled    SettingsCode = 60001
	SettingsCodeProfileSharedWithUsers SettingsCode = 70000
)

type UndeleteSync

type UndeleteSync struct {
	Chat []DeletedChat `plist:"recoverChatMetadataArray,omitempty"`
}

type UserErrorCounts

type UserErrorCounts struct {
	Missing []pushToken
	Failed  map[pushToken]types.IDSStatus
	Success []pushToken
	Total   int
}

func (*UserErrorCounts) MarshalZerologObject

func (uec *UserErrorCounts) MarshalZerologObject(evt *zerolog.Event)

type UserErrorCountsMap

type UserErrorCountsMap map[uri.ParsedURI]*UserErrorCounts

func (UserErrorCountsMap) MarshalZerologObject

func (uecm UserErrorCountsMap) MarshalZerologObject(evt *zerolog.Event)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL