feat: more reorganisation and keys endpoint

This commit is contained in:
DaanSelen
2026-04-23 16:51:18 +02:00
parent c3aac38089
commit 417cecf43f
10 changed files with 131 additions and 95 deletions
+7 -3
View File
@@ -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)
+5 -2
View File
@@ -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]
}
}
+13
View File
@@ -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)
+13 -53
View File
@@ -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
+50
View File
@@ -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 -1
View File
@@ -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
}
+4 -12
View File
@@ -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;"`
+2 -24
View File
@@ -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{
+9
View 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
}
+26
View File
@@ -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":