package push_common import ( "context" "encoding/json" "io" "net/http" "strconv" "strings" "git.bit5.ru/backend/errors" ) type PushId uint32 func (id PushId) String() string { return uint32ToString(uint32(id)) } //----------------------------------------------------------------------------- type PushPreview struct { Id PushId `json:"id"` Ctime uint32 `json:"ctime"` Stime uint32 `json:"stime"` Status int `json:"status"` Info string `json:"info,omitempty"` MaxVersion string `json:"maxVersion,omitempty"` Platforms []uint32 `json:"platforms,omitempty"` PlayersIds []uint32 `json:"playersIds,omitempty"` Title string `json:"title"` Message string `json:"message"` Total int `json:"total"` Sent int `json:"sent"` Fails int `json:"fails"` ForTest bool `json:"forTest,omitempty"` } //----------------------------------------------------------------------------- type PushDef struct { MaxVersion string `json:"maxVersion"` Platforms []uint32 `json:"platforms"` PlayersIds []uint32 `json:"playersIds"` Stime uint32 `json:"stime"` TextVariants []*TextVariant `json:"textVariants"` ForTest bool `json:"forTest"` ImageUrl string `json:"imageUrl"` } func (pushDef *PushDef) Validate() error { if len(pushDef.TextVariants) == 0 { return errors.New("No text variants") } return nil } func (pushDef *PushDef) Info() string { var strs []string if len(pushDef.Platforms) > 0 { strs = append(strs, "Platforms: "+sliceUint32ToString(pushDef.Platforms, ",")) } if len(pushDef.MaxVersion) > 0 { strs = append(strs, "Max.ver: "+pushDef.MaxVersion) } if len(pushDef.PlayersIds) > 0 { playersIdsStr := sliceUint32ToString(pushDef.PlayersIds, ",") strs = append(strs, "Plr.ids: "+playersIdsStr) } return strings.Join(strs, "; ") } func sliceUint32ToString(nums []uint32, sep string) string { strs := make([]string, 0, len(nums)) for _, num := range nums { str := strconv.FormatUint(uint64(num), 10) strs = append(strs, str) } return strings.Join(strs, sep) } //----------------------------------------------------------------------------- type IncomingPushInfo struct { Id int `json:"id"` MaxVersion string `json:"maxVersion"` Platforms []uint32 `json:"platforms"` PlayersIds []uint32 `json:"playersIds"` TextVariants []*TextVariant `json:"textVariants"` ImageUrl string `json:"imageUrl"` } //----------------------------------------------------------------------------- type TextVariant struct { Lang int `json:"lang"` Title string `json:"title"` Message string `json:"message"` } func FindTextVariantByLang(textVariants []*TextVariant, lang int) *TextVariant { for _, textVariant := range textVariants { if textVariant.Lang == lang { return textVariant } } return nil } func ReadTextVariantsFromRequest(request *http.Request, textVariants *[]*TextVariant) error { b, err := io.ReadAll(request.Body) if err != nil { return err } if b == nil { return errors.New("Can not read text variants. Request body bytes is nil.") } return json.Unmarshal(b, textVariants) } //----------------------------------------------------------------------------- type PushRequest struct { Title string `json:"title"` Message string `json:"message"` Info string `json:"info"` Label string `json:"label"` //Note: label for firebase Ttl uint32 `json:"ttl"` Jobs []PushJobRequest `json:"jobs"` ImageUrl string `json:"imageUrl"` } func (r *PushRequest) DeviceTokenAmount() uint32 { return jobRequests_deviceTokenAmount(r.Jobs) } func (r *PushRequest) Validate() error { return validateJobsRequests(r.Jobs) } func (r *PushRequest) FindJobByLang(lang int) *PushJobRequest { for _, j := range r.Jobs { if j.Language == lang { return &j } } return nil } func (r *PushRequest) GetPlatforms() []Platform { var platforms []Platform for _, jobRequest := range r.Jobs { p := jobRequest.Platform if !PlatformsContain(platforms, p) { platforms = append(platforms, p) } } return platforms } type PushLaunchRequest struct { Id int `json:"id"` JobRequests []PushJobRequest `json:"jobs"` // Длина среза jobRequests может быть равна 0. } //func (r *PushLaunchRequest) jobAmount() uint32 { // return uint32(len(r.JobRequests)) //} func (r *PushLaunchRequest) DeviceTokenAmount() uint32 { return jobRequests_deviceTokenAmount(r.JobRequests) } func (r *PushLaunchRequest) Validate(ctx context.Context) error { return validateJobsRequests(r.JobRequests) } func validateJobsRequests(jobRequests []PushJobRequest) error { for _, jobRequest := range jobRequests { if err := jobRequest.Validate(); err != nil { return err } } return nil } type PushJobRequest struct { Message string `json:"message"` Title string `json:"title"` Platform Platform `json:"platform"` Language int `json:"language"` Utc_delta int `json:"utc_delta"` Device_tokens []string `json:"device_tokens"` } func (j *PushJobRequest) Validate() error { if len(j.Message) == 0 { return errors.New("No message") } if len(j.Device_tokens) == 0 { return errors.New("No device tokens") } if j.Platform == PlatformUnknown { return errors.New("No platform") } return nil } func (req *PushJobRequest) deviceTokenAmount() uint32 { return uint32(len(req.Device_tokens)) } func jobRequests_deviceTokenAmount(jobRequests []PushJobRequest) uint32 { var total uint32 = 0 for _, jobRequest := range jobRequests { total += jobRequest.deviceTokenAmount() } return total } //----------------------------------------------------------------------------- type PushPayload struct { ImageUrl string `json:"imageUrl"` TextVariants []*TextVariant `json:"textVariants"` } func ReadPayloadFromRequest(request *http.Request, payload *PushPayload) error { b, err := io.ReadAll(request.Body) if err != nil { return err } if b == nil { return errors.New("Can not read text variants. Request body bytes is nil.") } return json.Unmarshal(b, payload) } //----------------------------------------------------------------------------- type Push struct { Id uint32 `json:"id"` Status int `json:"status"` Ctime uint32 `json:"ctime"` Mtime uint32 `json:"mtime"` Ttl uint32 `json:"ttl"` Stime uint32 `json:"stime"` Srtime uint32 `json:"srtime"` Info string `json:"info"` Label string `json:"label"` MaxVersion string `json:"maxVersion,omitempty"` Platforms []uint32 `json:"platforms,omitempty"` PlayersIds []uint32 `json:"playersIds,omitempty"` Title string `json:"title"` Message string `json:"message"` TextVariants []*TextVariant `json:"textVariants"` // For incoming push only. Jobs []*PushJob `json:"jobs"` // Incoming push has no jobs. Total int `json:"total"` Sent int `json:"sent"` // Incoming push has not field "Sent". Fails int `json:"fails"` // Incoming push has not field "Fails". ForTest bool `json:"forTest,omitempty"` ImageUrl string `json:"imageUrl,omitempty"` } func (push *Push) IsDone() bool { return push.Total == (push.Sent + push.Fails) } //----------------------------------------------------------------------------- type JobId uint32 type PushJob struct { Id JobId `json:"id"` Platform Platform `json:"platform"` Message string `json:"message"` Title string `json:"title"` Language int `json:"language"` Utc_delta int `json:"utc_delta"` Total int `json:"total"` Sent int `json:"sent"` Fails int `json:"fails"` } func (job *PushJob) IsDone() bool { return job.Total == (job.Sent + job.Fails) }