oklahomer/go-sarah

View on GitHub
_examples/simple/plugins/guess/props.go

Summary

Maintainability
A
35 mins
Test Coverage
// Package guess provides an example to set up a stateful command.
//
// This command returns sarah.UserContext as part of sarah.CommandResponse until the user inputs a correct number.
// As long as sarah.UserContext is returned, the next input from the same user is fed to the function defined in sarah.UserContext.
// When the user guesses the right number or inputs .abort, the user context is removed and the user is free to input the next desired command.
//
// This example uses an in-memory storage to store user contexts.
// See https://github.com/oklahomer/go-sarah-rediscontext to use external storage.
package guess

import (
    "context"
    "github.com/oklahomer/go-sarah/v4"
    "github.com/oklahomer/go-sarah/v4/slack"
    "math/rand"
    "strconv"
    "strings"
    "time"
)

func init() {
    sarah.RegisterCommandProps(SlackProps)
}

// SlackProps is a pre-built guess command properties for Slack.
var SlackProps = sarah.NewCommandPropsBuilder().
    BotType(slack.SLACK).
    Identifier("guess").
    Instruction("Input .guess to start a game.").
    MatchFunc(func(input sarah.Input) bool {
        return strings.HasPrefix(strings.TrimSpace(input.Message()), ".guess")
    }).
    Func(func(ctx context.Context, input sarah.Input) (*sarah.CommandResponse, error) {
        // Generate an answer value at the very beginning.
        rand.Seed(time.Now().UnixNano())
        answer := rand.Intn(10)

        // Let the user guess the right answer.
        return slack.NewResponse(
            input,
            "Input number.",
            slack.RespWithNext(func(c context.Context, i sarah.Input) (*sarah.CommandResponse, error) {
                return guessFunc(c, i, answer)
            }),
            slack.RespAsThreadReply(true),
        )
    }).
    MustBuild()

func guessFunc(_ context.Context, input sarah.Input, answer int) (*sarah.CommandResponse, error) {
    // For handiness, create a function that recursively calls guessFunc until the user inputs the right answer.
    retry := func(c context.Context, i sarah.Input) (*sarah.CommandResponse, error) {
        return guessFunc(c, i, answer)
    }

    // See if the user inputs a valid number.
    guess, err := strconv.Atoi(strings.TrimSpace(input.Message()))
    if err != nil {
        return slack.NewResponse(input, "Invalid input format.", slack.RespWithNext(retry), slack.RespAsThreadReply(true))
    }

    // If the guess is right, tell the user and finish the current user context.
    // Otherwise, let the user input the next guess with a bit of a hint.
    if guess == answer {
        return slack.NewResponse(input, "Correct!", slack.RespAsThreadReply(true))
    } else if guess > answer {
        return slack.NewResponse(input, "Smaller!", slack.RespWithNext(retry), slack.RespAsThreadReply(true))
    } else {
        return slack.NewResponse(input, "Bigger!", slack.RespWithNext(retry), slack.RespAsThreadReply(true))
    }
}