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