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