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  }