From 32bf24f9c57dcaac9e4e497510eac753a724392a Mon Sep 17 00:00:00 2001 From: Alexander Simmerl Date: Wed, 12 Apr 2017 15:38:25 +0200 Subject: [PATCH] Carry precompiled templates from notification pipeline To finally support all the local notifications we need a way to send the configured template per language in the actual notification. This change compiles all templates for all messages before returning it as part of a map from the pipeline. This could certainly be improved to not do unnecessary work but would need that the channel which has the device knowledge has to know about the templates, either way could be wasteful. For now we trade cpu time for complexity. --- cmd/sims/channel.go | 26 +++++++++++- core/pipieline.go | 92 +++++++++++++++++++++--------------------- core/pipieline_test.go | 64 +++++++++++++++-------------- 3 files changed, 106 insertions(+), 76 deletions(-) diff --git a/cmd/sims/channel.go b/cmd/sims/channel.go index c3d3efb..6444e74 100644 --- a/cmd/sims/channel.go +++ b/cmd/sims/channel.go @@ -1,12 +1,17 @@ package main import ( + "golang.org/x/text/language" + "github.com/tapglue/snaas/core" serr "github.com/tapglue/snaas/error" "github.com/tapglue/snaas/platform/sns" "github.com/tapglue/snaas/service/app" + "github.com/tapglue/snaas/service/device" ) +var languageDefault = language.English + type channelFunc func(*app.App, *core.Message) error func channelPush( @@ -43,7 +48,7 @@ func channelPush( return err } - err = push(d.Platform, d.EndpointARN, p.Scheme, msg.URN, msg.Message) + err = push(d.Platform, d.EndpointARN, p.Scheme, msg.URN, localiseMessage(d, msg.Messages)) if err != nil { if sns.IsDeliveryFailure(err) { return nil @@ -56,3 +61,22 @@ func channelPush( return nil } } + +func localiseMessage(d *device.Device, msgs map[string]string) string { + t, err := language.Parse(d.Language) + if err == nil { + b, _ := t.Base() + + msg, ok := msgs[b.String()] + if ok { + return msg + } + } + + defaultMsg, ok := msgs[languageDefault.String()] + if ok { + return defaultMsg + } + + return "" +} diff --git a/core/pipieline.go b/core/pipieline.go index 39600dd..994c6f9 100644 --- a/core/pipieline.go +++ b/core/pipieline.go @@ -6,8 +6,6 @@ import ( "text/template" "time" - "golang.org/x/text/language" - serr "github.com/tapglue/snaas/error" "github.com/tapglue/snaas/service/app" "github.com/tapglue/snaas/service/connection" @@ -30,7 +28,7 @@ const ( // Message is the envelope which holds the templated message produced by a // Pipeline together with the recipient and the URN to deliver with it. type Message struct { - Message string + Messages map[string]string Recipient uint64 URN string } @@ -82,29 +80,24 @@ func PipelineConnection(users user.Service) PipelineConnectionFunc { To: to, } - for _, r := range rules { - if !r.Criteria.Match(change) { + for _, currentRule := range rules { + if !currentRule.Criteria.Match(change) { continue } - for _, recipient := range r.Recipients { - rs, err := recipientsConnection()(currentApp, context, recipient.Query) + for _, recipient := range currentRule.Recipients { + cs, err := recipientsConnection()(currentApp, context, recipient.Query) if err != nil { return nil, err } - for _, r := range rs { - urn, err := compileTemplate(context, recipient.URN) - if err != nil { - return nil, err - } - - msg, err := compileTemplate(context, recipient.Templates[language.English.String()]) + for _, c := range cs { + msg, err := compileMessage(context, recipient, c) if err != nil { return nil, err } - ms = append(ms, &Message{Message: msg, Recipient: r.ID, URN: urn}) + ms = append(ms, msg) } } } @@ -113,6 +106,30 @@ func PipelineConnection(users user.Service) PipelineConnectionFunc { } } +func compileMessage( + context interface{}, + recipient rule.Recipient, + target *user.User, +) (*Message, error) { + urn, err := compileTemplate(context, recipient.URN) + if err != nil { + return nil, err + } + + msgs := map[string]string{} + + for lang, tmpl := range recipient.Templates { + msg, err := compileTemplate(context, tmpl) + if err != nil { + return nil, err + } + + msgs[lang] = msg + } + + return &Message{Messages: msgs, Recipient: target.ID, URN: urn}, nil +} + // PipelineEventFunc constructs a Pipeline that by applying the provided rules // outputs Messages. type PipelineEventFunc func( @@ -166,29 +183,24 @@ func PipelineEvent( ParentOwner: parentOwner, } - for _, r := range rules { - if !r.Criteria.Match(change) { + for _, currentRule := range rules { + if !currentRule.Criteria.Match(change) { continue } - for _, recipient := range r.Recipients { + for _, recipient := range currentRule.Recipients { rs, err := recipientsEvent()(currentApp, context, recipient.Query) if err != nil { return nil, err } for _, r := range rs { - urn, err := compileTemplate(context, recipient.URN) - if err != nil { - return nil, err - } - - msg, err := compileTemplate(context, recipient.Templates[language.English.String()]) + msg, err := compileMessage(context, recipient, r) if err != nil { return nil, err } - ms = append(ms, &Message{Message: msg, Recipient: r.ID, URN: urn}) + ms = append(ms, msg) } } } @@ -261,12 +273,12 @@ func PipelineObject( ParentOwner: parentOwner, } - for _, r := range rules { - if !r.Criteria.Match(change) { + for _, currentRule := range rules { + if !currentRule.Criteria.Match(change) { continue } - for _, recipient := range r.Recipients { + for _, recipient := range currentRule.Recipients { rs, err := recipientsObject( connections, objects, @@ -277,17 +289,12 @@ func PipelineObject( } for _, r := range rs { - urn, err := compileTemplate(context, recipient.URN) + msg, err := compileMessage(context, recipient, r) if err != nil { return nil, err } - msg, err := compileTemplate(context, recipient.Templates[language.English.String()]) - if err != nil { - return nil, err - } - - ms = append(ms, &Message{Message: msg, Recipient: r.ID, URN: urn}) + ms = append(ms, msg) } } } @@ -349,29 +356,24 @@ func PipelineReaction( Reaction: r, } - for _, r := range rules { - if !r.Criteria.Match(change) { + for _, currentRule := range rules { + if !currentRule.Criteria.Match(change) { continue } - for _, recipient := range r.Recipients { + for _, recipient := range currentRule.Recipients { rs, err := recipientsReaction()(currentApp, context, recipient.Query) if err != nil { return nil, err } for _, r := range rs { - urn, err := compileTemplate(context, recipient.URN) - if err != nil { - return nil, err - } - - msg, err := compileTemplate(context, recipient.Templates[language.English.String()]) + msg, err := compileMessage(context, recipient, r) if err != nil { return nil, err } - ms = append(ms, &Message{Message: msg, Recipient: r.ID, URN: urn}) + ms = append(ms, msg) } } } diff --git a/core/pipieline_test.go b/core/pipieline_test.go index 1fdc0a7..6d6f8c2 100644 --- a/core/pipieline_test.go +++ b/core/pipieline_test.go @@ -6,12 +6,13 @@ import ( "reflect" "testing" - "github.com/tapglue/snaas/service/reaction" + "golang.org/x/text/language" "github.com/tapglue/snaas/service/app" "github.com/tapglue/snaas/service/connection" "github.com/tapglue/snaas/service/event" "github.com/tapglue/snaas/service/object" + "github.com/tapglue/snaas/service/reaction" "github.com/tapglue/snaas/service/rule" "github.com/tapglue/snaas/service/user" ) @@ -98,7 +99,9 @@ func TestPipelineConnectionCondFrom(t *testing.T) { want := Messages{ { - Message: fmt.Sprintf("%s accepted your friend request", target.Username), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s accepted your friend request", target.Username), + }, Recipient: origin.ID, URN: fmt.Sprintf("tapglue/users/%d", target.ID), }, @@ -176,7 +179,9 @@ func TestPipelineConnectionCondTo(t *testing.T) { want := Messages{ { - Message: fmt.Sprintf("%s sent you a friend request", origin.Username), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s sent you a friend request", origin.Username), + }, Recipient: target.ID, URN: fmt.Sprintf("tapglue/users/%d", origin.ID), }, @@ -256,7 +261,9 @@ func TestPipelineReactionCondParentOwner(t *testing.T) { want := Messages{ { - Message: fmt.Sprintf("%s liked your post", liker.Username), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s liked your post", liker.Username), + }, Recipient: postOwner.ID, URN: fmt.Sprintf("tapglue/users/%d", liker.ID), }, @@ -268,11 +275,6 @@ func TestPipelineReactionCondParentOwner(t *testing.T) { } if !reflect.DeepEqual(have, want) { - for i, m := range have { - fmt.Printf("[%d|%s] %v\n", m.Recipient, m.URN, m.Message[i]) - fmt.Printf("[%d|%s] %v\n\n", want[i].Recipient, want[i].URN, want[i].Message) - } - t.Errorf("have %#v, want %#v", have, want) } } @@ -344,7 +346,9 @@ func TestPipelineEventCondParentOwner(t *testing.T) { want := Messages{ { - Message: fmt.Sprintf("%s liked your post", liker.Username), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s liked your post", liker.Username), + }, Recipient: postOwner.ID, URN: fmt.Sprintf("tapglue/users/%d", liker.ID), }, @@ -356,11 +360,6 @@ func TestPipelineEventCondParentOwner(t *testing.T) { } if !reflect.DeepEqual(have, want) { - for i, m := range have { - fmt.Printf("[%d|%s] %s\n", m.Recipient, m.URN, m.Message) - fmt.Printf("[%d|%s] %s\n\n", want[i].Recipient, want[i].URN, want[i].Message) - } - t.Errorf("have %#v, want %#v", have, want) } } @@ -452,13 +451,17 @@ func TestPipelineObjectCondFriends(t *testing.T) { want := Messages{ { Recipient: friend2.ID, - Message: fmt.Sprintf("%s just added a review", postOwner.Username), - URN: fmt.Sprintf("tapglue/posts/%d", post.ID), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s just added a review", postOwner.Username), + }, + URN: fmt.Sprintf("tapglue/posts/%d", post.ID), }, { Recipient: friend1.ID, - Message: fmt.Sprintf("%s just added a review", postOwner.Username), - URN: fmt.Sprintf("tapglue/posts/%d", post.ID), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s just added a review", postOwner.Username), + }, + URN: fmt.Sprintf("tapglue/posts/%d", post.ID), }, } @@ -556,13 +559,17 @@ func TestPipelineObjectCondObjectOwner(t *testing.T) { want := Messages{ { Recipient: commenter2.ID, - Message: fmt.Sprintf("%s also commented on %ss post", commenter3.Username, postOwner.Username), - URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment3.ID), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s also commented on %ss post", commenter3.Username, postOwner.Username), + }, + URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment3.ID), }, { Recipient: commenter1.ID, - Message: fmt.Sprintf("%s also commented on %ss post", commenter3.Username, postOwner.Username), - URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment3.ID), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s also commented on %ss post", commenter3.Username, postOwner.Username), + }, + URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment3.ID), }, } @@ -636,8 +643,10 @@ func TestPipelineObjectCondOwner(t *testing.T) { want := Messages{ { Recipient: postOwner.ID, - Message: fmt.Sprintf("%s commented on your post", commenter.Username), - URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment.ID), + Messages: map[string]string{ + language.English.String(): fmt.Sprintf("%s commented on your post", commenter.Username), + }, + URN: fmt.Sprintf("tapglue/posts/%d/comments/%d", post.ID, comment.ID), }, } @@ -651,11 +660,6 @@ func TestPipelineObjectCondOwner(t *testing.T) { } if !reflect.DeepEqual(have, want) { - for i, m := range have { - fmt.Printf("[%d|%s] %s\n", m.Recipient, m.URN, m.Message) - fmt.Printf("[%d|%s] %s\n\n", want[i].Recipient, want[i].URN, want[i].Message) - } - t.Errorf("have %#v, want %#v", have, want) } }