github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/api/api.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2016 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package api 26 27 import ( 28 "archive/tar" 29 "context" 30 "crypto/ecdsa" 31 "encoding/hex" 32 "errors" 33 "fmt" 34 "io" 35 "math/big" 36 "net/http" 37 "path" 38 "strings" 39 40 "bytes" 41 "mime" 42 "path/filepath" 43 "time" 44 45 "github.com/ethereum/go-ethereum/common" 46 "github.com/ethereum/go-ethereum/contracts/ens" 47 "github.com/ethereum/go-ethereum/core/types" 48 "github.com/ethereum/go-ethereum/metrics" 49 "github.com/ethereum/go-ethereum/swarm/log" 50 "github.com/ethereum/go-ethereum/swarm/multihash" 51 "github.com/ethereum/go-ethereum/swarm/spancontext" 52 "github.com/ethereum/go-ethereum/swarm/storage" 53 "github.com/ethereum/go-ethereum/swarm/storage/mru" 54 opentracing "github.com/opentracing/opentracing-go" 55 ) 56 57 var ( 58 ErrNotFound = errors.New("not found") 59 ) 60 61 var ( 62 apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil) 63 apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil) 64 apiPutCount = metrics.NewRegisteredCounter("api.put.count", nil) 65 apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil) 66 apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil) 67 apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil) 68 apiGetHTTP300 = metrics.NewRegisteredCounter("api.get.http.300", nil) 69 apiManifestUpdateCount = metrics.NewRegisteredCounter("api.manifestupdate.count", nil) 70 apiManifestUpdateFail = metrics.NewRegisteredCounter("api.manifestupdate.fail", nil) 71 apiManifestListCount = metrics.NewRegisteredCounter("api.manifestlist.count", nil) 72 apiManifestListFail = metrics.NewRegisteredCounter("api.manifestlist.fail", nil) 73 apiDeleteCount = metrics.NewRegisteredCounter("api.delete.count", nil) 74 apiDeleteFail = metrics.NewRegisteredCounter("api.delete.fail", nil) 75 apiGetTarCount = metrics.NewRegisteredCounter("api.gettar.count", nil) 76 apiGetTarFail = metrics.NewRegisteredCounter("api.gettar.fail", nil) 77 apiUploadTarCount = metrics.NewRegisteredCounter("api.uploadtar.count", nil) 78 apiUploadTarFail = metrics.NewRegisteredCounter("api.uploadtar.fail", nil) 79 apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil) 80 apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil) 81 apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil) 82 apiAddFileFail = metrics.NewRegisteredCounter("api.addfile.fail", nil) 83 apiRmFileCount = metrics.NewRegisteredCounter("api.removefile.count", nil) 84 apiRmFileFail = metrics.NewRegisteredCounter("api.removefile.fail", nil) 85 apiAppendFileCount = metrics.NewRegisteredCounter("api.appendfile.count", nil) 86 apiAppendFileFail = metrics.NewRegisteredCounter("api.appendfile.fail", nil) 87 apiGetInvalid = metrics.NewRegisteredCounter("api.get.invalid", nil) 88 ) 89 90 //解析程序接口使用ens将域名解析为哈希 91 type Resolver interface { 92 Resolve(string) (common.Hash, error) 93 } 94 95 //ResolveValidator用于验证包含的冲突解决程序 96 type ResolveValidator interface { 97 Resolver 98 Owner(node [32]byte) (common.Address, error) 99 HeaderByNumber(context.Context, *big.Int) (*types.Header, error) 100 } 101 102 //多解析程序返回noresolvererrror。如果没有解析程序,则解析 103 //可以找到地址。 104 type NoResolverError struct { 105 TLD string 106 } 107 108 //NewNoresolveError为给定的顶级域创建NoresolveError 109 func NewNoResolverError(tld string) *NoResolverError { 110 return &NoResolverError{TLD: tld} 111 } 112 113 //错误NoresolveError实现错误 114 func (e *NoResolverError) Error() string { 115 if e.TLD == "" { 116 return "no ENS resolver" 117 } 118 return fmt.Sprintf("no ENS endpoint configured to resolve .%s TLD names", e.TLD) 119 } 120 121 //多解析器用于基于TLD解析URL地址。 122 //每个TLD可以有多个解析器,并且 123 //将返回序列中的第一个。 124 type MultiResolver struct { 125 resolvers map[string][]ResolveValidator 126 nameHash func(string) common.Hash 127 } 128 129 //multisolver选项为multisolver设置选项,并用作 130 //其构造函数的参数。 131 type MultiResolverOption func(*MultiResolver) 132 133 //带冲突解决程序的多冲突解决程序选项将冲突解决程序添加到冲突解决程序列表中 134 //对于特定的TLD。如果tld是空字符串,将添加冲突解决程序 135 //到默认冲突解决程序列表中,将用于解决问题的冲突解决程序 136 //没有指定TLD解析程序的地址。 137 func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolverOption { 138 return func(m *MultiResolver) { 139 m.resolvers[tld] = append(m.resolvers[tld], r) 140 } 141 } 142 143 //写入时未使用MultiResolverOptionWithNameHash 144 func MultiResolverOptionWithNameHash(nameHash func(string) common.Hash) MultiResolverOption { 145 return func(m *MultiResolver) { 146 m.nameHash = nameHash 147 } 148 } 149 150 //newmultisolver创建multisolver的新实例。 151 func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { 152 m = &MultiResolver{ 153 resolvers: make(map[string][]ResolveValidator), 154 nameHash: ens.EnsNode, 155 } 156 for _, o := range opts { 157 o(m) 158 } 159 return m 160 } 161 162 //解析通过TLD选择一个解析程序来解析地址。 163 //如果有更多的默认解析器,或者特定的TLD, 164 //第一个不返回错误的哈希 165 //将被退回。 166 func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) { 167 rs, err := m.getResolveValidator(addr) 168 if err != nil { 169 return h, err 170 } 171 for _, r := range rs { 172 h, err = r.Resolve(addr) 173 if err == nil { 174 return 175 } 176 } 177 return 178 } 179 180 //validateOwner检查ENS以验证给定域的所有者是否为给定的ETH地址。 181 func (m *MultiResolver) ValidateOwner(name string, address common.Address) (bool, error) { 182 rs, err := m.getResolveValidator(name) 183 if err != nil { 184 return false, err 185 } 186 var addr common.Address 187 for _, r := range rs { 188 addr, err = r.Owner(m.nameHash(name)) 189 //如果不是我们检查的最后一个解析器,我们会隐藏错误。 190 if err == nil { 191 return addr == address, nil 192 } 193 } 194 return false, err 195 } 196 197 //HeaderByNumber使用给定域名的验证程序并检索给定块号的头 198 func (m *MultiResolver) HeaderByNumber(ctx context.Context, name string, blockNr *big.Int) (*types.Header, error) { 199 rs, err := m.getResolveValidator(name) 200 if err != nil { 201 return nil, err 202 } 203 for _, r := range rs { 204 var header *types.Header 205 header, err = r.HeaderByNumber(ctx, blockNr) 206 //如果不是我们检查的最后一个解析器,我们会隐藏错误。 207 if err == nil { 208 return header, nil 209 } 210 } 211 return nil, err 212 } 213 214 //GetResolveValidator使用主机名检索与顶级域关联的冲突解决程序 215 func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) { 216 rs := m.resolvers[""] 217 tld := path.Ext(name) 218 if tld != "" { 219 tld = tld[1:] 220 rstld, ok := m.resolvers[tld] 221 if ok { 222 return rstld, nil 223 } 224 } 225 if len(rs) == 0 { 226 return rs, NewNoResolverError(tld) 227 } 228 return rs, nil 229 } 230 231 //setnamehash设置将域散列为ENS使用的名称散列的散列函数 232 func (m *MultiResolver) SetNameHash(nameHash func(string) common.Hash) { 233 m.nameHash = nameHash 234 } 235 236 /* 237 API实现了与Web服务器/文件系统相关的内容存储和检索 238 在文件存储上 239 它是包含在以太坊堆栈中的文件存储的公共接口。 240 **/ 241 242 type API struct { 243 resource *mru.Handler 244 fileStore *storage.FileStore 245 dns Resolver 246 Decryptor func(context.Context, string) DecryptFunc 247 } 248 249 //new api API构造函数初始化新的API实例。 250 func NewAPI(fileStore *storage.FileStore, dns Resolver, resourceHandler *mru.Handler, pk *ecdsa.PrivateKey) (self *API) { 251 self = &API{ 252 fileStore: fileStore, 253 dns: dns, 254 resource: resourceHandler, 255 Decryptor: func(ctx context.Context, credentials string) DecryptFunc { 256 return self.doDecrypt(ctx, credentials, pk) 257 }, 258 } 259 return 260 } 261 262 //上传仅用于测试 263 func (a *API) Upload(ctx context.Context, uploadDir, index string, toEncrypt bool) (hash string, err error) { 264 fs := NewFileSystem(a) 265 hash, err = fs.Upload(uploadDir, index, toEncrypt) 266 return hash, err 267 } 268 269 //检索文件存储读取器API 270 func (a *API) Retrieve(ctx context.Context, addr storage.Address) (reader storage.LazySectionReader, isEncrypted bool) { 271 return a.fileStore.Retrieve(ctx, addr) 272 } 273 274 //store包装嵌入式文件存储的store api调用 275 func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(ctx context.Context) error, err error) { 276 log.Debug("api.store", "size", size) 277 return a.fileStore.Store(ctx, data, size, toEncrypt) 278 } 279 280 //当无法从ens解析uri时,返回erresolve。 281 type ErrResolve error 282 283 //将名称解析为内容寻址哈希 284 //其中地址可以是ENS名称,也可以是内容寻址哈希 285 func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) { 286 //如果未配置DNS,则返回错误 287 if a.dns == nil { 288 if hashMatcher.MatchString(address) { 289 return common.Hex2Bytes(address), nil 290 } 291 apiResolveFail.Inc(1) 292 return nil, fmt.Errorf("no DNS to resolve name: %q", address) 293 } 294 //尝试解析地址 295 resolved, err := a.dns.Resolve(address) 296 if err != nil { 297 if hashMatcher.MatchString(address) { 298 return common.Hex2Bytes(address), nil 299 } 300 return nil, err 301 } 302 return resolved[:], nil 303 } 304 305 //解析使用多解析程序将URI解析为地址。 306 func (a *API) ResolveURI(ctx context.Context, uri *URI, credentials string) (storage.Address, error) { 307 apiResolveCount.Inc(1) 308 log.Trace("resolving", "uri", uri.Addr) 309 310 var sp opentracing.Span 311 ctx, sp = spancontext.StartSpan( 312 ctx, 313 "api.resolve") 314 defer sp.Finish() 315 316 //如果URI不可变,请检查地址是否像哈希 317 if uri.Immutable() { 318 key := uri.Address() 319 if key == nil { 320 return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr) 321 } 322 return key, nil 323 } 324 325 addr, err := a.Resolve(ctx, uri.Addr) 326 if err != nil { 327 return nil, err 328 } 329 330 if uri.Path == "" { 331 return addr, nil 332 } 333 walker, err := a.NewManifestWalker(ctx, addr, a.Decryptor(ctx, credentials), nil) 334 if err != nil { 335 return nil, err 336 } 337 var entry *ManifestEntry 338 walker.Walk(func(e *ManifestEntry) error { 339 //如果条目与路径匹配,则设置条目并停止 340 //步行 341 if e.Path == uri.Path { 342 entry = e 343 //返回错误以取消漫游 344 return errors.New("found") 345 } 346 //忽略非清单文件 347 if e.ContentType != ManifestType { 348 return nil 349 } 350 //如果清单的路径是 351 //请求的路径,通过返回 352 //零,继续走 353 if strings.HasPrefix(uri.Path, e.Path) { 354 return nil 355 } 356 return ErrSkipManifest 357 }) 358 if entry == nil { 359 return nil, errors.New("not found") 360 } 361 addr = storage.Address(common.Hex2Bytes(entry.Hash)) 362 return addr, nil 363 } 364 365 //Put在文件存储区顶部提供单实例清单创建 366 func (a *API) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) { 367 apiPutCount.Inc(1) 368 r := strings.NewReader(content) 369 key, waitContent, err := a.fileStore.Store(ctx, r, int64(len(content)), toEncrypt) 370 if err != nil { 371 apiPutFail.Inc(1) 372 return nil, nil, err 373 } 374 manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType) 375 r = strings.NewReader(manifest) 376 key, waitManifest, err := a.fileStore.Store(ctx, r, int64(len(manifest)), toEncrypt) 377 if err != nil { 378 apiPutFail.Inc(1) 379 return nil, nil, err 380 } 381 return key, func(ctx context.Context) error { 382 err := waitContent(ctx) 383 if err != nil { 384 return err 385 } 386 return waitManifest(ctx) 387 }, nil 388 } 389 390 //get使用迭代清单检索和前缀匹配 391 //使用文件存储检索解析内容的基路径 392 //它返回一个段落阅读器、mimetype、状态、实际内容的键和一个错误。 393 func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage.Address, path string) (reader storage.LazySectionReader, mimeType string, status int, contentAddr storage.Address, err error) { 394 log.Debug("api.get", "key", manifestAddr, "path", path) 395 apiGetCount.Inc(1) 396 trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt) 397 if err != nil { 398 apiGetNotFound.Inc(1) 399 status = http.StatusNotFound 400 return nil, "", http.StatusNotFound, nil, err 401 } 402 403 log.Debug("trie getting entry", "key", manifestAddr, "path", path) 404 entry, _ := trie.getEntry(path) 405 406 if entry != nil { 407 log.Debug("trie got entry", "key", manifestAddr, "path", path, "entry.Hash", entry.Hash) 408 409 if entry.ContentType == ManifestType { 410 log.Debug("entry is manifest", "key", manifestAddr, "new key", entry.Hash) 411 adr, err := hex.DecodeString(entry.Hash) 412 if err != nil { 413 return nil, "", 0, nil, err 414 } 415 return a.Get(ctx, decrypt, adr, entry.Path) 416 } 417 418 //如果这是可变资源清单,我们需要做一些额外的工作 419 if entry.ContentType == ResourceContentType { 420 421 //获取资源rootaddr 422 log.Trace("resource type", "menifestAddr", manifestAddr, "hash", entry.Hash) 423 ctx, cancel := context.WithCancel(context.Background()) 424 defer cancel() 425 rootAddr := storage.Address(common.FromHex(entry.Hash)) 426 rsrc, err := a.resource.Load(ctx, rootAddr) 427 if err != nil { 428 apiGetNotFound.Inc(1) 429 status = http.StatusNotFound 430 log.Debug(fmt.Sprintf("get resource content error: %v", err)) 431 return reader, mimeType, status, nil, err 432 } 433 434 //使用此密钥检索最新更新 435 params := mru.LookupLatest(rootAddr) 436 rsrc, err = a.resource.Lookup(ctx, params) 437 if err != nil { 438 apiGetNotFound.Inc(1) 439 status = http.StatusNotFound 440 log.Debug(fmt.Sprintf("get resource content error: %v", err)) 441 return reader, mimeType, status, nil, err 442 } 443 444 //如果是多哈希,我们将透明地为这个多哈希指向的内容提供服务 445 //\t要解决这个问题,总的来说代价相当高,请查看是否可以更便宜地实现。 446 if rsrc.Multihash() { 447 448 //获取更新的数据 449 _, rsrcData, err := a.resource.GetContent(rootAddr) 450 if err != nil { 451 apiGetNotFound.Inc(1) 452 status = http.StatusNotFound 453 log.Warn(fmt.Sprintf("get resource content error: %v", err)) 454 return reader, mimeType, status, nil, err 455 } 456 457 //将该数据验证为多哈希 458 decodedMultihash, err := multihash.FromMultihash(rsrcData) 459 if err != nil { 460 apiGetInvalid.Inc(1) 461 status = http.StatusUnprocessableEntity 462 log.Warn("invalid resource multihash", "err", err) 463 return reader, mimeType, status, nil, err 464 } 465 manifestAddr = storage.Address(decodedMultihash) 466 log.Trace("resource is multihash", "key", manifestAddr) 467 468 //获取多哈希摘要指向的清单 469 trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, decrypt) 470 if err != nil { 471 apiGetNotFound.Inc(1) 472 status = http.StatusNotFound 473 log.Warn(fmt.Sprintf("loadManifestTrie (resource multihash) error: %v", err)) 474 return reader, mimeType, status, nil, err 475 } 476 477 //最后,获取清单条目 478 //它始终是路径“”上的条目 479 entry, _ = trie.getEntry(path) 480 if entry == nil { 481 status = http.StatusNotFound 482 apiGetNotFound.Inc(1) 483 err = fmt.Errorf("manifest (resource multihash) entry for '%s' not found", path) 484 log.Trace("manifest (resource multihash) entry not found", "key", manifestAddr, "path", path) 485 return reader, mimeType, status, nil, err 486 } 487 488 } else { 489 //数据是逐字返回的,因为它不是多哈希 490 return rsrc, "application/octet-stream", http.StatusOK, nil, nil 491 } 492 } 493 494 //无论是资源更新清单还是普通清单,我们都将在此收敛 495 //获取清单入口点的关键点,如果不含糊,则提供服务 496 contentAddr = common.Hex2Bytes(entry.Hash) 497 status = entry.Status 498 if status == http.StatusMultipleChoices { 499 apiGetHTTP300.Inc(1) 500 return nil, entry.ContentType, status, contentAddr, err 501 } 502 mimeType = entry.ContentType 503 log.Debug("content lookup key", "key", contentAddr, "mimetype", mimeType) 504 reader, _ = a.fileStore.Retrieve(ctx, contentAddr) 505 } else { 506 //未找到条目 507 status = http.StatusNotFound 508 apiGetNotFound.Inc(1) 509 err = fmt.Errorf("manifest entry for '%s' not found", path) 510 log.Trace("manifest entry not found", "key", contentAddr, "path", path) 511 } 512 return 513 } 514 515 func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Address, error) { 516 apiDeleteCount.Inc(1) 517 uri, err := Parse("bzz:/" + addr) 518 if err != nil { 519 apiDeleteFail.Inc(1) 520 return nil, err 521 } 522 key, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) 523 524 if err != nil { 525 return nil, err 526 } 527 newKey, err := a.UpdateManifest(ctx, key, func(mw *ManifestWriter) error { 528 log.Debug(fmt.Sprintf("removing %s from manifest %s", path, key.Log())) 529 return mw.RemoveEntry(path) 530 }) 531 if err != nil { 532 apiDeleteFail.Inc(1) 533 return nil, err 534 } 535 536 return newKey, nil 537 } 538 539 //GetDirectorytar以tarstream形式获取请求的目录 540 //它返回一个IO.reader和一个错误。不要忘记关闭()返回的readcloser 541 func (a *API) GetDirectoryTar(ctx context.Context, decrypt DecryptFunc, uri *URI) (io.ReadCloser, error) { 542 apiGetTarCount.Inc(1) 543 addr, err := a.Resolve(ctx, uri.Addr) 544 if err != nil { 545 return nil, err 546 } 547 walker, err := a.NewManifestWalker(ctx, addr, decrypt, nil) 548 if err != nil { 549 apiGetTarFail.Inc(1) 550 return nil, err 551 } 552 553 piper, pipew := io.Pipe() 554 555 tw := tar.NewWriter(pipew) 556 557 go func() { 558 err := walker.Walk(func(entry *ManifestEntry) error { 559 //忽略清单(walk将重复出现在清单中) 560 if entry.ContentType == ManifestType { 561 return nil 562 } 563 564 //检索条目的密钥和大小 565 reader, _ := a.Retrieve(ctx, storage.Address(common.Hex2Bytes(entry.Hash))) 566 size, err := reader.Size(ctx, nil) 567 if err != nil { 568 return err 569 } 570 571 //为条目编写tar头 572 hdr := &tar.Header{ 573 Name: entry.Path, 574 Mode: entry.Mode, 575 Size: size, 576 ModTime: entry.ModTime, 577 Xattrs: map[string]string{ 578 "user.swarm.content-type": entry.ContentType, 579 }, 580 } 581 582 if err := tw.WriteHeader(hdr); err != nil { 583 return err 584 } 585 586 //将文件复制到tar流中 587 n, err := io.Copy(tw, io.LimitReader(reader, hdr.Size)) 588 if err != nil { 589 return err 590 } else if n != size { 591 return fmt.Errorf("error writing %s: expected %d bytes but sent %d", entry.Path, size, n) 592 } 593 594 return nil 595 }) 596 //关闭tar writer,然后关闭pipew 597 //将剩余数据刷新到pipew 598 //不考虑误差值 599 tw.Close() 600 if err != nil { 601 apiGetTarFail.Inc(1) 602 pipew.CloseWithError(err) 603 } else { 604 pipew.Close() 605 } 606 }() 607 608 return piper, nil 609 } 610 611 //GetManifestList列出指定地址和前缀的清单项 612 //并将其作为清单返回 613 func (a *API) GetManifestList(ctx context.Context, decryptor DecryptFunc, addr storage.Address, prefix string) (list ManifestList, err error) { 614 apiManifestListCount.Inc(1) 615 walker, err := a.NewManifestWalker(ctx, addr, decryptor, nil) 616 if err != nil { 617 apiManifestListFail.Inc(1) 618 return ManifestList{}, err 619 } 620 621 err = walker.Walk(func(entry *ManifestEntry) error { 622 //处理非清单文件 623 if entry.ContentType != ManifestType { 624 //如果文件没有指定的前缀,则忽略该文件 625 if !strings.HasPrefix(entry.Path, prefix) { 626 return nil 627 } 628 629 //如果前缀后面的路径包含斜杠,请添加 630 //列表的公共前缀,否则添加条目 631 suffix := strings.TrimPrefix(entry.Path, prefix) 632 if index := strings.Index(suffix, "/"); index > -1 { 633 list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) 634 return nil 635 } 636 if entry.Path == "" { 637 entry.Path = "/" 638 } 639 list.Entries = append(list.Entries, entry) 640 return nil 641 } 642 643 //如果清单的路径是指定前缀的前缀 644 //然后通过返回nil和 645 //继续散步 646 if strings.HasPrefix(prefix, entry.Path) { 647 return nil 648 } 649 650 //如果清单的路径具有指定的前缀,则如果 651 //前缀后面的路径包含斜杠,请添加一个公共前缀 652 //到列表并跳过清单,否则递归到 653 //通过返回零并继续行走来显示 654 if strings.HasPrefix(entry.Path, prefix) { 655 suffix := strings.TrimPrefix(entry.Path, prefix) 656 if index := strings.Index(suffix, "/"); index > -1 { 657 list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1]) 658 return ErrSkipManifest 659 } 660 return nil 661 } 662 663 //清单既没有前缀,也不需要递归到 664 //所以跳过它 665 return ErrSkipManifest 666 }) 667 668 if err != nil { 669 apiManifestListFail.Inc(1) 670 return ManifestList{}, err 671 } 672 673 return list, nil 674 } 675 676 func (a *API) UpdateManifest(ctx context.Context, addr storage.Address, update func(mw *ManifestWriter) error) (storage.Address, error) { 677 apiManifestUpdateCount.Inc(1) 678 mw, err := a.NewManifestWriter(ctx, addr, nil) 679 if err != nil { 680 apiManifestUpdateFail.Inc(1) 681 return nil, err 682 } 683 684 if err := update(mw); err != nil { 685 apiManifestUpdateFail.Inc(1) 686 return nil, err 687 } 688 689 addr, err = mw.Store() 690 if err != nil { 691 apiManifestUpdateFail.Inc(1) 692 return nil, err 693 } 694 log.Debug(fmt.Sprintf("generated manifest %s", addr)) 695 return addr, nil 696 } 697 698 //修改加载清单并在重新计算和存储清单之前检查内容哈希。 699 func (a *API) Modify(ctx context.Context, addr storage.Address, path, contentHash, contentType string) (storage.Address, error) { 700 apiModifyCount.Inc(1) 701 quitC := make(chan bool) 702 trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) 703 if err != nil { 704 apiModifyFail.Inc(1) 705 return nil, err 706 } 707 if contentHash != "" { 708 entry := newManifestTrieEntry(&ManifestEntry{ 709 Path: path, 710 ContentType: contentType, 711 }, nil) 712 entry.Hash = contentHash 713 trie.addEntry(entry, quitC) 714 } else { 715 trie.deleteEntry(path, quitC) 716 } 717 718 if err := trie.recalcAndStore(); err != nil { 719 apiModifyFail.Inc(1) 720 return nil, err 721 } 722 return trie.ref, nil 723 } 724 725 //addfile创建一个新的清单条目,将其添加到swarm,然后将文件添加到swarm。 726 func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []byte, nameresolver bool) (storage.Address, string, error) { 727 apiAddFileCount.Inc(1) 728 729 uri, err := Parse("bzz:/" + mhash) 730 if err != nil { 731 apiAddFileFail.Inc(1) 732 return nil, "", err 733 } 734 mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) 735 if err != nil { 736 apiAddFileFail.Inc(1) 737 return nil, "", err 738 } 739 740 //修剪我们添加的根目录 741 if path[:1] == "/" { 742 path = path[1:] 743 } 744 745 entry := &ManifestEntry{ 746 Path: filepath.Join(path, fname), 747 ContentType: mime.TypeByExtension(filepath.Ext(fname)), 748 Mode: 0700, 749 Size: int64(len(content)), 750 ModTime: time.Now(), 751 } 752 753 mw, err := a.NewManifestWriter(ctx, mkey, nil) 754 if err != nil { 755 apiAddFileFail.Inc(1) 756 return nil, "", err 757 } 758 759 fkey, err := mw.AddEntry(ctx, bytes.NewReader(content), entry) 760 if err != nil { 761 apiAddFileFail.Inc(1) 762 return nil, "", err 763 } 764 765 newMkey, err := mw.Store() 766 if err != nil { 767 apiAddFileFail.Inc(1) 768 return nil, "", err 769 770 } 771 772 return fkey, newMkey.String(), nil 773 } 774 775 func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) { 776 apiUploadTarCount.Inc(1) 777 var contentKey storage.Address 778 tr := tar.NewReader(bodyReader) 779 defer bodyReader.Close() 780 var defaultPathFound bool 781 for { 782 hdr, err := tr.Next() 783 if err == io.EOF { 784 break 785 } else if err != nil { 786 apiUploadTarFail.Inc(1) 787 return nil, fmt.Errorf("error reading tar stream: %s", err) 788 } 789 790 //仅存储常规文件 791 if !hdr.FileInfo().Mode().IsRegular() { 792 continue 793 } 794 795 //在请求的路径下添加条目 796 manifestPath := path.Join(manifestPath, hdr.Name) 797 entry := &ManifestEntry{ 798 Path: manifestPath, 799 ContentType: hdr.Xattrs["user.swarm.content-type"], 800 Mode: hdr.Mode, 801 Size: hdr.Size, 802 ModTime: hdr.ModTime, 803 } 804 contentKey, err = mw.AddEntry(ctx, tr, entry) 805 if err != nil { 806 apiUploadTarFail.Inc(1) 807 return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err) 808 } 809 if hdr.Name == defaultPath { 810 entry := &ManifestEntry{ 811 Hash: contentKey.Hex(), 812 Path: "", //缺省条目 813 ContentType: hdr.Xattrs["user.swarm.content-type"], 814 Mode: hdr.Mode, 815 Size: hdr.Size, 816 ModTime: hdr.ModTime, 817 } 818 contentKey, err = mw.AddEntry(ctx, nil, entry) 819 if err != nil { 820 apiUploadTarFail.Inc(1) 821 return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err) 822 } 823 defaultPathFound = true 824 } 825 } 826 if defaultPath != "" && !defaultPathFound { 827 return contentKey, fmt.Errorf("default path %q not found", defaultPath) 828 } 829 return contentKey, nil 830 } 831 832 //removefile删除清单中的文件条目。 833 func (a *API) RemoveFile(ctx context.Context, mhash string, path string, fname string, nameresolver bool) (string, error) { 834 apiRmFileCount.Inc(1) 835 836 uri, err := Parse("bzz:/" + mhash) 837 if err != nil { 838 apiRmFileFail.Inc(1) 839 return "", err 840 } 841 mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) 842 if err != nil { 843 apiRmFileFail.Inc(1) 844 return "", err 845 } 846 847 //修剪我们添加的根目录 848 if path[:1] == "/" { 849 path = path[1:] 850 } 851 852 mw, err := a.NewManifestWriter(ctx, mkey, nil) 853 if err != nil { 854 apiRmFileFail.Inc(1) 855 return "", err 856 } 857 858 err = mw.RemoveEntry(filepath.Join(path, fname)) 859 if err != nil { 860 apiRmFileFail.Inc(1) 861 return "", err 862 } 863 864 newMkey, err := mw.Store() 865 if err != nil { 866 apiRmFileFail.Inc(1) 867 return "", err 868 869 } 870 871 return newMkey.String(), nil 872 } 873 874 //AppendFile删除旧清单,将文件条目附加到新清单,并将其添加到Swarm。 875 func (a *API) AppendFile(ctx context.Context, mhash, path, fname string, existingSize int64, content []byte, oldAddr storage.Address, offset int64, addSize int64, nameresolver bool) (storage.Address, string, error) { 876 apiAppendFileCount.Inc(1) 877 878 buffSize := offset + addSize 879 if buffSize < existingSize { 880 buffSize = existingSize 881 } 882 883 buf := make([]byte, buffSize) 884 885 oldReader, _ := a.Retrieve(ctx, oldAddr) 886 io.ReadAtLeast(oldReader, buf, int(offset)) 887 888 newReader := bytes.NewReader(content) 889 io.ReadAtLeast(newReader, buf[offset:], int(addSize)) 890 891 if buffSize < existingSize { 892 io.ReadAtLeast(oldReader, buf[addSize:], int(buffSize)) 893 } 894 895 combinedReader := bytes.NewReader(buf) 896 totalSize := int64(len(buf)) 897 898 //todo(jmozah):准备好后使用金字塔chunker附加 899 //oldreader:=a.retrieve(oldkey) 900 //newreader:=字节。newreader(内容) 901 //组合读卡器:=IO.MultiReader(OldReader、NewReader) 902 903 uri, err := Parse("bzz:/" + mhash) 904 if err != nil { 905 apiAppendFileFail.Inc(1) 906 return nil, "", err 907 } 908 mkey, err := a.ResolveURI(ctx, uri, EMPTY_CREDENTIALS) 909 if err != nil { 910 apiAppendFileFail.Inc(1) 911 return nil, "", err 912 } 913 914 //修剪我们添加的根目录 915 if path[:1] == "/" { 916 path = path[1:] 917 } 918 919 mw, err := a.NewManifestWriter(ctx, mkey, nil) 920 if err != nil { 921 apiAppendFileFail.Inc(1) 922 return nil, "", err 923 } 924 925 err = mw.RemoveEntry(filepath.Join(path, fname)) 926 if err != nil { 927 apiAppendFileFail.Inc(1) 928 return nil, "", err 929 } 930 931 entry := &ManifestEntry{ 932 Path: filepath.Join(path, fname), 933 ContentType: mime.TypeByExtension(filepath.Ext(fname)), 934 Mode: 0700, 935 Size: totalSize, 936 ModTime: time.Now(), 937 } 938 939 fkey, err := mw.AddEntry(ctx, io.Reader(combinedReader), entry) 940 if err != nil { 941 apiAppendFileFail.Inc(1) 942 return nil, "", err 943 } 944 945 newMkey, err := mw.Store() 946 if err != nil { 947 apiAppendFileFail.Inc(1) 948 return nil, "", err 949 950 } 951 952 return fkey, newMkey.String(), nil 953 } 954 955 //swarmfs_Unix使用的buildDirectoryTree 956 func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver bool) (addr storage.Address, manifestEntryMap map[string]*manifestTrieEntry, err error) { 957 958 uri, err := Parse("bzz:/" + mhash) 959 if err != nil { 960 return nil, nil, err 961 } 962 addr, err = a.Resolve(ctx, uri.Addr) 963 if err != nil { 964 return nil, nil, err 965 } 966 967 quitC := make(chan bool) 968 rootTrie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt) 969 if err != nil { 970 return nil, nil, fmt.Errorf("can't load manifest %v: %v", addr.String(), err) 971 } 972 973 manifestEntryMap = map[string]*manifestTrieEntry{} 974 err = rootTrie.listWithPrefix(uri.Path, quitC, func(entry *manifestTrieEntry, suffix string) { 975 manifestEntryMap[suffix] = entry 976 }) 977 978 if err != nil { 979 return nil, nil, fmt.Errorf("list with prefix failed %v: %v", addr.String(), err) 980 } 981 return addr, manifestEntryMap, nil 982 } 983 984 //ResourceLookup在特定期间和版本中查找可变资源更新 985 func (a *API) ResourceLookup(ctx context.Context, params *mru.LookupParams) (string, []byte, error) { 986 var err error 987 rsrc, err := a.resource.Load(ctx, params.RootAddr()) 988 if err != nil { 989 return "", nil, err 990 } 991 _, err = a.resource.Lookup(ctx, params) 992 if err != nil { 993 return "", nil, err 994 } 995 var data []byte 996 _, data, err = a.resource.GetContent(params.RootAddr()) 997 if err != nil { 998 return "", nil, err 999 } 1000 return rsrc.Name(), data, nil 1001 } 1002 1003 //创建可变资源 1004 func (a *API) ResourceCreate(ctx context.Context, request *mru.Request) error { 1005 return a.resource.New(ctx, request) 1006 } 1007 1008 //ResourceNewRequest创建一个请求对象以更新特定的可变资源 1009 func (a *API) ResourceNewRequest(ctx context.Context, rootAddr storage.Address) (*mru.Request, error) { 1010 return a.resource.NewUpdateRequest(ctx, rootAddr) 1011 } 1012 1013 //resourceupdate使用任意数据更新可变资源。 1014 //检索后,将按字节逐字检索更新。 1015 func (a *API) ResourceUpdate(ctx context.Context, request *mru.SignedResourceUpdate) (storage.Address, error) { 1016 return a.resource.Update(ctx, request) 1017 } 1018 1019 //ResourceHashSize返回可变资源哈希函数生成的摘要的大小 1020 func (a *API) ResourceHashSize() int { 1021 return a.resource.HashSize 1022 } 1023 1024 //resolvesourcemanifest检索给定地址的可变资源清单,并返回元数据块的地址。 1025 func (a *API) ResolveResourceManifest(ctx context.Context, addr storage.Address) (storage.Address, error) { 1026 trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt) 1027 if err != nil { 1028 return nil, fmt.Errorf("cannot load resource manifest: %v", err) 1029 } 1030 1031 entry, _ := trie.getEntry("") 1032 if entry.ContentType != ResourceContentType { 1033 return nil, fmt.Errorf("not a resource manifest: %s", addr) 1034 } 1035 1036 return storage.Address(common.FromHex(entry.Hash)), nil 1037 }