mirror of
https://github.com/makayabou/asg-server.git
synced 2026-05-02 17:43:36 +02:00
[messages] add messages priority
This commit is contained in:
parent
a3da29b56d
commit
11bdf0e033
23
internal/sms-gateway/handlers/converters/messages.go
Normal file
23
internal/sms-gateway/handlers/converters/messages.go
Normal file
@ -0,0 +1,23 @@
|
||||
package converters
|
||||
|
||||
import (
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
|
||||
)
|
||||
|
||||
func MessageToDTO(m messages.MessageOut) smsgateway.MobileMessage {
|
||||
return smsgateway.MobileMessage{
|
||||
Message: smsgateway.Message{
|
||||
ID: m.ID,
|
||||
Message: m.Message,
|
||||
SimNumber: m.SimNumber,
|
||||
WithDeliveryReport: m.WithDeliveryReport,
|
||||
IsEncrypted: m.IsEncrypted,
|
||||
PhoneNumbers: m.PhoneNumbers,
|
||||
TTL: m.TTL,
|
||||
ValidUntil: m.ValidUntil,
|
||||
Priority: m.Priority,
|
||||
},
|
||||
CreatedAt: m.CreatedAt,
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,19 @@ func (h *ThirdPartyController) post(user models.User, c *fiber.Ctx) error {
|
||||
return fmt.Errorf("can't get random device: %w", err)
|
||||
}
|
||||
|
||||
state, err := h.messagesSvc.Enqeue(device, req, messages.EnqueueOptions{SkipPhoneValidation: skipPhoneValidation})
|
||||
msg := messages.MessageIn{
|
||||
ID: req.ID,
|
||||
Message: req.Message,
|
||||
PhoneNumbers: req.PhoneNumbers,
|
||||
IsEncrypted: req.IsEncrypted,
|
||||
|
||||
SimNumber: req.SimNumber,
|
||||
WithDeliveryReport: req.WithDeliveryReport,
|
||||
TTL: req.TTL,
|
||||
ValidUntil: req.ValidUntil,
|
||||
Priority: req.Priority,
|
||||
}
|
||||
state, err := h.messagesSvc.Enqueue(device, msg, messages.EnqueueOptions{SkipPhoneValidation: skipPhoneValidation})
|
||||
if err != nil {
|
||||
var errValidation messages.ErrValidation
|
||||
if isBadRequest := errors.As(err, &errValidation); isBadRequest {
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
|
||||
"github.com/capcom6/go-helpers/anys"
|
||||
"github.com/capcom6/go-helpers/slices"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
@ -152,18 +153,25 @@ func (h *mobileHandler) patchDevice(device models.Device, c *fiber.Ctx) error {
|
||||
// @Tags Device, Messages
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} smsgateway.Message "List of pending messages"
|
||||
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
|
||||
// @Success 200 {object} smsgateway.MobileGetMessagesResponse "List of pending messages"
|
||||
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
|
||||
// @Router /mobile/v1/message [get]
|
||||
//
|
||||
// Get messages for sending
|
||||
func (h *mobileHandler) getMessage(device models.Device, c *fiber.Ctx) error {
|
||||
messages, err := h.messagesSvc.SelectPending(device.ID)
|
||||
msgs, err := h.messagesSvc.SelectPending(device.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get messages: %w", err)
|
||||
}
|
||||
|
||||
return c.JSON(messages)
|
||||
return c.JSON(
|
||||
smsgateway.MobileGetMessagesResponse(
|
||||
slices.Map(
|
||||
msgs,
|
||||
converters.MessageToDTO,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// @Summary Update message state
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE `messages`
|
||||
ADD `priority` tinyint NOT NULL DEFAULT 0;
|
||||
-- +goose StatementEnd
|
||||
---
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE `messages` DROP `priority`;
|
||||
-- +goose StatementEnd
|
||||
@ -58,6 +58,7 @@ type Message struct {
|
||||
ValidUntil *time.Time `gorm:"type:datetime"`
|
||||
SimNumber *uint8 `gorm:"type:tinyint(1) unsigned"`
|
||||
WithDeliveryReport bool `gorm:"not null;type:tinyint(1) unsigned"`
|
||||
Priority int8 `gorm:"not null;type:tinyint;default:0"`
|
||||
|
||||
IsHashed bool `gorm:"not null;type:tinyint(1) unsigned;default:0"`
|
||||
IsEncrypted bool `gorm:"not null;type:tinyint(1) unsigned;default:0"`
|
||||
|
||||
37
internal/sms-gateway/modules/messages/converters.go
Normal file
37
internal/sms-gateway/modules/messages/converters.go
Normal file
@ -0,0 +1,37 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/capcom6/go-helpers/slices"
|
||||
)
|
||||
|
||||
func messageToDomain(input models.Message) MessageOut {
|
||||
var ttl *uint64 = nil
|
||||
if input.ValidUntil != nil {
|
||||
secondsUntil := uint64(math.Max(0, time.Until(*input.ValidUntil).Seconds()))
|
||||
ttl = &secondsUntil
|
||||
}
|
||||
|
||||
return MessageOut{
|
||||
MessageIn: MessageIn{
|
||||
ID: input.ExtID,
|
||||
Message: input.Message,
|
||||
PhoneNumbers: slices.Map(input.Recipients, recipientToDomain),
|
||||
IsEncrypted: input.IsEncrypted,
|
||||
SimNumber: input.SimNumber,
|
||||
WithDeliveryReport: &input.WithDeliveryReport,
|
||||
TTL: ttl,
|
||||
ValidUntil: input.ValidUntil,
|
||||
Priority: smsgateway.MessagePriority(input.Priority),
|
||||
},
|
||||
CreatedAt: input.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func recipientToDomain(input models.MessageRecipient) string {
|
||||
return input.PhoneNumber
|
||||
}
|
||||
26
internal/sms-gateway/modules/messages/domain.go
Normal file
26
internal/sms-gateway/modules/messages/domain.go
Normal file
@ -0,0 +1,26 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
)
|
||||
|
||||
type MessageIn struct {
|
||||
ID string
|
||||
Message string
|
||||
PhoneNumbers []string
|
||||
IsEncrypted bool
|
||||
|
||||
SimNumber *uint8
|
||||
WithDeliveryReport *bool
|
||||
TTL *uint64
|
||||
ValidUntil *time.Time
|
||||
Priority smsgateway.MessagePriority
|
||||
}
|
||||
|
||||
type MessageOut struct {
|
||||
MessageIn
|
||||
|
||||
CreatedAt time.Time
|
||||
}
|
||||
@ -24,7 +24,7 @@ type repository struct {
|
||||
func (r *repository) SelectPending(deviceID string) (messages []models.Message, err error) {
|
||||
err = r.db.
|
||||
Where("device_id = ? AND state = ?", deviceID, models.ProcessingStatePending).
|
||||
Order("id DESC").
|
||||
Order("priority DESC, id DESC").
|
||||
Limit(100).
|
||||
Preload("Recipients").
|
||||
Find(&messages).
|
||||
|
||||
@ -95,39 +95,13 @@ func (s *Service) RunBackgroundTasks(ctx context.Context, wg *sync.WaitGroup) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Service) SelectPending(deviceID string) ([]smsgateway.Message, error) {
|
||||
func (s *Service) SelectPending(deviceID string) ([]MessageOut, error) {
|
||||
messages, err := s.messages.SelectPending(deviceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]smsgateway.Message, len(messages))
|
||||
for i, v := range messages {
|
||||
var ttl *uint64 = nil
|
||||
if v.ValidUntil != nil {
|
||||
delta := time.Until(*v.ValidUntil).Seconds()
|
||||
if delta > 0 {
|
||||
deltaInt := uint64(delta)
|
||||
ttl = &deltaInt
|
||||
} else {
|
||||
deltaInt := uint64(0)
|
||||
ttl = &deltaInt
|
||||
}
|
||||
}
|
||||
|
||||
result[i] = smsgateway.Message{
|
||||
ID: v.ExtID,
|
||||
Message: v.Message,
|
||||
SimNumber: v.SimNumber,
|
||||
WithDeliveryReport: anys.AsPointer[bool](v.WithDeliveryReport),
|
||||
IsEncrypted: v.IsEncrypted,
|
||||
PhoneNumbers: s.recipientsToDomain(v.Recipients),
|
||||
TTL: ttl,
|
||||
ValidUntil: v.ValidUntil,
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return slices.Map(messages, messageToDomain), nil
|
||||
}
|
||||
|
||||
func (s *Service) UpdateState(deviceID string, message smsgateway.MessageState) error {
|
||||
@ -154,7 +128,7 @@ func (s *Service) UpdateState(deviceID string, message smsgateway.MessageState)
|
||||
return err
|
||||
}
|
||||
|
||||
s.hashingTask.Enqeue(existing.ID)
|
||||
s.hashingTask.Enqueue(existing.ID)
|
||||
|
||||
s.messagesCounter.WithLabelValues(string(existing.State)).Inc()
|
||||
|
||||
@ -178,7 +152,7 @@ func (s *Service) GetState(user models.User, ID string) (smsgateway.MessageState
|
||||
return modelToMessageState(message), nil
|
||||
}
|
||||
|
||||
func (s *Service) Enqeue(device models.Device, message smsgateway.Message, opts EnqueueOptions) (smsgateway.MessageState, error) {
|
||||
func (s *Service) Enqueue(device models.Device, message MessageIn, opts EnqueueOptions) (smsgateway.MessageState, error) {
|
||||
state := smsgateway.MessageState{
|
||||
ID: "",
|
||||
State: smsgateway.ProcessingStatePending,
|
||||
@ -210,16 +184,18 @@ func (s *Service) Enqeue(device models.Device, message smsgateway.Message, opts
|
||||
}
|
||||
|
||||
msg := models.Message{
|
||||
DeviceID: device.ID,
|
||||
ExtID: message.ID,
|
||||
Message: message.Message,
|
||||
ValidUntil: validUntil,
|
||||
ExtID: message.ID,
|
||||
Message: message.Message,
|
||||
Recipients: s.recipientsToModel(message.PhoneNumbers),
|
||||
IsEncrypted: message.IsEncrypted,
|
||||
|
||||
DeviceID: device.ID,
|
||||
|
||||
SimNumber: message.SimNumber,
|
||||
WithDeliveryReport: anys.OrDefault[bool](message.WithDeliveryReport, true),
|
||||
IsEncrypted: message.IsEncrypted,
|
||||
Device: device,
|
||||
Recipients: s.recipientsToModel(message.PhoneNumbers),
|
||||
TimedModel: models.TimedModel{},
|
||||
WithDeliveryReport: anys.OrDefault(message.WithDeliveryReport, true),
|
||||
|
||||
Priority: int8(message.Priority),
|
||||
ValidUntil: validUntil,
|
||||
}
|
||||
if msg.ExtID == "" {
|
||||
msg.ExtID = s.idgen()
|
||||
@ -265,16 +241,6 @@ func (s *Service) Clean(ctx context.Context) error {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (s *Service) recipientsToDomain(input []models.MessageRecipient) []string {
|
||||
output := make([]string, len(input))
|
||||
|
||||
for i, v := range input {
|
||||
output[i] = v.PhoneNumber
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (s *Service) recipientsToModel(input []string) []models.MessageRecipient {
|
||||
output := make([]models.MessageRecipient, len(input))
|
||||
|
||||
|
||||
@ -53,7 +53,8 @@ func (t *HashingTask) Run(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *HashingTask) Enqeue(id uint64) {
|
||||
// Enqueue adds a message ID to the processing queue to be hashed in the next batch
|
||||
func (t *HashingTask) Enqueue(id uint64) {
|
||||
t.mux.Lock()
|
||||
t.queue[id] = struct{}{}
|
||||
t.mux.Unlock()
|
||||
|
||||
@ -20,8 +20,9 @@ Authorization: Basic {{credentials}}
|
||||
"phoneNumbers": [
|
||||
"{{phone}}"
|
||||
],
|
||||
"simNumber": {{$randomInt 1 2}},
|
||||
"withDeliveryReport": true
|
||||
"withDeliveryReport": true,
|
||||
"priority": 128,
|
||||
"simNumber": {{$randomInt 1 2}}
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
@ -704,7 +704,7 @@
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/smsgateway.Message"
|
||||
"$ref": "#/definitions/smsgateway.MobileMessage"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1164,6 +1164,7 @@
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority, messages with values greater than `99` will bypass limits and delays",
|
||||
"default": 0,
|
||||
"maximum": 127,
|
||||
"minimum": -128,
|
||||
"allOf": [
|
||||
@ -1206,12 +1207,12 @@
|
||||
127
|
||||
],
|
||||
"x-enum-comments": {
|
||||
"PriorityExpedited": "This and higher priority messages will bypass limits and delays"
|
||||
"PriorityBypassThreshold": "Threshold at which messages bypass limits and delays"
|
||||
},
|
||||
"x-enum-varnames": [
|
||||
"PriorityMinimum",
|
||||
"PriorityDefault",
|
||||
"PriorityExpedited",
|
||||
"PriorityBypassThreshold",
|
||||
"PriorityMaximum"
|
||||
]
|
||||
},
|
||||
@ -1327,6 +1328,83 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"smsgateway.MobileMessage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message",
|
||||
"phoneNumbers"
|
||||
],
|
||||
"properties": {
|
||||
"createdAt": {
|
||||
"description": "Message creation time",
|
||||
"type": "string",
|
||||
"example": "2020-01-01T00:00:00Z"
|
||||
},
|
||||
"id": {
|
||||
"description": "ID (if not set - will be generated)",
|
||||
"type": "string",
|
||||
"maxLength": 36,
|
||||
"example": "PyDmBQZZXYmyxMwED8Fzy"
|
||||
},
|
||||
"isEncrypted": {
|
||||
"description": "Is encrypted",
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"message": {
|
||||
"description": "Content",
|
||||
"type": "string",
|
||||
"maxLength": 65535,
|
||||
"example": "Hello World!"
|
||||
},
|
||||
"phoneNumbers": {
|
||||
"description": "Recipients (phone numbers)",
|
||||
"type": "array",
|
||||
"maxItems": 100,
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"example": [
|
||||
"79990001234"
|
||||
]
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority, messages with values greater than `99` will bypass limits and delays",
|
||||
"default": 0,
|
||||
"maximum": 127,
|
||||
"minimum": -128,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/smsgateway.MessagePriority"
|
||||
}
|
||||
],
|
||||
"example": 0
|
||||
},
|
||||
"simNumber": {
|
||||
"description": "SIM card number (1-3), if not set - default SIM will be used",
|
||||
"type": "integer",
|
||||
"maximum": 3,
|
||||
"example": 1
|
||||
},
|
||||
"ttl": {
|
||||
"description": "Time to live in seconds (conflicts with `validUntil`)",
|
||||
"type": "integer",
|
||||
"minimum": 5,
|
||||
"example": 86400
|
||||
},
|
||||
"validUntil": {
|
||||
"description": "Valid until (conflicts with `ttl`)",
|
||||
"type": "string",
|
||||
"example": "2020-01-01T00:00:00Z"
|
||||
},
|
||||
"withDeliveryReport": {
|
||||
"description": "With delivery report",
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"smsgateway.MobileRegisterRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -157,6 +157,7 @@ definitions:
|
||||
priority:
|
||||
allOf:
|
||||
- $ref: '#/definitions/smsgateway.MessagePriority'
|
||||
default: 0
|
||||
description: Priority, messages with values greater than `99` will bypass
|
||||
limits and delays
|
||||
example: 0
|
||||
@ -192,12 +193,11 @@ definitions:
|
||||
- 127
|
||||
type: integer
|
||||
x-enum-comments:
|
||||
PriorityExpedited: This and higher priority messages will bypass limits and
|
||||
delays
|
||||
PriorityBypassThreshold: Threshold at which messages bypass limits and delays
|
||||
x-enum-varnames:
|
||||
- PriorityMinimum
|
||||
- PriorityDefault
|
||||
- PriorityExpedited
|
||||
- PriorityBypassThreshold
|
||||
- PriorityMaximum
|
||||
smsgateway.MessageState:
|
||||
properties:
|
||||
@ -280,6 +280,66 @@ definitions:
|
||||
description: External IP
|
||||
type: string
|
||||
type: object
|
||||
smsgateway.MobileMessage:
|
||||
properties:
|
||||
createdAt:
|
||||
description: Message creation time
|
||||
example: "2020-01-01T00:00:00Z"
|
||||
type: string
|
||||
id:
|
||||
description: ID (if not set - will be generated)
|
||||
example: PyDmBQZZXYmyxMwED8Fzy
|
||||
maxLength: 36
|
||||
type: string
|
||||
isEncrypted:
|
||||
description: Is encrypted
|
||||
example: true
|
||||
type: boolean
|
||||
message:
|
||||
description: Content
|
||||
example: Hello World!
|
||||
maxLength: 65535
|
||||
type: string
|
||||
phoneNumbers:
|
||||
description: Recipients (phone numbers)
|
||||
example:
|
||||
- "79990001234"
|
||||
items:
|
||||
type: string
|
||||
maxItems: 100
|
||||
minItems: 1
|
||||
type: array
|
||||
priority:
|
||||
allOf:
|
||||
- $ref: '#/definitions/smsgateway.MessagePriority'
|
||||
default: 0
|
||||
description: Priority, messages with values greater than `99` will bypass
|
||||
limits and delays
|
||||
example: 0
|
||||
maximum: 127
|
||||
minimum: -128
|
||||
simNumber:
|
||||
description: SIM card number (1-3), if not set - default SIM will be used
|
||||
example: 1
|
||||
maximum: 3
|
||||
type: integer
|
||||
ttl:
|
||||
description: Time to live in seconds (conflicts with `validUntil`)
|
||||
example: 86400
|
||||
minimum: 5
|
||||
type: integer
|
||||
validUntil:
|
||||
description: Valid until (conflicts with `ttl`)
|
||||
example: "2020-01-01T00:00:00Z"
|
||||
type: string
|
||||
withDeliveryReport:
|
||||
description: With delivery report
|
||||
example: true
|
||||
type: boolean
|
||||
required:
|
||||
- message
|
||||
- phoneNumbers
|
||||
type: object
|
||||
smsgateway.MobileRegisterRequest:
|
||||
properties:
|
||||
name:
|
||||
@ -899,7 +959,7 @@ paths:
|
||||
description: List of pending messages
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/smsgateway.Message'
|
||||
$ref: '#/definitions/smsgateway.MobileMessage'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal server error
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user