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