mirror of https://github.com/statping/statping
updates
parent
afd6ec52f1
commit
077d1a5900
|
@ -54,8 +54,10 @@ func (s *Service) Check() {
|
|||
|
||||
func (s *Service) Record(response *http.Response) {
|
||||
db.QueryRow("INSERT INTO hits(service,latency,created_at) VALUES($1,$2,NOW()) returning id;", s.Id, s.Latency).Scan()
|
||||
OnHit(s)
|
||||
}
|
||||
|
||||
func (s *Service) Failure(issue string) {
|
||||
db.QueryRow("INSERT INTO failures(issue,service,created_at) VALUES($1,$2,NOW()) returning id;", issue, s.Id).Scan()
|
||||
OnFailure(s)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
import "github.com/hunterlong/statup/plugin"
|
||||
|
||||
func OnHit(s *Service) {
|
||||
for _, p := range allPlugins {
|
||||
p.OnHit(s.ToP())
|
||||
}
|
||||
}
|
||||
|
||||
func OnFailure(s *Service) {
|
||||
for _, p := range allPlugins {
|
||||
p.OnFailure(s.ToP())
|
||||
}
|
||||
}
|
||||
|
||||
func SelectPlugin(name string) plugin.PluginActions {
|
||||
for _, p := range allPlugins {
|
||||
if p.GetInfo().Name == name {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return plugin.PluginInfo{}
|
||||
}
|
||||
|
||||
func (s *Service) PluginFailures() []*plugin.Failure {
|
||||
var failed []*plugin.Failure
|
||||
for _, f := range s.Failures {
|
||||
fail := &plugin.Failure{
|
||||
f.Id,
|
||||
f.Issue,
|
||||
f.Service,
|
||||
f.CreatedAt,
|
||||
f.Ago,
|
||||
}
|
||||
failed = append(failed, fail)
|
||||
}
|
||||
return failed
|
||||
}
|
||||
|
||||
func (s *Service) ToP() *plugin.Service {
|
||||
out := &plugin.Service{
|
||||
s.Id,
|
||||
s.Name,
|
||||
s.Domain,
|
||||
s.Expected,
|
||||
s.ExpectedStatus,
|
||||
s.Interval,
|
||||
s.Method,
|
||||
s.Port,
|
||||
s.CreatedAt,
|
||||
s.Data,
|
||||
s.Online,
|
||||
s.Latency,
|
||||
s.Online24Hours,
|
||||
s.AvgResponse,
|
||||
s.TotalUptime,
|
||||
s.PluginFailures(),
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -15,9 +15,6 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link" href="/users">Users</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/plugins">Plugins</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/settings">Settings</a>
|
||||
</li>
|
||||
|
|
|
@ -49,9 +49,25 @@
|
|||
|
||||
{{ range .Plugins }}
|
||||
<div class="tab-pane fade" id="v-pills-{{.Name}}" role="tabpanel" aria-labelledby="v-pills-{{.Name}}-tab">
|
||||
<form action="/plugins/{{.Name}}/save" method="POST">
|
||||
{{safe .Form }}
|
||||
</form>
|
||||
|
||||
<h4 class="text-capitalize">{{ .Name }}</h4>
|
||||
<span class="text-muted">{{ .Description }}</span>
|
||||
|
||||
<form class="mt-3" method="POST" action="/plugins/{{.Name}}/save">
|
||||
{{ range .Form }}
|
||||
<div class="form-group">
|
||||
<label for="input_{{ .SQLValue }}" class="text-capitalize">{{ .Name }}</label>
|
||||
<input type="text" class="form-control" name="{{ .SQLValue }}" value="{{ .Val }}" id="input_{{ .SQLValue }}" placeholder="Example input" aria-describedby="help_{{ .SQLValue }}">
|
||||
|
||||
{{ if .Description }}
|
||||
<small id="help_{{ .SQLValue }}" class="form-text text-muted">
|
||||
{{ .Description }}
|
||||
</small>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
|
78
main.go
78
main.go
|
@ -28,7 +28,7 @@ var (
|
|||
jsBox *rice.Box
|
||||
tmplBox *rice.Box
|
||||
setupMode bool
|
||||
allPlugins []plg.Plugin
|
||||
allPlugins []plugin.PluginActions
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -70,45 +70,36 @@ func (c *Core) FetchPluginRepo() []PluginJSON {
|
|||
return pk
|
||||
}
|
||||
|
||||
func SelectPlugin(name string) *PluginJSON {
|
||||
for _, v := range core.FetchPluginRepo() {
|
||||
if v.Namespace == name {
|
||||
return &v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DownloadPlugin(name string) {
|
||||
plugin := SelectPlugin(name)
|
||||
var _, err = os.Stat("plugins/" + plugin.Namespace)
|
||||
if err != nil {
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
var file, _ = os.Create("plugins/" + plugin.Namespace)
|
||||
defer file.Close()
|
||||
}
|
||||
resp, err := http.Get("https://raw.githubusercontent.com/hunterlong/statup/master/plugins.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
file, err := os.OpenFile("plugins/"+plugin.Namespace, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.Write(body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = file.Sync()
|
||||
}
|
||||
//func DownloadPlugin(name string) {
|
||||
// plugin := SelectPlugin(name)
|
||||
// var _, err = os.Stat("plugins/" + plugin.Namespace)
|
||||
// if err != nil {
|
||||
// }
|
||||
// if os.IsNotExist(err) {
|
||||
// var file, _ = os.Create("plugins/" + plugin.Namespace)
|
||||
// defer file.Close()
|
||||
// }
|
||||
// resp, err := http.Get("https://raw.githubusercontent.com/hunterlong/statup/master/plugins.json")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer resp.Body.Close()
|
||||
// body, err := ioutil.ReadAll(resp.Body)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// file, err := os.OpenFile("plugins/"+plugin.Namespace, os.O_RDWR, 0644)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer file.Close()
|
||||
//
|
||||
// _, err = file.Write(body)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// err = file.Sync()
|
||||
//}
|
||||
|
||||
func main() {
|
||||
VERSION = "1.1.1"
|
||||
|
@ -177,14 +168,13 @@ func LoadPlugins() {
|
|||
fmt.Printf("Plugin '%v' could not load correctly, error: %v\n", f.Name(), "unexpected type from module symbol")
|
||||
continue
|
||||
}
|
||||
//plugin := plugActions.Plugin()
|
||||
//
|
||||
//fmt.Println(plugin.OnLoad)
|
||||
|
||||
plugActions.OnLoad()
|
||||
|
||||
allPlugins = append(allPlugins, *plug)
|
||||
allPlugins = append(allPlugins, plugActions)
|
||||
core.Plugins = append(core.Plugins, plugActions.GetInfo())
|
||||
}
|
||||
|
||||
fmt.Printf("Loaded %v Plugins\n", len(allPlugins))
|
||||
|
||||
ForEachPlugin()
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PluginActions interface {
|
||||
GetInfo() Info
|
||||
Routes() []Routing
|
||||
OnSave(map[string]string)
|
||||
OnInstall()
|
||||
OnUninstall()
|
||||
OnFailure(*Service)
|
||||
OnHit(*Service)
|
||||
OnSettingsSaved()
|
||||
OnNewUser()
|
||||
OnNewService()
|
||||
OnShutdown()
|
||||
OnLoad()
|
||||
OnBeforeRequest()
|
||||
OnAfterRequest()
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Id int64
|
||||
Name string
|
||||
Domain string
|
||||
Expected string
|
||||
ExpectedStatus int
|
||||
Interval int
|
||||
Method string
|
||||
Port int
|
||||
CreatedAt time.Time
|
||||
Data string
|
||||
Online bool
|
||||
Latency float64
|
||||
Online24Hours float32
|
||||
AvgResponse string
|
||||
TotalUptime string
|
||||
Failures []*Failure
|
||||
}
|
||||
|
||||
type Failure struct {
|
||||
Id int
|
||||
Issue string
|
||||
Service int
|
||||
CreatedAt time.Time
|
||||
Ago string
|
||||
}
|
||||
|
||||
type PluginInfo struct {
|
||||
Info Info
|
||||
PluginActions
|
||||
}
|
||||
|
||||
type Routing struct {
|
||||
URL string
|
||||
Method string
|
||||
Handler func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string
|
||||
Description string
|
||||
Form []FormElement
|
||||
}
|
||||
|
||||
type FormElement struct {
|
||||
Name string
|
||||
Description string
|
||||
SQLValue string
|
||||
SQLType string
|
||||
Value interface{}
|
||||
}
|
138
plugin/plugin.go
138
plugin/plugin.go
|
@ -2,37 +2,126 @@ package plugin
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
DB *sql.DB
|
||||
db *sql.DB
|
||||
AllPlugins []Info
|
||||
)
|
||||
|
||||
type PluginInfo struct {
|
||||
Info Info
|
||||
PluginActions
|
||||
Add
|
||||
func CreateSettingsTable(p Info) string {
|
||||
var tableValues []string
|
||||
for _, v := range p.Form {
|
||||
tb := fmt.Sprintf("%v %v", v.SQLValue, v.SQLType)
|
||||
tableValues = append(tableValues, tb)
|
||||
}
|
||||
vals := strings.Join(tableValues, ", ")
|
||||
out := fmt.Sprintf("CREATE TABLE settings_%v (%v);", p.Name, vals)
|
||||
smtp, _ := db.Prepare(out)
|
||||
_, _ = smtp.Exec()
|
||||
InitalSettings(p)
|
||||
return out
|
||||
}
|
||||
|
||||
type Routing struct {
|
||||
URL string
|
||||
Method string
|
||||
Handler func(http.ResponseWriter, *http.Request)
|
||||
func InitalSettings(p Info) {
|
||||
var tableValues []string
|
||||
var tableInput []string
|
||||
for _, v := range p.Form {
|
||||
val := fmt.Sprintf("'%v'", "example data")
|
||||
tableValues = append(tableValues, v.SQLValue)
|
||||
tableInput = append(tableInput, val)
|
||||
}
|
||||
vals := strings.Join(tableValues, ",")
|
||||
ins := strings.Join(tableInput, ",")
|
||||
sql := fmt.Sprintf("INSERT INTO settings_%v(%v) VALUES(%v);", p.Name, vals, ins)
|
||||
smtp, _ := db.Prepare(sql)
|
||||
_, _ = smtp.Exec()
|
||||
|
||||
SelectSettings(p)
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string
|
||||
Form string
|
||||
func (f FormElement) Val() string {
|
||||
var v string
|
||||
fmt.Println(f.Value)
|
||||
b, ok := f.Value.([]byte)
|
||||
if ok {
|
||||
v = string(b)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func SelectSettings(p Info) []*FormElement {
|
||||
|
||||
var newForm []*FormElement
|
||||
|
||||
sql := fmt.Sprintf("SELECT * FROM settings_%v LIMIT 1", p.Name)
|
||||
rows, err := db.Query(sql)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
count := len(p.Form)
|
||||
valuePtrs := make([]interface{}, count)
|
||||
values := make([]interface{}, count)
|
||||
|
||||
for rows.Next() {
|
||||
|
||||
for i, _ := range p.Form {
|
||||
valuePtrs[i] = &values[i]
|
||||
}
|
||||
|
||||
err = rows.Scan(valuePtrs...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for i, col := range p.Form {
|
||||
|
||||
var v interface{}
|
||||
|
||||
val := values[i]
|
||||
|
||||
b, ok := val.([]byte)
|
||||
|
||||
if ok {
|
||||
v = string(b)
|
||||
} else {
|
||||
v = val
|
||||
}
|
||||
|
||||
ll := &FormElement{
|
||||
Name: col.Name,
|
||||
Description: col.Description,
|
||||
SQLValue: col.SQLValue,
|
||||
SQLType: col.SQLType,
|
||||
Value: v,
|
||||
}
|
||||
|
||||
newForm = append(newForm, ll)
|
||||
|
||||
fmt.Println(col.SQLValue, v)
|
||||
|
||||
col.Value = v
|
||||
}
|
||||
|
||||
}
|
||||
return newForm
|
||||
}
|
||||
|
||||
func RunSQL(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
rows, err := db.Query(query, args)
|
||||
return rows, err
|
||||
}
|
||||
|
||||
func (i Info) Template() *template.Template {
|
||||
t := template.New("form")
|
||||
temp, _ := t.Parse(i.Form)
|
||||
temp, _ := t.Parse("hello nworld")
|
||||
return temp
|
||||
}
|
||||
|
||||
|
@ -57,27 +146,8 @@ func DownloadFile(filepath string, url string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type Add func(p PluginInfo)
|
||||
|
||||
type PluginActions interface {
|
||||
GetInfo() Info
|
||||
Routes() []Routing
|
||||
SaveForm()
|
||||
OnInstall()
|
||||
OnUninstall()
|
||||
OnFailure()
|
||||
OnHit()
|
||||
OnSettingsSaved()
|
||||
OnNewUser()
|
||||
OnNewService()
|
||||
OnShutdown()
|
||||
OnLoad()
|
||||
OnBeforeRequest()
|
||||
OnAfterRequest()
|
||||
}
|
||||
|
||||
func SetDatabase(db *sql.DB) {
|
||||
DB = db
|
||||
func SetDatabase(database *sql.DB) {
|
||||
db = database
|
||||
}
|
||||
|
||||
func (p *PluginInfo) InstallPlugin(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
Binary file not shown.
Binary file not shown.
72
web.go
72
web.go
|
@ -4,10 +4,10 @@ import (
|
|||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/hunterlong/statup/plugin"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -29,46 +29,28 @@ func RunHTTPServer() {
|
|||
r.Handle("/dashboard", http.HandlerFunc(DashboardHandler))
|
||||
r.Handle("/login", http.HandlerFunc(LoginHandler))
|
||||
r.Handle("/logout", http.HandlerFunc(LogoutHandler))
|
||||
|
||||
r.Handle("/services", http.HandlerFunc(ServicesHandler))
|
||||
r.Handle("/services", http.HandlerFunc(CreateServiceHandler)).Methods("POST")
|
||||
r.Handle("/service/{id}", http.HandlerFunc(ServicesViewHandler))
|
||||
r.Handle("/service/{id}", http.HandlerFunc(ServicesUpdateHandler)).Methods("POST")
|
||||
r.Handle("/service/{id}/edit", http.HandlerFunc(ServicesViewHandler))
|
||||
r.Handle("/service/{id}/delete", http.HandlerFunc(ServicesDeleteHandler))
|
||||
|
||||
r.Handle("/users", http.HandlerFunc(UsersHandler))
|
||||
r.Handle("/users", http.HandlerFunc(CreateUserHandler)).Methods("POST")
|
||||
|
||||
r.Handle("/settings", http.HandlerFunc(SettingsHandler))
|
||||
r.Handle("/plugins", http.HandlerFunc(PluginsHandler))
|
||||
r.Handle("/settings", http.HandlerFunc(PluginsHandler))
|
||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
|
||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
|
||||
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
||||
|
||||
for _, p := range allPlugins {
|
||||
symPlugin, _ := p.Lookup("Plugin")
|
||||
var pluginObject plugin.PluginActions
|
||||
pluginObject, ok := symPlugin.(plugin.PluginActions)
|
||||
|
||||
info := pluginObject.GetInfo()
|
||||
|
||||
if !ok {
|
||||
fmt.Printf("Plugin '%v' could not load correctly, error: %v\n", info.Name, "unexpected type from module symbol")
|
||||
continue
|
||||
}
|
||||
|
||||
plugin.AllPlugins = append(plugin.AllPlugins, info)
|
||||
|
||||
for _, route := range pluginObject.Routes() {
|
||||
info := p.GetInfo()
|
||||
for _, route := range p.Routes() {
|
||||
path := fmt.Sprintf("/plugins/%v/%v", info.Name, route.URL)
|
||||
r.Handle(path, http.HandlerFunc(route.Handler)).Methods(route.Method)
|
||||
fmt.Printf("Added Route %v for plugin %v\n", path, info.Name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
core.Plugins = plugin.AllPlugins
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: "0.0.0.0:8080",
|
||||
WriteTimeout: time.Second * 15,
|
||||
|
@ -235,16 +217,6 @@ func IsAuthenticated(r *http.Request) bool {
|
|||
return session.Values["authenticated"].(bool)
|
||||
}
|
||||
|
||||
func SettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
auth := IsAuthenticated(r)
|
||||
if !auth {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
tmpl := Parse("settings.html")
|
||||
tmpl.Execute(w, core)
|
||||
}
|
||||
|
||||
func PluginsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
auth := IsAuthenticated(r)
|
||||
if !auth {
|
||||
|
@ -254,8 +226,32 @@ func PluginsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
tmpl := ParsePlugins("plugins.html")
|
||||
core.FetchPluginRepo()
|
||||
|
||||
fmt.Println(core.FetchPluginRepo())
|
||||
tmpl.Execute(w, &core)
|
||||
for _, p := range allPlugins {
|
||||
for _, f := range p.GetInfo().Form {
|
||||
|
||||
f.Val()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tmpl.Execute(w, core)
|
||||
}
|
||||
|
||||
func PluginSavedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
auth := IsAuthenticated(r)
|
||||
if !auth {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
r.ParseForm()
|
||||
vars := mux.Vars(r)
|
||||
plugin := SelectPlugin(vars["name"])
|
||||
data := make(map[string]string)
|
||||
for k, v := range r.PostForm {
|
||||
data[k] = strings.Join(v, "")
|
||||
}
|
||||
plugin.OnSave(data)
|
||||
http.Redirect(w, r, "/settings", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func PluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -264,9 +260,9 @@ func PluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
DownloadPlugin(name)
|
||||
//vars := mux.Vars(r)
|
||||
//name := vars["name"]
|
||||
//DownloadPlugin(name)
|
||||
LoadConfig()
|
||||
http.Redirect(w, r, "/plugins", http.StatusSeeOther)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue