From a7ac44eda962b13c9a833295c3559a814569679a Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 12 Apr 2017 14:06:30 +0100 Subject: [PATCH] Handle template substitutions --- .../go-neb/services/riotbot/riotbot.go | 70 ++++++++++++++----- .../go-neb/services/riotbot/tutorial.yml | 13 ++-- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go b/src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go index a35329c..7f2d08d 100644 --- a/src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go +++ b/src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go @@ -2,10 +2,12 @@ package riotbot import ( + "bytes" "io/ioutil" "log" "path/filepath" "runtime" + "text/template" "time" yaml "gopkg.in/yaml.v2" @@ -21,19 +23,21 @@ type Service struct { // TutorialFlow represents the tutorial flow / steps type TutorialFlow struct { - ResourcesBaseURL string `yaml:"resources_base_url"` - BotName string `yaml:"bot_name"` - InitialDelay time.Duration `yaml:"initial_delay"` + ResourcesBaseURL string `yaml:"resources_base_url"` + Templates map[string]string `yaml:"templates"` + InitialDelay time.Duration `yaml:"initial_delay"` Tutorial struct { - Steps []struct { - Type string `yaml:"type"` - Body string `yaml:"text"` - Src string `yaml:"src"` - Delay time.Duration `yaml:"delay"` - } `yaml:"steps"` + Steps []TutorialStep `yaml:"steps"` } `yaml:"tutorial"` } +type TutorialStep struct { + Type string `yaml:"type"` + Body string `yaml:"body"` + Src string `yaml:"src"` + Delay time.Duration `yaml:"delay"` +} + // ServiceType of the Riotbot service const ServiceType = "riotbot" @@ -50,16 +54,18 @@ type Tutorial struct { currentStep int timer *time.Timer cli *gomatrix.Client + templates map[string]string } // NewTutorial creates a new Tutorial instance -func NewTutorial(roomID string, userID string, cli *gomatrix.Client) Tutorial { +func NewTutorial(roomID string, userID string, cli *gomatrix.Client, templates map[string]string) Tutorial { t := Tutorial{ roomID: roomID, userID: userID, currentStep: -1, timer: nil, cli: cli, + templates: templates, } return t } @@ -77,6 +83,7 @@ func (t *Tutorial) queueNextStep(delay time.Duration) { t.timer.Stop() } + log.Printf("Queueing next step of tutorial for user %s (current step %d) to run in %dms", t.userID, t.currentStep, delay) if delay > 0 { t.timer = time.NewTimer(time.Millisecond * delay) <-t.timer.C @@ -88,6 +95,7 @@ func (t *Tutorial) queueNextStep(delay time.Duration) { func (t Tutorial) nextStep() { t.currentStep++ + log.Printf("Performing next step (%d) of tutorial for %s", t.currentStep, t.userID) // Check that there is a valid mtutorial step to process if t.currentStep < len(tutorialFlow.Tutorial.Steps) { base := tutorialFlow.ResourcesBaseURL @@ -95,45 +103,69 @@ func (t Tutorial) nextStep() { // Check message type switch step.Type { case "image": + body := t.renderBody(step) msg := gomatrix.ImageMessage{ MsgType: "m.image", - Body: step.Body, + Body: body, URL: base + step.Src, } if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { log.Print("Failed to send Image message") + } else { + log.Printf("Seinding Image message - %s", body) } case "notice": + body := t.renderBody(step) msg := gomatrix.TextMessage{ MsgType: "m.notice", - Body: step.Body, + Body: body, } if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { - log.Printf("Failed to send Notice message - %s", step.Body) + log.Printf("Failed to send Notice message - %s", body) + } else { + log.Printf("Seinding Notice message - %s", body) } default: // text + body := t.renderBody(step) msg := gomatrix.TextMessage{ MsgType: "m.text", - Body: step.Body, + Body: body, } if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { - log.Printf("Failed to send Text message - %s", step.Body) + log.Printf("Failed to send Text message - %s", body) + } else { + log.Printf("Seinding Text message - %s", body) } } // TODO -- If last step, clean up tutorial instance // Set up timer for next step - if step.Delay > 0 { - t.timer = time.NewTimer(time.Millisecond * tutorialFlow.InitialDelay) - } + t.queueNextStep(step.Delay) } else { log.Println("Tutorial instance ended") // End of tutorial -- TODO remove tutorial instance } } +func (t Tutorial) renderBody(ts TutorialStep) string { + if ts.Body != "" { + tmpl, err := template.New("message").Parse(ts.Body) + if err != nil { + log.Print("Failed to create message template") + } + var msg bytes.Buffer + if err = tmpl.Execute(&msg, t.templates); err != nil { + log.Print("Failed to execute template substitution") + return "" + } + return msg.String() + } + + return "" +} + // Commands supported: // !start // Starts the tutorial. @@ -162,7 +194,7 @@ func initTutorialFlow(cli *gomatrix.Client, roomID string, userID string) string log.Print("Existing tutorial instance not found for this user") // Start a new instance of the riot tutorial - tutorial := NewTutorial(roomID, userID, cli) + tutorial := NewTutorial(roomID, userID, cli, tutorialFlow.Templates) tutorials = append(tutorials, tutorial) go tutorial.queueNextStep(tutorialFlow.InitialDelay) log.Printf("Starting Riot tutorial: %v", tutorial) diff --git a/src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml b/src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml index 8bc4083..8dc8b6a 100644 --- a/src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml +++ b/src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml @@ -1,5 +1,6 @@ resources_base_url: "mxc://matrix.org" -bot_name: Riotbot +templates: + BotName: Riotbot initial_delay: 3000 tutorial: steps: @@ -11,8 +12,12 @@ tutorial: - type: text body: "Hi there and welcome to Riot!" - delay: 3000 + delay: 1000 - type: text - body: "My name is {bot_name} and I am here to help you to get started using Riot!" - delay: 3000 + body: "My name is {{.BotName}} and I am here to help you to get started using Riot!" + delay: 1000 + - + type: text + body: "Before we get started... What is your name?" + delay: 1000