50 lines
1.7 KiB
Go
50 lines
1.7 KiB
Go
//go:build windows
|
|||
|
|
|
||
|
|
package notify
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os/exec"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// PowerShellToast raises a Windows toast notification by invoking
|
||
|
|
// PowerShell with an AppId-tagged script — the same mechanism go-toast
|
||
|
|
// uses, without the dependency.
|
||
|
|
type PowerShellToast struct {
|
||
|
|
AppID string
|
||
|
|
}
|
||
|
|
|
||
|
|
// Platform returns the PowerShell toast sender on Windows.
|
||
|
|
func Platform() Sender { return PowerShellToast{AppID: "agent-lib"} }
|
||
|
|
|
||
|
|
var toastScript = `$app = '%[1]s'
|
||
|
|
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
|
||
|
|
$tmpl = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
|
||
|
|
$txt = $tmpl.GetElementsByTagName('text')
|
||
|
|
$txt.Item(0).AppendChild($tmpl.CreateTextNode('%[2]s')) | Out-Null
|
||
|
|
$txt.Item(1).AppendChild($tmpl.CreateTextNode('%[3]s')) | Out-Null
|
||
|
|
$toast = [Windows.UI.Notifications.ToastNotification]::new($tmpl)
|
||
|
|
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($app).Show($toast)`
|
||
|
|
|
||
|
|
// Send fires one toast. It requires an interactive user session; callers
|
||
|
|
// must treat errors as non-fatal.
|
||
|
|
func (p PowerShellToast) Send(title, body string) error {
|
||
|
|
appID := p.AppID
|
||
|
|
if appID == "" {
|
||
|
|
appID = "agent-lib"
|
||
|
|
}
|
||
|
|
script := fmt.Sprintf(toastScript, escape(appID), escape(title), escape(body))
|
||
|
|
cmd := exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", script)
|
||
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||
|
|
return fmt.Errorf("toast failed: %v: %s", err, strings.TrimSpace(string(out)))
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// escape makes s safe inside a PowerShell single-quoted string.
|
||
|
|
func escape(s string) string {
|
||
|
|
r := strings.NewReplacer("'", "''", "\n", " ", "\r", " ")
|
||
|
|
return r.Replace(s)
|
||
|
|
}
|