feat: init commit
This commit is contained in:
parent
d899ee0b08
commit
d8e89bd5db
5
assets/banner.txt
Normal file
5
assets/banner.txt
Normal file
@ -0,0 +1,5 @@
|
||||
__ ______
|
||||
/ /______ ____ / / / /
|
||||
/ //_/ __ \/ __ \/ / / /
|
||||
/ ,< / /_/ / / / /_/_/_/
|
||||
/_/|_|\____/_/ /_(_|_|_)
|
67
auth/auth.go
Normal file
67
auth/auth.go
Normal file
@ -0,0 +1,67 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"kon/config"
|
||||
"kon/utils"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
var Hashes = map[string]time.Time{}
|
||||
var HashesMutex = sync.RWMutex{}
|
||||
|
||||
func CreateToken() string {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
||||
jwt.MapClaims{
|
||||
"reqHash": uniuri.New(),
|
||||
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||
})
|
||||
|
||||
tokenString, err := token.SignedString(config.AuthSecret)
|
||||
utils.CheckError(err)
|
||||
|
||||
return tokenString
|
||||
}
|
||||
|
||||
func VerifyToken(tokenString string) bool {
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return config.AuthSecret, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
_, does_claim_have_req_hash := claims["reqHash"]
|
||||
if does_claim_have_req_hash {
|
||||
HashesMutex.RLock()
|
||||
val, exists := Hashes[claims["reqHash"].(string)]
|
||||
HashesMutex.RUnlock()
|
||||
if exists {
|
||||
if time.Since(val) > 48*time.Hour {
|
||||
HashesMutex.Lock()
|
||||
Hashes[claims["reqHash"].(string)] = time.Now()
|
||||
HashesMutex.Unlock()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
HashesMutex.Lock()
|
||||
Hashes[claims["reqHash"].(string)] = time.Now()
|
||||
HashesMutex.Unlock()
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
log.Printf("Invalid JWT Token")
|
||||
return false
|
||||
}
|
||||
}
|
14
banner/banner.go
Normal file
14
banner/banner.go
Normal file
@ -0,0 +1,14 @@
|
||||
package banner
|
||||
|
||||
import (
|
||||
"kon/constants"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const Banner = " __ ______\n / /______ ____ / / / /\n / //_/ __ \\/ __ \\/ / / / \n / ,< / /_/ / / / /_/_/_/ \n /_/|_|\\____/_/ /_(_|_|_)"
|
||||
|
||||
func FormatBanner() string {
|
||||
d := color.New(color.FgHiWhite, color.Bold)
|
||||
return d.Sprint(Banner) + " " + constants.VersionString
|
||||
}
|
98
client/client.go
Normal file
98
client/client.go
Normal file
@ -0,0 +1,98 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"kon/auth"
|
||||
"kon/banner"
|
||||
"kon/client/state"
|
||||
"kon/config"
|
||||
"kon/constants"
|
||||
"kon/pon/paths/status"
|
||||
"kon/utils"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
func Status() {
|
||||
for host := range config.Config.Hosts {
|
||||
state.State.Mutex.Lock()
|
||||
state.State.Machines[host] = state.Machine{
|
||||
State: state.Working,
|
||||
JobStart: time.Now(),
|
||||
}
|
||||
state.State.Mutex.Unlock()
|
||||
go StatusThread(host)
|
||||
}
|
||||
DisplayState()
|
||||
}
|
||||
|
||||
func StatusThread(host string) {
|
||||
base, err := url.Parse("http://" + config.Config.Hosts[host] + constants.HostEndpoint)
|
||||
utils.CheckError(err)
|
||||
base.Path += "status"
|
||||
params := url.Values{}
|
||||
params.Add("token", auth.CreateToken())
|
||||
base.RawQuery = params.Encode()
|
||||
resp, err := http.Get(base.String())
|
||||
if utils.JobFailed(err, host) {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if utils.JobFailed(err, host) {
|
||||
return
|
||||
}
|
||||
var status status.Status
|
||||
err = json.Unmarshal(body, &status)
|
||||
if utils.JobFailed(err, host) {
|
||||
return
|
||||
}
|
||||
state.State.Mutex.Lock()
|
||||
state.State.Machines[host] = state.Machine{
|
||||
State: state.Completed,
|
||||
JobStart: state.State.Machines[host].JobStart,
|
||||
JobEnd: time.Now(),
|
||||
Message: fmt.Sprintf("[RAM: %0.2f%%] [Uptime: %s]", float64(status.MemUsed)/float64(status.MemTotal)*100.0, time.Duration(float64(status.Uptime)*float64(time.Second))),
|
||||
}
|
||||
state.State.Mutex.Unlock()
|
||||
}
|
||||
|
||||
func DisplayState() {
|
||||
finished := false
|
||||
for !finished {
|
||||
finished = true
|
||||
currentString := banner.FormatBanner() + "\n\n"
|
||||
state.State.Mutex.RLock()
|
||||
keys := make([]string, 0, len(state.State.Machines))
|
||||
for key := range state.State.Machines {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, host := range keys {
|
||||
line := ""
|
||||
switch state.State.Machines[host].State {
|
||||
case state.Working:
|
||||
finished = false
|
||||
d := color.New(color.FgHiYellow, color.Bold)
|
||||
line = d.Sprintf(" - [✸] %-15s %15s\n", host, time.Since(state.State.Machines[host].JobStart))
|
||||
case state.Error:
|
||||
d := color.New(color.FgHiRed, color.Bold)
|
||||
line = d.Sprintf(" - [✗] %-15s %15s %s\n", host, state.State.Machines[host].JobEnd.Sub(state.State.Machines[host].JobStart), state.State.Machines[host].Message)
|
||||
case state.Completed:
|
||||
d := color.New(color.FgHiGreen, color.Bold)
|
||||
line = d.Sprintf(" - [✔] %-15s %15s %s\n", host, state.State.Machines[host].JobEnd.Sub(state.State.Machines[host].JobStart), state.State.Machines[host].Message)
|
||||
}
|
||||
currentString += line
|
||||
}
|
||||
state.State.Mutex.RUnlock()
|
||||
print("\033[H\033[2J")
|
||||
println(currentString)
|
||||
}
|
||||
println("")
|
||||
}
|
28
client/state/state.go
Normal file
28
client/state/state.go
Normal file
@ -0,0 +1,28 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StateStruct struct {
|
||||
Machines map[string]Machine
|
||||
Mutex sync.RWMutex
|
||||
}
|
||||
|
||||
type Machine struct {
|
||||
State int
|
||||
JobStart time.Time
|
||||
JobEnd time.Time
|
||||
Message string
|
||||
}
|
||||
|
||||
const (
|
||||
Working = iota
|
||||
Completed
|
||||
Error
|
||||
)
|
||||
|
||||
var State StateStruct = StateStruct{
|
||||
Machines: map[string]Machine{},
|
||||
}
|
20
config/config.go
Normal file
20
config/config.go
Normal file
@ -0,0 +1,20 @@
|
||||
package config
|
||||
|
||||
type ConfigStruct struct {
|
||||
Hosts map[string]string
|
||||
}
|
||||
|
||||
var Config = ConfigStruct{
|
||||
Hosts: map[string]string{
|
||||
"alpha": "127.0.0.1",
|
||||
"beta": "127.0.0.1",
|
||||
"gamma": "127.0.0.1",
|
||||
"delta": "127.0.0.1",
|
||||
"epsilon": "127.0.0.1",
|
||||
"zeta": "127.0.0.1",
|
||||
"eta": "127.0.0.1",
|
||||
"omega": "127.0.0.1",
|
||||
},
|
||||
}
|
||||
|
||||
var AuthSecret = []byte("ChangeMe!")
|
5
constants/constants.go
Normal file
5
constants/constants.go
Normal file
@ -0,0 +1,5 @@
|
||||
package constants
|
||||
|
||||
const VersionString = "v0.0.1"
|
||||
|
||||
const HostEndpoint = ":3000"
|
25
go.mod
Normal file
25
go.mod
Normal file
@ -0,0 +1,25 @@
|
||||
module kon
|
||||
|
||||
go 1.22.1
|
||||
|
||||
require (
|
||||
github.com/dchest/uniuri v1.2.0
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/gofiber/fiber/v2 v2.52.4
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/mackerelio/go-osstat v0.2.4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
)
|
35
go.sum
Normal file
35
go.sum
Normal file
@ -0,0 +1,35 @@
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
|
||||
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
|
||||
github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs=
|
||||
github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJvtio5ZjJTbdlQ=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
5
help/help.go
Normal file
5
help/help.go
Normal file
@ -0,0 +1,5 @@
|
||||
package help
|
||||
|
||||
const Help = `
|
||||
Commands:
|
||||
- pon: start server`
|
31
main.go
Normal file
31
main.go
Normal file
@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kon/banner"
|
||||
"kon/client"
|
||||
"kon/help"
|
||||
"kon/pon"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
args := os.Args
|
||||
fmt.Println(banner.FormatBanner())
|
||||
if len(args) == 1 {
|
||||
fmt.Println(help.Help)
|
||||
} else if len(args) == 2 {
|
||||
switch args[1] {
|
||||
case "pon":
|
||||
pon.StartServer()
|
||||
case "status":
|
||||
client.Status()
|
||||
default:
|
||||
log.Fatal("Cannot find command.")
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Fatal("Too many arguments.")
|
||||
}
|
||||
}
|
12
pon/middlewares/middlewares.go
Normal file
12
pon/middlewares/middlewares.go
Normal file
@ -0,0 +1,12 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
)
|
||||
|
||||
func Init(app *fiber.App) {
|
||||
app.Use(logger.New(logger.Config{
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
}))
|
||||
}
|
11
pon/paths/paths.go
Normal file
11
pon/paths/paths.go
Normal file
@ -0,0 +1,11 @@
|
||||
package paths
|
||||
|
||||
import (
|
||||
"kon/pon/paths/status"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func Init(app *fiber.App) {
|
||||
app.Get("/status", status.HandleFunc)
|
||||
}
|
47
pon/paths/status/status.go
Normal file
47
pon/paths/status/status.go
Normal file
@ -0,0 +1,47 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"kon/auth"
|
||||
"kon/utils"
|
||||
"os"
|
||||
|
||||
"github.com/mackerelio/go-osstat/memory"
|
||||
"github.com/mackerelio/go-osstat/uptime"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
Hostname string
|
||||
MemUsed uint64
|
||||
MemTotal uint64
|
||||
Uptime uint64
|
||||
}
|
||||
|
||||
func GetStatus() Status {
|
||||
hostname, err := os.Hostname()
|
||||
utils.CheckError(err)
|
||||
memory, err := memory.Get()
|
||||
utils.CheckError(err)
|
||||
uptime, err := uptime.Get()
|
||||
utils.CheckError(err)
|
||||
|
||||
return Status{
|
||||
Hostname: hostname,
|
||||
MemUsed: memory.Used,
|
||||
MemTotal: memory.Total,
|
||||
Uptime: uint64(uptime) / 1000000000,
|
||||
}
|
||||
}
|
||||
|
||||
func HandleFunc(c *fiber.Ctx) error {
|
||||
queryValue := c.Query("token")
|
||||
if auth.VerifyToken(queryValue) {
|
||||
statusJSON, err := json.Marshal(GetStatus())
|
||||
utils.CheckError(err)
|
||||
return c.SendString(string(statusJSON))
|
||||
} else {
|
||||
return c.SendString("no")
|
||||
}
|
||||
}
|
16
pon/pon.go
Normal file
16
pon/pon.go
Normal file
@ -0,0 +1,16 @@
|
||||
package pon
|
||||
|
||||
import (
|
||||
"kon/constants"
|
||||
"kon/pon/middlewares"
|
||||
"kon/pon/paths"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func StartServer() {
|
||||
app := fiber.New()
|
||||
middlewares.Init(app)
|
||||
paths.Init(app)
|
||||
app.Listen(constants.HostEndpoint)
|
||||
}
|
28
utils/utils.go
Normal file
28
utils/utils.go
Normal file
@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"kon/client/state"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CheckError(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func JobFailed(err error, host string) bool {
|
||||
if err != nil {
|
||||
state.State.Mutex.Lock()
|
||||
state.State.Machines[host] = state.Machine{
|
||||
State: state.Error,
|
||||
Message: err.Error(),
|
||||
JobStart: state.State.Machines[host].JobStart,
|
||||
JobEnd: time.Now(),
|
||||
}
|
||||
state.State.Mutex.Unlock()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
Reference in New Issue
Block a user