feat: more reorganisation and keys endpoint
This commit is contained in:
@@ -19,14 +19,18 @@ func KickoffApi(logger *slog.Logger, env bootstrap.Environment, db *gorm.DB) {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
// For a nice looking logger:
|
||||
// r := gin.Default()
|
||||
// JSON logger: https://gin-gonic.com/en/docs/logging/structured-logging/
|
||||
// r := gin.Default() // default, this makes a nice looking log-trace but I want JSON
|
||||
r := gin.New()
|
||||
r.Use(middleware.SlogMiddleware(logger))
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
if env.AuthenticationEnabled {
|
||||
slog.Debug("activating authentication middleware") // only log when actually doign the thing it logs to do
|
||||
r.Use(middleware.AuthMiddleware())
|
||||
}
|
||||
|
||||
api := r.Group("/api")
|
||||
routes.RegisterApiRoutes(api /*env,*/, db)
|
||||
routes.RegisterApiRoutes(api, db)
|
||||
|
||||
file := r.Group("/file")
|
||||
routes.RegisterFileRoutes(file, env, db)
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
)
|
||||
|
||||
func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc {
|
||||
// Make a slog-looking logger, inspired by the gin docs themself
|
||||
// JSON logger: https://gin-gonic.com/en/docs/logging/structured-logging/
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
@@ -47,6 +49,8 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
headerParts := strings.Split(authorizationHeader, " ")
|
||||
// The header must be a specific format, 0 being the bearer text and 1 being the token itself, making it 2 pieces total
|
||||
// In the following if statement we verify both parts if the part after Bearer is empty its only 1 part for example
|
||||
if len(headerParts) != 2 || headerParts[0] != "Bearer" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, response.BasicResponse{
|
||||
Msg: "Authorization header is invalid",
|
||||
@@ -54,7 +58,6 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
givenKey := headerParts[1]
|
||||
slog.Info(givenKey)
|
||||
//givenKey := headerParts[1]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,19 @@ import (
|
||||
|
||||
func RegisterApiRoutes(api *gin.RouterGroup /* env runtime.Environment,*/, db *gorm.DB) {
|
||||
// prefix: api
|
||||
|
||||
api.GET("/keys", func(c *gin.Context) {
|
||||
|
||||
})
|
||||
|
||||
api.POST("/keys", func(c *gin.Context) {
|
||||
|
||||
})
|
||||
|
||||
api.DELETE("/keys", func(c *gin.Context) {
|
||||
|
||||
})
|
||||
|
||||
// Display the information on what is going on at the moment
|
||||
api.GET("/command", func(c *gin.Context) {
|
||||
state, err := database.GetState(db)
|
||||
|
||||
@@ -3,68 +3,27 @@ package bootstrap
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Environment struct {
|
||||
// Items made for the presentation of ORBITS
|
||||
Version string
|
||||
Codename string
|
||||
LogLevel string
|
||||
|
||||
DataDirectory string
|
||||
ContentDirectory string
|
||||
Hostname string
|
||||
Port int
|
||||
// Items made for the configuration of the server parts
|
||||
DataDirectory string
|
||||
ContentDirectory string
|
||||
Hostname string
|
||||
Port int
|
||||
AuthenticationEnabled bool
|
||||
|
||||
// Items made for the server watchdog
|
||||
WatchdogEnabled bool
|
||||
WatchdogInterval int
|
||||
WatchdogSyncMode string
|
||||
}
|
||||
|
||||
var (
|
||||
validSyncModes = []string{
|
||||
"sync",
|
||||
"strict",
|
||||
"dry",
|
||||
}
|
||||
)
|
||||
|
||||
// part of environment checking
|
||||
func safeStringGrab(key, fallback string) string {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeIntGrab(key string, fallback int) int {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if i, err := strconv.Atoi(v); err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeBoolGrab(key string, fallback bool) bool {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if b, err := strconv.ParseBool(v); err == nil {
|
||||
return b
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeSyncModeGrab(key, fallback string) string {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if slices.Contains(validSyncModes, v) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func GrabEnvironment() Environment {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
@@ -81,10 +40,11 @@ func GrabEnvironment() Environment {
|
||||
LogLevel: safeStringGrab("LOG_LEVEL", "debug"),
|
||||
|
||||
// GIN API configuration
|
||||
DataDirectory: safeStringGrab("DATA_DIR", fbBase),
|
||||
ContentDirectory: safeStringGrab("CONTENT_DIR", fbContent),
|
||||
Hostname: safeStringGrab("HOSTNAME", "0.0.0.0"),
|
||||
Port: safeIntGrab("PORT", 8080),
|
||||
DataDirectory: safeStringGrab("DATA_DIR", fbBase),
|
||||
ContentDirectory: safeStringGrab("CONTENT_DIR", fbContent),
|
||||
Hostname: safeStringGrab("HOSTNAME", "0.0.0.0"),
|
||||
Port: safeIntGrab("PORT", 8080),
|
||||
AuthenticationEnabled: safeBoolGrab("AUTH_ENABLED", true),
|
||||
|
||||
// watchdog configuration
|
||||
// watchdog is the integrity checker/steward
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
validSyncModes = []string{
|
||||
"sync",
|
||||
"strict",
|
||||
"dry",
|
||||
}
|
||||
)
|
||||
|
||||
// part of environment checking
|
||||
func safeStringGrab(key, fallback string) string {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeIntGrab(key string, fallback int) int {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if i, err := strconv.Atoi(v); err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeBoolGrab(key string, fallback bool) bool {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if b, err := strconv.ParseBool(v); err == nil {
|
||||
return b
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func safeSyncModeGrab(key, fallback string) string {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
if slices.Contains(validSyncModes, v) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package database
|
||||
|
||||
import (
|
||||
"orbits-server/internal/server/bootstrap"
|
||||
"orbits-server/internal/shared/utility"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
@@ -35,7 +36,7 @@ func KickoffDatabase(workDir string) (*gorm.DB, error) {
|
||||
if err := db.FirstOrCreate(&Command{}, Command{
|
||||
ID: 0,
|
||||
State: "idle",
|
||||
MediaType: Unspecified,
|
||||
MediaType: utility.Unspecified,
|
||||
}).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"orbits-server/internal/shared/utility"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MediaType string
|
||||
|
||||
const (
|
||||
Video MediaType = "video"
|
||||
Presentation MediaType = "presentation"
|
||||
Internet MediaType = "internet"
|
||||
Unspecified MediaType = "unspecified"
|
||||
)
|
||||
|
||||
type Timestamps struct {
|
||||
CreatedAt time.Time `gorm:"not null;"`
|
||||
UpdatedAt time.Time `gorm:"not null;"`
|
||||
@@ -26,10 +18,10 @@ type Command struct {
|
||||
// video
|
||||
// presentation
|
||||
// internet URL
|
||||
MediaType MediaType `gorm:"type:varchar(20);not null"` // Must specify what kind of file it is
|
||||
MediaType utility.MediaType `gorm:"type:varchar(20);not null;"` // Must specify what kind of file it is
|
||||
// Must be target list who are compelled to listen to the command
|
||||
// can be none when there is no targets specified (init stage)
|
||||
Targets []string `gorm:"type:json"`
|
||||
Targets []string `gorm:"type:json;"`
|
||||
// Must be the location where the file is downloadable on the API
|
||||
// can be none when there is no media specified (init stage)
|
||||
Location string
|
||||
@@ -64,7 +56,7 @@ type File struct {
|
||||
// video
|
||||
// presentation
|
||||
// internet URL
|
||||
MediaType MediaType `gorm:"type:varchar(20);not null;"`
|
||||
MediaType utility.MediaType `gorm:"type:varchar(20);not null;"`
|
||||
// the name given by the user
|
||||
MetaName string
|
||||
FileName string `gorm:"not null;"`
|
||||
|
||||
@@ -7,36 +7,14 @@ import (
|
||||
"orbits-server/internal/shared/utility"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 0: unspecified
|
||||
// 1: video
|
||||
// 2: presentation
|
||||
// 3: internet URL
|
||||
func CategorizeMediaType(ext string) (MediaType, bool) {
|
||||
|
||||
switch ext {
|
||||
case ".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4a":
|
||||
return Video, true
|
||||
case ".pptx", ".ppt", ".key", ".odp":
|
||||
return Presentation, true
|
||||
default:
|
||||
slog.Debug("marking file as invalid due to its undefined extension")
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateSafeName(category MediaType, ext string) string {
|
||||
return uuid.New().String() + "_" + string(category) + ext
|
||||
}
|
||||
|
||||
// it has been made more general for DRY purposes
|
||||
// this function should only be called after manually checking the filetype
|
||||
func BuildFileRecord(r io.Reader, origName string, contentDirectory string) (File, error) {
|
||||
ext := filepath.Ext(origName)
|
||||
category, ok := CategorizeMediaType(ext)
|
||||
category, ok := utility.CategorizeMediaType(ext)
|
||||
if !ok {
|
||||
return File{}, fmt.Errorf("unsupported filetype")
|
||||
}
|
||||
@@ -47,7 +25,7 @@ func BuildFileRecord(r io.Reader, origName string, contentDirectory string) (Fil
|
||||
return File{}, err
|
||||
}
|
||||
|
||||
safeName := GenerateSafeName(category, ext)
|
||||
safeName := utility.GenerateSafeName(category, ext)
|
||||
destPath := filepath.Join(contentDirectory, safeName)
|
||||
|
||||
fData := File{
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package utility
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func GenerateSafeName(category MediaType, ext string) string {
|
||||
return uuid.New().String() + "_" + string(category) + ext
|
||||
}
|
||||
@@ -6,6 +6,15 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MediaType string
|
||||
|
||||
const (
|
||||
Video MediaType = "video"
|
||||
Presentation MediaType = "presentation"
|
||||
Internet MediaType = "internet"
|
||||
Unspecified MediaType = "unspecified"
|
||||
)
|
||||
|
||||
func RemoveFile(p string) error {
|
||||
err := os.Remove(p)
|
||||
if err != nil {
|
||||
@@ -15,6 +24,23 @@ func RemoveFile(p string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 0: unspecified
|
||||
// 1: video
|
||||
// 2: presentation
|
||||
// 3: internet URL
|
||||
func CategorizeMediaType(ext string) (MediaType, bool) {
|
||||
|
||||
switch ext {
|
||||
case ".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4a":
|
||||
return Video, true
|
||||
case ".pptx", ".ppt", ".key", ".odp":
|
||||
return Presentation, true
|
||||
default:
|
||||
slog.Debug("marking file as invalid due to its undefined extension")
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func ParseSlogLevel(s string) slog.Level {
|
||||
switch strings.ToLower(s) {
|
||||
case "debug":
|
||||
|
||||
Reference in New Issue
Block a user