service close channels - ServiceInterface - service check from time.Duration

pull/78/head
Hunter Long 2018-09-08 15:16:26 -07:00
parent 49a264c525
commit 347f2798dd
22 changed files with 242 additions and 240 deletions

View File

@ -149,8 +149,9 @@ func RunOnce() {
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
} }
for _, s := range core.CoreApp.Services() { for _, s := range core.CoreApp.Services {
out := s.Check(true) out := s.(*types.Service)
out.Check(true)
fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online) fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online)
} }
} }

View File

@ -471,11 +471,11 @@ func RunDeleteService(t *testing.T) {
} }
func RunCreateService_Hits(t *testing.T) { func RunCreateService_Hits(t *testing.T) {
services := core.CoreApp.Services() services := core.CoreApp.Services
assert.NotNil(t, services) assert.NotNil(t, services)
assert.Equal(t, 19, len(services)) assert.Equal(t, 19, len(services))
for _, s := range services { for _, service := range services {
service := s.Check(true) service.Check(true)
assert.NotNil(t, service) assert.NotNil(t, service)
} }
} }

View File

@ -30,9 +30,8 @@ import (
) )
func CheckServices() { func CheckServices() {
CoreApp.SelectAllServices() utils.Log(1, fmt.Sprintf("Starting monitoring process for %v Services", len(CoreApp.Services)))
utils.Log(1, fmt.Sprintf("Starting monitoring process for %v DbServices", len(CoreApp.Services()))) for _, ser := range CoreApp.Services {
for _, ser := range CoreApp.Services() {
//go obj.StartCheckins() //go obj.StartCheckins()
go ser.CheckQueue(true) go ser.CheckQueue(true)
} }
@ -40,24 +39,25 @@ func CheckServices() {
func (s *Service) CheckQueue(record bool) { func (s *Service) CheckQueue(record bool) {
s.Checkpoint = time.Now() s.Checkpoint = time.Now()
s.SleepDuration = time.Duration((time.Duration(s.Id) * 100) * time.Millisecond)
CheckLoop: CheckLoop:
for { for {
select { select {
case <-s.Running: case <-s.Running:
utils.Log(1, fmt.Sprintf("Stopping service: %v", s.Name)) utils.Log(1, fmt.Sprintf("Stopping service: %v", s.Name))
break CheckLoop break CheckLoop
default: case <-time.After(s.SleepDuration):
utils.Log(1, fmt.Sprintf("Checking service: %v", s.Name))
s.Check(record) s.Check(record)
// Set next time checkpoint and maybe sleep.
s.Checkpoint = s.Checkpoint.Add(s.duration()) s.Checkpoint = s.Checkpoint.Add(s.duration())
if sleepDuration := s.Checkpoint.Sub(time.Now()); sleepDuration > 0 { sleep := s.Checkpoint.Sub(time.Now())
time.Sleep(sleepDuration) if !s.Online {
s.SleepDuration = s.duration()
} else {
s.SleepDuration = sleep
}
} }
continue continue
} }
}
} }
func (s *Service) duration() time.Duration { func (s *Service) duration() time.Duration {
@ -119,14 +119,13 @@ func (s *Service) checkTcp(record bool) *Service {
return s return s
} }
func (s *Service) Check(record bool) *Service { func (s *Service) Check(record bool) {
switch s.Type { switch s.Type {
case "http": case "http":
s.checkHttp(record) s.checkHttp(record)
case "tcp": case "tcp":
s.checkTcp(record) s.checkTcp(record)
} }
return s
} }
func (s *Service) checkHttp(record bool) *Service { func (s *Service) checkHttp(record bool) *Service {

View File

@ -36,8 +36,9 @@ func ReturnCheckin(s *types.Checkin) *Checkin {
} }
func FindCheckin(api string) *types.Checkin { func FindCheckin(api string) *types.Checkin {
for _, ser := range CoreApp.Services() { for _, ser := range CoreApp.Services {
for _, c := range ser.Checkins { service := ser.(*types.Service)
for _, c := range service.Checkins {
if c.Api == api { if c.Api == api {
return c return c
} }

View File

@ -22,7 +22,6 @@ import (
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
"os" "os"
"sort"
"time" "time"
) )
@ -113,8 +112,8 @@ func (c Core) MobileSASS() string {
// AllOnline will be true if all services are online // AllOnline will be true if all services are online
func (c Core) AllOnline() bool { func (c Core) AllOnline() bool {
for _, s := range CoreApp.Services() { for _, s := range CoreApp.Services {
if !s.Online { if !s.(*types.Service).Online {
return false return false
} }
} }
@ -136,7 +135,6 @@ func SelectCore() (*Core, error) {
} }
CoreApp.DbConnection = Configs.DbConn CoreApp.DbConnection = Configs.DbConn
CoreApp.Version = VERSION CoreApp.Version = VERSION
CoreApp.SelectAllServices()
if os.Getenv("USE_CDN") == "true" { if os.Getenv("USE_CDN") == "true" {
CoreApp.UseCdn = true CoreApp.UseCdn = true
} }
@ -152,13 +150,13 @@ func (c ServiceOrder) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order } func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
// Services returns each Service that is attached to this instance // Services returns each Service that is attached to this instance
func (c *Core) Services() []*Service { //func (c *Core) Services() []*Service {
var services []*Service // var services []*Service
servs := CoreApp.GetServices() // servs := CoreApp.GetServices()
sort.Sort(ServiceOrder(servs)) // sort.Sort(ServiceOrder(servs))
CoreApp.SetServices(servs) // CoreApp.SetServices(servs)
for _, ser := range servs { // for _, ser := range servs {
services = append(services, ReturnService(ser)) // services = append(services, ReturnService(ser))
} // }
return services // return services
} //}

View File

@ -19,6 +19,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/hunterlong/statup/source" "github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
@ -37,8 +38,9 @@ func ExportIndexHTML() string {
injectDatabase() injectDatabase()
CoreApp.SelectAllServices() CoreApp.SelectAllServices()
CoreApp.UseCdn = true CoreApp.UseCdn = true
for _, service := range CoreApp.Services() { for _, srv := range CoreApp.Services {
service = service.Check(true) service := srv.(*types.Service)
service.Check(true)
fmt.Println(service.Name, service.Online, service.Latency) fmt.Println(service.Name, service.Online, service.Latency)
} }
nav, _ := source.TmplBox.String("nav.html") nav, _ := source.TmplBox.String("nav.html")
@ -99,7 +101,7 @@ func ExportChartsJs() string {
}) })
t.Parse(render) t.Parse(render)
var tpl bytes.Buffer var tpl bytes.Buffer
if err := t.Execute(&tpl, CoreApp.Services()); err != nil { if err := t.Execute(&tpl, CoreApp.Services); err != nil {
utils.Log(3, err) utils.Log(3, err)
} }
result := tpl.String() result := tpl.String()

View File

@ -40,14 +40,17 @@ func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
return f.Id, row.Error return f.Id, row.Error
} }
func (s *Service) AllFailures() []*types.Failure { func (s *Service) AllFailures() []*Failure {
var fails []*types.Failure var fails []*Failure
col := failuresDB().Where("service = ?", s.Id).Order("id desc") col := failuresDB().Where("service = ?", s.Id).Order("id desc")
err := col.Find(&fails) err := col.Find(&fails)
if err.Error != nil { if err.Error != nil {
utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err)) utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
return nil return nil
} }
for _, f := range fails {
s.Failures = append(s.Failures, f)
}
return fails return fails
} }
@ -76,6 +79,16 @@ func (f *Failure) Delete() error {
return db.Error return db.Error
} }
func (c *Core) Count24HFailures() uint64 {
var count uint64
for _, s := range CoreApp.Services {
service := s.(*Service)
fails, _ := service.TotalFailures24()
count += fails
}
return count
}
func CountFailures() uint64 { func CountFailures() uint64 {
var count uint64 var count uint64
err := failuresDB().Count(&count) err := failuresDB().Count(&count)

View File

@ -34,29 +34,29 @@ func (s *Service) CreateHit(h *types.Hit) (int64, error) {
return h.Id, db.Error return h.Id, db.Error
} }
func (s *Service) Hits() ([]*Hit, error) { func (s *Service) Hits() ([]*types.Hit, error) {
var hits []*Hit var hits []*types.Hit
col := hitsDB().Where("service = ?", s.Id).Order("id desc") col := hitsDB().Where("service = ?", s.Id).Order("id desc")
err := col.Find(&hits) err := col.Find(&hits)
return hits, err.Error return hits, err.Error
} }
func (s *Service) LimitedHits() ([]*Hit, error) { func (s *Service) LimitedHits() ([]*types.Hit, error) {
var hits []*Hit var hits []*types.Hit
col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(1024) col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(1024)
err := col.Find(&hits) err := col.Find(&hits)
return reverseHits(hits), err.Error return reverseHits(hits), err.Error
} }
func reverseHits(input []*Hit) []*Hit { func reverseHits(input []*types.Hit) []*types.Hit {
if len(input) == 0 { if len(input) == 0 {
return input return input
} }
return append(reverseHits(input[1:]), input[0]) return append(reverseHits(input[1:]), input[0])
} }
func (s *Service) SelectHitsGroupBy(group string) ([]*Hit, error) { func (s *Service) SelectHitsGroupBy(group string) ([]*types.Hit, error) {
var hits []*Hit var hits []*types.Hit
col := hitsDB().Where("service = ?", s.Id) col := hitsDB().Where("service = ?", s.Id)
err := col.Find(&hits) err := col.Find(&hits)
return hits, err.Error return hits, err.Error

View File

@ -33,30 +33,27 @@ func ReturnService(s *types.Service) *Service {
} }
func SelectService(id int64) *Service { func SelectService(id int64) *Service {
for _, s := range CoreApp.Services() { for _, s := range CoreApp.Services {
if s.Service.Id == id { if s.(*Service).Id == id {
return s return s.(*Service)
} }
} }
return nil return nil
} }
func (c *Core) SelectAllServices() ([]*types.Service, error) { func (c *Core) SelectAllServices() ([]*Service, error) {
var services []*types.Service var services []*Service
var servs []*types.Service
db := servicesDB().Find(&services).Order("order_id desc") db := servicesDB().Find(&services).Order("order_id desc")
if db.Error != nil { if db.Error != nil {
utils.Log(3, fmt.Sprintf("service error: %v", db.Error)) utils.Log(3, fmt.Sprintf("service error: %v", db.Error))
return nil, db.Error return nil, db.Error
} }
for _, ser := range services { for _, service := range services {
single := ReturnService(ser) service.Start()
single.Start() service.AllCheckins()
single.AllCheckins() service.AllFailures()
single.AllFailures() CoreApp.Services = append(CoreApp.Services, service)
servs = append(servs, single.Service)
} }
CoreApp.SetServices(servs)
return services, db.Error return services, db.Error
} }
@ -190,7 +187,7 @@ func (s *Service) AvgUptime(ago time.Time) string {
} }
total, _ := s.TotalHitsSince(ago) total, _ := s.TotalHitsSince(ago)
if total == 0 { if total == 0 {
return "0" return "0.00"
} }
percent := float64(failed) / float64(total) * 100 percent := float64(failed) / float64(total) * 100
percent = 100 - percent percent = 100 - percent
@ -220,8 +217,8 @@ func (s *Service) TotalUptime() string {
} }
func (s *Service) index() int { func (s *Service) index() int {
for k, service := range CoreApp.Services() { for k, service := range CoreApp.Services {
if s.Id == service.Id { if s.Id == service.(*Service).Id {
return k return k
} }
} }
@ -229,19 +226,20 @@ func (s *Service) index() int {
} }
func updateService(service *Service) { func updateService(service *Service) {
service.Start()
index := service.index() index := service.index()
CoreApp.UpdateService(index, service.Service) CoreApp.Services[index] = service
} }
func (u *Service) Delete() error { func (u *Service) Delete() error {
i := u.index()
err := servicesDB().Delete(u) err := servicesDB().Delete(u)
if err.Error != nil { if err.Error != nil {
utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err.Error)) utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err.Error))
return err.Error return err.Error
} }
u.Close() u.Close()
CoreApp.RemoveService(u.index()) slice := CoreApp.Services
CoreApp.Services = append(slice[:i], slice[i+1:]...)
OnDeletedService(u) OnDeletedService(u)
return err.Error return err.Error
} }
@ -251,7 +249,6 @@ func (u *Service) UpdateSingle(attr ...interface{}) error {
} }
func (u *Service) Update(restart bool) error { func (u *Service) Update(restart bool) error {
u.CreatedAt = time.Now()
err := servicesDB().Update(u) err := servicesDB().Update(u)
if err.Error != nil { if err.Error != nil {
utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err)) utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err))
@ -259,11 +256,11 @@ func (u *Service) Update(restart bool) error {
} }
if restart { if restart {
u.Close() u.Close()
} u.Start()
updateService(u) u.SleepDuration = time.Duration(u.Interval) * time.Second
if restart {
go u.CheckQueue(true) go u.CheckQueue(true)
} }
updateService(u)
OnUpdateService(u) OnUpdateService(u)
return err.Error return err.Error
} }
@ -276,14 +273,19 @@ func (u *Service) Create() (int64, error) {
return 0, db.Error return 0, db.Error
} }
u.Start() u.Start()
CoreApp.AddService(u.Service) go u.CheckQueue(true)
CoreApp.Services = append(CoreApp.Services, u)
return u.Id, nil return u.Id, nil
} }
func CountOnline() int { func (c *Core) ServicesCount() int {
return len(c.Services)
}
func (c *Core) CountOnline() int {
amount := 0 amount := 0
for _, s := range CoreApp.Services() { for _, s := range CoreApp.Services {
if s.Online { if s.(*Service).Online {
amount++ amount++
} }
} }

View File

@ -35,17 +35,18 @@ func TestSelectHTTPService(t *testing.T) {
} }
func TestSelectAllServices(t *testing.T) { func TestSelectAllServices(t *testing.T) {
services := CoreApp.Services() services := CoreApp.Services
for _, s := range services { for _, s := range services {
service := s.Check(true) service := s.(*Service)
service.Check(true)
assert.True(t, service.IsRunning()) assert.True(t, service.IsRunning())
t.Logf("ID: %v %v\n", s.Id, s.Name) t.Logf("ID: %v %v\n", service.Id, service.Name)
} }
assert.Equal(t, 18, len(services)) assert.Equal(t, 18, len(services))
} }
func TestSelectTCPService(t *testing.T) { func TestSelectTCPService(t *testing.T) {
services := CoreApp.Services() services := CoreApp.Services
assert.Equal(t, 18, len(services)) assert.Equal(t, 18, len(services))
service := SelectService(5) service := SelectService(5)
assert.NotNil(t, service) assert.NotNil(t, service)
@ -72,8 +73,7 @@ func TestUpdateService(t *testing.T) {
func TestUpdateAllServices(t *testing.T) { func TestUpdateAllServices(t *testing.T) {
services, err := CoreApp.SelectAllServices() services, err := CoreApp.SelectAllServices()
assert.Nil(t, err) assert.Nil(t, err)
for k, s := range services { for k, srv := range services {
srv := ReturnService(s)
srv.Name = "Changed " + srv.Name srv.Name = "Changed " + srv.Name
srv.Interval = k + 3 srv.Interval = k + 3
err := srv.Update(true) err := srv.Update(true)
@ -83,9 +83,9 @@ func TestUpdateAllServices(t *testing.T) {
func TestServiceHTTPCheck(t *testing.T) { func TestServiceHTTPCheck(t *testing.T) {
service := SelectService(1) service := SelectService(1)
checked := service.Check(true) service.Check(true)
assert.Equal(t, "Changed Updated Google", checked.Name) assert.Equal(t, "Changed Updated Google", service.Name)
assert.True(t, checked.Online) assert.True(t, service.Online)
} }
func TestCheckHTTPService(t *testing.T) { func TestCheckHTTPService(t *testing.T) {
@ -98,9 +98,9 @@ func TestCheckHTTPService(t *testing.T) {
func TestServiceTCPCheck(t *testing.T) { func TestServiceTCPCheck(t *testing.T) {
service := SelectService(5) service := SelectService(5)
checked := service.Check(true) service.Check(true)
assert.Equal(t, "Changed Google DNS", checked.Name) assert.Equal(t, "Changed Google DNS", service.Name)
assert.True(t, checked.Online) assert.True(t, service.Online)
} }
func TestCheckTCPService(t *testing.T) { func TestCheckTCPService(t *testing.T) {
@ -167,7 +167,7 @@ func TestServiceSum(t *testing.T) {
} }
func TestCountOnline(t *testing.T) { func TestCountOnline(t *testing.T) {
amount := CountOnline() amount := CoreApp.CountOnline()
assert.Equal(t, 2, amount) assert.Equal(t, 2, amount)
} }
@ -216,9 +216,9 @@ func TestCreateFailingHTTPService(t *testing.T) {
func TestServiceFailedCheck(t *testing.T) { func TestServiceFailedCheck(t *testing.T) {
service := SelectService(20) service := SelectService(20)
assert.Equal(t, "Bad URL", service.Name) assert.Equal(t, "Bad URL", service.Name)
checked := service.Check(true) service.Check(true)
assert.Equal(t, "Bad URL", checked.Name) assert.Equal(t, "Bad URL", service.Name)
assert.False(t, checked.Online) assert.False(t, service.Online)
} }
func TestCreateFailingTCPService(t *testing.T) { func TestCreateFailingTCPService(t *testing.T) {
@ -241,9 +241,9 @@ func TestCreateFailingTCPService(t *testing.T) {
func TestServiceFailedTCPCheck(t *testing.T) { func TestServiceFailedTCPCheck(t *testing.T) {
service := SelectService(21) service := SelectService(21)
checked := service.Check(true) service.Check(true)
assert.Equal(t, "Bad TCP", checked.Name) assert.Equal(t, "Bad TCP", service.Name)
assert.False(t, checked.Online) assert.False(t, service.Online)
} }
func TestCreateServiceFailure(t *testing.T) { func TestCreateServiceFailure(t *testing.T) {
@ -267,7 +267,7 @@ func TestDeleteService(t *testing.T) {
err = service.Delete() err = service.Delete()
assert.Nil(t, err) assert.Nil(t, err)
services := CoreApp.Services() services := CoreApp.Services
assert.Equal(t, 20, len(services)) assert.Equal(t, 20, len(services))
} }
@ -282,10 +282,13 @@ func TestServiceCloseRoutine(t *testing.T) {
s.Start() s.Start()
assert.True(t, s.IsRunning()) assert.True(t, s.IsRunning())
t.Log(s.Checkpoint) t.Log(s.Checkpoint)
t.Log(s.SleepDuration)
go s.CheckQueue(false) go s.CheckQueue(false)
t.Log(s.Checkpoint) t.Log(s.Checkpoint)
t.Log(s.SleepDuration)
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
t.Log(s.Checkpoint) t.Log(s.Checkpoint)
t.Log(s.SleepDuration)
assert.True(t, s.IsRunning()) assert.True(t, s.IsRunning())
s.Close() s.Close()
assert.False(t, s.IsRunning()) assert.False(t, s.IsRunning())

View File

@ -156,7 +156,7 @@ func ApiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return return
} }
services := core.CoreApp.Services() services := core.CoreApp.Services
json.NewEncoder(w).Encode(services) json.NewEncoder(w).Encode(services)
} }

View File

@ -16,26 +16,19 @@
package handlers package handlers
import ( import (
"fmt"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"net/http" "net/http"
) )
type dashboard struct {
Core *core.Core
CountOnline int
CountServices int
Count24Failures uint64
}
func DashboardHandler(w http.ResponseWriter, r *http.Request) { func DashboardHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println()
if !IsAuthenticated(r) { if !IsAuthenticated(r) {
err := core.ErrorResponse{} err := core.ErrorResponse{}
ExecuteResponse(w, r, "login.html", err) ExecuteResponse(w, r, "login.html", err)
} else { } else {
fails := core.CountFailures() ExecuteResponse(w, r, "dashboard.html", core.CoreApp)
out := dashboard{core.CoreApp, core.CountOnline(), len(core.CoreApp.Services()), fails}
ExecuteResponse(w, r, "dashboard.html", out)
} }
} }

View File

@ -17,6 +17,7 @@ package handlers
import ( import (
"fmt" "fmt"
"github.com/gin-gonic/gin/json"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/source" "github.com/hunterlong/statup/source"
@ -25,6 +26,7 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"os" "os"
"reflect"
"time" "time"
) )
@ -105,9 +107,27 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
"CoreApp": func() *core.Core { "CoreApp": func() *core.Core {
return core.CoreApp return core.CoreApp
}, },
"Services": func() []types.ServiceInterface {
return core.CoreApp.Services
},
"USE_CDN": func() bool { "USE_CDN": func() bool {
return core.CoreApp.UseCdn return core.CoreApp.UseCdn
}, },
"Type": func(g interface{}) []string {
fooType := reflect.TypeOf(g)
var methods []string
methods = append(methods, fooType.String())
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
methods = append(methods, method.Name)
}
return methods
},
"ToJSON": func(g interface{}) template.HTML {
data, _ := json.Marshal(g)
return template.HTML(string(data))
},
"underscore": func(html string) string { "underscore": func(html string) string {
return utils.UnderScoreString(html) return utils.UnderScoreString(html)
}, },

View File

@ -41,10 +41,10 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
} }
metrics := []string{} metrics := []string{}
system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures()) system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures())
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services())) system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
metrics = append(metrics, system) metrics = append(metrics, system)
for _, ser := range core.CoreApp.Services() { for _, ser := range core.CoreApp.Services {
v := ser v := ser.(*core.Service)
online := 1 online := 1
if !v.Online { if !v.Online {
online = 0 online = 0

View File

@ -31,7 +31,7 @@ type Service struct {
} }
func RenderServiceChartsHandler(w http.ResponseWriter, r *http.Request) { func RenderServiceChartsHandler(w http.ResponseWriter, r *http.Request) {
services := core.CoreApp.Services() services := core.CoreApp.Services
w.Header().Set("Content-Type", "text/javascript") w.Header().Set("Content-Type", "text/javascript")
w.Header().Set("Cache-Control", "max-age=60") w.Header().Set("Cache-Control", "max-age=60")
ExecuteJSResponse(w, r, "charts.js", services) ExecuteJSResponse(w, r, "charts.js", services)
@ -42,7 +42,7 @@ func ServicesHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
return return
} }
ExecuteResponse(w, r, "services.html", core.CoreApp.Services()) ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
} }
type serviceOrder struct { type serviceOrder struct {
@ -106,10 +106,8 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err)) utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
} }
service = service.Check(true) core.OnNewService(core.ReturnService(service.Service))
go service.CheckQueue(true) ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
core.OnNewService(service)
ExecuteResponse(w, r, "services.html", core.CoreApp.Services())
} }
func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) { func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
@ -118,14 +116,13 @@ func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
vars := mux.Vars(r) vars := mux.Vars(r)
serv := core.SelectService(utils.StringInt(vars["id"])) service := core.SelectService(utils.StringInt(vars["id"]))
if serv == nil { if service == nil {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
service := serv
service.Delete() service.Delete()
ExecuteResponse(w, r, "services.html", core.CoreApp.Services()) ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
} }
func ServicesViewHandler(w http.ResponseWriter, r *http.Request) { func ServicesViewHandler(w http.ResponseWriter, r *http.Request) {
@ -144,8 +141,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
vars := mux.Vars(r) vars := mux.Vars(r)
serv := core.SelectService(utils.StringInt(vars["id"])) service := core.SelectService(utils.StringInt(vars["id"]))
service := serv
r.ParseForm() r.ParseForm()
name := r.PostForm.Get("name") name := r.PostForm.Get("name")
domain := r.PostForm.Get("domain") domain := r.PostForm.Get("domain")
@ -159,23 +155,21 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
postData := r.PostForm.Get("post_data") postData := r.PostForm.Get("post_data")
order, _ := strconv.Atoi(r.PostForm.Get("order")) order, _ := strconv.Atoi(r.PostForm.Get("order"))
serviceUpdate := core.ReturnService(&types.Service{ service.Name = name
Id: service.Id, service.Domain = domain
Name: name, service.Method = method
Domain: domain, service.ExpectedStatus = status
Method: method, service.Expected = expected
Expected: expected, service.Interval = interval
ExpectedStatus: status, service.Type = checkType
Interval: interval, service.Port = port
Type: checkType, service.PostData = postData
Port: port, service.Timeout = timeout
PostData: postData, service.Order = order
Timeout: timeout,
Order: order, service.Update(true)
}) service.Check(true)
serviceUpdate.Update(true) ExecuteResponse(w, r, "service.html", service)
serviceUpdate = serviceUpdate.Check(true)
ExecuteResponse(w, r, "service.html", serviceUpdate)
} }
func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) { func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
@ -186,7 +180,7 @@ func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
service := core.SelectService(utils.StringInt(vars["id"])) service := core.SelectService(utils.StringInt(vars["id"]))
service.DeleteFailures() service.DeleteFailures()
ExecuteResponse(w, r, "services.html", core.CoreApp.Services()) ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
} }
func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) { func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {

View File

@ -39,28 +39,29 @@ func SaveSettingsHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
r.ParseForm() r.ParseForm()
app := core.CoreApp
name := r.PostForm.Get("project") name := r.PostForm.Get("project")
if name != "" { if name != "" {
core.CoreApp.Name = name app.Name = name
} }
description := r.PostForm.Get("description") description := r.PostForm.Get("description")
if description != core.CoreApp.Description { if description != app.Description {
core.CoreApp.Description = description app.Description = description
} }
style := r.PostForm.Get("style") style := r.PostForm.Get("style")
if style != core.CoreApp.Style { if style != app.Style {
core.CoreApp.Style = style app.Style = style
} }
footer := r.PostForm.Get("footer") footer := r.PostForm.Get("footer")
if footer != core.CoreApp.Footer { if footer != app.Footer {
core.CoreApp.Footer = footer app.Footer = footer
} }
domain := r.PostForm.Get("domain") domain := r.PostForm.Get("domain")
if domain != core.CoreApp.Domain { if domain != app.Domain {
core.CoreApp.Domain = domain app.Domain = domain
} }
core.CoreApp.UseCdn = (r.PostForm.Get("enable_cdn") == "on") app.UseCdn = (r.PostForm.Get("enable_cdn") == "on")
core.CoreApp, _ = core.UpdateCore(core.CoreApp) core.CoreApp, _ = core.UpdateCore(app)
core.OnSettingsSaved(core.CoreApp.ToCore()) core.OnSettingsSaved(core.CoreApp.ToCore())
ExecuteResponse(w, r, "settings.html", core.CoreApp) ExecuteResponse(w, r, "settings.html", core.CoreApp)
} }

View File

@ -26,7 +26,7 @@ import (
) )
func SetupHandler(w http.ResponseWriter, r *http.Request) { func SetupHandler(w http.ResponseWriter, r *http.Request) {
if core.CoreApp.Services() != nil { if core.CoreApp.Services != nil {
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
return return
} }
@ -56,7 +56,7 @@ func SetupHandler(w http.ResponseWriter, r *http.Request) {
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) { func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
var err error var err error
if core.CoreApp.Services() != nil { if core.CoreApp.Services != nil {
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
return return
} }

View File

@ -25,12 +25,12 @@
<div class="row stats_area mb-5"> <div class="row stats_area mb-5">
<div class="col-4"> <div class="col-4">
<span class="lg_number">{{ .CountServices }}</span> <span class="lg_number">{{ .ServicesCount }}</span>
Total Services Total Services
</div> </div>
<div class="col-4"> <div class="col-4">
<span class="lg_number">{{ .Count24Failures }}</span> <span class="lg_number">{{ .Count24HFailures }}</span>
Failures last 24 Hours Failures last 24 Hours
</div> </div>
@ -47,7 +47,7 @@
<h3>Services</h3> <h3>Services</h3>
<div class="list-group mb-5 mt-3"> <div class="list-group mb-5 mt-3">
{{ range .Core.Services }} {{ range Services }}
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start"> <a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
<div class="d-flex w-100 justify-content-between"> <div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{.Name}}</h5> <h5 class="mb-1">{{.Name}}</h5>
@ -58,7 +58,7 @@
{{ end }} {{ end }}
</div> </div>
{{ range .Core.Services }} {{ range Services }}
{{ if .LimitedFailures }} {{ if .LimitedFailures }}
<h4 class="text-truncate">{{.Name}} Failures</h4> <h4 class="text-truncate">{{.Name}} Failures</h4>
<div class="list-group mt-3 mb-4"> <div class="list-group mt-3 mb-4">

View File

@ -17,7 +17,6 @@
</head> </head>
<body> <body>
<div class="container col-md-7 col-sm-12 mt-2 sm-container"> <div class="container col-md-7 col-sm-12 mt-2 sm-container">
<h1 class="col-12 text-center mb-4 mt-sm-3 header-title">{{.Name}}</h1> <h1 class="col-12 text-center mb-4 mt-sm-3 header-title">{{.Name}}</h1>
@ -28,7 +27,7 @@
<div class="col-12 full-col-12 mb-5"> <div class="col-12 full-col-12 mb-5">
<div class="list-group online_list"> <div class="list-group online_list">
{{ range .Services }} {{ range Services }}
<a href="#" class="service_li list-group-item list-group-item-action {{if not .Online}}bg-danger text-white{{ end }}" data-id="{{.Id}}"> <a href="#" class="service_li list-group-item list-group-item-action {{if not .Online}}bg-danger text-white{{ end }}" data-id="{{.Id}}">
{{ .Name }} {{ .Name }}
{{if .Online}} {{if .Online}}
@ -43,7 +42,7 @@
<div class="col-12 full-col-12"> <div class="col-12 full-col-12">
{{ if not .Services }} {{ if not Services }}
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<h4 class="alert-heading">No Services to Monitor!</h4> <h4 class="alert-heading">No Services to Monitor!</h4>
<p>Your Statup Status Page is working correctly, but you don't have any services to monitor. Go to the <b>Dashboard</b> and add a website to begin really using your status page!</p> <p>Your Statup Status Page is working correctly, but you don't have any services to monitor. Go to the <b>Dashboard</b> and add a website to begin really using your status page!</p>
@ -51,7 +50,7 @@
<p class="mb-0">If this is a bug, please make an issue in the Statup Github Repo. <a href="https://github.com/hunterlong/statup" class="btn btn-sm btn-outline-danger float-right">Statup Github Repo</a></p> <p class="mb-0">If this is a bug, please make an issue in the Statup Github Repo. <a href="https://github.com/hunterlong/statup" class="btn btn-sm btn-outline-danger float-right">Statup Github Repo</a></p>
</div> </div>
{{end}} {{end}}
{{ range .Services }} {{ range Services }}
<div class="mt-4" id="service_id_{{.Id}}"> <div class="mt-4" id="service_id_{{.Id}}">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">

View File

@ -1,7 +1,6 @@
package types package types
import ( import (
"sort"
"time" "time"
) )
@ -24,7 +23,7 @@ type Core struct {
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
DbConnection string `gorm:"-" json:"database"` DbConnection string `gorm:"-" json:"database"`
Started time.Time `gorm:"-" json:"started_on"` Started time.Time `gorm:"-" json:"started_on"`
dbServices []*Service `gorm:"-" json:"services,omitempty"` Services []ServiceInterface `gorm:"-" json:"services,omitempty"`
Plugins []Info `gorm:"-" json:"-"` Plugins []Info `gorm:"-" json:"-"`
Repos []PluginJSON `gorm:"-" json:"-"` Repos []PluginJSON `gorm:"-" json:"-"`
AllPlugins []PluginActions `gorm:"-" json:"-"` AllPlugins []PluginActions `gorm:"-" json:"-"`
@ -38,30 +37,9 @@ func (c ServiceOrder) Len() int { return len(c) }
func (c ServiceOrder) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c ServiceOrder) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order } func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
func (c *Core) SetServices(s []*Service) {
sort.Sort(ServiceOrder(c.dbServices))
c.dbServices = s
}
func (c *Core) UpdateService(index int, s *Service) {
c.dbServices[index] = s
}
func (c *Core) AddService(s *Service) {
c.dbServices = append(c.dbServices, s)
}
func (c *Core) RemoveService(s int) []*Service {
slice := c.dbServices
c.dbServices = append(slice[:s], slice[s+1:]...)
return c.dbServices
}
func (c *Core) GetServices() []*Service {
return c.dbServices
}
type CoreInterface interface { type CoreInterface interface {
SelectAllServices() ([]*Service, error) SelectAllServices() ([]*Service, error)
Services() []*Service Count24HFailures() uint64
ServicesCount() int
CountOnline() int
} }

View File

@ -14,8 +14,6 @@ type Failure struct {
} }
type FailureInterface interface { type FailureInterface interface {
Delete() error
// method functions
Ago() string Ago() string
ParseError() string ParseError() string
} }

