返回 DeepSeek-Reasonix
walk.go
根目录 / internal / attachment / walk.go
1 package attachment
2
3 import (
4 "encoding/json"
5
6 "reasonix/internal/sessioncontent"
7 )
8
9 // CollectJSONRefs extracts attachment objects from any JSON value that may
10 // contain ImageInput or AttachmentRef objects. It is used by export, import,
11 // and authorization rebuilds.
12 func CollectJSONRefs(raw []byte) []sessioncontent.Ref {
13 if len(raw) == 0 {
14 return nil
15 }
16 var value any
17 if err := json.Unmarshal(raw, &value); err != nil {
18 return nil
19 }
20 seen := map[string]sessioncontent.Ref{}
21 walkValue(value, seen)
22 if len(seen) == 0 {
23 return nil
24 }
25 out := make([]sessioncontent.Ref, 0, len(seen))
26 for _, ref := range seen {
27 out = append(out, ref)
28 }
29 return out
30 }
31
32 func walkValue(value any, seen map[string]sessioncontent.Ref) {
33 switch item := value.(type) {
34 case map[string]any:
35 if ref, ok := attachmentRefFromMap(item); ok {
36 key := ref.Digest + ":" + itoa(ref.Bytes) + ":" + ref.IndexDigest
37 seen[key] = ref
38 }
39 for _, nested := range item {
40 walkValue(nested, seen)
41 }
42 case []any:
43 for _, nested := range item {
44 walkValue(nested, seen)
45 }
46 }
47 }
48
49 func attachmentRefFromMap(item map[string]any) (sessioncontent.Ref, bool) {
50 content, _ := item["content"].(map[string]any)
51 if content == nil {
52 if _, ok := item["digest"].(string); ok && item["v"] == nil {
53 content = item
54 }
55 }
56 if content == nil {
57 return sessioncontent.Ref{}, false
58 }
59 digest, _ := content["digest"].(string)
60 if digest == "" {
61 return sessioncontent.Ref{}, false
62 }
63 ref := sessioncontent.Ref{
64 Digest: digest,
65 MediaType: stringField(content, "mediaType"),
66 Name: stringField(content, "name"),
67 IndexDigest: stringField(content, "indexDigest"),
68 }
69 switch bytes := content["bytes"].(type) {
70 case float64:
71 ref.Bytes = int64(bytes)
72 case json.Number:
73 n, _ := bytes.Int64()
74 ref.Bytes = n
75 }
76 switch block := content["integrityBlockBytes"].(type) {
77 case float64:
78 ref.IntegrityBlock = int64(block)
79 case json.Number:
80 n, _ := block.Int64()
81 ref.IntegrityBlock = n
82 }
83 if ref.Bytes <= 0 {
84 return sessioncontent.Ref{}, false
85 }
86 return ref, true
87 }
88
89 func stringField(item map[string]any, key string) string {
90 value, _ := item[key].(string)
91 return value
92 }
93
94 func itoa(n int64) string {
95 if n == 0 {
96 return "0"
97 }
98 var buf [20]byte
99 i := len(buf)
100 neg := n < 0
101 if neg {
102 n = -n
103 }
104 for n > 0 {
105 i--
106 buf[i] = byte('0' + n%10)
107 n /= 10
108 }
109 if neg {
110 i--
111 buf[i] = '-'
112 }
113 return string(buf[i:])
114 }
115
115 lines GO