diff --git a/cmd/database.go b/cmd/database.go
index bfc1798c..c438fac7 100644
--- a/cmd/database.go
+++ b/cmd/database.go
@@ -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{}}
}
diff --git a/types/core/init.go b/cmd/init.go
similarity index 60%
rename from types/core/init.go
rename to cmd/init.go
index 3e8b915b..b0141cc0 100644
--- a/types/core/init.go
+++ b/cmd/init.go
@@ -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
}
diff --git a/cmd/main.go b/cmd/main.go
index 3e66d75c..af5a0331 100644
--- a/cmd/main.go
+++ b/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
}
diff --git a/frontend/public/base.gohtml b/frontend/public/base.gohtml
index c5142dc9..525d21e2 100644
--- a/frontend/public/base.gohtml
+++ b/frontend/public/base.gohtml
@@ -18,7 +18,7 @@
{{if USING_ASSETS}}
-
+
{{else}}
<% _.each(htmlWebpackPlugin.tags.headTags, function(headTag) { %>
<%= headTag %> <% }) %>
diff --git a/frontend/src/forms/Notifier.vue b/frontend/src/forms/Notifier.vue
index d332b5da..29ea390b 100644
--- a/frontend/src/forms/Notifier.vue
+++ b/frontend/src/forms/Notifier.vue
@@ -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(() => {
diff --git a/handlers/api.go b/handlers/api.go
index b79a7611..6bb9b11e 100644
--- a/handlers/api.go
+++ b/handlers/api.go
@@ -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:
diff --git a/handlers/notifications.go b/handlers/notifications.go
index bc3e8946..b3b44cc3 100644
--- a/handlers/notifications.go
+++ b/handlers/notifications.go
@@ -1,42 +1,43 @@
-// Statping
-// Copyright (C) 2018. Hunter Long and the project contributors
-// Written by Hunter Long and the project contributors
+//// Statping
+//// Copyright (C) 2018. Hunter Long and the project contributors
+//// Written by Hunter Long 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 .
//
-// 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 .
-
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)
diff --git a/handlers/prometheus.go b/handlers/prometheus.go
index 9516669d..c0d9b569 100644
--- a/handlers/prometheus.go
+++ b/handlers/prometheus.go
@@ -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")
diff --git a/handlers/setup.go b/handlers/setup.go
index d995d06b..5541af86 100644
--- a/handlers/setup.go
+++ b/handlers/setup.go
@@ -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)
diff --git a/notifiers/command.go b/notifiers/command.go
index f73d3d7a..31384be4 100644
--- a/notifiers/command.go
+++ b/notifiers/command.go
@@ -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
-}
diff --git a/notifiers/discord.go b/notifiers/discord.go
index ae4c3e0a..1ec101a2 100644
--- a/notifiers/discord.go
+++ b/notifiers/discord.go
@@ -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 discord webhooker API.",
@@ -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
diff --git a/notifiers/doc.go b/notifiers/doc.go
deleted file mode 100644
index 25329d19..00000000
--- a/notifiers/doc.go
+++ /dev/null
@@ -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
diff --git a/notifiers/email.go b/notifiers/email.go
index 3141ffa8..520e8af2 100644
--- a/notifiers/email.go
+++ b/notifiers/email.go
@@ -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 = `
@@ -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
diff --git a/notifiers/events.go b/notifiers/events.go
deleted file mode 100644
index 12a07008..00000000
--- a/notifiers/events.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Statping
-// Copyright (C) 2018. Hunter Long and the project contributors
-// Written by Hunter Long 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 .
-
-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++
- }
- }
-}
diff --git a/notifiers/interface/doc.go b/notifiers/interface/doc.go
deleted file mode 100644
index 4fb4c946..00000000
--- a/notifiers/interface/doc.go
+++ /dev/null
@@ -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
diff --git a/notifiers/interfaces.go b/notifiers/interfaces.go
deleted file mode 100644
index bf58e992..00000000
--- a/notifiers/interfaces.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Statping
-// Copyright (C) 2018. Hunter Long and the project contributors
-// Written by Hunter Long 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 .
-
-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
-}
diff --git a/notifiers/line_notify.go b/notifiers/line_notify.go
index aeb77003..51f06787 100644
--- a/notifiers/line_notify.go
+++ b/notifiers/line_notify.go
@@ -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 LINE Notify API.",
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)
}
diff --git a/notifiers/mobile.go b/notifiers/mobile.go
index ec0e024d..66469eea 100644
--- a/notifiers/mobile.go
+++ b/notifiers/mobile.go
@@ -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)
diff --git a/notifiers/notifications_test.go b/notifiers/notifications_test.go
deleted file mode 100644
index f6b68f02..00000000
--- a/notifiers/notifications_test.go
+++ /dev/null
@@ -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())
-}
diff --git a/notifiers/notifiers.go b/notifiers/notifiers.go
index e8a82cd5..2a752dc6 100644
--- a/notifiers/notifiers.go
+++ b/notifiers/notifiers.go
@@ -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)
+ }
+ }
+}
diff --git a/notifiers/slack.go b/notifiers/slack.go
index 984a90db..abd30da8 100644
--- a/notifiers/slack.go
+++ b/notifiers/slack.go
@@ -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 slack API.",
@@ -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)
}
diff --git a/notifiers/struct.go b/notifiers/struct.go
deleted file mode 100644
index 5f2211df..00000000
--- a/notifiers/struct.go
+++ /dev/null
@@ -1,273 +0,0 @@
-// Statping
-// Copyright (C) 2018. Hunter Long and the project contributors
-// Written by Hunter Long 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 .
-
-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: "this is an example response",
- CreatedAt: utils.Now().Add(-24 * time.Hour),
-}
diff --git a/notifiers/telegram.go b/notifiers/telegram.go
index a1565577..857e5243 100644
--- a/notifiers/telegram.go
+++ b/notifiers/telegram.go
@@ -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 Telegram API Tutorial 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) {
diff --git a/notifiers/twilio.go b/notifiers/twilio.go
index 25e88881..39645fbe 100644
--- a/notifiers/twilio.go
+++ b/notifiers/twilio.go
@@ -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 Twilio API.",
@@ -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) {
diff --git a/notifiers/webhook.go b/notifiers/webhook.go
index 1c39c71d..93296b50 100644
--- a/notifiers/webhook.go
+++ b/notifiers/webhook.go
@@ -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
}
diff --git a/types/configs/connection.go b/types/configs/connection.go
index 639101a9..123abfca 100644
--- a/types/configs/connection.go
+++ b/types/configs/connection.go
@@ -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)
diff --git a/types/configs/database.go b/types/configs/database.go
index a35279f9..4312f324 100644
--- a/types/configs/database.go
+++ b/types/configs/database.go
@@ -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 {
diff --git a/types/configs/migration.go b/types/configs/migration.go
index a466373c..f96daa69 100644
--- a/types/configs/migration.go
+++ b/types/configs/migration.go
@@ -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()
diff --git a/notifiers/database.go b/types/notifications/database.go
similarity index 52%
rename from notifiers/database.go
rename to types/notifications/database.go
index 5fad2de8..1591ae35 100644
--- a/notifiers/database.go
+++ b/types/notifications/database.go
@@ -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
}
diff --git a/notifiers/methods.go b/types/notifications/methods.go
similarity index 65%
rename from notifiers/methods.go
rename to types/notifications/methods.go
index a7ccf177..07b9362f 100644
--- a/notifiers/methods.go
+++ b/types/notifications/methods.go
@@ -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)
diff --git a/types/notifications/struct.go b/types/notifications/struct.go
new file mode 100644
index 00000000..db5366db
--- /dev/null
+++ b/types/notifications/struct.go
@@ -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:"-"`
+}
diff --git a/types/notifier/interface.go b/types/notifier/interface.go
new file mode 100644
index 00000000..89906564
--- /dev/null
+++ b/types/notifier/interface.go
@@ -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
+}
diff --git a/types/services/notifier.go b/types/services/notifier.go
new file mode 100644
index 00000000..067acb60
--- /dev/null
+++ b/types/services/notifier.go
@@ -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
+}
diff --git a/types/services/routine.go b/types/services/routine.go
index 6f808a82..e979a782 100644
--- a/types/services/routine.go
+++ b/types/services/routine.go
@@ -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