mirror of https://github.com/statping/statping
notifications!!!
parent
d8a02b31a2
commit
12275f7522
|
@ -1,13 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/groups"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/types/incidents"
|
||||
"github.com/statping/statping/types/messages"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
)
|
||||
|
@ -18,5 +18,5 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifiers.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package core
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/services"
|
||||
)
|
||||
|
||||
func InitApp() error {
|
||||
if _, err := Select(); err != nil {
|
||||
if _, err := core.Select(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -16,7 +18,9 @@ func InitApp() error {
|
|||
|
||||
go services.CheckServices()
|
||||
|
||||
notifiers.InitNotifiers()
|
||||
|
||||
database.StartMaintenceRoutine()
|
||||
App.Setup = true
|
||||
core.App.Setup = true
|
||||
return nil
|
||||
}
|
14
cmd/main.go
14
cmd/main.go
|
@ -19,7 +19,6 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
@ -30,7 +29,6 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/statping/statping/handlers"
|
||||
"github.com/statping/statping/types/configs"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
)
|
||||
|
@ -165,11 +163,11 @@ func main() {
|
|||
exit(err)
|
||||
}
|
||||
|
||||
log.Infoln("Migrating Notifiers...")
|
||||
if err := notifiers.Migrate(); err != nil {
|
||||
exit(errors.Wrap(err, "error migrating notifiers"))
|
||||
}
|
||||
log.Infoln("Notifiers Migrated")
|
||||
//log.Infoln("Migrating Notifiers...")
|
||||
//if err := notifier.Migrate(); err != nil {
|
||||
// exit(errors.Wrap(err, "error migrating notifiers"))
|
||||
//}
|
||||
//log.Infoln("Notifiers Migrated")
|
||||
|
||||
if err := mainProcess(); err != nil {
|
||||
exit(err)
|
||||
|
@ -205,7 +203,7 @@ func mainProcess() error {
|
|||
return errors.Wrap(err, errStr)
|
||||
}
|
||||
|
||||
if err := core.InitApp(); err != nil {
|
||||
if err := InitApp(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
{{if USING_ASSETS}}
|
||||
<link href="css/vendor.css" rel="stylesheet">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
<link href="css/base.css" rel="stylesheet">
|
||||
<link href="css/main.css" rel="stylesheet">
|
||||
{{else}}
|
||||
<% _.each(htmlWebpackPlugin.tags.headTags, function(headTag) { %>
|
||||
<%= headTag %> <% }) %>
|
||||
|
|
|
@ -94,8 +94,8 @@ export default {
|
|||
this.form[field] = this.notifier[field]
|
||||
});
|
||||
await Api.notifier_save(this.form)
|
||||
const notifiers = await Api.notifiers()
|
||||
await this.$store.commit('setNotifiers', notifiers)
|
||||
// const notifiers = await Api.notifiers()
|
||||
// await this.$store.commit('setNotifiers', notifiers)
|
||||
this.saved = true
|
||||
this.loading = false
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -19,12 +19,12 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/groups"
|
||||
"github.com/statping/statping/types/incidents"
|
||||
"github.com/statping/statping/types/messages"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
|
@ -143,7 +143,7 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht
|
|||
case *services.Service:
|
||||
objName = "service"
|
||||
objId = v.Id
|
||||
case *notifiers.Notification:
|
||||
case *notifications.Notification:
|
||||
objName = "notifier"
|
||||
objId = v.Id
|
||||
case *core.Core:
|
||||
|
|
|
@ -1,42 +1,43 @@
|
|||
// Statping
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//// Statping
|
||||
//// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
//// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
////
|
||||
//// https://github.com/statping/statping
|
||||
////
|
||||
//// The licenses for most software and other practical works are designed
|
||||
//// to take away your freedom to share and change the works. By contrast,
|
||||
//// the GNU General Public License is intended to guarantee your freedom to
|
||||
//// share and change all versions of a program--to make sure it remains free
|
||||
//// software for all its users.
|
||||
////
|
||||
//// You should have received a copy of the GNU General Public License
|
||||
//// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// https://github.com/statping/statping
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var notifs []notifiers.Notifier
|
||||
all := notifiers.All()
|
||||
for _, v := range all {
|
||||
notifs = append(notifs, v)
|
||||
notifiers := services.AllNotifiers()
|
||||
var notifs []*notifications.Notification
|
||||
for _, n := range notifiers {
|
||||
notifs = append(notifs, n.Select())
|
||||
}
|
||||
returnJson(notifs, w, r)
|
||||
}
|
||||
|
||||
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
notifier, err := notifiers.Find(vars["notifier"])
|
||||
notifier, err := notifications.Find(vars["notifier"])
|
||||
if err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
|
@ -46,11 +47,12 @@ func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
notifer, err := notifiers.Find(vars["notifier"])
|
||||
notifer, err := notifications.Find(vars["notifier"])
|
||||
if err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err = decoder.Decode(¬ifer)
|
||||
|
@ -83,7 +85,7 @@ func testNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
apiSecret := form.Get("api_secret")
|
||||
limits := int(utils.ToInt(form.Get("limits")))
|
||||
|
||||
notifier, err := notifiers.Find(method)
|
||||
notifier, err := notifications.Find(method)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("issue saving notifier %v: %v", method, err))
|
||||
sendErrorJson(err, w, r)
|
||||
|
|
|
@ -17,7 +17,6 @@ package handlers
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
|
@ -104,25 +103,22 @@ func prometheusHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
}
|
||||
|
||||
for _, n := range notifiers.All() {
|
||||
for _, n := range services.AllNotifiers() {
|
||||
notif := n.Select()
|
||||
PrometheusComment(fmt.Sprintf("Notifier %s:", notif.Method))
|
||||
enabled := 0
|
||||
if notif.Enabled.Bool {
|
||||
enabled = 1
|
||||
PrometheusExportKey("notifier_on_success", notif.Id, notif.Method, notif.Hits.OnSuccess)
|
||||
PrometheusExportKey("notifier_on_failure", notif.Id, notif.Method, notif.Hits.OnFailure)
|
||||
PrometheusExportKey("notifier_on_user_new", notif.Id, notif.Method, notif.Hits.OnNewUser)
|
||||
PrometheusExportKey("notifier_on_user_update", notif.Id, notif.Method, notif.Hits.OnUpdatedUser)
|
||||
PrometheusExportKey("notifier_on_user_delete", notif.Id, notif.Method, notif.Hits.OnDeletedUser)
|
||||
PrometheusExportKey("notifier_on_service_new", notif.Id, notif.Method, notif.Hits.OnNewService)
|
||||
PrometheusExportKey("notifier_on_service_update", notif.Id, notif.Method, notif.Hits.OnUpdatedService)
|
||||
PrometheusExportKey("notifier_on_service_delete", notif.Id, notif.Method, notif.Hits.OnDeletedService)
|
||||
PrometheusExportKey("notifier_on_notifier_new", notif.Id, notif.Method, notif.Hits.OnNewNotifier)
|
||||
PrometheusExportKey("notifier_on_notifier_update", notif.Id, notif.Method, notif.Hits.OnUpdatedNotifier)
|
||||
PrometheusExportKey("notifier_on_notifier_save", notif.Id, notif.Method, notif.Hits.OnSave)
|
||||
}
|
||||
PrometheusExportKey("notifier_enabled", notif.Id, notif.Method, enabled)
|
||||
PrometheusExportKey("notifier_on_success", notif.Id, notif.Method, notif.Hits.OnSuccess)
|
||||
PrometheusExportKey("notifier_on_failure", notif.Id, notif.Method, notif.Hits.OnFailure)
|
||||
PrometheusExportKey("notifier_on_user_new", notif.Id, notif.Method, notif.Hits.OnNewUser)
|
||||
PrometheusExportKey("notifier_on_user_update", notif.Id, notif.Method, notif.Hits.OnUpdatedUser)
|
||||
PrometheusExportKey("notifier_on_user_delete", notif.Id, notif.Method, notif.Hits.OnDeletedUser)
|
||||
PrometheusExportKey("notifier_on_service_new", notif.Id, notif.Method, notif.Hits.OnNewService)
|
||||
PrometheusExportKey("notifier_on_service_update", notif.Id, notif.Method, notif.Hits.OnUpdatedService)
|
||||
PrometheusExportKey("notifier_on_service_delete", notif.Id, notif.Method, notif.Hits.OnDeletedService)
|
||||
PrometheusExportKey("notifier_on_notifier_new", notif.Id, notif.Method, notif.Hits.OnNewNotifier)
|
||||
PrometheusExportKey("notifier_on_notifier_update", notif.Id, notif.Method, notif.Hits.OnUpdatedNotifier)
|
||||
PrometheusExportKey("notifier_on_notifier_save", notif.Id, notif.Method, notif.Hits.OnSave)
|
||||
}
|
||||
|
||||
PrometheusComment("HTTP Metrics")
|
||||
|
|
|
@ -17,10 +17,10 @@ package handlers
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/configs"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -89,11 +89,11 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
log.Infoln("Migrating Notifiers...")
|
||||
if err := notifiers.Migrate(); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
//log.Infoln("Migrating Notifiers...")
|
||||
//if err := notifications.Migrate(); err != nil {
|
||||
// sendErrorJson(err, w, r)
|
||||
// return
|
||||
//}
|
||||
|
||||
c := &core.Core{
|
||||
Name: "Statping Sample Data",
|
||||
|
@ -117,12 +117,17 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
core.App = c
|
||||
|
||||
log.Infoln("Initializing new Statping instance")
|
||||
if err := core.InitApp(); err != nil {
|
||||
|
||||
if _, err := services.SelectAllServices(true); err != nil {
|
||||
log.Errorln(err)
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
go services.CheckServices()
|
||||
|
||||
core.App.Setup = true
|
||||
|
||||
CacheStorage.Delete("/")
|
||||
resetCookies()
|
||||
time.Sleep(1 * time.Second)
|
||||
|
|
|
@ -16,21 +16,26 @@
|
|||
package notifiers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*commandLine)(nil)
|
||||
var _ notifier.Notifier = (*commandLine)(nil)
|
||||
|
||||
type commandLine struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Command = &commandLine{&Notification{
|
||||
func (c *commandLine) Select() *notifications.Notification {
|
||||
return c.Notification
|
||||
}
|
||||
|
||||
var Command = &commandLine{¬ifications.Notification{
|
||||
Method: "command",
|
||||
Title: "Shell Command",
|
||||
Description: "Shell Command allows you to run a customized shell/bash Command on the local machine it's running on.",
|
||||
|
@ -39,7 +44,7 @@ var Command = &commandLine{&Notification{
|
|||
Delay: time.Duration(1 * time.Second),
|
||||
Icon: "fas fa-terminal",
|
||||
Host: "/bin/bash",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Shell or Bash",
|
||||
Placeholder: "/bin/bash",
|
||||
|
@ -65,28 +70,18 @@ func runCommand(app string, cmd ...string) (string, string, error) {
|
|||
return outStr, errStr, err
|
||||
}
|
||||
|
||||
func (u *commandLine) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// OnFailure for commandLine will trigger failing service
|
||||
func (u *commandLine) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), u.Var2)
|
||||
func (u *commandLine) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := u.GetValue("host")
|
||||
_, _, err := runCommand(u.Host, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// OnSuccess for commandLine will trigger successful service
|
||||
func (u *commandLine) OnSuccess(s *services.Service) {
|
||||
if !s.Online {
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), u.Var1)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave for commandLine triggers when this notifier has been saved
|
||||
func (u *commandLine) OnSave() error {
|
||||
u.AddQueue("saved", u.Var1)
|
||||
u.AddQueue("saved", u.Var2)
|
||||
return nil
|
||||
func (u *commandLine) OnSuccess(s *services.Service) error {
|
||||
msg := u.GetValue("host")
|
||||
_, _, err := runCommand(u.Host, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// OnTest for commandLine triggers when this notifier has been saved
|
||||
|
@ -97,10 +92,3 @@ func (u *commandLine) OnTest() error {
|
|||
utils.Log.Infoln(out)
|
||||
return err
|
||||
}
|
||||
|
||||
// Send for commandLine will send message to expo Command push notifications endpoint
|
||||
func (u *commandLine) Send(msg interface{}) error {
|
||||
cmd := msg.(string)
|
||||
_, _, err := runCommand(u.Host, cmd)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,19 +21,21 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*discord)(nil)
|
||||
var _ notifier.Notifier = (*discord)(nil)
|
||||
|
||||
type discord struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Discorder = &discord{&Notification{
|
||||
var Discorder = &discord{¬ifications.Notification{
|
||||
Method: "discord",
|
||||
Title: "discord",
|
||||
Description: "Send notifications to your discord channel using discord webhooks. Insert your discord channel Webhook URL to receive notifications. Based on the <a href=\"https://discordapp.com/developers/docs/resources/Webhook\">discord webhooker API</a>.",
|
||||
|
@ -42,7 +44,7 @@ var Discorder = &discord{&Notification{
|
|||
Delay: time.Duration(5 * time.Second),
|
||||
Host: "https://discordapp.com/api/webhooks/****/*****",
|
||||
Icon: "fab fa-discord",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "discord webhooker URL",
|
||||
Placeholder: "Insert your Webhook URL here",
|
||||
|
@ -51,38 +53,25 @@ var Discorder = &discord{&Notification{
|
|||
}
|
||||
|
||||
// Send will send a HTTP Post to the discord API. It accepts type: []byte
|
||||
func (u *discord) Send(msg interface{}) error {
|
||||
message := msg.(string)
|
||||
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(message), time.Duration(10*time.Second), true)
|
||||
func (u *discord) sendRequest(msg string) error {
|
||||
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *discord) Select() *Notification {
|
||||
func (u *discord) Select() *notifications.Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *discord) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *discord) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := fmt.Sprintf(`{"content": "Your service '%v' is currently failing! Reason: %v"}`, s.Name, f.Issue)
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
return u.sendRequest(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *discord) OnSuccess(s *services.Service) {
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
var msg interface{}
|
||||
msg = s.DownText
|
||||
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *discord) OnSave() error {
|
||||
msg := fmt.Sprintf(`{"content": "The discord notifier on Statping was just updated."}`)
|
||||
u.AddQueue("saved", msg)
|
||||
return nil
|
||||
func (u *discord) OnSuccess(s *services.Service) error {
|
||||
msg := fmt.Sprintf(`{"content": "Your service '%s' is currently online!"}`, s.Name)
|
||||
return u.sendRequest(msg)
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
// Package notifiers holds all the notifiers for Statping, which also includes
|
||||
// user created notifiers that have been accepted in a Push Request. Read the wiki
|
||||
// to see a full example of a notifier with all events, visit Statping's
|
||||
// notifier example code: https://github.com/statping/statping/wiki/Notifier-Example
|
||||
//
|
||||
// This package shouldn't contain any exports, to see how notifiers work
|
||||
// visit the core/notifier package at: https://godoc.org/github.com/statping/statping/core/notifier
|
||||
// and learn how to create your own custom notifier.
|
||||
package notifiers
|
|
@ -21,6 +21,8 @@ import (
|
|||
"fmt"
|
||||
"github.com/go-mail/mail"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
|
@ -28,7 +30,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*email)(nil)
|
||||
var _ notifier.Notifier = (*emailer)(nil)
|
||||
|
||||
const (
|
||||
mainEmailTemplate = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
@ -110,18 +112,22 @@ var (
|
|||
mailer *mail.Dialer
|
||||
)
|
||||
|
||||
type email struct {
|
||||
*Notification
|
||||
type emailer struct {
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Emailer = &email{&Notification{
|
||||
func (e *emailer) Select() *notifications.Notification {
|
||||
return e.Notification
|
||||
}
|
||||
|
||||
var email = &emailer{¬ifications.Notification{
|
||||
Method: "email",
|
||||
Title: "email",
|
||||
Description: "Send emails via SMTP when services are online or offline.",
|
||||
Author: "Hunter Long",
|
||||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Icon: "far fa-envelope",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "SMTP Host",
|
||||
Placeholder: "Insert your SMTP Host here.",
|
||||
|
@ -157,17 +163,7 @@ var Emailer = &email{&Notification{
|
|||
Placeholder: "",
|
||||
SmallText: "To Disable TLS/SSL insert 'true'",
|
||||
DbField: "api_key",
|
||||
}},
|
||||
}}
|
||||
|
||||
// Send will send the SMTP email with your authentication It accepts type: *emailOutgoing
|
||||
func (u *email) Send(msg interface{}) error {
|
||||
email := msg.(*emailOutgoing)
|
||||
err := u.dialSend(email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}}},
|
||||
}
|
||||
|
||||
type emailOutgoing struct {
|
||||
|
@ -181,7 +177,7 @@ type emailOutgoing struct {
|
|||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *email) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *emailer) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
email := &emailOutgoing{
|
||||
To: u.Var2,
|
||||
Subject: fmt.Sprintf("Service %v is Failing", s.Name),
|
||||
|
@ -189,40 +185,24 @@ func (u *email) OnFailure(s *services.Service, f *failures.Failure) {
|
|||
Data: interface{}(s),
|
||||
From: u.Var1,
|
||||
}
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), email)
|
||||
return u.dialSend(email)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *email) OnSuccess(s *services.Service) {
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
var msg string
|
||||
msg = s.DownText
|
||||
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
email := &emailOutgoing{
|
||||
To: u.Var2,
|
||||
Subject: msg,
|
||||
Template: mainEmailTemplate,
|
||||
Data: interface{}(s),
|
||||
From: u.Var1,
|
||||
}
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), email)
|
||||
func (u *emailer) OnSuccess(s *services.Service) error {
|
||||
msg := s.DownText
|
||||
email := &emailOutgoing{
|
||||
To: u.Var2,
|
||||
Subject: msg,
|
||||
Template: mainEmailTemplate,
|
||||
Data: interface{}(s),
|
||||
From: u.Var1,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *email) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *email) OnSave() error {
|
||||
utils.Log.Infoln(fmt.Sprintf("Notification %v is receiving updated information.", u.Method))
|
||||
// Do updating stuff here
|
||||
return nil
|
||||
return u.dialSend(email)
|
||||
}
|
||||
|
||||
// OnTest triggers when this notifier has been saved
|
||||
func (u *email) OnTest() error {
|
||||
func (u *emailer) OnTest() error {
|
||||
testService := &services.Service{
|
||||
Id: 1,
|
||||
Name: "Example Service",
|
||||
|
@ -247,8 +227,8 @@ func (u *email) OnTest() error {
|
|||
return u.dialSend(email)
|
||||
}
|
||||
|
||||
func (u *email) dialSend(email *emailOutgoing) error {
|
||||
mailer = mail.NewDialer(Emailer.Host, Emailer.Port, Emailer.Username, Emailer.Password)
|
||||
func (u *emailer) dialSend(email *emailOutgoing) error {
|
||||
mailer = mail.NewDialer(u.Host, u.Port, u.Username, u.Password)
|
||||
emailSource(email)
|
||||
m := mail.NewMessage()
|
||||
// if email setting TLS is Disabled
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
// Statping
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/statping/statping
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
"github.com/statping/statping/utils"
|
||||
)
|
||||
|
||||
// OnSave will trigger a notifier when it has been saved - Notifier interface
|
||||
func OnSave(method string) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(Notifier)) {
|
||||
notifier := comm.Select()
|
||||
if notifier.Method == method {
|
||||
comm.OnSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnFailure will be triggered when a service is failing - BasicEvents interface
|
||||
func OnFailure(s *services.Service, f *failures.Failure) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
|
||||
// check if User wants to receive every Status Change
|
||||
if s.UpdateNotify.Bool {
|
||||
// send only if User hasn't been already notified about the Downtime
|
||||
if !s.UserNotified {
|
||||
s.UserNotified = true
|
||||
goto sendMessages
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sendMessages:
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (s.Online || inLimits(comm)) {
|
||||
notifier := comm.(*Notification)
|
||||
log.
|
||||
WithField("trigger", "OnFailure").
|
||||
WithFields(utils.ToFields(notifier, s)).Debugln(fmt.Sprintf("Sending [OnFailure] '%v' notification for service %v", notifier.Method, s.Name))
|
||||
comm.(BasicEvents).OnFailure(s, f)
|
||||
comm.Select().Hits.OnFailure++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnSuccess will be triggered when a service is successful - BasicEvents interface
|
||||
func OnSuccess(s *services.Service) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
|
||||
// check if User wants to receive every Status Change
|
||||
if s.UpdateNotify.Bool && s.UserNotified {
|
||||
s.UserNotified = false
|
||||
}
|
||||
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (!s.Online || inLimits(comm)) {
|
||||
notifier := comm.(*Notification)
|
||||
log.
|
||||
WithField("trigger", "OnSuccess").
|
||||
WithFields(utils.ToFields(notifier, s)).Debugln(fmt.Sprintf("Sending [OnSuccess] '%v' notification for service %v", notifier.Method, s.Name))
|
||||
comm.(BasicEvents).OnSuccess(s)
|
||||
comm.Select().Hits.OnSuccess++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnNewService is triggered when a new service is created - ServiceEvents interface
|
||||
func OnNewService(s *services.Service) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.
|
||||
WithField("trigger", "OnNewService").
|
||||
Debugln(fmt.Sprintf("Sending new service notification for service %v", s.Name))
|
||||
comm.(ServiceEvents).OnNewService(s)
|
||||
comm.Select().Hits.OnNewService++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnUpdatedService is triggered when a service is updated - ServiceEvents interface
|
||||
func OnUpdatedService(s *services.Service) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Debugln(fmt.Sprintf("Sending updated service notification for service %v", s.Name))
|
||||
comm.(ServiceEvents).OnUpdatedService(s)
|
||||
comm.Select().Hits.OnUpdatedService++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnDeletedService is triggered when a service is deleted - ServiceEvents interface
|
||||
func OnDeletedService(s *services.Service) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Debugln(fmt.Sprintf("Sending deleted service notification for service %v", s.Name))
|
||||
comm.(ServiceEvents).OnDeletedService(s)
|
||||
comm.Select().Hits.OnDeletedService++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnNewUser is triggered when a new user is created - UserEvents interface
|
||||
func OnNewUser(u *users.User) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Debugln(fmt.Sprintf("Sending new user notification for user %v", u.Username))
|
||||
comm.(UserEvents).OnNewUser(u)
|
||||
comm.Select().Hits.OnNewUser++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnUpdatedUser is triggered when a new user is updated - UserEvents interface
|
||||
func OnUpdatedUser(u *users.User) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Debugln(fmt.Sprintf("Sending updated user notification for user %v", u.Username))
|
||||
comm.(UserEvents).OnUpdatedUser(u)
|
||||
comm.Select().Hits.OnUpdatedUser++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnDeletedUser is triggered when a new user is deleted - UserEvents interface
|
||||
func OnDeletedUser(u *users.User) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Debugln(fmt.Sprintf("Sending deleted user notification for user %v", u.Username))
|
||||
comm.(UserEvents).OnDeletedUser(u)
|
||||
comm.Select().Hits.OnDeletedUser++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// OnUpdatedCore is triggered when the CoreApp settings are saved - CoreEvents interface
|
||||
//func OnUpdatedCore(c *core.Core) {
|
||||
// for _, comm := range allNotifiers {
|
||||
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
// log.Debugln(fmt.Sprintf("Sending updated core notification"))
|
||||
// comm.(CoreEvents).OnUpdatedCore(c)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// OnStart is triggered when the Statping service has started
|
||||
//func OnStart(c *core.Core) {
|
||||
// for _, comm := range allNotifiers {
|
||||
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
// comm.(CoreEvents).OnUpdatedCore(c)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// OnNewNotifier is triggered when a new notifier is loaded
|
||||
func OnNewNotifier(n *Notification) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
comm.(NotifierEvents).OnNewNotifier(n)
|
||||
comm.Select().Hits.OnNewNotifier++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnUpdatedNotifier is triggered when a notifier has been updated
|
||||
func OnUpdatedNotifier(n *Notification) {
|
||||
for _, comm := range allNotifiers {
|
||||
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||
log.Infoln(fmt.Sprintf("Sending updated notifier for %v", n.Id))
|
||||
comm.(NotifierEvents).OnUpdatedNotifier(n)
|
||||
comm.Select().Hits.OnUpdatedNotifier++
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
// Package notifier contains the main functionality for the Statping Notification system
|
||||
//
|
||||
// Example Notifier
|
||||
//
|
||||
// Below is an example of a Notifier with multiple Form values to custom your inputs. Place your notifier go file
|
||||
// into the /notifiers/ directory and follow the example below.
|
||||
//
|
||||
// type ExampleNotifier struct {
|
||||
// *Notification
|
||||
// }
|
||||
//
|
||||
// var example = &ExampleNotifier{&Notification{
|
||||
// Method: "example",
|
||||
// Title: "Example Notifier",
|
||||
// Description: "This is an example of a notifier for Statping!",
|
||||
// Author: "Hunter Long",
|
||||
// AuthorUrl: "https://github.com/hunterlong",
|
||||
// Delay: time.Duration(3 * time.Second),
|
||||
// Limits: 7,
|
||||
// Form: []NotificationForm{{
|
||||
// Type: "text",
|
||||
// Title: "Host",
|
||||
// Placeholder: "Insert your Host here.",
|
||||
// DbField: "host",
|
||||
// SmallText: "this is where you would put the host",
|
||||
// }, {
|
||||
// Type: "text",
|
||||
// Title: "Username",
|
||||
// Placeholder: "Insert your Username here.",
|
||||
// DbField: "username",
|
||||
// }, {
|
||||
// Type: "password",
|
||||
// Title: "Password",
|
||||
// Placeholder: "Insert your Password here.",
|
||||
// DbField: "password",
|
||||
// }, {
|
||||
// Type: "number",
|
||||
// Title: "Port",
|
||||
// Placeholder: "Insert your Port here.",
|
||||
// DbField: "port",
|
||||
// }, {
|
||||
// Type: "text",
|
||||
// Title: "API Key",
|
||||
// Placeholder: "Insert your API Key here",
|
||||
// DbField: "api_key",
|
||||
// }, {
|
||||
// Type: "text",
|
||||
// Title: "API Secret",
|
||||
// Placeholder: "Insert your API Secret here",
|
||||
// DbField: "api_secret",
|
||||
// }, {
|
||||
// Type: "text",
|
||||
// Title: "Var 1",
|
||||
// Placeholder: "Insert your Var1 here",
|
||||
// DbField: "var1",
|
||||
// }, {
|
||||
// Type: "text",
|
||||
// Title: "Var2",
|
||||
// Placeholder: "Var2 goes here",
|
||||
// DbField: "var2",
|
||||
// }},
|
||||
// }}
|
||||
//
|
||||
// Load the Notifier
|
||||
//
|
||||
// Include the init() function with AddNotifier and your notification struct. This is ran on start of Statping
|
||||
// and will automatically create a new row in the database so the end user can save their own values.
|
||||
//
|
||||
// func init() {
|
||||
// AddNotifier(example)
|
||||
// }
|
||||
//
|
||||
// Required Methods for Notifier Interface
|
||||
//
|
||||
// Below are the required methods to have your notifier implement the Notifier interface. The Send method
|
||||
// will be where you would include the logic for your notification.
|
||||
//
|
||||
// // REQUIRED
|
||||
// func (n *ExampleNotifier) Send(msg interface{}) error {
|
||||
// message := msg.(string)
|
||||
// fmt.Printf("i received this string: %v\n", message)
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// // REQUIRED
|
||||
// func (n *ExampleNotifier) Select() *Notification {
|
||||
// return n.Notification
|
||||
// }
|
||||
//
|
||||
// // REQUIRED
|
||||
// func (n *ExampleNotifier) OnSave() error {
|
||||
// msg := fmt.Sprintf("received on save trigger")
|
||||
// n.AddQueue(msg)
|
||||
// return errors.New("onsave triggered")
|
||||
// }
|
||||
//
|
||||
// Basic Events for Notifier
|
||||
//
|
||||
// You must include OnSuccess and OnFailure methods for your notifier. Anytime a service is online or offline
|
||||
// these methods will be ran with the service corresponding to it.
|
||||
//
|
||||
// // REQUIRED - BASIC EVENT
|
||||
// func (n *ExampleNotifier) OnSuccess(s *services.Service) {
|
||||
// msg := fmt.Sprintf("received a count trigger for service: %v\n", s.Name)
|
||||
// n.AddQueue(msg)
|
||||
// }
|
||||
//
|
||||
// // REQUIRED - BASIC EVENT
|
||||
// func (n *ExampleNotifier) OnFailure(s *services.Service, f *types.Failure) {
|
||||
// msg := fmt.Sprintf("received a failure trigger for service: %v\n", s.Name)
|
||||
// n.AddQueue(msg)
|
||||
// }
|
||||
//
|
||||
// Additional Events
|
||||
//
|
||||
// You can implement your notifier to different types of events that are triggered. Checkout the wiki to
|
||||
// see more details and examples of how to build your own notifier.
|
||||
//
|
||||
// More info on: https://github.com/statping/statping/wiki/Notifiers
|
||||
package _interface
|
|
@ -1,72 +0,0 @@
|
|||
// Statping
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/statping/statping
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
)
|
||||
|
||||
// Notifier interface is required to create a new Notifier
|
||||
type Notifier interface {
|
||||
OnSave() error // OnSave is triggered when the notifier is saved
|
||||
Send(interface{}) error // OnSave is triggered when the notifier is saved
|
||||
Select() *Notification // Select returns the *Notification for a notifier
|
||||
}
|
||||
|
||||
// BasicEvents includes the most minimal events, failing and successful service triggers
|
||||
type BasicEvents interface {
|
||||
OnSuccess(*services.Service) // OnSuccess is triggered when a service is successful
|
||||
OnFailure(*services.Service, *failures.Failure) // OnFailure is triggered when a service is failing
|
||||
}
|
||||
|
||||
// Tester interface will include a function to Test users settings before saving
|
||||
type Tester interface {
|
||||
OnTest() error
|
||||
}
|
||||
|
||||
// ServiceEvents are events for Services
|
||||
type ServiceEvents interface {
|
||||
OnNewService(*services.Service)
|
||||
OnUpdatedService(*services.Service)
|
||||
OnDeletedService(*services.Service)
|
||||
}
|
||||
|
||||
// UserEvents are events for Users
|
||||
type UserEvents interface {
|
||||
OnNewUser(*users.User)
|
||||
OnUpdatedUser(*users.User)
|
||||
OnDeletedUser(*users.User)
|
||||
}
|
||||
|
||||
// CoreEvents are events for the main Core app
|
||||
//type CoreEvents interface {
|
||||
// OnUpdatedCore(*core.Core)
|
||||
// OnStart(*core.Core)
|
||||
//}
|
||||
|
||||
// NotifierEvents are events for other Notifiers
|
||||
type NotifierEvents interface {
|
||||
OnNewNotifier(*Notification)
|
||||
OnUpdatedNotifier(*Notification)
|
||||
}
|
||||
|
||||
// HTTPRouter interface will allow your notifier to accept http GET/POST requests
|
||||
type HTTPRouter interface {
|
||||
OnGET() error
|
||||
OnPOST() error
|
||||
}
|
|
@ -18,6 +18,8 @@ package notifiers
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/url"
|
||||
|
@ -25,24 +27,28 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*lineNotifier)(nil)
|
||||
var _ notifier.Notifier = (*lineNotifier)(nil)
|
||||
|
||||
const (
|
||||
lineNotifyMethod = "line_notify"
|
||||
)
|
||||
|
||||
type lineNotifier struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var LineNotify = &lineNotifier{&Notification{
|
||||
func (l *lineNotifier) Select() *notifications.Notification {
|
||||
return l.Notification
|
||||
}
|
||||
|
||||
var LineNotify = &lineNotifier{¬ifications.Notification{
|
||||
Method: lineNotifyMethod,
|
||||
Title: "LINE Notify",
|
||||
Description: "LINE Notify will send notifications to your LINE Notify account when services are offline or online. Based on the <a href=\"https://notify-bot.line.me/doc/en/\">LINE Notify API</a>.",
|
||||
Author: "Kanin Peanviriyakulkit",
|
||||
AuthorUrl: "https://github.com/dogrocker",
|
||||
Icon: "far fa-bell",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Access Token",
|
||||
Placeholder: "Insert your Line Notify Access Token here.",
|
||||
|
@ -51,8 +57,7 @@ var LineNotify = &lineNotifier{&Notification{
|
|||
}
|
||||
|
||||
// Send will send a HTTP Post with the Authorization to the notify-api.line.me server. It accepts type: string
|
||||
func (u *lineNotifier) Send(msg interface{}) error {
|
||||
message := msg.(string)
|
||||
func (u *lineNotifier) sendMessage(message string) error {
|
||||
v := url.Values{}
|
||||
v.Set("message", message)
|
||||
headers := []string{fmt.Sprintf("Authorization=Bearer %v", u.ApiSecret)}
|
||||
|
@ -60,31 +65,20 @@ func (u *lineNotifier) Send(msg interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (u *lineNotifier) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *lineNotifier) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *lineNotifier) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *lineNotifier) OnSuccess(s *services.Service) {
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
var msg string
|
||||
msg = s.DownText
|
||||
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
}
|
||||
func (u *lineNotifier) OnSuccess(s *services.Service) error {
|
||||
msg := fmt.Sprintf("Service %s is online!", s.Name)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *lineNotifier) OnSave() error {
|
||||
msg := fmt.Sprintf("Notification %v is receiving updated information.", u.Method)
|
||||
utils.Log.Infoln(msg)
|
||||
u.AddQueue("saved", msg)
|
||||
return nil
|
||||
// OnTest triggers when this notifier has been saved
|
||||
func (u *lineNotifier) OnTest() error {
|
||||
msg := fmt.Sprintf("Testing if Line Notifier is working!")
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
|
|
@ -20,20 +20,26 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*mobilePush)(nil)
|
||||
var _ notifier.Notifier = (*mobilePush)(nil)
|
||||
|
||||
const mobileIdentifier = "com.statping"
|
||||
|
||||
type mobilePush struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Mobile = &mobilePush{&Notification{
|
||||
func (m *mobilePush) Select() *notifications.Notification {
|
||||
return m.Notification
|
||||
}
|
||||
|
||||
var Mobile = &mobilePush{¬ifications.Notification{
|
||||
Method: "mobile",
|
||||
Title: "Mobile Notifications",
|
||||
Description: `Receive push notifications on your Mobile device using the Statping App. You can scan the Authentication QR Code found in Settings to get the Mobile app setup in seconds.
|
||||
|
@ -42,7 +48,7 @@ var Mobile = &mobilePush{&Notification{
|
|||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Delay: time.Duration(5 * time.Second),
|
||||
Icon: "fas fa-mobile-alt",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Device Identifiers",
|
||||
Placeholder: "A list of your Mobile device push notification ID's.",
|
||||
|
@ -57,10 +63,6 @@ var Mobile = &mobilePush{&Notification{
|
|||
}}},
|
||||
}
|
||||
|
||||
func (u *mobilePush) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
func dataJson(s *services.Service, f *failures.Failure) map[string]interface{} {
|
||||
serviceId := "0"
|
||||
if s != nil {
|
||||
|
@ -85,7 +87,7 @@ func dataJson(s *services.Service, f *failures.Failure) map[string]interface{} {
|
|||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *mobilePush) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *mobilePush) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
data := dataJson(s, f)
|
||||
msg := &pushArray{
|
||||
Message: fmt.Sprintf("Your service '%v' is currently failing! Reason: %v", s.Name, f.Issue),
|
||||
|
@ -93,30 +95,19 @@ func (u *mobilePush) OnFailure(s *services.Service, f *failures.Failure) {
|
|||
Topic: mobileIdentifier,
|
||||
Data: data,
|
||||
}
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
return u.Send(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *mobilePush) OnSuccess(s *services.Service) {
|
||||
func (u *mobilePush) OnSuccess(s *services.Service) error {
|
||||
data := dataJson(s, nil)
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
var msgStr string
|
||||
msgStr = s.DownText
|
||||
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
msg := &pushArray{
|
||||
Message: msgStr,
|
||||
Title: "Service Online",
|
||||
Topic: mobileIdentifier,
|
||||
Data: data,
|
||||
}
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
msg := &pushArray{
|
||||
Message: "Service is Online!",
|
||||
Title: "Service Online",
|
||||
Topic: mobileIdentifier,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *mobilePush) OnSave() error {
|
||||
return nil
|
||||
return u.Send(msg)
|
||||
}
|
||||
|
||||
// OnTest triggers when this notifier has been saved
|
||||
|
@ -143,12 +134,10 @@ func (u *mobilePush) OnTest() error {
|
|||
firstLog := output.Logs[0].Error
|
||||
return fmt.Errorf("Mobile Notification error: %v", firstLog)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Send will send message to Statping push notifications endpoint
|
||||
func (u *mobilePush) Send(msg interface{}) error {
|
||||
pushMessage := msg.(*pushArray)
|
||||
func (u *mobilePush) Send(pushMessage *pushArray) error {
|
||||
pushMessage.Tokens = []string{u.Var1}
|
||||
pushMessage.Platform = utils.ToInt(u.Var2)
|
||||
_, err := pushRequest(pushMessage)
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
package notifiers
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var form1 = NotificationForm{
|
||||
Type: "text",
|
||||
Title: "Example Input",
|
||||
DbField: "Host",
|
||||
Required: true,
|
||||
IsHidden: false,
|
||||
IsList: false,
|
||||
IsSwitch: false,
|
||||
}
|
||||
|
||||
var form2 = NotificationForm{
|
||||
Type: "text",
|
||||
Title: "Example Input 2",
|
||||
DbField: "ApiKey",
|
||||
Required: true,
|
||||
IsHidden: false,
|
||||
IsList: false,
|
||||
IsSwitch: false,
|
||||
}
|
||||
|
||||
var example = &exampleNotif{&Notification{
|
||||
Method: "example",
|
||||
Enabled: null.NewNullBool(true),
|
||||
Limits: 3,
|
||||
Removable: false,
|
||||
Form: []NotificationForm{form1, form2},
|
||||
Delay: 30,
|
||||
}}
|
||||
|
||||
type exampleNotif struct {
|
||||
*Notification
|
||||
}
|
||||
|
||||
func (e *exampleNotif) OnSave() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *exampleNotif) Select() *Notification {
|
||||
return e.Notification
|
||||
}
|
||||
|
||||
func (e *exampleNotif) Send(data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.CreateTable(&Notification{})
|
||||
db.Create(example.Select())
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
appendList(example)
|
||||
itemer, err := Find(example.Method)
|
||||
require.Nil(t, err)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
assert.Equal(t, "example", item.Method)
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
|
||||
example := &Notification{
|
||||
Method: "anotherexample",
|
||||
Title: "Example 2",
|
||||
Description: "New Message here",
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "anotherexample", example.Method)
|
||||
assert.Equal(t, "Example 2", example.Title)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
|
||||
items := All()
|
||||
assert.Len(t, items, 2)
|
||||
assert.Len(t, allNotifiers, 2)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
itemer, err := Find("anotherexample")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, itemer)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
item.Host = "Updated Host Var"
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated Host Var", item.Host)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
itemer, err := Find("example2")
|
||||
require.Nil(t, err)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 2)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -2,105 +2,28 @@ package notifiers
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
allowedVars = []string{"host", "username", "password", "port", "api_key", "api_secret", "var1", "var2"}
|
||||
)
|
||||
|
||||
func SendEvent(data ...interface{}) {
|
||||
d1 := data[0]
|
||||
service, ok := d1.(*services.Service)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
d2 := data[1]
|
||||
if d2 == nil {
|
||||
OnSuccess(service)
|
||||
}
|
||||
fail, ok := d2.(*failures.Failure)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
OnFailure(service, fail)
|
||||
}
|
||||
|
||||
func checkNotifierForm(n *Notification) error {
|
||||
for _, f := range n.Form {
|
||||
contains := contains(f.DbField, allowedVars)
|
||||
if !contains {
|
||||
return fmt.Errorf("the DbField '%v' is not allowed, allowed vars: %v", f.DbField, allowedVars)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(s string, arr []string) bool {
|
||||
for _, v := range arr {
|
||||
if strings.ToLower(s) == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddNotifier accept a Notifier interface to be added into the array
|
||||
func AddNotifiers(notifiers ...Notifier) error {
|
||||
log.Infof("Initiating %d Notifiers\n", len(notifiers))
|
||||
|
||||
for _, n := range notifiers {
|
||||
notif := n.Select()
|
||||
log.Infof("Initiating %s Notifier\n", notif.Method)
|
||||
|
||||
if err := checkNotifierForm(notif); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Creating %s Notifier\n", notif.Method)
|
||||
if err := notif.Create(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if notif.Enabled.Bool {
|
||||
notif.Close()
|
||||
notif.Start()
|
||||
go Queue(notif)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// startAllNotifiers will start the go routine for each loaded notifier
|
||||
func startAllNotifiers() {
|
||||
for _, notify := range All() {
|
||||
n := notify.Select()
|
||||
log.Infof("Initiating %s Notifier\n", n.Method)
|
||||
if utils.IsType(notify, new(Notifier)) {
|
||||
if n.Enabled.Bool {
|
||||
n.Close()
|
||||
n.Start()
|
||||
go Queue(notify)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Migrate() error {
|
||||
return AddNotifiers(
|
||||
func InitNotifiers() {
|
||||
Add(
|
||||
slacker,
|
||||
Command,
|
||||
Discorder,
|
||||
Emailer,
|
||||
email,
|
||||
LineNotify,
|
||||
Mobile,
|
||||
Slacker,
|
||||
Telegram,
|
||||
Twilio,
|
||||
Webhook,
|
||||
Mobile,
|
||||
)
|
||||
}
|
||||
|
||||
func Add(notifs ...services.ServiceNotifier) {
|
||||
for _, n := range notifs {
|
||||
services.AddNotifier(n)
|
||||
if err := n.Select().Create(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"strings"
|
||||
|
@ -27,7 +29,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*slack)(nil)
|
||||
var _ notifier.Notifier = (*slack)(nil)
|
||||
|
||||
const (
|
||||
slackMethod = "slack"
|
||||
|
@ -37,10 +39,14 @@ const (
|
|||
)
|
||||
|
||||
type slack struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Slacker = &slack{&Notification{
|
||||
func (s *slack) Select() *notifications.Notification {
|
||||
return s.Notification
|
||||
}
|
||||
|
||||
var slacker = &slack{¬ifications.Notification{
|
||||
Method: slackMethod,
|
||||
Title: "slack",
|
||||
Description: "Send notifications to your slack channel when a service is offline. Insert your Incoming webhooker URL for your channel to receive notifications. Based on the <a href=\"https://api.slack.com/incoming-webhooks\">slack API</a>.",
|
||||
|
@ -49,7 +55,7 @@ var Slacker = &slack{&Notification{
|
|||
Delay: time.Duration(10 * time.Second),
|
||||
Host: "https://webhooksurl.slack.com/***",
|
||||
Icon: "fab fa-slack",
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Incoming webhooker Url",
|
||||
Placeholder: "Insert your slack Webhook URL here.",
|
||||
|
@ -59,15 +65,14 @@ var Slacker = &slack{&Notification{
|
|||
}}},
|
||||
}
|
||||
|
||||
func parseSlackMessage(id int64, temp string, data interface{}) error {
|
||||
func parseSlackMessage(id int64, temp string, data interface{}) string {
|
||||
buf := new(bytes.Buffer)
|
||||
slackTemp, _ := template.New("slack").Parse(temp)
|
||||
err := slackTemp.Execute(buf, data)
|
||||
if err != nil {
|
||||
return err
|
||||
return err.Error()
|
||||
}
|
||||
Slacker.AddQueue(fmt.Sprintf("service_%v", id), buf.String())
|
||||
return nil
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type slackMessage struct {
|
||||
|
@ -78,51 +83,44 @@ type slackMessage struct {
|
|||
}
|
||||
|
||||
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
|
||||
func (u *slack) Send(msg interface{}) error {
|
||||
message := msg.(string)
|
||||
_, _, err := utils.HttpRequest(u.Host, "POST", "application/json", nil, strings.NewReader(message), time.Duration(10*time.Second), true)
|
||||
func (u *slack) sendSlack(msg string) error {
|
||||
contents, resp, err := utils.HttpRequest(u.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
||||
defer resp.Body.Close()
|
||||
fmt.Println("CONTENTS: ", string(contents))
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *slack) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
func (u *slack) OnTest() error {
|
||||
contents, _, err := utils.HttpRequest(u.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(`{"text":"testing message"}`)), time.Duration(10*time.Second), true)
|
||||
contents, resp, err := utils.HttpRequest(u.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(`{"text":"testing message"}`)), time.Duration(10*time.Second), true)
|
||||
defer resp.Body.Close()
|
||||
if string(contents) != "ok" {
|
||||
return errors.New("The slack response was incorrect, check the URL")
|
||||
return errors.New("the slack response was incorrect, check the URL")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *slack) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *slack) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
message := slackMessage{
|
||||
Service: s,
|
||||
Template: failingTemplate,
|
||||
Time: utils.Now().Unix(),
|
||||
Issue: f.Issue,
|
||||
}
|
||||
parseSlackMessage(s.Id, failingTemplate, message)
|
||||
msg := parseSlackMessage(s.Id, failingTemplate, message)
|
||||
return u.sendSlack(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *slack) OnSuccess(s *services.Service) {
|
||||
if !s.Online {
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
message := slackMessage{
|
||||
Service: s,
|
||||
Template: successTemplate,
|
||||
Time: utils.Now().Unix(),
|
||||
}
|
||||
parseSlackMessage(s.Id, successTemplate, message)
|
||||
func (u *slack) OnSuccess(s *services.Service) error {
|
||||
message := slackMessage{
|
||||
Service: s,
|
||||
Template: successTemplate,
|
||||
Time: utils.Now().Unix(),
|
||||
}
|
||||
}
|
||||
msg := parseSlackMessage(s.Id, successTemplate, message)
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *slack) OnSave() error {
|
||||
message := fmt.Sprintf("Notification %v is receiving updated information.", u.Method)
|
||||
u.AddQueue("saved", message)
|
||||
return nil
|
||||
fmt.Println("Sending OnSuccess message!")
|
||||
fmt.Println(msg)
|
||||
fmt.Printf("%s\n", u.Host)
|
||||
return u.sendSlack(msg)
|
||||
}
|
||||
|
|
|
@ -1,273 +0,0 @@
|
|||
// Statping
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/statping/statping
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// db holds the Statping database connection
|
||||
log = utils.Log.WithField("type", "notifier")
|
||||
allNotifiers []Notifier
|
||||
)
|
||||
|
||||
// Notification contains all the fields for a Statping Notifier.
|
||||
type Notification struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Method string `gorm:"column:method" json:"method"`
|
||||
Host string `gorm:"not null;column:host" json:"host,omitempty"`
|
||||
Port int `gorm:"not null;column:port" json:"port,omitempty"`
|
||||
Username string `gorm:"not null;column:username" json:"username,omitempty"`
|
||||
Password string `gorm:"not null;column:password" json:"password,omitempty"`
|
||||
Var1 string `gorm:"not null;column:var1" json:"var1,omitempty"`
|
||||
Var2 string `gorm:"not null;column:var2" json:"var2,omitempty"`
|
||||
ApiKey string `gorm:"not null;column:api_key" json:"api_key,omitempty"`
|
||||
ApiSecret string `gorm:"not null;column:api_secret" json:"api_secret,omitempty"`
|
||||
Enabled null.NullBool `gorm:"column:enabled;type:boolean;default:false" json:"enabled"`
|
||||
Limits int `gorm:"not null;column:limits" json:"limits"`
|
||||
Removable bool `gorm:"column:removable" json:"removeable"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Form []NotificationForm `gorm:"-" json:"form"`
|
||||
logs []*NotificationLog `gorm:"-" json:"logs"`
|
||||
Title string `gorm:"-" json:"title"`
|
||||
Description string `gorm:"-" json:"description"`
|
||||
Author string `gorm:"-" json:"author"`
|
||||
AuthorUrl string `gorm:"-" json:"author_url"`
|
||||
Icon string `gorm:"-" json:"icon"`
|
||||
Delay time.Duration `gorm:"-" json:"delay,string"`
|
||||
Queue []*QueueData `gorm:"-" json:"-"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
testable bool `gorm:"-" json:"testable"`
|
||||
|
||||
Hits notificationHits
|
||||
Notifier
|
||||
}
|
||||
|
||||
type notificationHits struct {
|
||||
OnSuccess int64 `gorm:"-" json:"-"`
|
||||
OnFailure int64 `gorm:"-" json:"-"`
|
||||
OnSave int64 `gorm:"-" json:"-"`
|
||||
OnNewService int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedService int64 `gorm:"-" json:"-"`
|
||||
OnDeletedService int64 `gorm:"-" json:"-"`
|
||||
OnNewUser int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedUser int64 `gorm:"-" json:"-"`
|
||||
OnDeletedUser int64 `gorm:"-" json:"-"`
|
||||
OnNewNotifier int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedNotifier int64 `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// QueueData is the struct for the messaging queue with service
|
||||
type QueueData struct {
|
||||
Id string
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
// NotificationForm contains the HTML fields for each variable/input you want the notifier to accept.
|
||||
type NotificationForm struct {
|
||||
Type string `json:"type"` // the html input type (text, password, email)
|
||||
Title string `json:"title"` // include a title for ease of use
|
||||
Placeholder string `json:"placeholder"` // add a placeholder for the input
|
||||
DbField string `json:"field"` // true variable key for input
|
||||
SmallText string `json:"small_text"` // insert small text under a html input
|
||||
Required bool `json:"required"` // require this input on the html form
|
||||
IsHidden bool `json:"hidden"` // hide this form element from end user
|
||||
IsList bool `json:"list"` // make this form element a comma separated list
|
||||
IsSwitch bool `json:"switch"` // make the notifier a boolean true/false switch
|
||||
}
|
||||
|
||||
// NotificationLog contains the normalized message from previously sent notifications
|
||||
type NotificationLog struct {
|
||||
Message string `json:"message"`
|
||||
Time utils.Timestamp `json:"time"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// normalizeType will accept multiple interfaces and converts it into a string for logging
|
||||
func normalizeType(ty interface{}) string {
|
||||
switch v := ty.(type) {
|
||||
case int, int32, int64:
|
||||
return fmt.Sprintf("%v", v)
|
||||
case float32, float64:
|
||||
return fmt.Sprintf("%v", v)
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
case []string:
|
||||
return fmt.Sprintf("%v", v)
|
||||
case interface{}, map[string]interface{}:
|
||||
j, _ := json.Marshal(v)
|
||||
return string(j)
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Log will record a new notification into memory and will show the logs on the settings page
|
||||
func (n *Notification) makeLog(msg interface{}) {
|
||||
log := &NotificationLog{
|
||||
Message: normalizeType(msg),
|
||||
Time: utils.Timestamp(utils.Now()),
|
||||
Timestamp: utils.Now(),
|
||||
}
|
||||
n.logs = append(n.logs, log)
|
||||
}
|
||||
|
||||
// Logs returns an array of the notifiers logs
|
||||
func (n *Notification) Logs() []*NotificationLog {
|
||||
return reverseLogs(n.logs)
|
||||
}
|
||||
|
||||
// reverseLogs will reverse the notifier's logs to be time desc
|
||||
func reverseLogs(input []*NotificationLog) []*NotificationLog {
|
||||
if len(input) == 0 {
|
||||
return input
|
||||
}
|
||||
return append(reverseLogs(input[1:]), input[0])
|
||||
}
|
||||
|
||||
// SelectNotification returns the Notification struct from the database
|
||||
func SelectNotification(n Notifier) (*Notification, error) {
|
||||
notifier := n.Select()
|
||||
err := db.Where("method = ?", notifier.Method).Find(¬ifier)
|
||||
return notifier, err.Error()
|
||||
}
|
||||
|
||||
// SelectNotifier returns the Notification struct from the database
|
||||
func SelectNotifier(method string) (*Notification, Notifier, error) {
|
||||
for _, comm := range allNotifiers {
|
||||
n, ok := comm.(Notifier)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("incorrect notification type: %v", reflect.TypeOf(n).String())
|
||||
}
|
||||
notifier := n.Select()
|
||||
if notifier.Method == method {
|
||||
return notifier, comm.(Notifier), nil
|
||||
}
|
||||
}
|
||||
return nil, nil, errors.New("cannot find notifier")
|
||||
}
|
||||
|
||||
// Queue is the FIFO go routine to send notifications when objects are triggered
|
||||
func Queue(notifer Notifier) {
|
||||
n := notifer.(*Notification)
|
||||
rateLimit := n.Delay
|
||||
|
||||
CheckNotifier:
|
||||
for {
|
||||
select {
|
||||
case <-n.Running:
|
||||
break CheckNotifier
|
||||
case <-time.After(rateLimit):
|
||||
n := notifer.(*Notification)
|
||||
fmt.Printf("checking %s %d\n", n.Method, len(n.Queue))
|
||||
if len(n.Queue) > 0 {
|
||||
ok, _ := n.WithinLimits()
|
||||
if ok {
|
||||
msg := n.Queue[0]
|
||||
err := notifer.Send(msg.Data)
|
||||
if err != nil {
|
||||
log.WithFields(utils.ToFields(n, msg)).Error(fmt.Sprintf("Notifier '%v' had an error: %v", n.Method, err))
|
||||
} else {
|
||||
log.WithFields(utils.ToFields(n, msg)).Debug(fmt.Sprintf("Notifier '%v' sent outgoing message (%v) %v left in queue.", n.Method, msg.Id, len(n.Queue)))
|
||||
}
|
||||
n.makeLog(msg.Data)
|
||||
if len(n.Queue) > 1 {
|
||||
n.Queue = n.Queue[1:]
|
||||
} else {
|
||||
n.Queue = nil
|
||||
}
|
||||
rateLimit = n.Delay
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// install will check the database for the notification, if its not inserted it will insert a new record for it
|
||||
//func install(n Notifier) error {
|
||||
// log.WithFields(utils.ToFields(n)).
|
||||
// Debugln(fmt.Sprintf("Checking if notifier '%v' is installed", n.Select().Method))
|
||||
//
|
||||
// if Exists(n.Select().Method) {
|
||||
// AllCommunications = append(AllCommunications, n)
|
||||
// } else {
|
||||
// _, err := insertDatabase(n)
|
||||
// if err != nil {
|
||||
// log.Errorln(err)
|
||||
// return err
|
||||
// }
|
||||
// AllCommunications = append(AllCommunications, n)
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
// isEnabled returns true if the notifier is enabled
|
||||
func isEnabled(n interface{}) bool {
|
||||
notifier := n.(Notifier).Select()
|
||||
return notifier.Enabled.Bool
|
||||
}
|
||||
|
||||
// inLimits will return true if the notifier is within sending limits
|
||||
func inLimits(n interface{}) bool {
|
||||
notifier := n.(Notifier).Select()
|
||||
ok, _ := notifier.WithinLimits()
|
||||
return ok
|
||||
}
|
||||
|
||||
// WithinLimits returns true if the notifier is within its sending limits
|
||||
func (n *Notification) WithinLimits() (bool, error) {
|
||||
if n.SentLastMinute() == 0 {
|
||||
return true, nil
|
||||
}
|
||||
if n.SentLastMinute() >= n.Limits {
|
||||
return false, fmt.Errorf("notifier sent %v out of %v in last minute", n.SentLastMinute(), n.Limits)
|
||||
}
|
||||
if n.LastSent().Seconds() == 0 {
|
||||
return true, nil
|
||||
}
|
||||
if n.Delay.Seconds() >= n.LastSent().Seconds() {
|
||||
return false, fmt.Errorf("notifiers delay (%v) is greater than last message sent (%v)", n.Delay.Seconds(), n.LastSent().Seconds())
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ExampleService can be used for the OnTest() method for notifiers
|
||||
var ExampleService = &services.Service{
|
||||
Id: 1,
|
||||
Name: "Interpol - All The Rage Back Home",
|
||||
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 30,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 20,
|
||||
LastStatusCode: 404,
|
||||
Expected: null.NewNullString("test example"),
|
||||
LastResponse: "<html>this is an example response</html>",
|
||||
CreatedAt: utils.Now().Add(-24 * time.Hour),
|
||||
}
|
|
@ -20,6 +20,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/url"
|
||||
|
@ -27,13 +29,17 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*telegram)(nil)
|
||||
var _ notifier.Notifier = (*telegram)(nil)
|
||||
|
||||
type telegram struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Telegram = &telegram{&Notification{
|
||||
func (t *telegram) Select() *notifications.Notification {
|
||||
return t.Notification
|
||||
}
|
||||
|
||||
var Telegram = &telegram{¬ifications.Notification{
|
||||
Method: "telegram",
|
||||
Title: "Telegram",
|
||||
Description: "Receive notifications on your Telegram channel when a service has an issue. You must get a Telegram API token from the /botfather. Review the <a target=\"_blank\" href=\"http://techthoughts.info/how-to-create-a-telegram-bot-and-send-messages-via-api\">Telegram API Tutorial</a> to learn how to generate a new API Token.",
|
||||
|
@ -41,7 +47,7 @@ var Telegram = &telegram{&Notification{
|
|||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Icon: "fab fa-telegram-plane",
|
||||
Delay: time.Duration(5 * time.Second),
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Telegram API Token",
|
||||
Placeholder: "383810182:EEx829dtCeufeQYXG7CUdiQopqdmmxBPO7-s",
|
||||
|
@ -58,13 +64,8 @@ var Telegram = &telegram{&Notification{
|
|||
}}},
|
||||
}
|
||||
|
||||
func (u *telegram) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// Send will send a HTTP Post to the Telegram API. It accepts type: string
|
||||
func (u *telegram) Send(msg interface{}) error {
|
||||
message := msg.(string)
|
||||
func (u *telegram) sendMessage(message string) error {
|
||||
apiEndpoint := fmt.Sprintf("https://api.telegram.org/bot%v/sendMessage", u.ApiSecret)
|
||||
|
||||
v := url.Values{}
|
||||
|
@ -84,35 +85,21 @@ func (u *telegram) Send(msg interface{}) error {
|
|||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *telegram) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *telegram) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *telegram) OnSuccess(s *services.Service) {
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
var msg interface{}
|
||||
msg = s.DownText
|
||||
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *telegram) OnSave() error {
|
||||
utils.Log.Infoln(fmt.Sprintf("Notification %v is receiving updated information.", u.Method))
|
||||
|
||||
// Do updating stuff here
|
||||
|
||||
return nil
|
||||
func (u *telegram) OnSuccess(s *services.Service) error {
|
||||
msg := fmt.Sprintf("Your service '%v' is currently online!", s.Name)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnTest will test the Twilio SMS messaging
|
||||
func (u *telegram) OnTest() error {
|
||||
msg := fmt.Sprintf("Testing the Twilio SMS Notifier on your Statping server")
|
||||
return u.Send(msg)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
func telegramSuccess(res []byte) (bool, telegramResponse) {
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/url"
|
||||
|
@ -27,13 +29,17 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*twilio)(nil)
|
||||
var _ notifier.Notifier = (*twilio)(nil)
|
||||
|
||||
type twilio struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Twilio = &twilio{&Notification{
|
||||
func (t *twilio) Select() *notifications.Notification {
|
||||
return t.Notification
|
||||
}
|
||||
|
||||
var Twilio = &twilio{¬ifications.Notification{
|
||||
Method: "twilio",
|
||||
Title: "Twilio",
|
||||
Description: "Receive SMS text messages directly to your cellphone when a service is offline. You can use a Twilio test account with limits. This notifier uses the <a href=\"https://www.twilio.com/docs/usage/api\">Twilio API</a>.",
|
||||
|
@ -41,7 +47,7 @@ var Twilio = &twilio{&Notification{
|
|||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Icon: "far fa-comment-alt",
|
||||
Delay: time.Duration(10 * time.Second),
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Account SID",
|
||||
Placeholder: "Insert your Twilio Account SID",
|
||||
|
@ -68,13 +74,8 @@ var Twilio = &twilio{&Notification{
|
|||
}}},
|
||||
}
|
||||
|
||||
func (u *twilio) Select() *Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// Send will send a HTTP Post to the Twilio SMS API. It accepts type: string
|
||||
func (u *twilio) Send(msg interface{}) error {
|
||||
message := msg.(string)
|
||||
func (u *twilio) sendMessage(message string) error {
|
||||
twilioUrl := fmt.Sprintf("https://api.twilio.com/2010-04-01/Accounts/%v/Messages.json", u.GetValue("api_key"))
|
||||
|
||||
v := url.Values{}
|
||||
|
@ -94,35 +95,21 @@ func (u *twilio) Send(msg interface{}) error {
|
|||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (u *twilio) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (u *twilio) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (u *twilio) OnSuccess(s *services.Service) {
|
||||
if !s.Online || !s.SuccessNotified {
|
||||
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
var msg string
|
||||
msg = s.DownText
|
||||
|
||||
u.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (u *twilio) OnSave() error {
|
||||
utils.Log.Infoln(fmt.Sprintf("Notification %v is receiving updated information.", u.Method))
|
||||
|
||||
// Do updating stuff here
|
||||
|
||||
return nil
|
||||
func (u *twilio) OnSuccess(s *services.Service) error {
|
||||
msg := fmt.Sprintf("Your service '%v' is currently online!", s.Name)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
// OnTest will test the Twilio SMS messaging
|
||||
func (u *twilio) OnTest() error {
|
||||
msg := fmt.Sprintf("Testing the Twilio SMS Notifier")
|
||||
return u.Send(msg)
|
||||
return u.sendMessage(msg)
|
||||
}
|
||||
|
||||
func twilioSuccess(res []byte) (bool, twilioResponse) {
|
||||
|
|
|
@ -19,6 +19,8 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/notifier"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"io/ioutil"
|
||||
|
@ -27,17 +29,17 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var _ Notifier = (*webhooker)(nil)
|
||||
var _ notifier.Notifier = (*webhooker)(nil)
|
||||
|
||||
const (
|
||||
webhookMethod = "webhook"
|
||||
)
|
||||
|
||||
type webhooker struct {
|
||||
*Notification
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
var Webhook = &webhooker{&Notification{
|
||||
var Webhook = &webhooker{¬ifications.Notification{
|
||||
Method: webhookMethod,
|
||||
Title: "HTTP webhooker",
|
||||
Description: "Send a custom HTTP request to a specific URL with your own body, headers, and parameters.",
|
||||
|
@ -45,7 +47,7 @@ var Webhook = &webhooker{&Notification{
|
|||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Icon: "fas fa-code-branch",
|
||||
Delay: time.Duration(1 * time.Second),
|
||||
Form: []NotificationForm{{
|
||||
Form: []notifications.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "HTTP Endpoint",
|
||||
Placeholder: "http://webhookurl.com/JW2MCP4SKQP",
|
||||
|
@ -89,7 +91,7 @@ func (w *webhooker) Send(msg interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (w *webhooker) Select() *Notification {
|
||||
func (w *webhooker) Select() *notifications.Notification {
|
||||
return w.Notification
|
||||
}
|
||||
|
||||
|
@ -131,7 +133,7 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) {
|
|||
}
|
||||
|
||||
func (w *webhooker) OnTest() error {
|
||||
body := replaceBodyText(w.Var2, ExampleService, nil)
|
||||
body := replaceBodyText(w.Var2, nil, nil)
|
||||
resp, err := w.sendHttpWebhook(body)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -143,21 +145,17 @@ func (w *webhooker) OnTest() error {
|
|||
}
|
||||
|
||||
// OnFailure will trigger failing service
|
||||
func (w *webhooker) OnFailure(s *services.Service, f *failures.Failure) {
|
||||
func (w *webhooker) OnFailure(s *services.Service, f *failures.Failure) error {
|
||||
msg := replaceBodyText(w.Var2, s, f)
|
||||
w.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
resp, err := w.sendHttpWebhook(msg)
|
||||
defer resp.Body.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// OnSuccess will trigger successful service
|
||||
func (w *webhooker) OnSuccess(s *services.Service) {
|
||||
if !s.Online {
|
||||
w.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
||||
msg := replaceBodyText(w.Var2, s, nil)
|
||||
w.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSave triggers when this notifier has been saved
|
||||
func (w *webhooker) OnSave() error {
|
||||
return nil
|
||||
func (w *webhooker) OnSuccess(s *services.Service) error {
|
||||
msg := replaceBodyText(w.Var2, s, nil)
|
||||
resp, err := w.sendHttpWebhook(msg)
|
||||
defer resp.Body.Close()
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"github.com/jinzhu/gorm"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/failures"
|
||||
|
@ -13,6 +12,7 @@ import (
|
|||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/types/incidents"
|
||||
"github.com/statping/statping/types/messages"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
|
@ -100,7 +100,7 @@ func initModels(db database.Database) {
|
|||
hits.SetDB(db)
|
||||
failures.SetDB(db)
|
||||
checkins.SetDB(db)
|
||||
notifiers.SetDB(db)
|
||||
notifications.SetDB(db)
|
||||
incidents.SetDB(db)
|
||||
users.SetDB(db)
|
||||
messages.SetDB(db)
|
||||
|
|
|
@ -2,7 +2,6 @@ package configs
|
|||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/failures"
|
||||
|
@ -10,6 +9,7 @@ import (
|
|||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/types/incidents"
|
||||
"github.com/statping/statping/types/messages"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
"github.com/statping/statping/utils"
|
||||
|
@ -73,7 +73,7 @@ func (d *DbConfig) Delete() error {
|
|||
|
||||
// DropDatabase will DROP each table Statping created
|
||||
func (d *DbConfig) DropDatabase() error {
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifiers.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
log.Infoln("Dropping Database Tables...")
|
||||
for _, t := range DbModels {
|
||||
if err := d.Db.DropTableIfExists(t); err != nil {
|
||||
|
@ -94,7 +94,7 @@ func (d *DbConfig) Close() {
|
|||
func (d *DbConfig) CreateDatabase() error {
|
||||
var err error
|
||||
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifiers.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
|
||||
log.Infoln("Creating Database Tables...")
|
||||
for _, table := range DbModels {
|
||||
|
|
|
@ -5,7 +5,8 @@ import (
|
|||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/failures"
|
||||
|
@ -52,7 +53,7 @@ func (c *DbConfig) DatabaseChanges() error {
|
|||
//If this function has an issue, it will ROLLBACK to the previous state.
|
||||
func (c *DbConfig) MigrateDatabase() error {
|
||||
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifiers.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
|
||||
log.Infoln("Migrating Database Tables...")
|
||||
tx := c.Db.Begin()
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
package notifiers
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/statping/statping/database"
|
||||
)
|
||||
|
||||
var db database.Database
|
||||
var (
|
||||
db database.Database
|
||||
)
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Notification{})
|
||||
}
|
||||
|
||||
func appendList(n Notifier) {
|
||||
allNotifiers = append(allNotifiers, n)
|
||||
}
|
||||
|
||||
func Find(name string) (*Notification, error) {
|
||||
for _, n := range allNotifiers {
|
||||
notif := n.(*Notification)
|
||||
if notif.Method == name {
|
||||
return notif, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("notifier not found")
|
||||
}
|
||||
|
||||
func All() []Notifier {
|
||||
return allNotifiers
|
||||
func Find(method string) (*Notification, error) {
|
||||
var notification Notification
|
||||
q := db.Where("method = ?", method).Find(¬ification)
|
||||
return ¬ification, q.Error()
|
||||
}
|
||||
|
||||
func (n *Notification) Create() error {
|
||||
|
@ -36,7 +25,6 @@ func (n *Notification) Create() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
appendList(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -45,7 +33,6 @@ func (n *Notification) Update() error {
|
|||
if n.Enabled.Bool {
|
||||
n.Close()
|
||||
n.Start()
|
||||
go Queue(n)
|
||||
} else {
|
||||
n.Close()
|
||||
}
|
||||
|
@ -53,6 +40,8 @@ func (n *Notification) Update() error {
|
|||
return err.Error()
|
||||
}
|
||||
|
||||
func (n *Notification) Delete() error {
|
||||
return nil
|
||||
func loadAll() []*Notification {
|
||||
var notifications []*Notification
|
||||
db.Find(¬ifications)
|
||||
return notifications
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package notifiers
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -21,49 +21,48 @@ func (n *Notification) AfterFind() (err error) {
|
|||
}
|
||||
|
||||
// AddQueue will add any type of interface (json, string, struct, etc) into the Notifiers queue
|
||||
func (n *Notification) AddQueue(uid string, msg interface{}) {
|
||||
data := &QueueData{uid, msg}
|
||||
n.Queue = append(n.Queue, data)
|
||||
log.WithFields(utils.ToFields(data, n)).Debug(fmt.Sprintf("Notifier '%v' added new item (%v) to the queue. (%v queued)", n.Method, uid, len(n.Queue)))
|
||||
}
|
||||
//func (n *Notification) AddQueue(uid string, msg interface{}) {
|
||||
// data := &QueueData{uid, msg}
|
||||
// n.Queue = append(n.Queue, data)
|
||||
// log.WithFields(utils.ToFields(data, n)).Debug(fmt.Sprintf("Notifier '%v' added new item (%v) to the queue. (%v queued)", n.Method, uid, len(n.Queue)))
|
||||
//}
|
||||
|
||||
// CanTest returns true if the notifier implements the OnTest interface
|
||||
func (n *Notification) CanTest() bool {
|
||||
return n.testable
|
||||
}
|
||||
//func (n *Notification) CanTest() bool {
|
||||
// return n.testable
|
||||
//}
|
||||
|
||||
// LastSent returns a time.Duration of the last sent notification for the notifier
|
||||
func (n *Notification) LastSent() time.Duration {
|
||||
if len(n.logs) == 0 {
|
||||
return time.Duration(0)
|
||||
}
|
||||
last := n.Logs()[0]
|
||||
since := time.Since(last.Timestamp)
|
||||
since := time.Since(n.lastSent)
|
||||
return since
|
||||
}
|
||||
|
||||
// SentLastHour returns the total amount of notifications sent in last 1 hour
|
||||
func (n *Notification) SentLastHour() int {
|
||||
since := utils.Now().Add(-1 * time.Hour)
|
||||
return n.SentLast(since)
|
||||
}
|
||||
func (n *Notification) CanSend() bool {
|
||||
if !n.Enabled.Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SentLastMinute returns the total amount of notifications sent in last 1 minute
|
||||
func (n *Notification) SentLastMinute() int {
|
||||
since := utils.Now().Add(-1 * time.Minute)
|
||||
return n.SentLast(since)
|
||||
}
|
||||
fmt.Println("Last sent: ", n.lastSent.String())
|
||||
fmt.Println("Last count: ", n.lastSentCount)
|
||||
fmt.Println("Last sent before now: ", n.lastSent.Add(60*time.Second).Before(utils.Now()))
|
||||
|
||||
// SentLast accept a time.Time and returns the amount of sent notifications within your time to current
|
||||
func (n *Notification) SentLast(since time.Time) int {
|
||||
sent := 0
|
||||
for _, v := range n.Logs() {
|
||||
lastTime := time.Time(v.Time).UTC()
|
||||
if lastTime.After(since) {
|
||||
sent++
|
||||
// the last sent notification was past 1 minute (limit per minute)
|
||||
if n.lastSent.Add(60 * time.Second).Before(utils.Now()) {
|
||||
if n.lastSentCount != 0 {
|
||||
n.lastSentCount--
|
||||
}
|
||||
}
|
||||
return sent
|
||||
|
||||
// dont send if already beyond the notifier's limit
|
||||
if n.lastSentCount >= n.Limits {
|
||||
return false
|
||||
}
|
||||
|
||||
// action to do since notifier is able to send
|
||||
n.lastSentCount++
|
||||
n.lastSent = utils.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
// GetValue returns the database value of a accept DbField value.
|
||||
|
@ -130,18 +129,6 @@ func (n *Notification) ResetQueue() {
|
|||
n.Queue = nil
|
||||
}
|
||||
|
||||
// ResetQueue will clear the notifiers Queue for a service
|
||||
func (n *Notification) ResetUniqueQueue(uid string) []*QueueData {
|
||||
var queue []*QueueData
|
||||
for _, v := range n.Queue {
|
||||
if v.Id != uid {
|
||||
queue = append(queue, v)
|
||||
}
|
||||
}
|
||||
n.Queue = queue
|
||||
return queue
|
||||
}
|
||||
|
||||
// start will start the go routine for the notifier queue
|
||||
func (n *Notification) Start() {
|
||||
n.Running = make(chan bool)
|
|
@ -0,0 +1,74 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
log = utils.Log
|
||||
)
|
||||
|
||||
// Notification contains all the fields for a Statping Notifier.
|
||||
type Notification struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Method string `gorm:"column:method" json:"method"`
|
||||
Host string `gorm:"not null;column:host" json:"host,omitempty"`
|
||||
Port int `gorm:"not null;column:port" json:"port,omitempty"`
|
||||
Username string `gorm:"not null;column:username" json:"username,omitempty"`
|
||||
Password string `gorm:"not null;column:password" json:"password,omitempty"`
|
||||
Var1 string `gorm:"not null;column:var1" json:"var1,omitempty"`
|
||||
Var2 string `gorm:"not null;column:var2" json:"var2,omitempty"`
|
||||
ApiKey string `gorm:"not null;column:api_key" json:"api_key,omitempty"`
|
||||
ApiSecret string `gorm:"not null;column:api_secret" json:"api_secret,omitempty"`
|
||||
Enabled null.NullBool `gorm:"column:enabled;type:boolean;default:false" json:"enabled"`
|
||||
Limits int `gorm:"not null;column:limits" json:"limits"`
|
||||
Removable bool `gorm:"column:removable" json:"removeable"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Form []NotificationForm `gorm:"-" json:"form"`
|
||||
Title string `gorm:"-" json:"title"`
|
||||
Description string `gorm:"-" json:"description"`
|
||||
Author string `gorm:"-" json:"author"`
|
||||
AuthorUrl string `gorm:"-" json:"author_url"`
|
||||
Icon string `gorm:"-" json:"icon"`
|
||||
Delay time.Duration `gorm:"-" json:"delay,string"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
|
||||
Queue []RunFunc `gorm:"-" json:"-"`
|
||||
|
||||
lastSent time.Time `gorm:"-" json:"-"`
|
||||
lastSentCount int `gorm:"-" json:"-"`
|
||||
|
||||
Hits notificationHits `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
type RunFunc func(interface{}) error
|
||||
|
||||
// NotificationForm contains the HTML fields for each variable/input you want the notifier to accept.
|
||||
type NotificationForm struct {
|
||||
Type string `json:"type"` // the html input type (text, password, email)
|
||||
Title string `json:"title"` // include a title for ease of use
|
||||
Placeholder string `json:"placeholder"` // add a placeholder for the input
|
||||
DbField string `json:"field"` // true variable key for input
|
||||
SmallText string `json:"small_text"` // insert small text under a html input
|
||||
Required bool `json:"required"` // require this input on the html form
|
||||
IsHidden bool `json:"hidden"` // hide this form element from end user
|
||||
IsList bool `json:"list"` // make this form element a comma separated list
|
||||
IsSwitch bool `json:"switch"` // make the notifier a boolean true/false switch
|
||||
}
|
||||
|
||||
type notificationHits struct {
|
||||
OnSuccess int64 `gorm:"-" json:"-"`
|
||||
OnFailure int64 `gorm:"-" json:"-"`
|
||||
OnSave int64 `gorm:"-" json:"-"`
|
||||
OnNewService int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedService int64 `gorm:"-" json:"-"`
|
||||
OnDeletedService int64 `gorm:"-" json:"-"`
|
||||
OnNewUser int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedUser int64 `gorm:"-" json:"-"`
|
||||
OnDeletedUser int64 `gorm:"-" json:"-"`
|
||||
OnNewNotifier int64 `gorm:"-" json:"-"`
|
||||
OnUpdatedNotifier int64 `gorm:"-" json:"-"`
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package notifier
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/services"
|
||||
)
|
||||
|
||||
// Notifier interface is required to create a new Notifier
|
||||
type Notifier interface {
|
||||
OnSuccess(*services.Service) error // OnSuccess is triggered when a service is successful
|
||||
OnFailure(*services.Service, *failures.Failure) error // OnFailure is triggered when a service is failing
|
||||
OnTest() error // OnTest is triggered for testing
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
)
|
||||
|
||||
var (
|
||||
allNotifiers []ServiceNotifier
|
||||
)
|
||||
|
||||
func AllNotifiers() []ServiceNotifier {
|
||||
return allNotifiers
|
||||
}
|
||||
|
||||
type ServiceNotifier interface {
|
||||
OnSuccess(*Service) error // OnSuccess is triggered when a service is successful
|
||||
OnFailure(*Service, *failures.Failure) error // OnFailure is triggered when a service is failing
|
||||
OnTest() error // OnTest is triggered for testing
|
||||
Select() *notifications.Notification // OnTest is triggered for testing
|
||||
}
|
|
@ -3,16 +3,17 @@ package services
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/tatsushid/go-fastping"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/tatsushid/go-fastping"
|
||||
)
|
||||
|
||||
// checkServices will start the checking go routine for each service
|
||||
|
@ -242,10 +243,36 @@ func recordSuccess(s *Service) {
|
|||
fmt.Sprintf("Service #%d '%v' Successful Response: %s | Lookup in: %s | Online: %v | Interval: %d seconds", s.Id, s.Name, humanMicro(hit.Latency), humanMicro(hit.PingTime), s.Online, s.Interval))
|
||||
s.LastLookupTime = hit.PingTime
|
||||
s.LastLatency = hit.Latency
|
||||
//notifiers.OnSuccess(s)
|
||||
sendSuccess(s)
|
||||
s.SuccessNotified = true
|
||||
}
|
||||
|
||||
func AddNotifier(n ServiceNotifier) {
|
||||
allNotifiers = append(allNotifiers, n)
|
||||
}
|
||||
|
||||
func sendSuccess(s *Service) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
// dont send notification if server was already previous online
|
||||
if s.SuccessNotified {
|
||||
return
|
||||
}
|
||||
for _, n := range allNotifiers {
|
||||
notif := n.Select()
|
||||
if notif.CanSend() {
|
||||
log.Infof("Sending notification to: %s!", notif.Method)
|
||||
if err := n.OnSuccess(s); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
s.UserNotified = true
|
||||
s.SuccessNotified = true
|
||||
//s.UpdateNotify.Bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recordFailure will create a new 'Failure' record in the database for a offline service
|
||||
func recordFailure(s *Service, issue string) {
|
||||
s.LastOffline = utils.Now()
|
||||
|
@ -266,7 +293,32 @@ func recordFailure(s *Service, issue string) {
|
|||
s.Online = false
|
||||
s.SuccessNotified = false
|
||||
s.DownText = s.DowntimeText()
|
||||
//notifiers.OnFailure(s, fail)
|
||||
sendFailure(s, fail)
|
||||
}
|
||||
|
||||
func sendFailure(s *Service, f *failures.Failure) {
|
||||
if !s.AllowNotifications.Bool {
|
||||
return
|
||||
}
|
||||
|
||||
// ignore failure if user was already notified and
|
||||
// they have "continuous notifications" switched off.
|
||||
if s.UserNotified && !s.UpdateNotify.Bool {
|
||||
return
|
||||
}
|
||||
|
||||
for _, n := range allNotifiers {
|
||||
notif := n.Select()
|
||||
if notif.CanSend() {
|
||||
log.Infof("Sending Failure notification to: %s!", notif.Method)
|
||||
if err := n.OnFailure(s, f); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
s.UserNotified = true
|
||||
s.SuccessNotified = true
|
||||
//s.UpdateNotify.Bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check will run checkHttp for HTTP services and checkTcp for TCP services
|
||||
|
|
Loading…
Reference in New Issue