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