View File

@ -38,10 +38,11 @@ type Service struct {
Latency float64 `gorm:"-" json:"latency"` Latency float64 `gorm:"-" json:"latency"`
Online24Hours float32 `gorm:"-" json:"24_hours_online"` Online24Hours float32 `gorm:"-" json:"24_hours_online"`
AvgResponse string `gorm:"-" json:"avg_response"` AvgResponse string `gorm:"-" json:"avg_response"`
Failures []*Failure `gorm:"-" json:"failures"` Failures []interface{} `gorm:"-" json:"failures"`
Checkins []*Checkin `gorm:"-" json:"checkins"` Checkins []*Checkin `gorm:"-" json:"checkins"`
Running chan bool `gorm:"-" json:"-"` Running chan bool `gorm:"-" json:"-"`
Checkpoint time.Time `gorm:"-" json:"-"` Checkpoint time.Time `gorm:"-" json:"-"`
SleepDuration time.Duration `gorm:"-" json:"-"`
LastResponse string `gorm:"-" json:"-"` LastResponse string `gorm:"-" json:"-"`
LastStatusCode int `gorm:"-" json:"status_code"` LastStatusCode int `gorm:"-" json:"status_code"`
LastOnline time.Time `gorm:"-" json:"last_online"` LastOnline time.Time `gorm:"-" json:"last_online"`
@ -52,7 +53,7 @@ type Service struct {
type ServiceInterface interface { type ServiceInterface interface {
// Database functions // Database functions
Create() (int64, error) Create() (int64, error)
Update() error Update(bool) error
Delete() error Delete() error
// Basic Method functions // Basic Method functions
AvgTime() float64 AvgTime() float64
@ -60,12 +61,13 @@ type ServiceInterface interface {
Online24() float32 Online24() float32
SmallText() string SmallText() string
GraphData() string GraphData() string
AvgUptime() string AvgUptime(time.Time) string
AvgUptime24() string
ToJSON() string ToJSON() string
// Failure functions // Failure functions
CreateFailure(*Failure) (int64, error) CreateFailure(*Failure) (int64, error)
LimitedFailures() []*Failure //LimitedFailures() []interface{}
AllFailures() []*Failure //AllFailures() []*Failure
TotalFailuresSince(time.Time) (uint64, error) TotalFailuresSince(time.Time) (uint64, error)
TotalFailures24() (uint64, error) TotalFailures24() (uint64, error)
TotalFailures() (uint64, error) TotalFailures() (uint64, error)
@ -80,17 +82,15 @@ type ServiceInterface interface {
SelectHitsGroupBy(string) ([]*Hit, error) SelectHitsGroupBy(string) ([]*Hit, error)
// Go Routines // Go Routines
CheckQueue(bool) CheckQueue(bool)
Check(bool) *Service Check(bool)
checkHttp(bool) *Service //checkHttp(bool) *Service
checkTcp(bool) *Service //checkTcp(bool) *Service
// Checkin functions // Checkin functions
AllCheckins() []*Checkin AllCheckins() []*Checkin
} }
func (s *Service) Start() { func (s *Service) Start() {
if s.Running == nil {
s.Running = make(chan bool) s.Running = make(chan bool)
}
} }
func (s *Service) Close() { func (s *Service) Close() {