Compare commits

...

9 Commits
v1.0.3 ... main

7 changed files with 380 additions and 8 deletions

2
go.mod
View File

@ -1,3 +1,5 @@
module git.bit5.ru/backend/push_common
go 1.19
require git.bit5.ru/backend/errors v1.0.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
git.bit5.ru/backend/errors v1.0.0 h1:WWJ0sly44q1HQjN01X75ZAGKZwwY5Ml+XVDXMjCkToA=
git.bit5.ru/backend/errors v1.0.0/go.mod h1:75faRwsnpM0Se00/Bh7fysWQXV8oMjNJFQ6f7+r9k3Y=

51
platform.go Normal file
View File

@ -0,0 +1,51 @@
package push_common
type Platform int
const (
PlatformUnknown Platform = 0
PlatformIos Platform = 1
PlatformAndroid Platform = 2
PlatformAmazon Platform = 3
PlatformSamsung Platform = 4
PlatformHuawei Platform = 5
)
func PlatformToString(p Platform) string {
switch p {
case PlatformUnknown:
return "unknown"
case PlatformIos:
return "ios"
case PlatformAndroid:
return "android"
case PlatformAmazon:
return "amazon"
case PlatformSamsung:
return "samsung"
case PlatformHuawei:
return "huawei"
}
return "error"
}
// Когда в pushd добавляется транспорт для новой платформы,
// то эту платформу нужно указать в этой функции.
func GetSupportedPlatforms() []Platform {
return []Platform{
PlatformIos,
PlatformAndroid,
//PlatformAmazon,
PlatformSamsung,
PlatformHuawei,
}
}
func PlatformsContain(platforms []Platform, p Platform) bool {
for _, item := range platforms {
if item == p {
return true
}
}
return false
}

View File

@ -1,5 +1,16 @@
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 {
@ -27,8 +38,254 @@ type PushPreview struct {
//-----------------------------------------------------------------------------
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)
}

43
push_type.go Normal file
View File

@ -0,0 +1,43 @@
package push_common
import "strings"
type PushType uint8
const (
PushType_User PushType = 1
PushType_Auto PushType = 2
)
func PushTypeToString(pt PushType) string {
switch pt {
case PushType_User:
return "user"
case PushType_Auto:
return "auto"
}
return "error"
}
const AutoPushInfoPrefix = "#"
// Автоматическое пуш-оповещение - пуш-оповещение,
// которое было создано автоматически (а не пользователем инсайдера).
func IsAutoPush(pushInfo string) bool {
return strings.HasPrefix(pushInfo, AutoPushInfoPrefix)
}
// Пользовательское пуш-оповещение - пуш-оповещение,
// которое было создано пользователем инсайдера (а не автоматически).
func IsUserPush(pushInfo string) bool {
isAuto := IsAutoPush(pushInfo)
return !isAuto
}
func ConvertPushInfoToType(pushInfo string) PushType {
if IsAutoPush(pushInfo) {
return PushType_Auto
} else {
return PushType_User
}
}

25
server.go Normal file
View File

@ -0,0 +1,25 @@
package push_common
type ServerInfo struct {
RevisionHash string `json:"revisionHash"`
Time uint32 `json:"time"`
Hostname string `json:"hostname"`
RedisConnectionConf *RedisConnectionConf `json:"redisConnectionConf"`
ActivePushAmount uint32 `json:"activePushAmount"`
UptraceInfo *UptraceInfo `json:"uptraceInfo"`
}
type RedisConnectionConf struct {
Host string `json:"host"`
Port int `json:"port"`
Db int `json:"db"`
Prefix string `json:"prefix"`
}
type UptraceInfo struct {
UptraceOn bool `json:"uptraceOn"`
UptraceDSN string `json:"uptraceDSN"`
ServiceName string `json:"serviceName"`
ServiceVersion string `json:"serviceVersion"`
DeploymentEnvironment string `json:"deploymentEnvironment"`
}

View File

@ -5,11 +5,3 @@ import "strconv"
func uint32ToString(n uint32) string {
return strconv.FormatUint(uint64(n), 10)
}
type UptraceInfo struct {
UptraceOn bool `json:"uptraceOn"`
UptraceDSN string `json:"uptraceDSN"`
ServiceName string `json:"serviceName"`
ServiceVersion string `json:"serviceVersion"`
DeploymentEnvironment string `json:"deploymentEnvironment"`
}