Browse Source

Handle template substitutions

rxl881/riotbot
Richard Lewis 8 years ago
parent
commit
a7ac44eda9
  1. 62
      src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go
  2. 13
      src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml

62
src/github.com/matrix-org/go-neb/services/riotbot/riotbot.go

@ -2,10 +2,12 @@
package riotbot package riotbot
import ( import (
"bytes"
"io/ioutil" "io/ioutil"
"log" "log"
"path/filepath" "path/filepath"
"runtime" "runtime"
"text/template"
"time" "time"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
@ -22,16 +24,18 @@ type Service struct {
// TutorialFlow represents the tutorial flow / steps // TutorialFlow represents the tutorial flow / steps
type TutorialFlow struct { type TutorialFlow struct {
ResourcesBaseURL string `yaml:"resources_base_url"` ResourcesBaseURL string `yaml:"resources_base_url"`
BotName string `yaml:"bot_name"`
Templates map[string]string `yaml:"templates"`
InitialDelay time.Duration `yaml:"initial_delay"` InitialDelay time.Duration `yaml:"initial_delay"`
Tutorial struct { Tutorial struct {
Steps []struct {
Steps []TutorialStep `yaml:"steps"`
} `yaml:"tutorial"`
}
type TutorialStep struct {
Type string `yaml:"type"` Type string `yaml:"type"`
Body string `yaml:"text"`
Body string `yaml:"body"`
Src string `yaml:"src"` Src string `yaml:"src"`
Delay time.Duration `yaml:"delay"` Delay time.Duration `yaml:"delay"`
} `yaml:"steps"`
} `yaml:"tutorial"`
} }
// ServiceType of the Riotbot service // ServiceType of the Riotbot service
@ -50,16 +54,18 @@ type Tutorial struct {
currentStep int currentStep int
timer *time.Timer timer *time.Timer
cli *gomatrix.Client cli *gomatrix.Client
templates map[string]string
} }
// NewTutorial creates a new Tutorial instance // 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{ t := Tutorial{
roomID: roomID, roomID: roomID,
userID: userID, userID: userID,
currentStep: -1, currentStep: -1,
timer: nil, timer: nil,
cli: cli, cli: cli,
templates: templates,
} }
return t return t
} }
@ -77,6 +83,7 @@ func (t *Tutorial) queueNextStep(delay time.Duration) {
t.timer.Stop() 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 { if delay > 0 {
t.timer = time.NewTimer(time.Millisecond * delay) t.timer = time.NewTimer(time.Millisecond * delay)
<-t.timer.C <-t.timer.C
@ -88,6 +95,7 @@ func (t *Tutorial) queueNextStep(delay time.Duration) {
func (t Tutorial) nextStep() { func (t Tutorial) nextStep() {
t.currentStep++ 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 // Check that there is a valid mtutorial step to process
if t.currentStep < len(tutorialFlow.Tutorial.Steps) { if t.currentStep < len(tutorialFlow.Tutorial.Steps) {
base := tutorialFlow.ResourcesBaseURL base := tutorialFlow.ResourcesBaseURL
@ -95,45 +103,69 @@ func (t Tutorial) nextStep() {
// Check message type // Check message type
switch step.Type { switch step.Type {
case "image": case "image":
body := t.renderBody(step)
msg := gomatrix.ImageMessage{ msg := gomatrix.ImageMessage{
MsgType: "m.image", MsgType: "m.image",
Body: step.Body,
Body: body,
URL: base + step.Src, URL: base + step.Src,
} }
if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil {
log.Print("Failed to send Image message") log.Print("Failed to send Image message")
} else {
log.Printf("Seinding Image message - %s", body)
} }
case "notice": case "notice":
body := t.renderBody(step)
msg := gomatrix.TextMessage{ msg := gomatrix.TextMessage{
MsgType: "m.notice", MsgType: "m.notice",
Body: step.Body,
Body: body,
} }
if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { 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 default: // text
body := t.renderBody(step)
msg := gomatrix.TextMessage{ msg := gomatrix.TextMessage{
MsgType: "m.text", MsgType: "m.text",
Body: step.Body,
Body: body,
} }
if _, e := t.cli.SendMessageEvent(t.roomID, "m.room.message", msg); e != nil { 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 // TODO -- If last step, clean up tutorial instance
// Set up timer for next step // Set up timer for next step
if step.Delay > 0 {
t.timer = time.NewTimer(time.Millisecond * tutorialFlow.InitialDelay)
}
t.queueNextStep(step.Delay)
} else { } else {
log.Println("Tutorial instance ended") log.Println("Tutorial instance ended")
// End of tutorial -- TODO remove tutorial instance // 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: // Commands supported:
// !start // !start
// Starts the tutorial. // 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") log.Print("Existing tutorial instance not found for this user")
// Start a new instance of the riot tutorial // Start a new instance of the riot tutorial
tutorial := NewTutorial(roomID, userID, cli)
tutorial := NewTutorial(roomID, userID, cli, tutorialFlow.Templates)
tutorials = append(tutorials, tutorial) tutorials = append(tutorials, tutorial)
go tutorial.queueNextStep(tutorialFlow.InitialDelay) go tutorial.queueNextStep(tutorialFlow.InitialDelay)
log.Printf("Starting Riot tutorial: %v", tutorial) log.Printf("Starting Riot tutorial: %v", tutorial)

13
src/github.com/matrix-org/go-neb/services/riotbot/tutorial.yml

@ -1,5 +1,6 @@
resources_base_url: "mxc://matrix.org" resources_base_url: "mxc://matrix.org"
bot_name: Riotbot
templates:
BotName: Riotbot
initial_delay: 3000 initial_delay: 3000
tutorial: tutorial:
steps: steps:
@ -11,8 +12,12 @@ tutorial:
- -
type: text type: text
body: "Hi there and welcome to Riot!" body: "Hi there and welcome to Riot!"
delay: 3000
delay: 1000
- -
type: text 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
Loading…
Cancel
Save