Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

74 lines
2.4 KiB
Go

package unraid
import (
"context"
"encoding/json"
"errors"
"strings"
"time"
"github.com/itworx/pulse/internal/share"
)
// ShareSource maps Unraid's bounded, read-only shares query. Share usage is reported
// by Unraid in KiB; Pulse's domain contract consistently uses bytes. The API does not
// expose a complete placement scan in this selection, so no placement is inferred.
type ShareSource struct {
Client *Client
Now func() time.Time
}
func (s ShareSource) Snapshot(ctx context.Context) (share.RawSnapshot, error) {
if s.Client == nil {
return share.RawSnapshot{}, errors.New("Unraid client is required")
}
payload, err := s.Client.Query(ctx, "shares")
if err != nil {
return share.RawSnapshot{}, err
}
var response struct {
Shares []struct {
ID string `json:"id"`
Name string `json:"name"`
Used json.RawMessage `json:"used"`
Size json.RawMessage `json:"size"`
Include []string `json:"include"`
Exclude []string `json:"exclude"`
Cache bool `json:"cache"`
Allocator string `json:"allocator"`
} `json:"shares"`
}
if err := json.Unmarshal(payload, &response); err != nil {
return share.RawSnapshot{}, errors.New("decode Unraid shares response")
}
if len(response.Shares) > 1000 {
return share.RawSnapshot{}, errors.New("Unraid share response exceeds bounds")
}
now := time.Now().UTC()
if s.Now != nil {
now = s.Now().UTC()
}
items := make([]share.RawShare, 0, len(response.Shares))
for _, item := range response.Shares {
used, err := rawUint(item.Used)
if err != nil || strings.TrimSpace(item.ID) == "" || strings.TrimSpace(item.Name) == "" {
return share.RawSnapshot{}, errors.New("Unraid share identity or usage is invalid")
}
// `cache` is a boolean in this API version. Preserve exactly that fact instead
// of inventing a legacy mover policy or a primary/secondary placement.
cachePolicy := "disabled"
if item.Cache {
cachePolicy = "enabled"
}
items = append(items, share.RawShare{
ID: item.ID,
Name: item.Name,
StoragePolicy: share.StoragePolicy{Allocation: strings.TrimSpace(item.Allocator), CachePolicy: cachePolicy},
UsedBytes: kilobytes(used),
SizeObservedAt: now,
SizeState: share.SizeAvailable,
})
}
return share.RawSnapshot{Source: share.Source{ID: "unraid", Type: "unraid"}, Shares: items, ObservedAt: now, ReceivedAt: now}, nil
}