feat: updated pkg implementations

This commit is contained in:
David Allen 2025-08-24 20:40:53 -06:00
parent 86f37555b2
commit 8b161135ff
Signed by: towk
GPG key ID: 0430CDBE22619155
10 changed files with 579 additions and 140 deletions

View file

@ -10,33 +10,55 @@ import (
"strings"
"time"
"git.towk2.me/towk/configurator/pkg/util"
"git.towk2.me/towk/makeshift/internal/archive"
makeshift "git.towk2.me/towk/makeshift/pkg"
"git.towk2.me/towk/makeshift/pkg/storage"
"github.com/rs/zerolog/log"
)
func (s *Service) Download() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download")
path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download")
pluginNames = r.URL.Query()["plugins"]
profileIDs = r.URL.Query()["profiles"]
fileInfo os.FileInfo
out *os.File
store *storage.MemoryStorage = new(storage.MemoryStorage)
hooks []makeshift.Hook
contents []byte
errs []error
err error
)
// initialize storage
store.Init()
log.Debug().
Str("path", path).
Str("client_host", r.Host).
Strs("plugins", pluginNames).
Strs("profiles", profileIDs).
Any("query", r.URL.Query()).
Msg("Service.Download()")
// prepare profiles
errs = s.loadProfiles(profileIDs, store, errs)
if len(errs) > 0 {
log.Error().Errs("errs", errs).Msg("errors occurred loading profiles")
errs = []error{}
}
// determine if path is directory, file, or exists
if fileInfo, err = os.Stat(path); err == nil {
if fileInfo.IsDir() {
// create an archive of the directory and download
log.Debug().
Str("type", "directory").
Msg("Service.Download()")
// get the final archive path
archivePath := fmt.Sprintf("%d.tar.gz", time.Now().Unix())
out, err = os.Create(archivePath)
if err != nil {
@ -44,28 +66,40 @@ func (s *Service) Download() http.HandlerFunc {
return
}
filesToArchive := []string{}
// get a list of filenames to archive
filenamesToArchive := []string{}
filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
filesToArchive = append(filesToArchive, path)
filenamesToArchive = append(filenamesToArchive, path)
}
return nil
})
log.Debug().Strs("files", filesToArchive).Send()
err = util.CreateArchive(filesToArchive, out)
log.Debug().Strs("files", filenamesToArchive).Send()
// prepare plugins
hooks, errs = s.loadPlugins(pluginNames, store, nil, errs)
if len(errs) > 0 {
log.Error().Errs("errs", errs).Msg("errors occurred loading plugins")
errs = []error{}
}
// create an archive of the directory, run hooks, and download
err = archive.Create(filenamesToArchive, out, hooks)
if err != nil {
s.writeErrorResponse(w, fmt.Sprintf("failed to create archive: %v", err.Error()), http.StatusInternalServerError)
return
}
// load the final archive
contents, err = os.ReadFile(archivePath)
if err != nil {
s.writeErrorResponse(w, fmt.Sprintf("failed to read archive: %v", err.Error()), http.StatusInternalServerError)
s.writeErrorResponse(w, fmt.Sprintf("failed to read archive contents: %v", err.Error()), http.StatusInternalServerError)
return
}
w.Write(contents)
// clean up the temporary archive
err = os.Remove(archivePath)
if err != nil {
log.Error().Err(err).Msg("failed to remove temporary archive")
@ -77,12 +111,53 @@ func (s *Service) Download() http.HandlerFunc {
log.Debug().
Str("type", "file").
Msg("Service.Download()")
contents, err = os.ReadFile(path)
if err != nil {
s.writeErrorResponse(w, fmt.Sprintf("failed to read file to download: %v", err.Error()), http.StatusInternalServerError)
s.writeErrorResponse(w, fmt.Sprintf("failed to read file to download: %v", err), http.StatusInternalServerError)
return
}
w.Write(contents)
// prepare plugins
store.Set("file", contents)
hooks, errs = s.loadPlugins(pluginNames, store, nil, errs)
if len(errs) > 0 {
log.Error().Errs("errs", errs).Msg("errors occurred loading plugins")
errs = []error{}
}
// run pre-hooks to modify the contents of the file before archiving
log.Debug().Int("hook_count", len(hooks)).Msg("running hooks")
for _, hook := range hooks {
log.Debug().Any("hook", map[string]any{
"data": hook.Data,
"args": hook.Args,
"plugin": map[string]string{
"name": hook.Plugin.Name(),
"description": hook.Plugin.Description(),
"version": hook.Plugin.Version(),
},
}).Send()
err = hook.Run()
if err != nil {
log.Error().Err(err).Str("plugin", hook.Plugin.Name()).Msg("failed to run plugin")
continue
}
}
// take the contents from the last hook and update files
var (
hook = hooks[len(hooks)-1]
data any
)
data, err = hook.Data.Get("out")
if err != nil {
s.writeErrorResponse(w, fmt.Sprintf("failed to get data from hook: %v", err), http.StatusInternalServerError)
return
}
w.Write([]byte(data.(string)))
}
} else {
s.writeErrorResponse(w, err.Error(), http.StatusBadRequest)
@ -150,3 +225,70 @@ func (s *Service) GetStatus(w http.ResponseWriter, r *http.Request) {
return
}
}
func (s *Service) loadProfiles(profileIDs []string, store storage.KVStore, errs []error) []error {
// load data from profiles into the data store
for i, profileID := range profileIDs {
var (
profilePath = s.PathForProfileWithID(profileID)
profile *makeshift.Profile
err error
)
if i > DEFAULT_PROFILES_MAX_COUNT {
log.Warn().Msg("max profiles count reached...stopping")
return errs
}
if profileID == "" {
log.Warn().Msg("profile ID is empty...skipping")
continue
}
log.Debug().
Str("id", profileID).
Str("path", profilePath).
Msg("load profile")
profile, err = LoadProfileFromFile(profilePath)
if err != nil {
errs = append(errs, err)
continue
}
store.Set(profileID, profile)
}
return errs
}
func (s *Service) loadPlugins(pluginNames []string, store storage.KVStore, args []string, errs []error) ([]makeshift.Hook, []error) {
// create hooks to run from provided plugins specified
var hooks []makeshift.Hook
for i, pluginName := range pluginNames {
var (
pluginPath string = s.PathForPluginWithName(pluginName)
plugin makeshift.Plugin
err error
)
if i > DEFAULT_PLUGINS_MAX_COUNT {
log.Warn().Msg("max plugins count reached...stopping")
return hooks, errs
}
if pluginName == "" {
log.Warn().Msg("plugin name is empty...skipping")
continue
}
log.Debug().
Str("name", pluginName).
Str("path", pluginPath).
Msg("load plugin")
// load the plugin from disk
plugin, err = LoadPluginFromFile(pluginPath)
if err != nil {
errs = append(errs, err)
continue
}
hooks = append(hooks, makeshift.Hook{
Data: store,
Args: args,
Plugin: plugin,
})
}
return hooks, errs
}