/
service.provider.go
164 lines (141 loc) · 4.57 KB
/
service.provider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package provider
import (
"fmt"
"log"
"net/http"
"time"
"github.com/google/go-cmp/cmp"
"github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
"github.com/systemfiles/stay-up/api/models"
"github.com/systemfiles/stay-up/api/types"
"github.com/systemfiles/stay-up/api/util"
"gorm.io/gorm/clause"
)
type ServiceProviderError struct{
Message string
}
func (e *ServiceProviderError) Error() string {
return fmt.Sprintf("Service Provider Error: %s", e.Message)
}
func CreateService(name, description, host, protocol string, port, timeout int64) (models.Service, error) {
// Create model from request data
svc := models.Service{
Name: name,
Description: description,
Host: host,
Port: port,
Protocol: util.GetProtocolFromString(protocol),
CurrentStatus: types.UP,
TimeoutMs: timeout,
LastDown: time.Now(),
UptimeSeconds: 0,
LatencyMs: 0,
}
// Open DB connection
db, err := util.GetDBInstance()
if err != nil {
return models.Service{}, &ServiceProviderError{Message: "Could not get a valid database instance"}
}
// Create model in DB
if err := db.Create(&svc).Error; err != nil {
return models.Service{}, &ServiceProviderError{Message: fmt.Sprintf("Failed to create the service in target database. Reason: %s", err)}
}
return svc, nil
}
func GetServiceById(id uint64) (models.Service, error) {
// open database connection
db, err := util.GetDBInstance()
if err != nil {
return models.Service{}, &ServiceProviderError{Message: "Could not get a valid database instance"}
}
// find service with id
var svc models.Service
db.First(&svc, id)
if svc.ID != id {
return models.Service{}, &ServiceProviderError{Message: fmt.Sprintf("Could not find service with ID, %d.", id)}
}
return svc, nil
}
func StreamServiceData(ws *websocket.Conn, timeout time.Duration, lastResponse time.Time, errChan chan error) {
var services []models.Service
var lastService []models.Service
for {
err := ws.WriteMessage(websocket.PingMessage, []byte("keepalive"))
if err != nil {
log.Println("Client Not Reachable - Closed connection")
ws.Close() // Cannot reach client (close the connection)
return
}
if err := GetAllServices(&services); err != nil {
log.Println("Failed to get service from database")
errChan <- echo.NewHTTPError(http.StatusInternalServerError, "Failed to get services from data source")
}
if !cmp.Equal(services, lastService) {
// If data has changed from the first sent data then send updated data
if err := ws.WriteJSON(services); err != nil {
log.Println(fmt.Sprintf("Websocket write failed ... %s", err.Error()))
errChan <- echo.NewHTTPError(http.StatusInternalServerError, "Websocket write failed ... ")
}
lastResponse = time.Now()
lastService = services
} else {
lastResponse = time.Now()
}
// wait before next iteration
time.Sleep(time.Duration(timeout / 2))
if (time.Since(lastResponse) > timeout) {
log.Println("Closed connection")
ws.Close()
return
}
}
}
func UpdateServiceWithId(id uint64, attr string, val interface{}) (models.Service, error) {
// open database connection
db, err := util.GetDBInstance()
if err != nil {
return models.Service{}, &ServiceProviderError{Message: "Could not get a valid database instance"}
}
// find service model with given primary_key -> id
var svc models.Service
db.First(&svc, id)
if svc.ID != id {
return models.Service{}, &ServiceProviderError{Message: fmt.Sprintf("Could not find service with ID, %d.", id)}
}
// make update
if err := db.Model(&svc).Update(attr, val).Error; err != nil {
return models.Service{}, &ServiceProviderError{Message: fmt.Sprintf("Could not perform the update. Reason %s", err.Error())}
}
return svc, nil
}
func DeleteServiceWithId(id uint64) error {
// open database connection
db, err := util.GetDBInstance()
if err != nil {
return &ServiceProviderError{Message: "Could not get a valid database instance"}
}
// find service using ID
var svc models.Service
db.First(&svc, id)
if svc.ID != id {
return &ServiceProviderError{Message: fmt.Sprintf("Could not find service with ID, %d.", id)}
}
// delete the service
if err := db.Delete(&svc).Error; err != nil {
return &ServiceProviderError{Message: fmt.Sprintf("Failed to delete service from database. Reason: %s", err)}
}
return nil
}
func GetAllServices(dest *[]models.Service) error {
// open database connection
db, err := util.GetDBInstance()
if err != nil {
return err
}
// get services from database
if err := db.Order(clause.OrderByColumn{Column: clause.Column{Name: "id"}, Desc: false}).Find(&dest).Error; err != nil {
return err
}
return nil
}