1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
package notificator
import (
"fmt"
"os/exec"
"runtime"
"strconv"
"strings"
)
type Options struct {
DefaultIcon string
AppName string
}
const (
UR_NORMAL = "normal"
UR_CRITICAL = "critical"
)
type notifier interface {
push(title string, text string, iconPath string) *exec.Cmd
pushCritical(title string, text string, iconPath string) *exec.Cmd
}
type Notificator struct {
notifier notifier
defaultIcon string
}
func (n Notificator) Push(title string, text string, iconPath string, urgency string) error {
icon := n.defaultIcon
if iconPath != "" {
icon = iconPath
}
if urgency == UR_CRITICAL {
return n.notifier.pushCritical(title, text, icon).Run()
}
return n.notifier.push(title, text, icon).Run()
}
type osxNotificator struct {
AppName string
}
func (o osxNotificator) push(title string, text string, iconPath string) *exec.Cmd {
// Checks if terminal-notifier exists, and is accessible.
// if terminal-notifier exists, use it.
// else, fall back to osascript. (Mavericks and later.)
if CheckTermNotif() {
return exec.Command("terminal-notifier", "-title", o.AppName, "-message", text, "-subtitle", title, "-appIcon", iconPath)
} else if CheckMacOSVersion() {
title = strings.Replace(title, `"`, `\"`, -1)
text = strings.Replace(text, `"`, `\"`, -1)
notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, o.AppName, title)
return exec.Command("osascript", "-e", notification)
}
// finally falls back to growlnotify.
return exec.Command("growlnotify", "-n", o.AppName, "--image", iconPath, "-m", title)
}
// Causes the notification to stick around until clicked.
func (o osxNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
// same function as above...
if CheckTermNotif() {
// timeout set to 30 seconds, to show the importance of the notification
return exec.Command("terminal-notifier", "-title", o.AppName, "-message", text, "-subtitle", title, "-timeout", "30")
} else if CheckMacOSVersion() {
notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, o.AppName, title)
return exec.Command("osascript", "-e", notification)
}
return exec.Command("growlnotify", "-n", o.AppName, "--image", iconPath, "-m", title)
}
type linuxNotificator struct {
AppName string
}
func (l linuxNotificator) push(title string, text string, iconPath string) *exec.Cmd {
return exec.Command("notify-send", "-i", iconPath, title, text, "-a", l.AppName)
}
// Causes the notification to stick around until clicked.
func (l linuxNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
return exec.Command("notify-send", "-i", iconPath, title, text, "-a", l.AppName, "-u", "critical")
}
type windowsNotificator struct{}
func (w windowsNotificator) push(title string, text string, iconPath string) *exec.Cmd {
return exec.Command("growlnotify", "/i:", iconPath, "/t:", title, text)
}
// Causes the notification to stick around until clicked.
func (w windowsNotificator) pushCritical(title string, text string, iconPath string) *exec.Cmd {
return exec.Command("growlnotify", "/i:", iconPath, "/t:", title, text, "/s", "true", "/p", "2")
}
func New(o Options) *Notificator {
var Notifier notifier
switch runtime.GOOS {
case "darwin":
Notifier = osxNotificator{AppName: o.AppName}
case "linux":
Notifier = linuxNotificator{AppName: o.AppName}
case "windows":
Notifier = windowsNotificator{}
}
return &Notificator{notifier: Notifier, defaultIcon: o.DefaultIcon}
}
// Helper function for macOS
func CheckTermNotif() bool {
// Checks if terminal-notifier exists, and is accessible.
if err := exec.Command("which", "terminal-notifier").Run(); err != nil {
return false
}
// no error, so return true. (terminal-notifier exists)
return true
}
func CheckMacOSVersion() bool {
// Checks if the version of macOS is 10.9 or Higher (osascript support for notifications.)
cmd := exec.Command("sw_vers", "-productVersion")
check, _ := cmd.Output()
version := strings.Split(strings.TrimSpace(string(check)), ".")
// semantic versioning of macOS
major, _ := strconv.Atoi(version[0])
minor, _ := strconv.Atoi(version[1])
if major < 10 {
return false
} else if major == 10 && minor < 9 {
return false
} else {
return true
}
}
|