Files
2026-05-17 00:51:17 -05:00

175 lines
3.8 KiB
Go

package handlers
import (
"context"
"log"
"os"
"path/filepath"
"time"
agentRuntime "overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/wire"
)
func parseIconRequestItems(raw interface{}) []wire.FileIconRequestItem {
arr, _ := raw.([]interface{})
out := make([]wire.FileIconRequestItem, 0, len(arr))
for _, v := range arr {
m := coerceStringMap(v)
if m == nil {
continue
}
key, _ := m["key"].(string)
if key == "" {
continue
}
path, _ := m["path"].(string)
ext, _ := m["ext"].(string)
out = append(out, wire.FileIconRequestItem{Key: key, Path: path, Ext: ext})
}
return out
}
func parseThumbRequestItems(raw interface{}) []wire.FileThumbnailRequestItem {
arr, _ := raw.([]interface{})
out := make([]wire.FileThumbnailRequestItem, 0, len(arr))
for _, v := range arr {
m := coerceStringMap(v)
if m == nil {
continue
}
key, _ := m["key"].(string)
path, _ := m["path"].(string)
if key == "" || path == "" {
continue
}
size := 0
switch s := m["size"].(type) {
case float64:
size = int(s)
case int64:
size = int(s)
case uint64:
size = int(s)
case int:
size = s
}
out = append(out, wire.FileThumbnailRequestItem{Key: key, Path: path, Size: size})
}
return out
}
func coerceStringMap(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok {
return m
}
if m, ok := v.(map[interface{}]interface{}); ok {
out := make(map[string]interface{}, len(m))
for k, val := range m {
if ks, ok := k.(string); ok {
out[ks] = val
}
}
return out
}
return nil
}
func HandleFileIcon(ctx context.Context, env *agentRuntime.Env, cmdID string, items []wire.FileIconRequestItem) error {
out := make([]wire.FileIconResultItem, 0, len(items))
for _, item := range items {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
png, err := extractFileIconPNG(item.Path, item.Ext)
ri := wire.FileIconResultItem{Key: item.Key}
if err != nil {
ri.Error = err.Error()
} else {
ri.PNG = png
}
out = append(out, ri)
}
return wire.WriteMsg(ctx, env.Conn, wire.FileIconResult{
Type: "file_icon_result",
CommandID: cmdID,
Icons: out,
})
}
func HandleFileThumbnail(ctx context.Context, env *agentRuntime.Env, cmdID string, items []wire.FileThumbnailRequestItem) error {
out := make([]wire.FileThumbnailResultItem, 0, len(items))
for _, item := range items {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
jpegBytes, w, h, err := extractFileThumbnailJPEG(item.Path, item.Size)
ri := wire.FileThumbnailResultItem{Key: item.Key}
if err != nil {
ri.Error = err.Error()
} else {
ri.JPEG = jpegBytes
ri.W = w
ri.H = h
}
out = append(out, ri)
}
return wire.WriteMsg(ctx, env.Conn, wire.FileThumbnailResult{
Type: "file_thumb_result",
CommandID: cmdID,
Thumbs: out,
})
}
func HandleFolderSize(ctx context.Context, env *agentRuntime.Env, cmdID string, path string) error {
log.Printf("file_dirsize: %s", path)
var bytes, files, dirs int64
lastEmit := time.Now()
emit := func(done bool, errMsg string) error {
return wire.WriteMsg(ctx, env.Conn, wire.FolderSizeResult{
Type: "file_dirsize_result",
CommandID: cmdID,
Path: path,
Bytes: bytes,
Files: files,
Dirs: dirs,
Done: done,
Error: errMsg,
})
}
walkErr := filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
return nil // skip unreadable entries
}
select {
case <-ctx.Done():
return ctx.Err()
default:
}
if info.IsDir() {
dirs++
} else {
files++
bytes += info.Size()
}
if time.Since(lastEmit) >= 400*time.Millisecond {
lastEmit = time.Now()
_ = emit(false, "")
}
return nil
})
errMsg := ""
if walkErr != nil && walkErr != context.Canceled {
errMsg = walkErr.Error()
}
return emit(true, errMsg)
}