diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3322622 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +# Sox environment variables + +# Port to listen on (default: 4567) +PORT=4567 + +# Base URL of your Campfire instance (used by the timer command to post notifications) +CAMPFIRE_URL=https://your-campfire-instance.example.com + +# Token used in the notification POST URL path +CAMPFIRE_TOKEN=your_token_here diff --git a/cmd_timer.go b/cmd_timer.go new file mode 100644 index 0000000..89fbcd0 --- /dev/null +++ b/cmd_timer.go @@ -0,0 +1,61 @@ +package main + +import ( + "fmt" + "io" + "log" + "net/http" + "os" + "strings" + "time" +) + +type TimerPlugin struct{} + +func (p TimerPlugin) Name() string { return "timer" } + +func (p TimerPlugin) ShortHelp() string { return "set a timer" } + +func (p TimerPlugin) DetailedHelp() string { + return "Usage: timer \nSets a timer. When it goes off, posts a message to the room.\nExamples: timer 5m, timer 1h30m, timer 90s" +} + +func (p TimerPlugin) Execute(msg BotMessage, args string) string { + d, err := time.ParseDuration(strings.TrimSpace(args)) + if err != nil || d <= 0 { + return "Usage: timer <duration> (e.g. timer 5m, timer 1h30m)" + } + + if os.Getenv("CAMPFIRE_URL") == "" || os.Getenv("CAMPFIRE_TOKEN") == "" { + return "Cannot set timer: CAMPFIRE_URL and CAMPFIRE_TOKEN must be configured." + } + + firesAt := time.Now().Add(d) + + go func() { + time.Sleep(d) + sendTimerNotification(msg, d) + }() + + return fmt.Sprintf("Timer set for %s. Will go off at %s.", d, firesAt.Format("15:04:05")) +} + +func sendTimerNotification(msg BotMessage, d time.Duration) { + baseURL := os.Getenv("CAMPFIRE_URL") + token := os.Getenv("CAMPFIRE_TOKEN") + if baseURL == "" || token == "" { + log.Println("timer: CAMPFIRE_URL or CAMPFIRE_TOKEN not set, cannot send notification") + return + } + + url := fmt.Sprintf("%s/rooms/%d/%s/messages", baseURL, msg.Room.ID, token) + body := fmt.Sprintf("%s your %s timer is done!", msg.User.Name, d) + + resp, err := http.Post(url, "text/plain", strings.NewReader(body)) + if err != nil { + log.Printf("timer: failed to send notification: %v", err) + return + } + defer resp.Body.Close() + io.Copy(io.Discard, resp.Body) +} diff --git a/flake.nix b/flake.nix index df15ee7..6b20c38 100644 --- a/flake.nix +++ b/flake.nix @@ -61,7 +61,7 @@ in { default = pkgs.mkShell { - buildInputs = with pkgs; [ go gopls gotools go-tools ]; + buildInputs = with pkgs; [ go gopls gotools go-tools libqalculate ]; }; }); diff --git a/go.mod b/go.mod index bf83753..d3db718 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module sox go 1.22.0 + +require github.com/joho/godotenv v1.5.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d61b19e --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/main.go b/main.go index 3bbe436..450595f 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,8 @@ import ( "fmt" "net/http" "os" + + "github.com/joho/godotenv" ) type BotMessage struct { @@ -35,9 +37,11 @@ func init() { registerPlugin(HiPlugin{}) registerPlugin(TracePlugin{}) registerPlugin(HelpPlugin{}) + registerPlugin(TimerPlugin{}) } func main() { + godotenv.Load() fmt.Println("Sox started") http.HandleFunc("/", commandHandler)