Add metrics for mobile versions snapshots (#28191)

* Add metrics for mobile versions snapshots

* Add notifications disabled and fix lint

* Address feedback

* Verify all references to JobTypeActiveUsers

* Fix typos

* Improve platform values

* Add test and MySQL support
Этот коммит содержится в:
Daniel Espino García
2024-09-24 12:02:19 +02:00
коммит произвёл GitHub
родитель d45a54a8e9
Коммит 040838b056
17 изменённых файлов: 489 добавлений и 0 удалений

Просмотреть файл

@@ -175,6 +175,7 @@ func (a *App) SessionHasPermissionToReadJob(session model.Session, jobType strin
model.JobTypeExportProcess, model.JobTypeExportProcess,
model.JobTypeExportDelete, model.JobTypeExportDelete,
model.JobTypeCloud, model.JobTypeCloud,
model.JobTypeMobileSessionMetadata,
model.JobTypeExtractContent: model.JobTypeExtractContent:
return a.SessionHasPermissionTo(session, model.PermissionReadJobs), model.PermissionReadJobs return a.SessionHasPermissionTo(session, model.PermissionReadJobs), model.PermissionReadJobs
} }

Просмотреть файл

@@ -55,6 +55,7 @@ import (
"github.com/mattermost/mattermost/server/v8/channels/jobs/last_accessible_file" "github.com/mattermost/mattermost/server/v8/channels/jobs/last_accessible_file"
"github.com/mattermost/mattermost/server/v8/channels/jobs/last_accessible_post" "github.com/mattermost/mattermost/server/v8/channels/jobs/last_accessible_post"
"github.com/mattermost/mattermost/server/v8/channels/jobs/migrations" "github.com/mattermost/mattermost/server/v8/channels/jobs/migrations"
"github.com/mattermost/mattermost/server/v8/channels/jobs/mobile_session_metadata"
"github.com/mattermost/mattermost/server/v8/channels/jobs/notify_admin" "github.com/mattermost/mattermost/server/v8/channels/jobs/notify_admin"
"github.com/mattermost/mattermost/server/v8/channels/jobs/plugins" "github.com/mattermost/mattermost/server/v8/channels/jobs/plugins"
"github.com/mattermost/mattermost/server/v8/channels/jobs/post_persistent_notifications" "github.com/mattermost/mattermost/server/v8/channels/jobs/post_persistent_notifications"
@@ -1565,6 +1566,12 @@ func (s *Server) initJobs() {
active_users.MakeScheduler(s.Jobs), active_users.MakeScheduler(s.Jobs),
) )
s.Jobs.RegisterJobType(
model.JobTypeMobileSessionMetadata,
mobile_session_metadata.MakeWorker(s.Jobs, s.Store(), func() einterfaces.MetricsInterface { return s.GetMetrics() }),
mobile_session_metadata.MakeScheduler(s.Jobs),
)
s.Jobs.RegisterJobType( s.Jobs.RegisterJobType(
model.JobTypeResendInvitationEmail, model.JobTypeResendInvitationEmail,
resend_invitation_email.MakeWorker(s.Jobs, New(ServerConnector(s.Channels())), s.Store(), s.telemetryService), resend_invitation_email.MakeWorker(s.Jobs, New(ServerConnector(s.Channels())), s.Store(), s.telemetryService),

Просмотреть файл

@@ -0,0 +1,20 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package mobile_session_metadata
import (
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/channels/jobs"
)
const schedFreq = 24 * time.Hour
func MakeScheduler(jobServer *jobs.JobServer) *jobs.PeriodicScheduler {
isEnabled := func(cfg *model.Config) bool {
return *cfg.MetricsSettings.EnableClientMetrics
}
return jobs.NewPeriodicScheduler(jobServer, model.JobTypeMobileSessionMetadata, schedFreq, isEnabled)
}

Просмотреть файл

@@ -0,0 +1,42 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package mobile_session_metadata
import (
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/v8/channels/jobs"
"github.com/mattermost/mattermost/server/v8/channels/store"
"github.com/mattermost/mattermost/server/v8/einterfaces"
)
func MakeWorker(jobServer *jobs.JobServer, store store.Store, getMetrics func() einterfaces.MetricsInterface) *jobs.SimpleWorker {
const workerName = "MobileSessionMetadata"
isEnabled := func(cfg *model.Config) bool {
return *cfg.MetricsSettings.EnableClientMetrics
}
execute := func(logger mlog.LoggerIFace, job *model.Job) error {
defer jobServer.HandleJobPanic(logger, job)
metrics := getMetrics()
if metrics == nil {
return nil
}
versions, err := store.Session().GetMobileSessionMetadata()
if err != nil {
return err
}
metrics.ClearMobileClientSessionMetadata()
for _, v := range versions {
metrics.ObserveMobileClientSessionMetadata(v.Version, v.Platform, v.Count, v.NotificationDisabled)
}
return nil
}
worker := jobs.NewSimpleWorker(workerName, jobServer, execute, isEnabled)
return worker
}

Просмотреть файл

@@ -8710,6 +8710,24 @@ func (s *OpenTracingLayerSessionStore) GetLRUSessions(c request.CTX, userID stri
return result, err return result, err
} }
func (s *OpenTracingLayerSessionStore) GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.GetMobileSessionMetadata")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.SessionStore.GetMobileSessionMetadata()
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) { func (s *OpenTracingLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.GetSessions") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.GetSessions")

Просмотреть файл

@@ -9938,6 +9938,27 @@ func (s *RetryLayerSessionStore) GetLRUSessions(c request.CTX, userID string, li
} }
func (s *RetryLayerSessionStore) GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error) {
tries := 0
for {
result, err := s.SessionStore.GetMobileSessionMetadata()
if err == nil {
return result, nil
}
if !isRepeatableError(err) {
return result, err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return result, err
}
timepkg.Sleep(100 * timepkg.Millisecond)
}
}
func (s *RetryLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) { func (s *RetryLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) {
tries := 0 tries := 0

Просмотреть файл

@@ -164,6 +164,38 @@ func (me SqlSessionStore) GetSessionsWithActiveDeviceIds(userId string) ([]*mode
return sessions, nil return sessions, nil
} }
func (me SqlSessionStore) GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error) {
versionProp := model.SessionPropMobileVersion
notificationDisabledProp := model.SessionPropDeviceNotificationDisabled
platformQuery := "NULLIF(SPLIT_PART(deviceid, ':', 1), '')"
if me.DriverName() == model.DatabaseDriverMysql {
versionProp = "$." + versionProp
notificationDisabledProp = "$." + notificationDisabledProp
platformQuery = "NULLIF(SUBSTRING_INDEX(deviceid, ':', 1), deviceid)"
}
query, args, err := me.getQueryBuilder().
Select(fmt.Sprintf(
"COUNT(userid) AS Count, COALESCE(%s,'N/A') AS Platform, COALESCE(props->>'%s','N/A') AS Version, COALESCE(props->>'%s','false') as NotificationDisabled",
platformQuery,
versionProp,
notificationDisabledProp,
)).
From("Sessions").
GroupBy("Platform", "Version", "NotificationDisabled").
ToSql()
if err != nil {
return nil, errors.Wrap(err, "sessions_tosql")
}
versions := []*model.MobileSessionMetadata{}
err = me.GetReplicaX().Select(&versions, query, args...)
if err != nil {
return nil, errors.Wrap(err, "failed get mobile session metadata")
}
return versions, nil
}
func (me SqlSessionStore) GetSessionsExpired(thresholdMillis int64, mobileOnly bool, unnotifiedOnly bool) ([]*model.Session, error) { func (me SqlSessionStore) GetSessionsExpired(thresholdMillis int64, mobileOnly bool, unnotifiedOnly bool) ([]*model.Session, error) {
now := model.GetMillis() now := model.GetMillis()
builder := me.getQueryBuilder(). builder := me.getQueryBuilder().

Просмотреть файл

@@ -503,6 +503,7 @@ type SessionStore interface {
Save(c request.CTX, session *model.Session) (*model.Session, error) Save(c request.CTX, session *model.Session) (*model.Session, error)
GetSessions(c request.CTX, userID string) ([]*model.Session, error) GetSessions(c request.CTX, userID string) ([]*model.Session, error)
GetLRUSessions(c request.CTX, userID string, limit uint64, offset uint64) ([]*model.Session, error) GetLRUSessions(c request.CTX, userID string, limit uint64, offset uint64) ([]*model.Session, error)
GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error)
GetSessionsWithActiveDeviceIds(userID string) ([]*model.Session, error) GetSessionsWithActiveDeviceIds(userID string) ([]*model.Session, error)
GetSessionsExpired(thresholdMillis int64, mobileOnly bool, unnotifiedOnly bool) ([]*model.Session, error) GetSessionsExpired(thresholdMillis int64, mobileOnly bool, unnotifiedOnly bool) ([]*model.Session, error)
UpdateExpiredNotify(sessionid string, notified bool) error UpdateExpiredNotify(sessionid string, notified bool) error

Просмотреть файл

@@ -121,6 +121,36 @@ func (_m *SessionStore) GetLRUSessions(c request.CTX, userID string, limit uint6
return r0, r1 return r0, r1
} }
// GetMobileSessionMetadata provides a mock function with given fields:
func (_m *SessionStore) GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error) {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for GetMobileSessionMetadata")
}
var r0 []*model.MobileSessionMetadata
var r1 error
if rf, ok := ret.Get(0).(func() ([]*model.MobileSessionMetadata, error)); ok {
return rf()
}
if rf, ok := ret.Get(0).(func() []*model.MobileSessionMetadata); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.MobileSessionMetadata)
}
}
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetSessions provides a mock function with given fields: c, userID // GetSessions provides a mock function with given fields: c, userID
func (_m *SessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) { func (_m *SessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) {
ret := _m.Called(c, userID) ret := _m.Called(c, userID)

Просмотреть файл

@@ -38,6 +38,7 @@ func TestSessionStore(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("GetSessionsExpired", func(t *testing.T) { testGetSessionsExpired(t, rctx, ss) }) t.Run("GetSessionsExpired", func(t *testing.T) { testGetSessionsExpired(t, rctx, ss) })
t.Run("UpdateExpiredNotify", func(t *testing.T) { testUpdateExpiredNotify(t, rctx, ss) }) t.Run("UpdateExpiredNotify", func(t *testing.T) { testUpdateExpiredNotify(t, rctx, ss) })
t.Run("GetLRUSessions", func(t *testing.T) { testGetLRUSessions(t, rctx, ss) }) t.Run("GetLRUSessions", func(t *testing.T) { testGetLRUSessions(t, rctx, ss) })
t.Run("GetMobileSessionMetadata", func(t *testing.T) { testGetMobileSessionMetadata(t, rctx, ss) })
} }
func testSessionStoreSave(t *testing.T, rctx request.CTX, ss store.Store) { func testSessionStoreSave(t *testing.T, rctx request.CTX, ss store.Store) {
@@ -456,3 +457,84 @@ func testGetLRUSessions(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, s2.Id, sessions[1].Id) require.Equal(t, s2.Id, sessions[1].Id)
require.Equal(t, s1.Id, sessions[2].Id) require.Equal(t, s1.Id, sessions[2].Id)
} }
func testGetMobileSessionMetadata(t *testing.T, rctx request.CTX, ss store.Store) {
userId1 := model.NewId()
userId2 := model.NewId()
userId3 := model.NewId()
userId4 := model.NewId()
userId5 := model.NewId()
// Clear existing sessions.
err := ss.Session().RemoveAllSessions()
require.NoError(t, err)
s1 := &model.Session{}
s1.UserId = userId1
s1.ExpiresAt = model.GetMillis() + 10000
_, err = ss.Session().Save(rctx, s1)
require.NoError(t, err)
s2 := &model.Session{}
s2.UserId = userId2
s2.DeviceId = "android:" + model.NewId()
s2.ExpiresAt = model.GetMillis() + 10000
s2.Props = model.StringMap{
model.SessionPropDeviceNotificationDisabled: "false",
model.SessionPropMobileVersion: "1.2.3",
}
_, err = ss.Session().Save(rctx, s2)
require.NoError(t, err)
s3 := &model.Session{}
s3.UserId = userId3
s3.DeviceId = "ios:" + model.NewId()
s3.ExpiresAt = model.GetMillis() + 10000
s3.Props = model.StringMap{
model.SessionPropDeviceNotificationDisabled: "true",
model.SessionPropMobileVersion: "1.2.3",
}
_, err = ss.Session().Save(rctx, s3)
require.NoError(t, err)
s4 := &model.Session{}
s4.UserId = userId4
s4.DeviceId = "android:" + model.NewId()
s4.ExpiresAt = model.GetMillis() + 10000
s4.Props = model.StringMap{
model.SessionPropDeviceNotificationDisabled: "true",
model.SessionPropMobileVersion: "3.2.1",
}
_, err = ss.Session().Save(rctx, s4)
require.NoError(t, err)
s5 := &model.Session{}
s5.UserId = userId5
s5.DeviceId = "android:" + model.NewId()
s5.ExpiresAt = model.GetMillis() + 10000
s5.Props = model.StringMap{
model.SessionPropDeviceNotificationDisabled: "true",
model.SessionPropMobileVersion: "3.2.1",
}
_, err = ss.Session().Save(rctx, s5)
require.NoError(t, err)
metadata, err := ss.Session().GetMobileSessionMetadata()
require.NoError(t, err)
require.Len(t, metadata, 4)
found := false
for _, d := range metadata {
if d.NotificationDisabled == "true" &&
d.Platform == "android" &&
d.Version == "3.2.1" {
found = true
require.Equal(t, float64(2), d.Count)
}
}
require.True(t, found)
}

Просмотреть файл

@@ -7849,6 +7849,22 @@ func (s *TimerLayerSessionStore) GetLRUSessions(c request.CTX, userID string, li
return result, err return result, err
} }
func (s *TimerLayerSessionStore) GetMobileSessionMetadata() ([]*model.MobileSessionMetadata, error) {
start := time.Now()
result, err := s.SessionStore.GetMobileSessionMetadata()
elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("SessionStore.GetMobileSessionMetadata", success, elapsed)
}
return result, err
}
func (s *TimerLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) { func (s *TimerLayerSessionStore) GetSessions(c request.CTX, userID string) ([]*model.Session, error) {
start := time.Now() start := time.Now()

Просмотреть файл

@@ -118,4 +118,6 @@ type MetricsInterface interface {
ObserveMobileClientLoadDuration(platform string, elapsed float64) ObserveMobileClientLoadDuration(platform string, elapsed float64)
ObserveMobileClientChannelSwitchDuration(platform string, elapsed float64) ObserveMobileClientChannelSwitchDuration(platform string, elapsed float64)
ObserveMobileClientTeamSwitchDuration(platform string, elapsed float64) ObserveMobileClientTeamSwitchDuration(platform string, elapsed float64)
ClearMobileClientSessionMetadata()
ObserveMobileClientSessionMetadata(version string, platform string, value float64, notificationDisabled string)
} }

Просмотреть файл

@@ -28,6 +28,11 @@ func (_m *MetricsInterface) AddMemCacheMissCounter(cacheName string, amount floa
_m.Called(cacheName, amount) _m.Called(cacheName, amount)
} }
// ClearMobileClientSessionMetadata provides a mock function with given fields:
func (_m *MetricsInterface) ClearMobileClientSessionMetadata() {
_m.Called()
}
// DecrementHTTPWebSockets provides a mock function with given fields: originClient // DecrementHTTPWebSockets provides a mock function with given fields: originClient
func (_m *MetricsInterface) DecrementHTTPWebSockets(originClient string) { func (_m *MetricsInterface) DecrementHTTPWebSockets(originClient string) {
_m.Called(originClient) _m.Called(originClient)
@@ -373,6 +378,11 @@ func (_m *MetricsInterface) ObserveMobileClientLoadDuration(platform string, ela
_m.Called(platform, elapsed) _m.Called(platform, elapsed)
} }
// ObserveMobileClientSessionMetadata provides a mock function with given fields: version, platform, value, notificationDisabled
func (_m *MetricsInterface) ObserveMobileClientSessionMetadata(version string, platform string, value float64, notificationDisabled string) {
_m.Called(version, platform, value, notificationDisabled)
}
// ObserveMobileClientTeamSwitchDuration provides a mock function with given fields: platform, elapsed // ObserveMobileClientTeamSwitchDuration provides a mock function with given fields: platform, elapsed
func (_m *MetricsInterface) ObserveMobileClientTeamSwitchDuration(platform string, elapsed float64) { func (_m *MetricsInterface) ObserveMobileClientTeamSwitchDuration(platform string, elapsed float64) {
_m.Called(platform, elapsed) _m.Called(platform, elapsed)

Просмотреть файл

@@ -215,6 +215,7 @@ type MetricsInterfaceImpl struct {
MobileClientLoadDuration *prometheus.HistogramVec MobileClientLoadDuration *prometheus.HistogramVec
MobileClientChannelSwitchDuration *prometheus.HistogramVec MobileClientChannelSwitchDuration *prometheus.HistogramVec
MobileClientTeamSwitchDuration *prometheus.HistogramVec MobileClientTeamSwitchDuration *prometheus.HistogramVec
MobileClientSessionMetadataGauge *prometheus.GaugeVec
} }
func init() { func init() {
@@ -1335,6 +1336,17 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
) )
m.Registry.MustRegister(m.MobileClientTeamSwitchDuration) m.Registry.MustRegister(m.MobileClientTeamSwitchDuration)
m.MobileClientSessionMetadataGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: MetricsNamespace,
Subsystem: MetricsSubsystemClientsMobileApp,
Name: "mobile_session_metadata",
Help: "The number of mobile sessions in each version, platform and whether they have the notifications disabled",
},
[]string{"version", "platform", "notifications_disabled"},
)
m.Registry.MustRegister(m.MobileClientSessionMetadataGauge)
return m return m
} }
@@ -1850,6 +1862,14 @@ func (mi *MetricsInterfaceImpl) ObserveMobileClientTeamSwitchDuration(platform s
mi.MobileClientTeamSwitchDuration.With(prometheus.Labels{"platform": platform}).Observe(elapsed) mi.MobileClientTeamSwitchDuration.With(prometheus.Labels{"platform": platform}).Observe(elapsed)
} }
func (mi *MetricsInterfaceImpl) ObserveMobileClientSessionMetadata(version string, platform string, value float64, notificationDisabled string) {
mi.MobileClientSessionMetadataGauge.With(prometheus.Labels{"version": version, "platform": platform, "notifications_disabled": notificationDisabled}).Set(value)
}
func (mi *MetricsInterfaceImpl) ClearMobileClientSessionMetadata() {
mi.MobileClientSessionMetadataGauge.Reset()
}
func extractDBCluster(driver, connectionString string) (string, error) { func extractDBCluster(driver, connectionString string) (string, error) {
host, err := extractHost(driver, connectionString) host, err := extractHost(driver, connectionString)
if err != nil { if err != nil {

Просмотреть файл

@@ -40,6 +40,7 @@ const (
JobTypeDeleteOrphanDraftsMigration = "delete_orphan_drafts_migration" JobTypeDeleteOrphanDraftsMigration = "delete_orphan_drafts_migration"
JobTypeExportUsersToCSV = "export_users_to_csv" JobTypeExportUsersToCSV = "export_users_to_csv"
JobTypeDeleteDmsPreferencesMigration = "delete_dms_preferences_migration" JobTypeDeleteDmsPreferencesMigration = "delete_dms_preferences_migration"
JobTypeMobileSessionMetadata = "mobile_session_metadata"
JobStatusPending = "pending" JobStatusPending = "pending"
JobStatusInProgress = "in_progress" JobStatusInProgress = "in_progress"
@@ -72,6 +73,7 @@ var AllJobTypes = [...]string{
JobTypeLastAccessibleFile, JobTypeLastAccessibleFile,
JobTypeCleanupDesktopTokens, JobTypeCleanupDesktopTokens,
JobTypeRefreshPostStats, JobTypeRefreshPostStats,
JobTypeMobileSessionMetadata,
} }
type Job struct { type Job struct {

Просмотреть файл

@@ -39,6 +39,13 @@ const (
//msgp:tuple StringMap //msgp:tuple StringMap
type StringMap map[string]string type StringMap map[string]string
type MobileSessionMetadata struct {
Version string
Platform string
Count float64
NotificationDisabled string
}
// Session contains the user session details. // Session contains the user session details.
// This struct's serializer methods are auto-generated. If a new field is added/removed, // This struct's serializer methods are auto-generated. If a new field is added/removed,
// please run make gen-serialized. // please run make gen-serialized.

Просмотреть файл

@@ -9,6 +9,184 @@ import (
"github.com/tinylib/msgp/msgp" "github.com/tinylib/msgp/msgp"
) )
// DecodeMsg implements msgp.Decodable
func (z *MobileSessionMetadata) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
case "Version":
z.Version, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Version")
return
}
case "Platform":
z.Platform, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Platform")
return
}
case "Count":
z.Count, err = dc.ReadFloat64()
if err != nil {
err = msgp.WrapError(err, "Count")
return
}
case "NotificationDisabled":
z.NotificationDisabled, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "NotificationDisabled")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *MobileSessionMetadata) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 4
// write "Version"
err = en.Append(0x84, 0xa7, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e)
if err != nil {
return
}
err = en.WriteString(z.Version)
if err != nil {
err = msgp.WrapError(err, "Version")
return
}
// write "Platform"
err = en.Append(0xa8, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d)
if err != nil {
return
}
err = en.WriteString(z.Platform)
if err != nil {
err = msgp.WrapError(err, "Platform")
return
}
// write "Count"
err = en.Append(0xa5, 0x43, 0x6f, 0x75, 0x6e, 0x74)
if err != nil {
return
}
err = en.WriteFloat64(z.Count)
if err != nil {
err = msgp.WrapError(err, "Count")
return
}
// write "NotificationDisabled"
err = en.Append(0xb4, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64)
if err != nil {
return
}
err = en.WriteString(z.NotificationDisabled)
if err != nil {
err = msgp.WrapError(err, "NotificationDisabled")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *MobileSessionMetadata) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 4
// string "Version"
o = append(o, 0x84, 0xa7, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e)
o = msgp.AppendString(o, z.Version)
// string "Platform"
o = append(o, 0xa8, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d)
o = msgp.AppendString(o, z.Platform)
// string "Count"
o = append(o, 0xa5, 0x43, 0x6f, 0x75, 0x6e, 0x74)
o = msgp.AppendFloat64(o, z.Count)
// string "NotificationDisabled"
o = append(o, 0xb4, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64)
o = msgp.AppendString(o, z.NotificationDisabled)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MobileSessionMetadata) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
switch msgp.UnsafeString(field) {
case "Version":
z.Version, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Version")
return
}
case "Platform":
z.Platform, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Platform")
return
}
case "Count":
z.Count, bts, err = msgp.ReadFloat64Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "Count")
return
}
case "NotificationDisabled":
z.NotificationDisabled, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "NotificationDisabled")
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *MobileSessionMetadata) Msgsize() (s int) {
s = 1 + 8 + msgp.StringPrefixSize + len(z.Version) + 9 + msgp.StringPrefixSize + len(z.Platform) + 6 + msgp.Float64Size + 21 + msgp.StringPrefixSize + len(z.NotificationDisabled)
return
}
// DecodeMsg implements msgp.Decodable // DecodeMsg implements msgp.Decodable
func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) { func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) {
var zb0001 uint32 var zb0001 uint32