github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/api/manifest.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:43</date> 10 //</624450112281645056> 11 12 13 package api 14 15 import ( 16 "bytes" 17 "context" 18 "encoding/json" 19 "errors" 20 "fmt" 21 "io" 22 "net/http" 23 "strings" 24 "time" 25 26 "github.com/ethereum/go-ethereum/swarm/storage/feed" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/swarm/log" 30 "github.com/ethereum/go-ethereum/swarm/storage" 31 ) 32 33 const ( 34 ManifestType = "application/bzz-manifest+json" 35 FeedContentType = "application/bzz-feed" 36 37 manifestSizeLimit = 5 * 1024 * 1024 38 ) 39 40 //清单代表一个群体清单 41 type Manifest struct { 42 Entries []ManifestEntry `json:"entries,omitempty"` 43 } 44 45 //manifest entry表示群清单中的条目 46 type ManifestEntry struct { 47 Hash string `json:"hash,omitempty"` 48 Path string `json:"path,omitempty"` 49 ContentType string `json:"contentType,omitempty"` 50 Mode int64 `json:"mode,omitempty"` 51 Size int64 `json:"size,omitempty"` 52 ModTime time.Time `json:"mod_time,omitempty"` 53 Status int `json:"status,omitempty"` 54 Access *AccessEntry `json:"access,omitempty"` 55 Feed *feed.Feed `json:"feed,omitempty"` 56 } 57 58 //manifestList表示清单中列出文件的结果 59 type ManifestList struct { 60 CommonPrefixes []string `json:"common_prefixes,omitempty"` 61 Entries []*ManifestEntry `json:"entries,omitempty"` 62 } 63 64 //new manifest创建并存储新的空清单 65 func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) { 66 var manifest Manifest 67 data, err := json.Marshal(&manifest) 68 if err != nil { 69 return nil, err 70 } 71 addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt) 72 if err != nil { 73 return nil, err 74 } 75 err = wait(ctx) 76 return addr, err 77 } 78 79 //支持来自BZZ的群源的清单黑客:方案 80 //有关更多信息,请参阅swarm/api/api.go:api.get()。 81 func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) { 82 var manifest Manifest 83 entry := ManifestEntry{ 84 Feed: feed, 85 ContentType: FeedContentType, 86 } 87 manifest.Entries = append(manifest.Entries, entry) 88 data, err := json.Marshal(&manifest) 89 if err != nil { 90 return nil, err 91 } 92 addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false) 93 if err != nil { 94 return nil, err 95 } 96 err = wait(ctx) 97 return addr, err 98 } 99 100 //manifestwriter用于添加和删除基础清单中的条目 101 type ManifestWriter struct { 102 api *API 103 trie *manifestTrie 104 quitC chan bool 105 } 106 107 func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) { 108 trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) 109 if err != nil { 110 return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) 111 } 112 return &ManifestWriter{a, trie, quitC}, nil 113 } 114 115 //附录存储给定的数据并将结果地址添加到清单中 116 func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (addr storage.Address, err error) { 117 entry := newManifestTrieEntry(e, nil) 118 if data != nil { 119 var wait func(context.Context) error 120 addr, wait, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted) 121 if err != nil { 122 return nil, err 123 } 124 err = wait(ctx) 125 if err != nil { 126 return nil, err 127 } 128 entry.Hash = addr.Hex() 129 } 130 if entry.Hash == "" { 131 return addr, errors.New("missing entry hash") 132 } 133 m.trie.addEntry(entry, m.quitC) 134 return addr, nil 135 } 136 137 //removeentry从清单中删除给定路径 138 func (m *ManifestWriter) RemoveEntry(path string) error { 139 m.trie.deleteEntry(path, m.quitC) 140 return nil 141 } 142 143 //存储存储清单,返回结果存储地址 144 func (m *ManifestWriter) Store() (storage.Address, error) { 145 return m.trie.ref, m.trie.recalcAndStore() 146 } 147 148 //manifestwalker用于递归地遍历清单中的条目和 149 //它的所有子流形 150 type ManifestWalker struct { 151 api *API 152 trie *manifestTrie 153 quitC chan bool 154 } 155 156 func (a *API) NewManifestWalker(ctx context.Context, addr storage.Address, decrypt DecryptFunc, quitC chan bool) (*ManifestWalker, error) { 157 trie, err := loadManifest(ctx, a.fileStore, addr, quitC, decrypt) 158 if err != nil { 159 return nil, fmt.Errorf("error loading manifest %s: %s", addr, err) 160 } 161 return &ManifestWalker{a, trie, quitC}, nil 162 } 163 164 //errskipmanifest用作walkfn的返回值,以指示 165 //应跳过清单 166 var ErrSkipManifest = errors.New("skip this manifest") 167 168 //walkfn是递归访问的每个条目调用的函数类型 169 //显性步行 170 type WalkFn func(entry *ManifestEntry) error 171 172 //以递归方式遍历清单,为中的每个条目调用walkfn 173 //清单,包括子流形 174 func (m *ManifestWalker) Walk(walkFn WalkFn) error { 175 return m.walk(m.trie, "", walkFn) 176 } 177 178 func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) error { 179 for _, entry := range &trie.entries { 180 if entry == nil { 181 continue 182 } 183 entry.Path = prefix + entry.Path 184 err := walkFn(&entry.ManifestEntry) 185 if err != nil { 186 if entry.ContentType == ManifestType && err == ErrSkipManifest { 187 continue 188 } 189 return err 190 } 191 if entry.ContentType != ManifestType { 192 continue 193 } 194 if err := trie.loadSubTrie(entry, nil); err != nil { 195 return err 196 } 197 if err := m.walk(entry.subtrie, entry.Path, walkFn); err != nil { 198 return err 199 } 200 } 201 return nil 202 } 203 204 type manifestTrie struct { 205 fileStore *storage.FileStore 206 entries [257]*manifestTrieEntry //按basepath的第一个字符索引,条目[256]是空的basepath条目。 207 ref storage.Address //如果裁判!=nil,存储 208 encrypted bool 209 decrypt DecryptFunc 210 } 211 212 func newManifestTrieEntry(entry *ManifestEntry, subtrie *manifestTrie) *manifestTrieEntry { 213 return &manifestTrieEntry{ 214 ManifestEntry: *entry, 215 subtrie: subtrie, 216 } 217 } 218 219 type manifestTrieEntry struct { 220 ManifestEntry 221 222 subtrie *manifestTrie 223 } 224 225 func loadManifest(ctx context.Context, fileStore *storage.FileStore, addr storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //非递归子树按需下载 226 log.Trace("manifest lookup", "addr", addr) 227 //通过文件存储检索清单 228 manifestReader, isEncrypted := fileStore.Retrieve(ctx, addr) 229 log.Trace("reader retrieved", "addr", addr) 230 return readManifest(manifestReader, addr, fileStore, isEncrypted, quitC, decrypt) 231 } 232 233 func readManifest(mr storage.LazySectionReader, addr storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //非递归子树按需下载 234 235 //TODO检查超大清单的大小 236 size, err := mr.Size(mr.Context(), quitC) 237 if err != nil { //大小=0 238 //无法确定大小意味着没有根块 239 log.Trace("manifest not found", "addr", addr) 240 err = fmt.Errorf("Manifest not Found") 241 return 242 } 243 if size > manifestSizeLimit { 244 log.Warn("manifest exceeds size limit", "addr", addr, "size", size, "limit", manifestSizeLimit) 245 err = fmt.Errorf("Manifest size of %v bytes exceeds the %v byte limit", size, manifestSizeLimit) 246 return 247 } 248 manifestData := make([]byte, size) 249 read, err := mr.Read(manifestData) 250 if int64(read) < size { 251 log.Trace("manifest not found", "addr", addr) 252 if err == nil { 253 err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size) 254 } 255 return 256 } 257 258 log.Debug("manifest retrieved", "addr", addr) 259 var man struct { 260 Entries []*manifestTrieEntry `json:"entries"` 261 } 262 err = json.Unmarshal(manifestData, &man) 263 if err != nil { 264 err = fmt.Errorf("Manifest %v is malformed: %v", addr.Log(), err) 265 log.Trace("malformed manifest", "addr", addr) 266 return 267 } 268 269 log.Trace("manifest entries", "addr", addr, "len", len(man.Entries)) 270 271 trie = &manifestTrie{ 272 fileStore: fileStore, 273 encrypted: isEncrypted, 274 decrypt: decrypt, 275 } 276 for _, entry := range man.Entries { 277 err = trie.addEntry(entry, quitC) 278 if err != nil { 279 return 280 } 281 } 282 return 283 } 284 285 func (mt *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) error { 286 mt.ref = nil //trie已修改,需要根据需要重新计算哈希 287 288 if entry.ManifestEntry.Access != nil { 289 if mt.decrypt == nil { 290 return errors.New("dont have decryptor") 291 } 292 293 err := mt.decrypt(&entry.ManifestEntry) 294 if err != nil { 295 return err 296 } 297 } 298 299 if len(entry.Path) == 0 { 300 mt.entries[256] = entry 301 return nil 302 } 303 304 b := entry.Path[0] 305 oldentry := mt.entries[b] 306 if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) { 307 mt.entries[b] = entry 308 return nil 309 } 310 311 cpl := 0 312 for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) { 313 cpl++ 314 } 315 316 if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) { 317 if mt.loadSubTrie(oldentry, quitC) != nil { 318 return nil 319 } 320 entry.Path = entry.Path[cpl:] 321 oldentry.subtrie.addEntry(entry, quitC) 322 oldentry.Hash = "" 323 return nil 324 } 325 326 commonPrefix := entry.Path[:cpl] 327 328 subtrie := &manifestTrie{ 329 fileStore: mt.fileStore, 330 encrypted: mt.encrypted, 331 } 332 entry.Path = entry.Path[cpl:] 333 oldentry.Path = oldentry.Path[cpl:] 334 subtrie.addEntry(entry, quitC) 335 subtrie.addEntry(oldentry, quitC) 336 337 mt.entries[b] = newManifestTrieEntry(&ManifestEntry{ 338 Path: commonPrefix, 339 ContentType: ManifestType, 340 }, subtrie) 341 return nil 342 } 343 344 func (mt *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { 345 for _, e := range &mt.entries { 346 if e != nil { 347 cnt++ 348 entry = e 349 } 350 } 351 return 352 } 353 354 func (mt *manifestTrie) deleteEntry(path string, quitC chan bool) { 355 mt.ref = nil //trie已修改,需要根据需要重新计算哈希 356 357 if len(path) == 0 { 358 mt.entries[256] = nil 359 return 360 } 361 362 b := path[0] 363 entry := mt.entries[b] 364 if entry == nil { 365 return 366 } 367 if entry.Path == path { 368 mt.entries[b] = nil 369 return 370 } 371 372 epl := len(entry.Path) 373 if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { 374 if mt.loadSubTrie(entry, quitC) != nil { 375 return 376 } 377 entry.subtrie.deleteEntry(path[epl:], quitC) 378 entry.Hash = "" 379 //如果子树少于2个元素,则删除它 380 cnt, lastentry := entry.subtrie.getCountLast() 381 if cnt < 2 { 382 if lastentry != nil { 383 lastentry.Path = entry.Path + lastentry.Path 384 } 385 mt.entries[b] = lastentry 386 } 387 } 388 } 389 390 func (mt *manifestTrie) recalcAndStore() error { 391 if mt.ref != nil { 392 return nil 393 } 394 395 var buffer bytes.Buffer 396 buffer.WriteString(`{"entries":[`) 397 398 list := &Manifest{} 399 for _, entry := range &mt.entries { 400 if entry != nil { 401 if entry.Hash == "" { //托多:平行化 402 err := entry.subtrie.recalcAndStore() 403 if err != nil { 404 return err 405 } 406 entry.Hash = entry.subtrie.ref.Hex() 407 } 408 list.Entries = append(list.Entries, entry.ManifestEntry) 409 } 410 411 } 412 413 manifest, err := json.Marshal(list) 414 if err != nil { 415 return err 416 } 417 418 sr := bytes.NewReader(manifest) 419 ctx := context.TODO() 420 addr, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted) 421 if err2 != nil { 422 return err2 423 } 424 err2 = wait(ctx) 425 mt.ref = addr 426 return err2 427 } 428 429 func (mt *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) { 430 if entry.ManifestEntry.Access != nil { 431 if mt.decrypt == nil { 432 return errors.New("dont have decryptor") 433 } 434 435 err := mt.decrypt(&entry.ManifestEntry) 436 if err != nil { 437 return err 438 } 439 } 440 441 if entry.subtrie == nil { 442 hash := common.Hex2Bytes(entry.Hash) 443 entry.subtrie, err = loadManifest(context.TODO(), mt.fileStore, hash, quitC, mt.decrypt) 444 entry.Hash = "" //可能不匹配,应重新计算 445 } 446 return 447 } 448 449 func (mt *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error { 450 plen := len(prefix) 451 var start, stop int 452 if plen == 0 { 453 start = 0 454 stop = 256 455 } else { 456 start = int(prefix[0]) 457 stop = start 458 } 459 460 for i := start; i <= stop; i++ { 461 select { 462 case <-quitC: 463 return fmt.Errorf("aborted") 464 default: 465 } 466 entry := mt.entries[i] 467 if entry != nil { 468 epl := len(entry.Path) 469 if entry.ContentType == ManifestType { 470 l := plen 471 if epl < l { 472 l = epl 473 } 474 if prefix[:l] == entry.Path[:l] { 475 err := mt.loadSubTrie(entry, quitC) 476 if err != nil { 477 return err 478 } 479 err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb) 480 if err != nil { 481 return err 482 } 483 } 484 } else { 485 if (epl >= plen) && (prefix == entry.Path[:plen]) { 486 cb(entry, rp+entry.Path[plen:]) 487 } 488 } 489 } 490 } 491 return nil 492 } 493 494 func (mt *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) { 495 return mt.listWithPrefixInt(prefix, "", quitC, cb) 496 } 497 498 func (mt *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) { 499 log.Trace(fmt.Sprintf("findPrefixOf(%s)", path)) 500 501 if len(path) == 0 { 502 return mt.entries[256], 0 503 } 504 505 //查看第一个字符是否在清单项中 506 b := path[0] 507 entry = mt.entries[b] 508 if entry == nil { 509 return mt.entries[256], 0 510 } 511 512 epl := len(entry.Path) 513 log.Trace(fmt.Sprintf("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)) 514 if len(path) <= epl { 515 if entry.Path[:len(path)] == path { 516 if entry.ContentType == ManifestType { 517 err := mt.loadSubTrie(entry, quitC) 518 if err == nil && entry.subtrie != nil { 519 subentries := entry.subtrie.entries 520 for i := 0; i < len(subentries); i++ { 521 sub := subentries[i] 522 if sub != nil && sub.Path == "" { 523 return sub, len(path) 524 } 525 } 526 } 527 entry.Status = http.StatusMultipleChoices 528 } 529 pos = len(path) 530 return 531 } 532 return nil, 0 533 } 534 if path[:epl] == entry.Path { 535 log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType)) 536 //子条目是清单、加载子条目 537 if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) { 538 err := mt.loadSubTrie(entry, quitC) 539 if err != nil { 540 return nil, 0 541 } 542 sub, pos := entry.subtrie.findPrefixOf(path[epl:], quitC) 543 if sub != nil { 544 entry = sub 545 pos += epl 546 return sub, pos 547 } else if path == entry.Path { 548 entry.Status = http.StatusMultipleChoices 549 } 550 551 } else { 552 //条目不是清单,请将其返回 553 if path != entry.Path { 554 return nil, 0 555 } 556 } 557 } 558 return nil, 0 559 } 560 561 //文件系统清单始终包含规范化路径 562 //没有前导或尾随斜杠,内部只有单个斜杠 563 func RegularSlashes(path string) (res string) { 564 for i := 0; i < len(path); i++ { 565 if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) { 566 res = res + path[i:i+1] 567 } 568 } 569 if (len(res) > 0) && (res[len(res)-1] == '/') { 570 res = res[:len(res)-1] 571 } 572 return 573 } 574 575 func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { 576 path := RegularSlashes(spath) 577 var pos int 578 quitC := make(chan bool) 579 entry, pos = mt.findPrefixOf(path, quitC) 580 return entry, path[:pos] 581 } 582