refactor: unify code formatting and improve push/search implementations
- Remove BOM from all Go source files - Standardize import ordering and whitespace across handlers and services - Replace PostgreSQL full-text search with ILIKE pattern matching in post and user repositories - Enhance JPush client with TLS transport, rate limit monitoring, and simplified API - Refactor PushService to include userID in device management methods - Add MaxDevicesPerUser limit and extract helper functions for push payload construction
This commit is contained in:
@@ -2,10 +2,12 @@ package jpush
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -16,8 +18,8 @@ import (
|
||||
|
||||
const (
|
||||
PushAPIBaseURL = "https://api.jpush.cn/v3"
|
||||
DeviceAPIBaseURL = "https://device.jpush.cn/v3"
|
||||
ReportAPIBaseURL = "https://report.jpush.cn/v3"
|
||||
DeviceAPIBaseURL = "https://device.jpush.cn/v3"
|
||||
ReportAPIBaseURL = "https://report.jpush.cn/v3"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
@@ -26,14 +28,25 @@ type Client struct {
|
||||
production bool
|
||||
httpClient *http.Client
|
||||
logger *zap.Logger
|
||||
lastRateLimit *RateLimitInfo
|
||||
}
|
||||
|
||||
func NewClient(appKey, masterSecret string, production bool, logger *zap.Logger) *Client {
|
||||
transport := &http.Transport{
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 20,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS12},
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 10 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}
|
||||
return &Client{
|
||||
appKey: appKey,
|
||||
masterSecret: masterSecret,
|
||||
production: production,
|
||||
httpClient: &http.Client{Timeout: 30 * time.Second},
|
||||
httpClient: &http.Client{Timeout: 30 * time.Second, Transport: transport},
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -79,9 +92,9 @@ type IOSNotif struct {
|
||||
}
|
||||
|
||||
type PushOptions struct {
|
||||
TimeToLive int `json:"time_to_live,omitempty"`
|
||||
ApnsProduction bool `json:"apns_production"`
|
||||
ApnsCollapseID string `json:"apns_collapse_id,omitempty"`
|
||||
TimeToLive int `json:"time_to_live,omitempty"`
|
||||
ApnsProduction bool `json:"apns_production"`
|
||||
ApnsCollapseID string `json:"apns_collapse_id,omitempty"`
|
||||
}
|
||||
|
||||
type PushResponse struct {
|
||||
@@ -96,7 +109,7 @@ type RateLimitInfo struct {
|
||||
}
|
||||
|
||||
type APIError struct {
|
||||
ErrCode int `json:"code"`
|
||||
ErrCode int `json:"code"`
|
||||
ErrMessage string `json:"message"`
|
||||
ErrDetail struct {
|
||||
Code int `json:"code"`
|
||||
@@ -199,6 +212,14 @@ func (c *Client) Push(payload map[string]any) (*PushResponse, *RateLimitInfo, er
|
||||
return nil, rateLimit, err
|
||||
}
|
||||
|
||||
c.lastRateLimit = rateLimit
|
||||
if rateLimit != nil && rateLimit.Limit > 0 && rateLimit.Remaining < rateLimit.Limit/10 {
|
||||
c.logger.Warn("jpush rate limit approaching",
|
||||
zap.Int("remaining", rateLimit.Remaining),
|
||||
zap.Int("limit", rateLimit.Limit),
|
||||
)
|
||||
}
|
||||
|
||||
result, parseErr := c.parseResponse(resp, respBody)
|
||||
if parseErr != nil {
|
||||
c.logger.Error("jpush push response parse failed",
|
||||
@@ -214,7 +235,7 @@ func (c *Client) Push(payload map[string]any) (*PushResponse, *RateLimitInfo, er
|
||||
return result, rateLimit, parseErr
|
||||
}
|
||||
|
||||
func (c *Client) PushByRegistrationIDs(registrationIDs []string, notification *Notification, extras map[string]any) (*PushResponse, error) {
|
||||
func (c *Client) PushByRegistrationIDs(registrationIDs []string, notification *Notification) (*PushResponse, error) {
|
||||
if len(registrationIDs) == 0 {
|
||||
return nil, fmt.Errorf("registration IDs cannot be empty")
|
||||
}
|
||||
@@ -228,8 +249,6 @@ func (c *Client) PushByRegistrationIDs(registrationIDs []string, notification *N
|
||||
zap.String("alert", notification.Alert),
|
||||
)
|
||||
|
||||
mergeExtras(notification, extras)
|
||||
|
||||
payload := map[string]any{
|
||||
"platform": "all",
|
||||
"audience": map[string]any{"registration_id": registrationIDs},
|
||||
@@ -256,7 +275,7 @@ func (c *Client) PushByRegistrationIDs(registrationIDs []string, notification *N
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Client) PushByAliases(aliases []string, notification *Notification, extras map[string]any) (*PushResponse, error) {
|
||||
func (c *Client) PushByAliases(aliases []string, notification *Notification) (*PushResponse, error) {
|
||||
if len(aliases) == 0 {
|
||||
return nil, fmt.Errorf("aliases cannot be empty")
|
||||
}
|
||||
@@ -270,8 +289,6 @@ func (c *Client) PushByAliases(aliases []string, notification *Notification, ext
|
||||
zap.String("alert", notification.Alert),
|
||||
)
|
||||
|
||||
mergeExtras(notification, extras)
|
||||
|
||||
payload := map[string]any{
|
||||
"platform": "all",
|
||||
"audience": map[string]any{"alias": aliases},
|
||||
@@ -295,7 +312,7 @@ func (c *Client) PushByAliases(aliases []string, notification *Notification, ext
|
||||
zap.Int("count", len(aliases)),
|
||||
zap.String("msg_id", result.MsgID),
|
||||
)
|
||||
return result, err
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Client) PushAll(notification *Notification) (*PushResponse, error) {
|
||||
@@ -325,29 +342,7 @@ func (c *Client) PushAll(notification *Notification) (*PushResponse, error) {
|
||||
c.logger.Info("jpush push all success",
|
||||
zap.String("msg_id", result.MsgID),
|
||||
)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func mergeExtras(notification *Notification, extras map[string]any) {
|
||||
if extras == nil {
|
||||
return
|
||||
}
|
||||
if notification.Android != nil {
|
||||
if notification.Android.Extras == nil {
|
||||
notification.Android.Extras = make(map[string]any)
|
||||
}
|
||||
for k, v := range extras {
|
||||
notification.Android.Extras[k] = v
|
||||
}
|
||||
}
|
||||
if notification.IOS != nil {
|
||||
if notification.IOS.Extras == nil {
|
||||
notification.IOS.Extras = make(map[string]any)
|
||||
}
|
||||
for k, v := range extras {
|
||||
notification.IOS.Extras[k] = v
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func BuildNotification(title, body string, notificationType string, extras map[string]any) *Notification {
|
||||
@@ -394,7 +389,7 @@ func (c *Client) GetDeviceInfo(registrationID string) (*DeviceInfo, error) {
|
||||
zap.String("registration_id", registrationID),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/devices/" + url.PathEscape(registrationID)
|
||||
path := DeviceAPIBaseURL + "/devices/" + url.PathEscape(registrationID)
|
||||
resp, body, _, err := c.doRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -427,7 +422,7 @@ func (c *Client) SetDeviceAlias(registrationID string, alias string) error {
|
||||
zap.String("alias", alias),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/devices/" + url.PathEscape(registrationID)
|
||||
path := DeviceAPIBaseURL + "/devices/" + url.PathEscape(registrationID)
|
||||
payload := map[string]any{
|
||||
"alias": alias,
|
||||
}
|
||||
@@ -461,7 +456,7 @@ func (c *Client) SetDeviceTags(registrationID string, addTags, removeTags []stri
|
||||
zap.Strings("remove_tags", removeTags),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/devices/" + url.PathEscape(registrationID)
|
||||
path := DeviceAPIBaseURL + "/devices/" + url.PathEscape(registrationID)
|
||||
tags := map[string]any{}
|
||||
if len(addTags) > 0 {
|
||||
tags["add"] = addTags
|
||||
@@ -499,7 +494,7 @@ func (c *Client) GetAliasRegistrationIDs(alias string) ([]string, error) {
|
||||
zap.String("alias", alias),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/aliases/" + url.PathEscape(alias)
|
||||
path := DeviceAPIBaseURL + "/aliases/" + url.PathEscape(alias)
|
||||
resp, body, _, err := c.doRequest("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -532,7 +527,7 @@ func (c *Client) DeleteAlias(alias string) error {
|
||||
zap.String("alias", alias),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/aliases/" + url.PathEscape(alias)
|
||||
path := DeviceAPIBaseURL + "/aliases/" + url.PathEscape(alias)
|
||||
resp, body, _, err := c.doRequest("DELETE", path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -559,7 +554,7 @@ func (c *Client) RemoveAliasDevices(alias string, registrationIDs []string) erro
|
||||
zap.Int("count", len(registrationIDs)),
|
||||
)
|
||||
|
||||
path := DeviceAPIBaseURL + "/v3/aliases/" + url.PathEscape(alias)
|
||||
path := DeviceAPIBaseURL + "/aliases/" + url.PathEscape(alias)
|
||||
payload := map[string]any{
|
||||
"registration_ids": map[string]any{
|
||||
"remove": registrationIDs,
|
||||
|
||||
Reference in New Issue
Block a user