2018-12-04 05:57:11 +00:00
// Statping
2018-08-16 06:22:20 +00:00
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
2018-12-04 04:17:29 +00:00
// https://github.com/hunterlong/statping
2018-08-16 06:22:20 +00:00
//
// The licenses for most software and other practical works are designed
// to take away your freedom to share and change the works. By contrast,
// the GNU General Public License is intended to guarantee your freedom to
// share and change all versions of a program--to make sure it remains free
// software for all its users.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-06-30 00:57:05 +00:00
package core
2018-06-22 06:56:44 +00:00
import (
"fmt"
2018-10-06 09:50:39 +00:00
"github.com/ararog/timeago"
2020-02-25 07:41:28 +00:00
"github.com/hunterlong/statping/database"
2018-12-04 04:17:29 +00:00
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
2018-06-22 06:56:44 +00:00
"time"
)
2018-10-07 22:38:56 +00:00
type Checkin struct {
2020-02-25 07:41:28 +00:00
* database . CheckinObj
2018-08-20 07:20:05 +00:00
}
2018-06-30 00:57:05 +00:00
2018-11-21 03:39:40 +00:00
type CheckinHit struct {
2018-10-03 10:47:32 +00:00
* types . CheckinHit
}
2018-12-06 19:03:55 +00:00
// Select returns a *types.Checkin
func ( c * Checkin ) Select ( ) * types . Checkin {
return c . Checkin
}
2018-10-07 22:38:56 +00:00
// Routine for checking if the last Checkin was within its interval
2020-02-25 07:41:28 +00:00
func CheckinRoutine ( checkin database . Checkiner ) {
2020-02-26 07:29:58 +00:00
c := checkin . Model ( )
if checkin . Hits ( ) . Last ( ) == nil {
2018-10-07 22:38:56 +00:00
return
}
reCheck := c . Period ( )
CheckinLoop :
for {
select {
case <- c . Running :
2019-12-28 09:01:07 +00:00
log . Infoln ( fmt . Sprintf ( "Stopping checkin routine: %v" , c . Name ) )
2018-12-06 19:03:55 +00:00
c . Failing = false
2018-10-07 22:38:56 +00:00
break CheckinLoop
case <- time . After ( reCheck ) :
2019-12-28 09:01:07 +00:00
log . Infoln ( fmt . Sprintf ( "Checkin %v is expected at %v, checking every %v" , c . Name , utils . FormatDuration ( c . Expected ( ) ) , utils . FormatDuration ( c . Period ( ) ) ) )
2020-02-26 07:29:58 +00:00
if c . Expected ( ) <= 0 {
issue := fmt . Sprintf ( "Checkin %v is failing, no request since %v" , c . Name , checkin . Hits ( ) . Last ( ) . CreatedAt )
2019-12-28 09:01:07 +00:00
log . Errorln ( issue )
2020-02-25 07:41:28 +00:00
2020-02-26 07:29:58 +00:00
CreateCheckinFailure ( checkin )
2018-10-07 22:38:56 +00:00
}
reCheck = c . Period ( )
}
continue
}
}
// String will return a Checkin API string
func ( c * Checkin ) String ( ) string {
2018-10-02 07:26:49 +00:00
return c . ApiKey
2018-06-30 00:57:05 +00:00
}
2020-02-25 07:41:28 +00:00
func CreateCheckinFailure ( checkin database . Checkiner ) ( int64 , error ) {
2020-02-26 07:29:58 +00:00
c := checkin . Model ( )
service := checkin . Service ( )
2018-12-06 19:03:55 +00:00
c . Failing = true
2020-02-25 07:41:28 +00:00
fail := & types . Failure {
2018-10-07 22:38:56 +00:00
Issue : fmt . Sprintf ( "Checkin %v was not reported %v ago, it expects a request every %v" , c . Name , utils . FormatDuration ( c . Expected ( ) ) , utils . FormatDuration ( c . Period ( ) ) ) ,
Method : "checkin" ,
MethodId : c . Id ,
Service : service . Id ,
2018-12-06 19:03:55 +00:00
Checkin : c . Id ,
PingTime : c . Expected ( ) . Seconds ( ) ,
}
2020-02-25 07:41:28 +00:00
_ , err := database . Create ( fail )
if err != nil {
return 0 , err
}
//sort.Sort(types.FailSort(c.Failures()))
return fail . Id , err
2018-12-06 19:03:55 +00:00
}
2018-11-16 16:42:49 +00:00
// AllCheckins returns all checkin in system
2020-02-25 07:41:28 +00:00
func AllCheckins ( ) [ ] * database . CheckinObj {
checkins := database . AllCheckins ( )
2018-11-16 16:42:49 +00:00
return checkins
}
2018-10-07 22:38:56 +00:00
// SelectCheckin will find a Checkin based on the API supplied
func SelectCheckin ( api string ) * Checkin {
2018-12-06 19:03:55 +00:00
for _ , s := range Services ( ) {
2020-02-26 05:38:03 +00:00
for _ , c := range s . Checkins ( ) {
2020-02-25 07:41:28 +00:00
if c . ApiKey == api {
return & Checkin { c }
2018-12-06 19:03:55 +00:00
}
}
}
return nil
2018-10-07 22:38:56 +00:00
}
2018-11-21 03:39:40 +00:00
// AllHits returns all of the CheckinHits for a given Checkin
func ( c * Checkin ) AllHits ( ) [ ] * types . CheckinHit {
var checkins [ ] * types . CheckinHit
2020-02-19 04:07:22 +00:00
Database ( & types . CheckinHit { } ) . Where ( "checkin = ?" , c . Id ) . Order ( "id DESC" ) . Find ( & checkins )
2018-10-03 10:47:32 +00:00
return checkins
}
2018-12-06 19:03:55 +00:00
// Hits returns all of the CheckinHits for a given Checkin
2020-02-24 05:53:15 +00:00
func ( c * Checkin ) AllFailures ( ) [ ] * types . Failure {
var failures [ ] * types . Failure
Database ( & types . Failure { } ) .
Where ( "checkin = ?" , c . Id ) .
Where ( "method = 'checkin'" ) .
Order ( "id desc" ) .
Find ( & failures )
return failures
2018-12-06 19:03:55 +00:00
}
2020-02-24 05:53:15 +00:00
func ( c * Checkin ) GetFailures ( count int ) [ ] * types . Failure {
2018-11-21 03:39:40 +00:00
var failures [ ] * types . Failure
2020-02-24 05:53:15 +00:00
Database ( & types . Failure { } ) .
Where ( "checkin = ?" , c . Id ) .
Where ( "method = 'checkin'" ) .
Limit ( count ) .
Order ( "id desc" ) .
Find ( & failures )
2018-11-21 03:39:40 +00:00
return failures
}
2018-10-07 22:38:56 +00:00
// Create will create a new Checkin
2020-02-26 05:38:03 +00:00
func ( c * Checkin ) Delete ( ) {
2018-10-07 22:38:56 +00:00
c . Close ( )
2019-01-10 16:47:01 +00:00
i := c . index ( )
2020-02-26 05:38:03 +00:00
srv := c . Service ( )
slice := srv . Service . Checkins
srv . Service . Checkins = append ( slice [ : i ] , slice [ i + 1 : ] ... )
2018-10-07 22:38:56 +00:00
}
2019-01-10 16:47:01 +00:00
// index returns a checkin index int for updating the *checkin.Service slice
func ( c * Checkin ) index ( ) int {
2020-02-26 05:38:03 +00:00
for k , checkin := range c . Service ( ) . Checkins ( ) {
2020-02-25 07:41:28 +00:00
if c . Id == checkin . Model ( ) . Id {
2019-01-10 16:47:01 +00:00
return k
}
}
return 0
}
2018-10-07 22:38:56 +00:00
// Create will create a new Checkin
func ( c * Checkin ) Create ( ) ( int64 , error ) {
2018-10-07 04:48:33 +00:00
c . ApiKey = utils . RandomString ( 7 )
2020-02-25 07:41:28 +00:00
_ , err := database . Create ( c )
if err != nil {
log . Warnln ( err )
return 0 , err
2018-10-04 08:18:55 +00:00
}
2018-12-06 19:03:55 +00:00
c . Start ( )
2020-02-25 07:41:28 +00:00
go CheckinRoutine ( c )
return c . Id , err
2018-10-06 03:35:53 +00:00
}
2018-10-07 22:38:56 +00:00
// Update will update a Checkin
func ( c * Checkin ) Update ( ) ( int64 , error ) {
2020-02-19 04:07:22 +00:00
row := Database ( c ) . Update ( & c )
2020-01-26 21:01:43 +00:00
if row . Error ( ) != nil {
log . Warnln ( row . Error ( ) )
return 0 , row . Error ( )
2018-06-22 06:56:44 +00:00
}
2020-01-26 21:01:43 +00:00
return c . Id , row . Error ( )
2018-06-22 06:56:44 +00:00
}
2018-10-07 04:48:33 +00:00
// Create will create a new successful checkinHit
2018-11-21 03:39:40 +00:00
func ( c * CheckinHit ) Create ( ) ( int64 , error ) {
2018-10-07 05:04:06 +00:00
if c . CreatedAt . IsZero ( ) {
2019-12-28 09:01:07 +00:00
c . CreatedAt = utils . Now ( )
2018-10-04 08:18:55 +00:00
}
2020-02-19 04:07:22 +00:00
row := Database ( c ) . Create ( & c )
2020-01-26 21:01:43 +00:00
if row . Error ( ) != nil {
log . Warnln ( row . Error ( ) )
return 0 , row . Error ( )
2018-10-03 10:47:32 +00:00
}
2020-01-26 21:01:43 +00:00
return c . Id , row . Error ( )
2018-10-03 10:47:32 +00:00
}
2018-10-07 04:48:33 +00:00
// Ago returns the duration of time between now and the last successful checkinHit
2018-11-21 03:39:40 +00:00
func ( c * CheckinHit ) Ago ( ) string {
2019-12-28 09:01:07 +00:00
got , _ := timeago . TimeAgoWithTime ( utils . Now ( ) , c . CreatedAt )
2018-10-06 09:50:39 +00:00
return got
}
2018-10-07 22:38:56 +00:00
// RecheckCheckinFailure will check if a Service Checkin has been reported yet
func ( c * Checkin ) RecheckCheckinFailure ( guard chan struct { } ) {
2019-12-28 09:01:07 +00:00
between := utils . Now ( ) . Sub ( utils . Now ( ) ) . Seconds ( )
2018-06-22 06:56:44 +00:00
if between > float64 ( c . Interval ) {
fmt . Println ( "rechecking every 15 seconds!" )
time . Sleep ( 15 * time . Second )
guard <- struct { } { }
c . RecheckCheckinFailure ( guard )
} else {
fmt . Println ( "i recovered!!" )
}
<- guard
}