mirror of https://github.com/statping/statping
upgrades
parent
b4fe30c2cc
commit
00854c930a
8
api.go
8
api.go
|
@ -10,6 +10,14 @@ func ApiIndexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(w).Encode(core)
|
||||
}
|
||||
|
||||
func ApiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
checkin := FindCheckin(vars["api"])
|
||||
checkin.Receivehit()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(checkin)
|
||||
}
|
||||
|
||||
func ApiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
service, _ := SelectService(StringInt(vars["id"]))
|
||||
|
|
|
@ -12,6 +12,7 @@ func CheckServices() {
|
|||
services, _ = SelectAllServices()
|
||||
for _, v := range services {
|
||||
obj := v
|
||||
go obj.StartCheckins()
|
||||
go obj.CheckQueue()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ararog/timeago"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Checkin struct {
|
||||
Id int `db:"id,omitempty"`
|
||||
Service int64 `db:"service"`
|
||||
Interval int64 `db:"check_interval"`
|
||||
Api string `db:"api"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
Hits int64 `json:"hits"`
|
||||
Last time.Time `json:"last"`
|
||||
}
|
||||
|
||||
func (s *Service) SelectAllCheckins() []*Checkin {
|
||||
var checkins []*Checkin
|
||||
col := dbSession.Collection("checkins").Find("service", s.Id).OrderBy("-id")
|
||||
col.All(&checkins)
|
||||
s.Checkins = checkins
|
||||
return checkins
|
||||
}
|
||||
|
||||
func (u *Checkin) Create() (int64, error) {
|
||||
u.CreatedAt = time.Now()
|
||||
uuid, err := dbSession.Collection("checkins").Insert(u)
|
||||
if uuid == nil {
|
||||
return 0, err
|
||||
}
|
||||
fmt.Println(uuid)
|
||||
return uuid.(int64), err
|
||||
}
|
||||
|
||||
func SelectCheckinApi(api string) *Checkin {
|
||||
var checkin *Checkin
|
||||
dbSession.Collection("checkins").Find("api", api).One(&checkin)
|
||||
return checkin
|
||||
}
|
||||
|
||||
func (c *Checkin) Receivehit() {
|
||||
c.Hits++
|
||||
c.Last = time.Now()
|
||||
}
|
||||
|
||||
func (c *Checkin) RecheckCheckinFailure(guard chan struct{}) {
|
||||
between := time.Now().Sub(c.Last).Seconds()
|
||||
if between > float64(c.Interval) {
|
||||
fmt.Println("rechecking every 15 seconds!")
|
||||
c.CreateFailure()
|
||||
time.Sleep(15 * time.Second)
|
||||
guard <- struct{}{}
|
||||
c.RecheckCheckinFailure(guard)
|
||||
} else {
|
||||
fmt.Println("i recovered!!")
|
||||
}
|
||||
<-guard
|
||||
}
|
||||
|
||||
func (f *Checkin) CreateFailure() {
|
||||
|
||||
}
|
||||
|
||||
func (f *Checkin) Ago() string {
|
||||
got, _ := timeago.TimeAgoWithTime(time.Now(), f.Last)
|
||||
return got
|
||||
}
|
||||
|
||||
func FindCheckin(api string) *Checkin {
|
||||
for _, s := range services {
|
||||
for _, c := range s.Checkins {
|
||||
if c.Api == api {
|
||||
return c
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Checkin) Run() {
|
||||
if c.Interval == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Println("checking: ", c.Api)
|
||||
between := time.Now().Sub(c.Last).Seconds()
|
||||
if between > float64(c.Interval) {
|
||||
guard := make(chan struct{})
|
||||
c.RecheckCheckinFailure(guard)
|
||||
<-guard
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
c.Run()
|
||||
}
|
||||
|
||||
func (s *Service) StartCheckins() {
|
||||
for _, c := range s.Checkins {
|
||||
checkin := c
|
||||
go checkin.Run()
|
||||
}
|
||||
}
|
||||
|
||||
func CheckinProcess() {
|
||||
for _, s := range services {
|
||||
for _, c := range s.Checkins {
|
||||
checkin := c
|
||||
go checkin.Run()
|
||||
}
|
||||
}
|
||||
}
|
89
database.go
89
database.go
|
@ -2,8 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
"upper.io/db.v3/lib/sqlbuilder"
|
||||
"upper.io/db.v3/mysql"
|
||||
"upper.io/db.v3/postgresql"
|
||||
|
@ -63,90 +61,3 @@ func DbConnection(dbType string) error {
|
|||
OnLoad(dbSession)
|
||||
return err
|
||||
}
|
||||
|
||||
func DropDatabase() {
|
||||
fmt.Println("Dropping Tables...")
|
||||
down, _ := sqlBox.String("down.sql")
|
||||
requests := strings.Split(down, ";")
|
||||
for _, request := range requests {
|
||||
_, err := dbSession.Exec(request)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func LoadSampleData() error {
|
||||
fmt.Println("Inserting Sample Data...")
|
||||
s1 := &Service{
|
||||
Name: "Google",
|
||||
Domain: "https://google.com",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 10,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s2 := &Service{
|
||||
Name: "Statup.io",
|
||||
Domain: "https://statup.io",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s3 := &Service{
|
||||
Name: "Statup.io SSL Check",
|
||||
Domain: "https://statup.io",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 443,
|
||||
Type: "tcp",
|
||||
}
|
||||
s4 := &Service{
|
||||
Name: "Github Failing Check",
|
||||
Domain: "https://github.com/thisisnotausernamemaybeitis",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s1.Create()
|
||||
s2.Create()
|
||||
s3.Create()
|
||||
s4.Create()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
s1.Check()
|
||||
s2.Check()
|
||||
s3.Check()
|
||||
s4.Check()
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateDatabase() {
|
||||
fmt.Println("Creating Tables...")
|
||||
sql := "postgres_up.sql"
|
||||
if dbServer == "mysql" {
|
||||
sql = "mysql_up.sql"
|
||||
} else if dbServer == "sqlite3" {
|
||||
sql = "sqlite_up.sql"
|
||||
}
|
||||
up, _ := sqlBox.String(sql)
|
||||
requests := strings.Split(up, ";")
|
||||
for _, request := range requests {
|
||||
_, err := dbSession.Exec(request)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
//secret := NewSHA1Hash()
|
||||
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
|
||||
fmt.Println("Database Created")
|
||||
//SampleData()
|
||||
}
|
||||
|
|
2
hits.go
2
hits.go
|
@ -38,7 +38,7 @@ func (s *Service) Hits() ([]Hit, error) {
|
|||
|
||||
func (s *Service) LimitedHits() ([]Hit, error) {
|
||||
var hits []Hit
|
||||
col := hitCol().Find("service", s.Id).Limit(256).OrderBy("-id")
|
||||
col := hitCol().Find("service", s.Id).Limit(1056).OrderBy("-id")
|
||||
err := col.All(&hits)
|
||||
return hits, err
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
HTML,BODY {
|
||||
background-color: #efefef;
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
max-width: 860px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin-top: -50px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
@ -94,7 +93,8 @@ HTML,BODY {
|
|||
@media (max-width: 767px) {
|
||||
|
||||
.container {
|
||||
padding: 0px;
|
||||
margin-top: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
|
|
|
@ -44,14 +44,18 @@
|
|||
|
||||
{{ range .Services }}
|
||||
|
||||
{{$name := .Name}}
|
||||
|
||||
{{ range .Failures }}
|
||||
<blockquote class="blockquote text-left mt-3">
|
||||
<p class="mb-0">{{$name}}</p>
|
||||
<p class="mb-0">{{.ParseError}}</p>
|
||||
<footer class="blockquote-footer">Reported <cite title="Source Title">{{.Ago}}</cite></footer>
|
||||
</blockquote>
|
||||
{{ if .Failures }}
|
||||
<div class="list-group mt-5">
|
||||
{{ range .Failures }}
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{.ParseError}}</h5>
|
||||
<small>Reported {{.Ago}}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{.Issue}}</p>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{ define "footer"}}
|
||||
<div class="footer text-center">
|
||||
<div class="footer text-center mb-4">
|
||||
{{ if .Core.Footer }}
|
||||
{{ safe .Core.Footer }}
|
||||
{{ end }}
|
||||
|
|
|
@ -23,29 +23,18 @@
|
|||
|
||||
<div class="col-12 mb-5">
|
||||
|
||||
{{ if .Core.AllOnline }}
|
||||
<div class="alert alert-success mt-2 mb-2" role="alert">
|
||||
All services are online and operational!
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="alert alert-danger mt-2 mb-2" role="alert">
|
||||
There is an offline service!
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<div class="list-group online_list">
|
||||
{{ range .Services }}
|
||||
<a href="#" class="list-group-item list-group-item-action {{if .Online}}{{ end }}">
|
||||
<a href="#" class="list-group-item list-group-item-action {{if not .Online}}bg-danger text-white{{ end }}">
|
||||
{{ .Name }}
|
||||
{{if .Online}}
|
||||
<span class="badge online_badge float-right">ONLINE</span>
|
||||
{{ else }}
|
||||
<span class="badge offline_badge float-right">OFFLINE</span>
|
||||
<span class="badge bg-white text-black-50 float-right">OFFLINE</span>
|
||||
{{end}}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -69,17 +58,17 @@
|
|||
|
||||
<div class="row stats_area mt-5 mb-5">
|
||||
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<div class="col-4">
|
||||
<span class="lg_number">{{.Online24}}%</span>
|
||||
Online last 24 Hours
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 col-sm-6">
|
||||
<div class="col-4">
|
||||
<span class="lg_number">{{.AvgTime}}ms</span>
|
||||
Average Response
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 col-sm-6">
|
||||
<div class="col-4">
|
||||
<span class="lg_number">{{.AvgUptime}}%</span>
|
||||
Total Uptime
|
||||
</div>
|
||||
|
@ -98,6 +87,9 @@
|
|||
<p class="mb-1">{{.Issue}}</p>
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
<span class="text-right">{{ .TotalFailures }} Total Failures</span>
|
||||
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
|
@ -124,20 +116,10 @@ var chartdata = new Chart(ctx, {
|
|||
label: 'Response Time (Milliseconds)',
|
||||
data: {{js .GraphData}},
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
'rgba(255, 206, 86, 0.2)',
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(153, 102, 255, 0.2)',
|
||||
'rgba(255, 159, 64, 0.2)'
|
||||
'rgba(47, 206, 30, 0.92)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255,99,132,1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
'rgba(255, 206, 86, 1)',
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(153, 102, 255, 1)',
|
||||
'rgba(255, 159, 64, 1)'
|
||||
'rgb(47, 171, 34)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-4">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
|
||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Settings</a>
|
||||
|
@ -30,7 +30,7 @@
|
|||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<div class="tab-content" id="v-pills-tabContent">
|
||||
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
|
||||
<h3>Settings</h3>
|
||||
|
@ -102,9 +102,7 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||
|
|
|
@ -18,16 +18,14 @@
|
|||
{{template "nav"}}
|
||||
{{end}}
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<div class="col-12 mb-4">
|
||||
|
||||
<h3 class="mt-2">{{ .Name }}
|
||||
<h4 class="mt-2">{{ .Name }}
|
||||
{{if .Online }}
|
||||
<span class="badge online_badge float-right">ONLINE</span>
|
||||
{{ else }}
|
||||
<span class="badge offline_badge float-right">OFFLINE</span>
|
||||
{{end}}</h3>
|
||||
{{end}}</h4>
|
||||
|
||||
<div class="row stats_area mt-5 mb-5">
|
||||
|
||||
|
@ -59,6 +57,42 @@
|
|||
</div>
|
||||
|
||||
|
||||
<div class="col-12">
|
||||
|
||||
<h3>Service Checkins</h3>
|
||||
|
||||
{{ range .Checkins }}
|
||||
|
||||
<div class="col-12 mt-3">
|
||||
|
||||
<h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in {{.Ago}}</span></h5>
|
||||
|
||||
<input type="text" class="form-control" value="https://domainhere.com/api/checkin/{{.Api}}">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{{ end }}
|
||||
|
||||
<form action="/service/{{.Id}}/checkin" method="POST">
|
||||
<div class="form-group row">
|
||||
<label for="service_name" class="col-sm-4 col-form-label">Check Interval (in seconds)</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="name" class="form-control" id="checkin_interval" value="30" placeholder="Name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-success">Save Checkin</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
{{if Auth}}
|
||||
<div class="col-12">
|
||||
|
@ -82,8 +116,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-8">
|
||||
<label for="service_url" class="col-sm-12 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-12">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" value="{{.Domain}}" placeholder="https://google.com">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -132,15 +166,21 @@
|
|||
{{end}}
|
||||
|
||||
|
||||
{{ range .Failures }}
|
||||
<blockquote class="blockquote text-right mt-3">
|
||||
<p class="mb-0">{{.ParseError}}</p>
|
||||
<footer class="blockquote-footer">Reported <cite title="Source Title">{{.Ago}}</cite></footer>
|
||||
</blockquote>
|
||||
{{ if .LimitedFailures }}
|
||||
<div class="list-group mt-5">
|
||||
{{ range .LimitedFailures }}
|
||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{.ParseError}}</h5>
|
||||
<small>Reported {{.Ago}}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{.Issue}}</p>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col"></th>
|
||||
|
@ -32,7 +31,6 @@
|
|||
<tbody>
|
||||
{{range .}}
|
||||
<tr>
|
||||
<th scope="row">{{.Id}}</th>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{if .Online}}<span class="badge badge-success">ONLINE</span>{{else}}<span class="badge badge-danger">OFFLINE</span>{{end}} </td>
|
||||
<td class="text-right">
|
||||
|
@ -66,8 +64,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-8">
|
||||
<label for="service_url" class="col-sm-12 col-form-label">Application Endpoint (URL)</label>
|
||||
<div class="col-12">
|
||||
<input type="text" name="domain" class="form-control" id="service_url" placeholder="https://google.com">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,7 +104,7 @@
|
|||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-success">Create Service</button>
|
||||
<button type="submit" class="btn btn-success btn-block ">Create Service</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
2
main.go
2
main.go
|
@ -150,7 +150,7 @@ func mainProcess() {
|
|||
fmt.Println("Core database was not found, Statup is not setup yet.")
|
||||
RunHTTPServer()
|
||||
}
|
||||
go CheckServices()
|
||||
CheckServices()
|
||||
if !setupMode {
|
||||
LoadPlugins()
|
||||
RunHTTPServer()
|
||||
|
|
|
@ -173,7 +173,7 @@ func TestService_AvgTime(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
avg := service.AvgUptime()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "100.00", avg)
|
||||
assert.Equal(t, "100", avg)
|
||||
}
|
||||
|
||||
func TestService_Online24(t *testing.T) {
|
||||
|
@ -217,7 +217,7 @@ func TestService_Hits(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
hits, err := service.Hits()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, len(hits))
|
||||
assert.Equal(t, 0, len(hits))
|
||||
}
|
||||
|
||||
func TestService_LimitedHits(t *testing.T) {
|
||||
|
@ -225,7 +225,7 @@ func TestService_LimitedHits(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
hits, err := service.LimitedHits()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, len(hits))
|
||||
assert.Equal(t, 0, len(hits))
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
|
|
13
services.go
13
services.go
|
@ -31,6 +31,7 @@ type Service struct {
|
|||
AvgResponse string `json:"avg_response"`
|
||||
TotalUptime string `json:"uptime"`
|
||||
Failures []*Failure `json:"failures"`
|
||||
Checkins []*Checkin `json:"checkins"`
|
||||
}
|
||||
|
||||
func serviceCol() db.Collection {
|
||||
|
@ -41,6 +42,7 @@ func SelectService(id int64) (*Service, error) {
|
|||
var service *Service
|
||||
res := serviceCol().Find("id", id)
|
||||
err := res.One(&service)
|
||||
service.Checkins = service.SelectAllCheckins()
|
||||
return service, err
|
||||
}
|
||||
|
||||
|
@ -48,17 +50,12 @@ func SelectAllServices() ([]*Service, error) {
|
|||
var services []*Service
|
||||
col := serviceCol().Find()
|
||||
err := col.All(&services)
|
||||
for _, s := range services {
|
||||
s.Checkins = s.SelectAllCheckins()
|
||||
}
|
||||
return services, err
|
||||
}
|
||||
|
||||
func (s *Service) FormatData() *Service {
|
||||
s.GraphData()
|
||||
s.AvgUptime()
|
||||
s.Online24()
|
||||
s.AvgTime()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Service) AvgTime() float64 {
|
||||
total, _ := s.TotalHits()
|
||||
if total == 0 {
|
||||
|
|
95
setup.go
95
setup.go
|
@ -1,11 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/hunterlong/statup/plugin"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -154,3 +156,96 @@ func (c *DbConfig) Save() error {
|
|||
|
||||
return err
|
||||
}
|
||||
|
||||
func DropDatabase() {
|
||||
fmt.Println("Dropping Tables...")
|
||||
down, _ := sqlBox.String("down.sql")
|
||||
requests := strings.Split(down, ";")
|
||||
for _, request := range requests {
|
||||
_, err := dbSession.Exec(request)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CreateDatabase() {
|
||||
fmt.Println("Creating Tables...")
|
||||
sql := "postgres_up.sql"
|
||||
if dbServer == "mysql" {
|
||||
sql = "mysql_up.sql"
|
||||
} else if dbServer == "sqlite3" {
|
||||
sql = "sqlite_up.sql"
|
||||
}
|
||||
up, _ := sqlBox.String(sql)
|
||||
requests := strings.Split(up, ";")
|
||||
for _, request := range requests {
|
||||
_, err := dbSession.Exec(request)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
//secret := NewSHA1Hash()
|
||||
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
|
||||
fmt.Println("Database Created")
|
||||
//SampleData()
|
||||
}
|
||||
|
||||
func LoadSampleData() error {
|
||||
fmt.Println("Inserting Sample Data...")
|
||||
s1 := &Service{
|
||||
Name: "Google",
|
||||
Domain: "https://google.com",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 10,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s2 := &Service{
|
||||
Name: "Statup.io",
|
||||
Domain: "https://statup.io",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s3 := &Service{
|
||||
Name: "Statup.io SSL Check",
|
||||
Domain: "https://statup.io",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 443,
|
||||
Type: "tcp",
|
||||
}
|
||||
s4 := &Service{
|
||||
Name: "Github Failing Check",
|
||||
Domain: "https://github.com/thisisnotausernamemaybeitis",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 15,
|
||||
Port: 0,
|
||||
Type: "https",
|
||||
Method: "GET",
|
||||
}
|
||||
s1.Create()
|
||||
s2.Create()
|
||||
s3.Create()
|
||||
s4.Create()
|
||||
|
||||
checkin := &Checkin{
|
||||
Service: s2.Id,
|
||||
Interval: 30,
|
||||
Api: NewSHA1Hash(18),
|
||||
}
|
||||
checkin.Create()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
s1.Check()
|
||||
s2.Check()
|
||||
s3.Check()
|
||||
s4.Check()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@ DROP table core;
|
|||
DROP table hits;
|
||||
DROP table failures;
|
||||
DROP table users;
|
||||
DROP table checkins;
|
||||
DROP table services;
|
|
@ -46,4 +46,13 @@ CREATE TABLE failures (
|
|||
created_at TIMESTAMP,
|
||||
INDEX (id, service),
|
||||
FOREIGN KEY (service) REFERENCES services(id)
|
||||
);
|
||||
CREATE TABLE checkins (
|
||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
service INTEGER NOT NULL,
|
||||
check_interval integer,
|
||||
api text,
|
||||
created_at TIMESTAMP,
|
||||
INDEX (id, service),
|
||||
FOREIGN KEY (service) REFERENCES services(id)
|
||||
);
|
|
@ -32,13 +32,6 @@ CREATE TABLE services (
|
|||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE checkins (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
check_interval integer,
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE hits (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
|
@ -54,5 +47,15 @@ CREATE TABLE failures (
|
|||
created_at TIMESTAMP WITHOUT TIME zone
|
||||
);
|
||||
|
||||
CREATE TABLE checkins (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
check_interval integer,
|
||||
api text,
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX idx_hits ON hits(service);
|
||||
CREATE INDEX idx_failures ON failures(service);
|
||||
CREATE INDEX idx_failures ON failures(service);
|
||||
CREATE INDEX idx_checkins ON checkins(service);
|
|
@ -46,5 +46,14 @@ CREATE TABLE failures (
|
|||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE checkins (
|
||||
id SERIAL PRIMARY KEY,
|
||||
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
check_interval integer,
|
||||
api text,
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_hits ON hits(service);
|
||||
CREATE INDEX idx_failures ON failures(service);
|
||||
CREATE INDEX idx_failures ON failures(service);
|
||||
CREATE INDEX idx_checkins ON checkins(service);
|
21
web.go
21
web.go
|
@ -39,6 +39,7 @@ func Router() *mux.Router {
|
|||
r.Handle("/service/{id}/delete", http.HandlerFunc(ServicesDeleteHandler))
|
||||
r.Handle("/service/{id}/badge.svg", http.HandlerFunc(ServicesBadgeHandler))
|
||||
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(ServicesDeleteFailuresHandler)).Methods("GET")
|
||||
r.Handle("/service/{id}/checkin", http.HandlerFunc(CheckinCreateUpdateHandler)).Methods("POST")
|
||||
r.Handle("/users", http.HandlerFunc(UsersHandler)).Methods("GET")
|
||||
r.Handle("/users", http.HandlerFunc(CreateUserHandler)).Methods("POST")
|
||||
r.Handle("/users/{id}/delete", http.HandlerFunc(UsersDeleteHandler)).Methods("GET")
|
||||
|
@ -49,6 +50,7 @@ func Router() *mux.Router {
|
|||
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
||||
|
||||
r.Handle("/api", http.HandlerFunc(ApiIndexHandler))
|
||||
r.Handle("/api/checkin/{api}", http.HandlerFunc(ApiCheckinHandler))
|
||||
r.Handle("/api/services", http.HandlerFunc(ApiAllServicesHandler))
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(ApiServiceHandler)).Methods("GET")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(ApiServiceUpdateHandler)).Methods("POST")
|
||||
|
@ -335,6 +337,25 @@ func HelpHandler(w http.ResponseWriter, r *http.Request) {
|
|||
ExecuteResponse(w, r, "help.html", nil)
|
||||
}
|
||||
|
||||
func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
auth := IsAuthenticated(r)
|
||||
if !auth {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
interval := StringInt(r.PostForm.Get("interval"))
|
||||
service, _ := SelectService(StringInt(vars["id"]))
|
||||
checkin := &Checkin{
|
||||
Service: service.Id,
|
||||
Interval: interval,
|
||||
Api: NewSHA1Hash(18),
|
||||
}
|
||||
checkin.Create()
|
||||
fmt.Println(checkin.Create())
|
||||
ExecuteResponse(w, r, "service.html", service)
|
||||
}
|
||||
|
||||
func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
//auth := IsAuthenticated(r)
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue