Send channel as prefix for compat clients
This commit is contained in:
parent
8826cb0312
commit
b2df0a5a02
@ -18,15 +18,6 @@
|
||||
|
||||
- deploy
|
||||
|
||||
- diff my currently used scnsend script vs the one in the docs here
|
||||
|
||||
- (?) use str-ids (hide counts and prevents wrong-joins) -> see psycho
|
||||
-> ensre that all queries that return multiple are properly ordered
|
||||
-> how does it work with existing data?
|
||||
-> do i care, there are only 2 active users... (are there?)
|
||||
|
||||
- convert existing user-ids on compat /send endpoint
|
||||
|
||||
- error logging as goroutine, gets all errors via channel,
|
||||
(channel buffered - nonblocking send, second channel that gets a message when sender failed )
|
||||
(then all errors end up in _second_ sqlite table)
|
||||
@ -47,10 +38,6 @@
|
||||
|
||||
- ios purchase verification
|
||||
|
||||
- return channel as "[..] asdf" in compat methods (mark clients as compat and send compat FB to them...)
|
||||
(then we can replace the old server without switching phone clients)
|
||||
(still needs switching of the send-script)
|
||||
|
||||
- move to KeyToken model
|
||||
* [X] User can have multiple keys with different permissions
|
||||
* [X] compat simply uses default-keys
|
||||
@ -62,12 +49,14 @@
|
||||
- We no longer have a route to reshuffle all keys (previously in updateUser), add a /user/:uid/keys/reset ?
|
||||
Would delete all existing keys and create 3 new ones?
|
||||
|
||||
- TODO comments
|
||||
- TODO-comments
|
||||
|
||||
#### PERSONAL
|
||||
|
||||
- in my script: use `srvname` for sendername
|
||||
|
||||
- switch send script everywhere (we can use the new server, but we need to send correct channels)
|
||||
|
||||
#### UNSURE
|
||||
|
||||
- (?) default-priority for channels
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -37,10 +38,11 @@ func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
|
||||
|
||||
for ctr := 1; ; ctr++ {
|
||||
|
||||
wrap, panicObj := callPanicSafe(fn, g)
|
||||
wrap, stackTrace, panicObj := callPanicSafe(fn, g)
|
||||
if panicObj != nil {
|
||||
log.Error().Interface("panicObj", panicObj).Msg("Panic occured (in gin handler)")
|
||||
wrap = APIError(g, 500, apierr.PANIC, "A panic occured in the HTTP handler", errors.New(fmt.Sprintf("%+v", panicObj)))
|
||||
log.Error().Msg(stackTrace)
|
||||
wrap = APIError(g, 500, apierr.PANIC, "A panic occured in the HTTP handler", errors.New(fmt.Sprintf("%+v\n\n@:\n%s", panicObj, stackTrace)))
|
||||
}
|
||||
|
||||
if g.Writer.Written() {
|
||||
@ -138,16 +140,17 @@ func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp HTTPResponse,
|
||||
}
|
||||
}
|
||||
|
||||
func callPanicSafe(fn WHandlerFunc, g *gin.Context) (res HTTPResponse, panicObj any) {
|
||||
func callPanicSafe(fn WHandlerFunc, g *gin.Context) (res HTTPResponse, stackTrace string, panicObj any) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
res = nil
|
||||
stackTrace = string(debug.Stack())
|
||||
panicObj = rec
|
||||
}
|
||||
}()
|
||||
|
||||
res = fn(g)
|
||||
return res, nil
|
||||
return res, "", nil
|
||||
}
|
||||
|
||||
func resetBody(g *gin.Context) error {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
@ -540,7 +541,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
compMsgs = append(compMsgs, models.CompatMessage{
|
||||
Title: v.Title,
|
||||
Title: compatizeMessageTitle(ctx, h.app, v),
|
||||
Body: v.Content,
|
||||
Priority: v.Priority,
|
||||
Timestamp: v.Timestamp().Unix(),
|
||||
@ -788,7 +789,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
|
||||
Success: true,
|
||||
Message: "ok",
|
||||
Data: models.CompatMessage{
|
||||
Title: msg.Title,
|
||||
Title: compatizeMessageTitle(ctx, h.app, msg),
|
||||
Body: msg.Content,
|
||||
Trimmed: langext.Ptr(false),
|
||||
Priority: msg.Priority,
|
||||
@ -935,3 +936,16 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
|
||||
IsPro: user.IsPro,
|
||||
}))
|
||||
}
|
||||
|
||||
func compatizeMessageTitle(ctx *logic.AppContext, app *logic.Application, msg models.Message) string {
|
||||
if msg.ChannelInternalName == "main" {
|
||||
return msg.Title
|
||||
}
|
||||
|
||||
channel, err := app.Database.Primary.GetChannelByID(ctx, msg.ChannelID)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[%s] %s", "%SCN-ERR%", msg.Title)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[%s] %s", channel.DisplayName, msg.Title)
|
||||
}
|
||||
|
@ -284,7 +284,17 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
||||
|
||||
for _, client := range clients {
|
||||
|
||||
fcmDelivID, err := h.app.DeliverMessage(ctx, client, msg)
|
||||
isCompatClient, err := h.database.IsCompatClient(ctx, client.ClientID)
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query compat_clients", err))
|
||||
}
|
||||
|
||||
var titleOverride *string = nil
|
||||
if isCompatClient {
|
||||
titleOverride = langext.Ptr(compatizeMessageTitle(ctx, h.app, msg))
|
||||
}
|
||||
|
||||
fcmDelivID, err := h.app.DeliverMessage(ctx, client, msg, titleOverride)
|
||||
if err != nil {
|
||||
_, err = h.database.CreateRetryDelivery(ctx, client, msg)
|
||||
if err != nil {
|
||||
|
@ -266,6 +266,11 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
||||
clientid = &_clientid
|
||||
|
||||
usedFCM[*user.FcmToken] = _clientid
|
||||
|
||||
_, err = dbnew.Exec(ctx, "INSERT INTO compat_clients (client_id) VALUES (:cid)", sq.PP{"cid": _clientid})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,3 +155,26 @@ func (db *Database) SetAck(ctx TxContext, userid models.UserID, msgid models.Mes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) IsCompatClient(ctx TxContext, clientid models.ClientID) (bool, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM compat_clients WHERE client_id = :id LIMIT 1", sq.PP{
|
||||
"id": clientid,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
res := rows.Next()
|
||||
|
||||
err = rows.Close()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@ -214,6 +214,13 @@ CREATE UNIQUE INDEX "idx_compatacks_messageid" ON compat_acks (message_id
|
||||
CREATE UNIQUE INDEX "idx_compatacks_userid_messageid" ON compat_acks (user_id, message_id);
|
||||
|
||||
|
||||
CREATE TABLE compat_clients
|
||||
(
|
||||
client_id TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_compatclient_clientid" ON compat_clients (client_id);
|
||||
|
||||
|
||||
CREATE TABLE `meta`
|
||||
(
|
||||
meta_key TEXT NOT NULL,
|
||||
|
@ -154,7 +154,7 @@ func (j *DeliveryRetryJob) redeliver(ctx *logic.SimpleContext, delivery models.D
|
||||
}
|
||||
} else {
|
||||
|
||||
fcmDelivID, err := j.app.DeliverMessage(ctx, client, msg)
|
||||
fcmDelivID, err := j.app.DeliverMessage(ctx, client, msg, nil)
|
||||
if err == nil {
|
||||
err = j.app.Database.Primary.SetDeliverySuccess(ctx, delivery, *fcmDelivID)
|
||||
if err != nil {
|
||||
|
@ -347,9 +347,9 @@ func (app *Application) NormalizeUsername(v string) string {
|
||||
return v
|
||||
}
|
||||
|
||||
func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message) (*string, error) {
|
||||
func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (*string, error) {
|
||||
if client.FCMToken != nil {
|
||||
fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg)
|
||||
fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride)
|
||||
if err != nil {
|
||||
log.Warn().Str("MessageID", msg.MessageID.String()).Str("ClientID", client.ClientID.String()).Err(err).Msg("FCM Delivery failed")
|
||||
return nil, err
|
||||
|
@ -12,6 +12,6 @@ func NewDummy() NotificationClient {
|
||||
return &DummyConnector{}
|
||||
}
|
||||
|
||||
func (d DummyConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message) (string, error) {
|
||||
func (d DummyConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error) {
|
||||
return "%DUMMY%", nil
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ type Notification struct {
|
||||
Priority int
|
||||
}
|
||||
|
||||
func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message) (string, error) {
|
||||
func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error) {
|
||||
|
||||
uri := "https://fcm.googleapis.com/v1/projects/" + fb.fbProject + "/messages:send"
|
||||
|
||||
@ -62,7 +62,7 @@ func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.
|
||||
"timestamp": strconv.FormatInt(msg.Timestamp().Unix(), 10),
|
||||
"priority": strconv.Itoa(msg.Priority),
|
||||
"trimmed": langext.Conditional(msg.NeedsTrim(), "true", "false"),
|
||||
"title": msg.Title,
|
||||
"title": langext.Coalesce(compatTitleOverride, msg.Title),
|
||||
"body": langext.Coalesce(msg.TrimmedContent(), ""),
|
||||
},
|
||||
"token": *client.FCMToken,
|
||||
|
@ -6,5 +6,5 @@ import (
|
||||
)
|
||||
|
||||
type NotificationClient interface {
|
||||
SendNotification(ctx context.Context, client models.Client, msg models.Message) (string, error)
|
||||
SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error)
|
||||
}
|
||||
|
@ -8,8 +8,9 @@ import (
|
||||
)
|
||||
|
||||
type SinkData struct {
|
||||
Message models.Message
|
||||
Client models.Client
|
||||
Message models.Message
|
||||
Client models.Client
|
||||
CompatTitleOverride *string
|
||||
}
|
||||
|
||||
type TestSink struct {
|
||||
@ -24,7 +25,7 @@ func (d *TestSink) Last() SinkData {
|
||||
return d.Data[len(d.Data)-1]
|
||||
}
|
||||
|
||||
func (d *TestSink) SendNotification(ctx context.Context, client models.Client, msg models.Message) (string, error) {
|
||||
func (d *TestSink) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error) {
|
||||
id, err := langext.NewHexUUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -33,8 +34,9 @@ func (d *TestSink) SendNotification(ctx context.Context, client models.Client, m
|
||||
key := "TestSink[" + id + "]"
|
||||
|
||||
d.Data = append(d.Data, SinkData{
|
||||
Message: msg,
|
||||
Client: client,
|
||||
Message: msg,
|
||||
Client: client,
|
||||
CompatTitleOverride: compatTitleOverride,
|
||||
})
|
||||
|
||||
return key, nil
|
||||
|
@ -694,3 +694,41 @@ func TestCompatRequery(t *testing.T) {
|
||||
tt.AssertEqual(t, "count", 0, rq7.Count)
|
||||
|
||||
}
|
||||
|
||||
func TestCompatTitlePatch(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
pusher := ws.Pusher.(*push.TestSink)
|
||||
|
||||
r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/v2/users", gin.H{
|
||||
"agent_model": "DUMMY_PHONE",
|
||||
"agent_version": "4X",
|
||||
"client_type": "ANDROID",
|
||||
"fcm_token": "DUMMY_FCM",
|
||||
})
|
||||
|
||||
uid := r0["user_id"].(string)
|
||||
admintok := r0["admin_key"].(string)
|
||||
sendtok := r0["send_key"].(string)
|
||||
|
||||
type clientlist struct {
|
||||
Clients []gin.H `json:"clients"`
|
||||
}
|
||||
|
||||
clist1 := tt.RequestAuthGet[clientlist](t, admintok, baseUrl, fmt.Sprintf("/api/v2/users/%s/clients", url.QueryEscape(uid)))
|
||||
|
||||
tt.SetCompatClient(t, ws, clist1.Clients[0]["client_id"].(string))
|
||||
|
||||
_ = tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": sendtok,
|
||||
"user_id": uid,
|
||||
"title": "HelloWorld_001",
|
||||
"channel": "TestChan",
|
||||
})
|
||||
|
||||
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", pusher.Last().Message.Title)
|
||||
tt.AssertStrRepEqual(t, "msg.ovrTitle", "[TestChan] HelloWorld_001", pusher.Last().CompatTitleOverride)
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package util
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@ -64,3 +65,14 @@ func CreateCompatID(t *testing.T, ws *logic.Application, idtype string, newid st
|
||||
|
||||
return uidold
|
||||
}
|
||||
|
||||
func SetCompatClient(t *testing.T, ws *logic.Application, cid string) {
|
||||
ctx := ws.NewSimpleTransactionContext(5 * time.Second)
|
||||
defer ctx.Cancel()
|
||||
|
||||
_, err := ws.Database.Primary.DB().Exec(ctx, "INSERT INTO compat_clients (client_id) VALUES (:cid)", sq.PP{"cid": cid})
|
||||
TestFailIfErr(t, err)
|
||||
|
||||
err = ctx.CommitTransaction()
|
||||
TestFailIfErr(t, err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user