1
0
mirror of https://github.com/nxshock/gron.git synced 2024-11-27 03:41:00 +05:00
gron/httpserver.go

233 lines
5.0 KiB
Go
Raw Permalink Normal View History

2022-03-26 13:23:39 +05:00
package main
import (
"bytes"
2022-03-28 20:35:55 +05:00
_ "embed"
2022-03-26 13:23:39 +05:00
"fmt"
"io/fs"
2022-03-27 13:12:36 +05:00
"net"
2022-03-26 13:23:39 +05:00
"net/http"
2022-10-21 20:12:41 +05:00
"sort"
2022-11-20 14:44:03 +05:00
"sync"
2022-03-26 13:23:39 +05:00
"time"
2022-11-20 14:44:03 +05:00
"github.com/gorilla/websocket"
2022-03-26 13:23:39 +05:00
log "github.com/sirupsen/logrus"
)
2022-11-20 14:44:03 +05:00
type WsConnections struct {
2024-04-03 13:47:20 +05:00
connections map[*WsConnection]struct{}
2022-11-20 14:44:03 +05:00
mutex sync.Mutex
}
func (wc *WsConnections) Add(c *websocket.Conn) {
wc.mutex.Lock()
defer wc.mutex.Unlock()
2024-04-03 13:47:20 +05:00
wc.connections[NewWsConnection(c)] = struct{}{}
2022-11-20 14:44:03 +05:00
}
func (wc *WsConnections) Delete(c *websocket.Conn) {
wc.mutex.Lock()
defer wc.mutex.Unlock()
2024-04-03 13:47:20 +05:00
for k := range wc.connections {
if k.w == c {
delete(wc.connections, k)
break
}
}
2022-11-20 14:44:03 +05:00
}
func (wc *WsConnections) Send(message interface{}) {
for conn := range wc.connections {
2024-04-03 13:47:20 +05:00
go func(conn *WsConnection) { _ = conn.Send(message) }(conn)
2022-11-20 14:44:03 +05:00
}
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var wsConnections = &WsConnections{
2024-04-03 13:47:20 +05:00
connections: make(map[*WsConnection]struct{})}
2022-11-20 14:44:03 +05:00
2022-03-26 13:23:39 +05:00
func httpServer(listenAddress string) {
if listenAddress == "none" {
return
}
2022-03-26 13:23:39 +05:00
http.HandleFunc("/", handler)
2022-03-26 20:20:00 +05:00
http.HandleFunc("/reloadJobs", handleReloadJobs)
2022-03-26 16:44:46 +05:00
http.HandleFunc("/shutdown", handleShutdown)
2022-03-26 13:23:39 +05:00
http.HandleFunc("/start", handleForceStart)
http.HandleFunc("/details", handleDetails)
2022-11-20 14:44:03 +05:00
http.HandleFunc("/ws", handleWebSocket)
2022-03-26 13:23:39 +05:00
log.WithField("job", "http_server").Fatal(http.ListenAndServe(listenAddress, nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.RequestURI != "/" {
fs, err := fs.Sub(siteFS, "webui")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.FileServer(http.FS(fs)).ServeHTTP(w, r)
2022-03-26 13:23:39 +05:00
return
}
2022-03-26 20:20:00 +05:00
globalMutex.RLock()
2022-03-26 13:23:39 +05:00
buf := new(bytes.Buffer)
2022-10-21 20:12:41 +05:00
jobs := make(map[string][]*Job)
2022-11-20 14:44:03 +05:00
for _, jobEntry := range kernel.c.Entries() {
2022-03-28 19:55:43 +05:00
job := jobEntry.Job.(*Job)
job.NextLaunch = jobEntry.Next.Format(config.TimeFormat)
2022-10-21 20:12:41 +05:00
jobs[job.JobConfig.Category] = append(jobs[job.JobConfig.Category], job)
}
var keys []string
for k, v := range jobs {
keys = append(keys, k)
sort.Slice(v, func(i, j int) bool {
return v[i].Name < v[j].Name
})
2022-03-26 13:23:39 +05:00
}
2022-10-21 20:12:41 +05:00
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
_ = templates.ExecuteTemplate(buf, "index.htm", struct {
Categories []string
Jobs map[string][]*Job
}{
Categories: keys,
Jobs: jobs,
})
2022-03-26 20:20:00 +05:00
globalMutex.RUnlock()
2022-03-26 13:23:39 +05:00
_, _ = buf.WriteTo(w)
2022-03-26 13:23:39 +05:00
}
2022-11-20 14:44:03 +05:00
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
wsConnections.Add(conn)
defer wsConnections.Delete(conn)
var startMessage struct {
JobName string
}
for {
err := conn.ReadJSON(&startMessage)
if err != nil {
log.Println(err)
break
}
for _, jobEntry := range kernel.c.Entries() {
job := jobEntry.Job.(*Job)
if job.Name == startMessage.JobName {
host, _, err := net.SplitHostPort(conn.RemoteAddr().String())
if err != nil {
host = r.RemoteAddr
}
log.WithField("job", "http_server").Printf("Forced start %s from %s.", job.Name, host)
go job.Run()
break
}
}
}
}
2022-03-26 13:23:39 +05:00
func handleForceStart(w http.ResponseWriter, r *http.Request) {
jobName := r.FormValue("jobName")
if jobName == "" {
http.Error(w, "job name is not specified", http.StatusBadRequest)
return
}
2022-11-20 14:44:03 +05:00
for _, jobEntry := range kernel.c.Entries() {
2022-03-26 13:23:39 +05:00
job := jobEntry.Job.(*Job)
2022-03-29 19:45:31 +05:00
if job.Name == jobName {
2022-03-27 13:12:36 +05:00
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
host = r.RemoteAddr
}
2022-03-29 21:27:29 +05:00
log.WithField("job", "http_server").Printf("Forced start %s from %s.", job.Name, host)
2022-03-26 13:23:39 +05:00
go job.Run()
time.Sleep(time.Second / 4) // wait some time for job start
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
}
http.Error(w, fmt.Sprintf("there is no job with name %s", jobName), http.StatusBadRequest)
}
2022-03-26 16:44:46 +05:00
func handleShutdown(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Application terminated.\n"))
2022-03-26 16:44:46 +05:00
go func() {
time.Sleep(time.Second)
log.WithField("job", "http_server").Infoln("Shutdown requested")
2022-10-23 10:23:35 +05:00
_ = kernel.Stop(nil)
2022-03-26 16:44:46 +05:00
}()
}
2022-03-26 20:20:00 +05:00
func handleReloadJobs(w http.ResponseWriter, r *http.Request) {
globalMutex.Lock()
defer globalMutex.Unlock()
2022-10-23 10:23:35 +05:00
kernel.c.Stop()
2022-03-26 20:20:00 +05:00
2022-10-23 10:23:35 +05:00
for _, entry := range kernel.c.Entries() {
kernel.c.Remove(entry.ID)
2022-03-26 20:20:00 +05:00
}
err := initJobs()
if err != nil {
http.Error(w, fmt.Sprintf("reload jobs error: %v", err), http.StatusInternalServerError)
return
}
2022-10-23 10:23:35 +05:00
kernel.c.Start()
2022-03-26 20:20:00 +05:00
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
2022-03-28 20:35:55 +05:00
func handleDetails(w http.ResponseWriter, r *http.Request) {
jobName := r.FormValue("jobName")
if jobName == "" {
http.Error(w, "job name is not specified", http.StatusBadRequest)
return
}
2022-10-23 10:23:35 +05:00
jobEntries := kernel.c.Entries()
for _, jobEntry := range jobEntries {
job := jobEntry.Job.(*Job)
if job.Name == jobName {
err := templates.ExecuteTemplate(w, "details.htm", job)
if err != nil {
fmt.Println(err)
}
return
}
}
http.Error(w, fmt.Sprintf("there is no job with name %s", jobName), http.StatusBadRequest)
2022-03-28 20:35:55 +05:00
}