obrimbaseapi/essential/visible/service/helper/filesystem/filesystem.go

532 lines
12 KiB
Go

package filesystem
import (
"errors"
"fmt"
"io/fs"
"os"
"os/user"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
)
// ObrimFilesystemResult represents the standardized utility response.
type ObrimFilesystemResult struct {
Status bool `json:"status"`
Code string `json:"code"`
Payload any `json:"payload"`
}
// obrimFilesystemEntry represents a filesystem listing entry.
type obrimFilesystemEntry struct {
Name string `json:"name"`
Path string `json:"path"`
Entity string `json:"entity"`
Size int64 `json:"size"`
ModifiedTime time.Time `json:"modified_time"`
}
// ObrimFilesystem executes a filesystem operation and returns a structured result.
func ObrimFilesystem(operationType string, config map[string]any) map[string]any {
if config == nil {
config = map[string]any{}
}
if err := obrimFilesystemValidate(operationType, config); err != nil {
return ObrimStatus(false, "FAILED_VALIDATION", nil)
}
switch operationType {
case "list":
return obrimFilesystemList(config)
case "check":
return obrimFilesystemCheck(config)
case "create":
return obrimFilesystemCreate(config)
case "delete":
return obrimFilesystemDelete(config)
case "permission":
return obrimFilesystemPermission(config)
default:
return ObrimStatus(false, "FAILED_UNSUPPORTED_TYPE", nil)
}
}
// obrimFilesystemValidate validates operation type and configuration.
func obrimFilesystemValidate(operationType string, config map[string]any) error {
allowedTypes := map[string]bool{
"list": true,
"check": true,
"create": true,
"delete": true,
"permission": true,
}
if !allowedTypes[operationType] {
return errors.New("unsupported type")
}
switch operationType {
case "create", "delete":
entity := strings.TrimSpace(fmt.Sprintf("%v", config["entity"]))
if entity != "file" && entity != "directory" {
return errors.New("invalid entity")
}
}
if strategy, ok := config["strategy"]; ok {
value := fmt.Sprintf("%v", strategy)
if value != "user" && value != "custom" {
return errors.New("invalid strategy")
}
if value == "custom" {
if strings.TrimSpace(fmt.Sprintf("%v", config["base"])) == "" {
return errors.New("missing base")
}
}
}
return nil
}
// obrimFilesystemResolve resolves and normalizes filesystem paths.
func obrimFilesystemResolve(config map[string]any) (string, error) {
base := "."
if strategy, ok := config["strategy"]; ok {
switch fmt.Sprintf("%v", strategy) {
case "user":
currentUser, err := user.Current()
if err != nil {
return "", err
}
base = currentUser.HomeDir
case "custom":
base = fmt.Sprintf("%v", config["base"])
}
}
name := strings.TrimSpace(fmt.Sprintf("%v", config["name"]))
resolved := filepath.Join(base, name)
absolute, err := filepath.Abs(filepath.Clean(resolved))
if err != nil {
return "", err
}
return absolute, nil
}
// obrimFilesystemPayload builds standardized payload structures.
func obrimFilesystemPayload(payload map[string]any) map[string]any {
return payload
}
// obrimFilesystemEntityType determines filesystem entity type.
func obrimFilesystemEntityType(path string) string {
info, err := os.Stat(path)
if err != nil {
return "unknown"
}
if info.IsDir() {
return "directory"
}
return "file"
}
// obrimFilesystemPermissionValidate validates permission specifications.
func obrimFilesystemPermissionValidate(permission string) error {
if permission == "" {
return errors.New("permission required")
}
_, err := fs.FileMode(0).String(), error(nil)
return err
}
// obrimFilesystemList executes filesystem listing operations.
func obrimFilesystemList(config map[string]any) map[string]any {
basePath, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
entries, err := obrimFilesystemListTraverse(basePath, config)
if err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
entries = obrimFilesystemListFilter(entries, config)
entries = obrimFilesystemListSort(entries, config)
payload := obrimFilesystemPayload(map[string]any{
"entries": entries,
"total": len(entries),
"recursive": getBool(config, "recursive"),
"base_path": basePath,
})
return ObrimStatus(true, "SUCCESS_LIST", payload)
}
// obrimFilesystemListTraverse traverses filesystem entities according to listing configuration.
func obrimFilesystemListTraverse(basePath string, config map[string]any) ([]obrimFilesystemEntry, error) {
var entries []obrimFilesystemEntry
recursive := getBool(config, "recursive")
if recursive {
err := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == basePath {
return nil
}
entries = append(entries, obrimFilesystemEntry{
Name: info.Name(),
Path: path,
Entity: obrimFilesystemEntityType(path),
Size: info.Size(),
ModifiedTime: info.ModTime(),
})
return nil
})
return entries, err
}
list, err := os.ReadDir(basePath)
if err != nil {
return nil, err
}
for _, item := range list {
info, _ := item.Info()
entries = append(entries, obrimFilesystemEntry{
Name: item.Name(),
Path: filepath.Join(basePath, item.Name()),
Entity: map[bool]string{true: "directory", false: "file"}[item.IsDir()],
Size: info.Size(),
ModifiedTime: info.ModTime(),
})
}
return entries, nil
}
// obrimFilesystemListFilter applies entity and pattern filtering.
func obrimFilesystemListFilter(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
var filtered []obrimFilesystemEntry
entity := strings.TrimSpace(fmt.Sprintf("%v", config["entity"]))
pattern := strings.TrimSpace(fmt.Sprintf("%v", config["filter_pattern"]))
includeHidden := getBool(config, "include_hidden")
for _, entry := range entries {
if !includeHidden && strings.HasPrefix(entry.Name, ".") {
continue
}
if entity != "" && entry.Entity != entity {
continue
}
if pattern != "" {
match, _ := filepath.Match(pattern, entry.Name)
if !match {
continue
}
}
filtered = append(filtered, entry)
}
return filtered
}
// obrimFilesystemListSort applies result sorting behavior.
func obrimFilesystemListSort(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
sortBy := strings.TrimSpace(fmt.Sprintf("%v", config["sort_by"]))
order := strings.TrimSpace(fmt.Sprintf("%v", config["sort_order"]))
sort.Slice(entries, func(i, j int) bool {
var result bool
switch sortBy {
case "size":
result = entries[i].Size < entries[j].Size
case "modified":
result = entries[i].ModifiedTime.Before(entries[j].ModifiedTime)
default:
result = entries[i].Name < entries[j].Name
}
if order == "desc" {
return !result
}
return result
})
return entries
}
// obrimFilesystemCheck executes filesystem validation operations.
func obrimFilesystemCheck(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
_, err = os.Stat(path)
exists := err == nil
readable, writable := obrimFilesystemCheckAccess(path)
payload := obrimFilesystemPayload(map[string]any{
"path": path,
"exists": exists,
"entity": obrimFilesystemEntityType(path),
"readable": readable,
"writable": writable,
})
return ObrimStatus(true, "SUCCESS_CHECK", payload)
}
// obrimFilesystemCheckAccess verifies filesystem accessibility requirements.
func obrimFilesystemCheckAccess(path string) (bool, bool) {
readable := true
writable := true
file, err := os.Open(path)
if err != nil {
readable = false
} else {
_ = file.Close()
}
file, err = os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
writable = false
} else {
_ = file.Close()
}
return readable, writable
}
// obrimFilesystemCreate executes filesystem entity creation operations.
func obrimFilesystemCreate(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
entity := fmt.Sprintf("%v", config["entity"])
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
switch entity {
case "file":
err = obrimFilesystemCreateFile(path)
case "directory":
err = obrimFilesystemCreateDirectory(path)
}
if err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
hidden := getBool(config, "hidden")
payload := obrimFilesystemPayload(map[string]any{
"path": path,
"entity": entity,
"hidden": hidden,
"created": true,
})
return ObrimStatus(true, "SUCCESS_CREATE", payload)
}
// obrimFilesystemCreateFile creates a filesystem file.
func obrimFilesystemCreateFile(path string) error {
file, err := os.Create(path)
if err != nil {
return err
}
return file.Close()
}
// obrimFilesystemCreateDirectory creates a filesystem directory.
func obrimFilesystemCreateDirectory(path string) error {
return os.MkdirAll(path, 0755)
}
// obrimFilesystemDelete executes filesystem entity deletion operations.
func obrimFilesystemDelete(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
entity := fmt.Sprintf("%v", config["entity"])
switch entity {
case "file":
err = obrimFilesystemDeleteFile(path)
case "directory":
err = obrimFilesystemDeleteDirectory(path, getBool(config, "recursive"))
}
if err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
payload := obrimFilesystemPayload(map[string]any{
"path": path,
"entity": entity,
"deleted": true,
})
return ObrimStatus(true, "SUCCESS_DELETE", payload)
}
// obrimFilesystemDeleteFile deletes a filesystem file.
func obrimFilesystemDeleteFile(path string) error {
return os.Remove(path)
}
// obrimFilesystemDeleteDirectory deletes a filesystem directory.
func obrimFilesystemDeleteDirectory(path string, recursive bool) error {
if recursive {
return os.RemoveAll(path)
}
return os.Remove(path)
}
// obrimFilesystemPermission executes filesystem permission operations.
func obrimFilesystemPermission(config map[string]any) map[string]any {
mode := strings.TrimSpace(fmt.Sprintf("%v", config["mode"]))
switch mode {
case "write":
return obrimFilesystemPermissionWrite(config)
default:
return obrimFilesystemPermissionRead(config)
}
}
// obrimFilesystemPermissionRead retrieves filesystem permissions.
func obrimFilesystemPermissionRead(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
info, err := os.Stat(path)
if err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
payload := obrimFilesystemPayload(map[string]any{
"path": path,
"permission": info.Mode().Perm().String(),
"mode": "read",
"updated": false,
})
return ObrimStatus(true, "SUCCESS_PERMISSION", payload)
}
// obrimFilesystemPermissionWrite updates filesystem permissions.
func obrimFilesystemPermissionWrite(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
}
permission := strings.TrimSpace(fmt.Sprintf("%v", config["permission"]))
if err := obrimFilesystemPermissionValidate(permission); err != nil {
return ObrimStatus(false, "FAILED_VALIDATION", nil)
}
var mode os.FileMode
_, err = fmt.Sscanf(permission, "%o", &mode)
if err != nil {
return ObrimStatus(false, "FAILED_VALIDATION", nil)
}
if runtime.GOOS != "windows" {
if err := os.Chmod(path, mode); err != nil {
return ObrimStatus(false, "FAILED_EXECUTION", nil)
}
}
payload := obrimFilesystemPayload(map[string]any{
"path": path,
"permission": permission,
"mode": "write",
"updated": true,
})
return ObrimStatus(true, "SUCCESS_PERMISSION", payload)
}
// ObrimStatus returns standardized utility status responses.
func ObrimStatus(status bool, code string, payload any) map[string]any {
return map[string]any{
"status": status,
"code": code,
"payload": payload,
}
}
// getBool safely reads boolean config values.
func getBool(config map[string]any, key string) bool {
value, ok := config[key]
if !ok {
return false
}
boolean, ok := value.(bool)
if !ok {
return false
}
return boolean
}