134 lines
3.2 KiB
Go
134 lines
3.2 KiB
Go
package send
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/nicholas-fedor/shoutrrr/internal/dedupe"
|
|
internalUtil "github.com/nicholas-fedor/shoutrrr/internal/util"
|
|
"github.com/nicholas-fedor/shoutrrr/pkg/router"
|
|
"github.com/nicholas-fedor/shoutrrr/pkg/types"
|
|
"github.com/nicholas-fedor/shoutrrr/pkg/util"
|
|
cli "github.com/nicholas-fedor/shoutrrr/shoutrrr/cmd"
|
|
)
|
|
|
|
// MaximumNArgs defines the maximum number of arguments accepted by the command.
|
|
const (
|
|
MaximumNArgs = 2
|
|
MaxMessageLength = 100
|
|
)
|
|
|
|
// Cmd sends a notification using a service URL.
|
|
var Cmd = &cobra.Command{
|
|
Use: "send",
|
|
Short: "Send a notification using a service url",
|
|
Args: cobra.MaximumNArgs(MaximumNArgs),
|
|
PreRun: internalUtil.LoadFlagsFromAltSources,
|
|
RunE: Run,
|
|
}
|
|
|
|
func init() {
|
|
Cmd.Flags().BoolP("verbose", "v", false, "")
|
|
Cmd.Flags().StringArrayP("url", "u", []string{}, "The notification url")
|
|
_ = Cmd.MarkFlagRequired("url")
|
|
Cmd.Flags().
|
|
StringP("message", "m", "", "The message to send to the notification url, or - to read message from stdin")
|
|
|
|
_ = Cmd.MarkFlagRequired("message")
|
|
Cmd.Flags().StringP("title", "t", "", "The title used for services that support it")
|
|
}
|
|
|
|
func logf(format string, a ...any) {
|
|
fmt.Fprintf(os.Stderr, format+"\n", a...)
|
|
}
|
|
|
|
func run(cmd *cobra.Command) error {
|
|
flags := cmd.Flags()
|
|
verbose, _ := flags.GetBool("verbose")
|
|
|
|
urls, _ := flags.GetStringArray("url")
|
|
urls = dedupe.RemoveDuplicates(urls)
|
|
message, _ := flags.GetString("message")
|
|
title, _ := flags.GetString("title")
|
|
|
|
if message == "-" {
|
|
logf("Reading from STDIN...")
|
|
|
|
stringBuilder := strings.Builder{}
|
|
|
|
count, err := io.Copy(&stringBuilder, os.Stdin)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read message from stdin: %w", err)
|
|
}
|
|
|
|
logf("Read %d byte(s)", count)
|
|
|
|
message = stringBuilder.String()
|
|
}
|
|
|
|
var logger *log.Logger
|
|
|
|
if verbose {
|
|
urlsPrefix := "URLs:"
|
|
for i, url := range urls {
|
|
logf("%s %s", urlsPrefix, url)
|
|
|
|
if i == 0 {
|
|
// Only display "URLs:" prefix for first line, replace with indentation for the subsequent
|
|
urlsPrefix = strings.Repeat(" ", len(urlsPrefix))
|
|
}
|
|
}
|
|
|
|
logf("Message: %s", util.Ellipsis(message, MaxMessageLength))
|
|
|
|
if title != "" {
|
|
logf("Title: %v", title)
|
|
}
|
|
|
|
logger = log.New(os.Stderr, "SHOUTRRR ", log.LstdFlags)
|
|
} else {
|
|
logger = util.DiscardLogger
|
|
}
|
|
|
|
serviceRouter, err := router.New(logger, urls...)
|
|
if err != nil {
|
|
return cli.ConfigurationError(fmt.Sprintf("error invoking send: %s", err))
|
|
}
|
|
|
|
params := make(types.Params)
|
|
if title != "" {
|
|
params["title"] = title
|
|
}
|
|
|
|
errs := serviceRouter.SendAsync(message, ¶ms)
|
|
for err := range errs {
|
|
if err != nil {
|
|
return cli.TaskUnavailable(err.Error())
|
|
}
|
|
|
|
logf("Notification sent")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Run executes the send command and handles its result.
|
|
func Run(cmd *cobra.Command, _ []string) error {
|
|
err := run(cmd)
|
|
if err != nil {
|
|
var result cli.Result
|
|
if errors.As(err, &result) && result.ExitCode != cli.ExUsage {
|
|
// If the error is not related to CLI usage, report error and exit to avoid cobra error output
|
|
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
|
os.Exit(result.ExitCode)
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|