github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/api/manifest.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:43</date>
    10  //</624450112281645056>
    11  
    12  
    13  package api
    14  
    15  import (
    16  	"bytes"
    17  	"context"
    18  	"encoding/json"
    19  	"errors"
    20  	"fmt"
    21  	"io"
    22  	"net/http"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/swarm/storage/feed"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/swarm/log"
    30  	"github.com/ethereum/go-ethereum/swarm/storage"
    31  )
    32  
    33  const (
    34  	ManifestType    = "application/bzz-manifest+json"
    35  	FeedContentType = "application/bzz-feed"
    36  
    37  	manifestSizeLimit = 5 * 1024 * 1024
    38  )
    39  
    40  //清单代表一个群体清单
    41  type Manifest struct {
    42  	Entries []ManifestEntry `json:"entries,omitempty"`
    43  }
    44  
    45  //manifest entry表示群清单中的条目
    46  type ManifestEntry struct {
    47  	Hash        string       `json:"hash,omitempty"`
    48  	Path        string       `json:"path,omitempty"`
    49  	ContentType string       `json:"contentType,omitempty"`
    50  	Mode        int64        `json:"mode,omitempty"`
    51  	Size        int64        `json:"size,omitempty"`
    52  	ModTime     time.Time    `json:"mod_time,omitempty"`
    53  	Status      int          `json:"status,omitempty"`
    54  	Access      *AccessEntry `json:"access,omitempty"`
    55  	Feed        *feed.Feed   `json:"feed,omitempty"`
    56  }
    57  
    58  //manifestList表示清单中列出文件的结果
    59  type ManifestList struct {
    60  	CommonPrefixes []string         `json:"common_prefixes,omitempty"`
    61  	Entries        []*ManifestEntry `json:"entries,omitempty"`
    62  }
    63  
    64  //new manifest创建并存储新的空清单
    65  func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) {
    66  	var manifest Manifest
    67  	data, err := json.Marshal(&manifest)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	err = wait(ctx)
    76  	return addr, err
    77  }
    78  
    79  //支持来自BZZ的群源的清单黑客:方案
    80  //有关更多信息,请参阅swarm/api/api.go:api.get()。
    81  func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) {
    82  	var manifest Manifest
    83  	entry := ManifestEntry{
    84  		Feed:        feed,
    85  		ContentType: FeedContentType,
    86  	}
    87  	manifest.Entries = append(manifest.Entries, entry)
    88  	data, err := json.Marshal(&manifest)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	addr, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	err = wait(ctx)
    97  	return addr, err
    98  }
    99  
   100  //manifestwriter用于添加和删除基础清单中的条目
   101  type ManifestWriter struct {
   102  	api   *API
   103  	trie  *manifestTrie
   104  	quitC chan bool
   105  }
   106  
   107  func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) {
   108  	trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
   109  	if err != nil {
   110  		return nil, fmt.Errorf("error loading manifest %s: %s", addr, err)
   111  	}
   112  	return &ManifestWriter{a, trie, quitC}, nil
   113  }
   114  
   115  //附录存储给定的数据并将结果地址添加到清单中
   116  func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (addr storage.Address, err error) {
   117  	entry := newManifestTrieEntry(e, nil)
   118  	if data != nil {
   119  		var wait func(context.Context) error
   120  		addr, wait, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted)
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  		err = wait(ctx)
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  		entry.Hash = addr.Hex()
   129  	}
   130  	if entry.Hash == "" {
   131  		return addr, errors.New("missing entry hash")
   132  	}
   133  	m.trie.addEntry(entry, m.quitC)
   134  	return addr, nil
   135  }
   136  
   137  //removeentry从清单中删除给定路径
   138  func (m *ManifestWriter) RemoveEntry(path string) error {
   139  	m.trie.deleteEntry(path, m.quitC)
   140  	return nil
   141  }
   142  
   143  //存储存储清单,返回结果存储地址
   144  func (m *ManifestWriter) Store() (storage.Address, error) {
   145  	return m.trie.ref, m.trie.recalcAndStore()
   146  }
   147  
   148  //manifestwalker用于递归地遍历清单中的条目和
   149  //它的所有子流形
   150  type ManifestWalker struct {
   151  	api   *API
   152  	trie  *manifestTrie
   153  	quitC chan bool
   154  }
   155  
   156  func (a *API) NewManifestWalker(ctx context.Context, addr storage.Address, decrypt DecryptFunc, quitC chan bool) (*ManifestWalker, error) {
   157  	trie, err := loadManifest(ctx, a.fileStore, addr, quitC, decrypt)
   158  	if err != nil {
   159  		return nil, fmt.Errorf("error loading manifest %s: %s", addr, err)
   160  	}
   161  	return &ManifestWalker{a, trie, quitC}, nil
   162  }
   163  
   164  //errskipmanifest用作walkfn的返回值,以指示
   165  //应跳过清单
   166  var ErrSkipManifest = errors.New("skip this manifest")
   167  
   168  //walkfn是递归访问的每个条目调用的函数类型
   169  //显性步行
   170  type WalkFn func(entry *ManifestEntry) error
   171  
   172  //以递归方式遍历清单,为中的每个条目调用walkfn
   173  //清单,包括子流形
   174  func (m *ManifestWalker) Walk(walkFn WalkFn) error {
   175  	return m.walk(m.trie, "", walkFn)
   176  }
   177  
   178  func (m *ManifestWalker) walk(trie *manifestTrie, prefix string, walkFn WalkFn) error {
   179  	for _, entry := range &trie.entries {
   180  		if entry == nil {
   181  			continue
   182  		}
   183  		entry.Path = prefix + entry.Path
   184  		err := walkFn(&entry.ManifestEntry)
   185  		if err != nil {
   186  			if entry.ContentType == ManifestType && err == ErrSkipManifest {
   187  				continue
   188  			}
   189  			return err
   190  		}
   191  		if entry.ContentType != ManifestType {
   192  			continue
   193  		}
   194  		if err := trie.loadSubTrie(entry, nil); err != nil {
   195  			return err
   196  		}
   197  		if err := m.walk(entry.subtrie, entry.Path, walkFn); err != nil {
   198  			return err
   199  		}
   200  	}
   201  	return nil
   202  }
   203  
   204  type manifestTrie struct {
   205  	fileStore *storage.FileStore
   206  entries   [257]*manifestTrieEntry //按basepath的第一个字符索引,条目[256]是空的basepath条目。
   207  ref       storage.Address         //如果裁判!=nil,存储
   208  	encrypted bool
   209  	decrypt   DecryptFunc
   210  }
   211  
   212  func newManifestTrieEntry(entry *ManifestEntry, subtrie *manifestTrie) *manifestTrieEntry {
   213  	return &manifestTrieEntry{
   214  		ManifestEntry: *entry,
   215  		subtrie:       subtrie,
   216  	}
   217  }
   218  
   219  type manifestTrieEntry struct {
   220  	ManifestEntry
   221  
   222  	subtrie *manifestTrie
   223  }
   224  
   225  func loadManifest(ctx context.Context, fileStore *storage.FileStore, addr storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //非递归子树按需下载
   226  	log.Trace("manifest lookup", "addr", addr)
   227  //通过文件存储检索清单
   228  	manifestReader, isEncrypted := fileStore.Retrieve(ctx, addr)
   229  	log.Trace("reader retrieved", "addr", addr)
   230  	return readManifest(manifestReader, addr, fileStore, isEncrypted, quitC, decrypt)
   231  }
   232  
   233  func readManifest(mr storage.LazySectionReader, addr storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //非递归子树按需下载
   234  
   235  //TODO检查超大清单的大小
   236  	size, err := mr.Size(mr.Context(), quitC)
   237  if err != nil { //大小=0
   238  //无法确定大小意味着没有根块
   239  		log.Trace("manifest not found", "addr", addr)
   240  		err = fmt.Errorf("Manifest not Found")
   241  		return
   242  	}
   243  	if size > manifestSizeLimit {
   244  		log.Warn("manifest exceeds size limit", "addr", addr, "size", size, "limit", manifestSizeLimit)
   245  		err = fmt.Errorf("Manifest size of %v bytes exceeds the %v byte limit", size, manifestSizeLimit)
   246  		return
   247  	}
   248  	manifestData := make([]byte, size)
   249  	read, err := mr.Read(manifestData)
   250  	if int64(read) < size {
   251  		log.Trace("manifest not found", "addr", addr)
   252  		if err == nil {
   253  			err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size)
   254  		}
   255  		return
   256  	}
   257  
   258  	log.Debug("manifest retrieved", "addr", addr)
   259  	var man struct {
   260  		Entries []*manifestTrieEntry `json:"entries"`
   261  	}
   262  	err = json.Unmarshal(manifestData, &man)
   263  	if err != nil {
   264  		err = fmt.Errorf("Manifest %v is malformed: %v", addr.Log(), err)
   265  		log.Trace("malformed manifest", "addr", addr)
   266  		return
   267  	}
   268  
   269  	log.Trace("manifest entries", "addr", addr, "len", len(man.Entries))
   270  
   271  	trie = &manifestTrie{
   272  		fileStore: fileStore,
   273  		encrypted: isEncrypted,
   274  		decrypt:   decrypt,
   275  	}
   276  	for _, entry := range man.Entries {
   277  		err = trie.addEntry(entry, quitC)
   278  		if err != nil {
   279  			return
   280  		}
   281  	}
   282  	return
   283  }
   284  
   285  func (mt *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) error {
   286  mt.ref = nil //trie已修改,需要根据需要重新计算哈希
   287  
   288  	if entry.ManifestEntry.Access != nil {
   289  		if mt.decrypt == nil {
   290  			return errors.New("dont have decryptor")
   291  		}
   292  
   293  		err := mt.decrypt(&entry.ManifestEntry)
   294  		if err != nil {
   295  			return err
   296  		}
   297  	}
   298  
   299  	if len(entry.Path) == 0 {
   300  		mt.entries[256] = entry
   301  		return nil
   302  	}
   303  
   304  	b := entry.Path[0]
   305  	oldentry := mt.entries[b]
   306  	if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) {
   307  		mt.entries[b] = entry
   308  		return nil
   309  	}
   310  
   311  	cpl := 0
   312  	for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) {
   313  		cpl++
   314  	}
   315  
   316  	if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) {
   317  		if mt.loadSubTrie(oldentry, quitC) != nil {
   318  			return nil
   319  		}
   320  		entry.Path = entry.Path[cpl:]
   321  		oldentry.subtrie.addEntry(entry, quitC)
   322  		oldentry.Hash = ""
   323  		return nil
   324  	}
   325  
   326  	commonPrefix := entry.Path[:cpl]
   327  
   328  	subtrie := &manifestTrie{
   329  		fileStore: mt.fileStore,
   330  		encrypted: mt.encrypted,
   331  	}
   332  	entry.Path = entry.Path[cpl:]
   333  	oldentry.Path = oldentry.Path[cpl:]
   334  	subtrie.addEntry(entry, quitC)
   335  	subtrie.addEntry(oldentry, quitC)
   336  
   337  	mt.entries[b] = newManifestTrieEntry(&ManifestEntry{
   338  		Path:        commonPrefix,
   339  		ContentType: ManifestType,
   340  	}, subtrie)
   341  	return nil
   342  }
   343  
   344  func (mt *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
   345  	for _, e := range &mt.entries {
   346  		if e != nil {
   347  			cnt++
   348  			entry = e
   349  		}
   350  	}
   351  	return
   352  }
   353  
   354  func (mt *manifestTrie) deleteEntry(path string, quitC chan bool) {
   355  mt.ref = nil //trie已修改,需要根据需要重新计算哈希
   356  
   357  	if len(path) == 0 {
   358  		mt.entries[256] = nil
   359  		return
   360  	}
   361  
   362  	b := path[0]
   363  	entry := mt.entries[b]
   364  	if entry == nil {
   365  		return
   366  	}
   367  	if entry.Path == path {
   368  		mt.entries[b] = nil
   369  		return
   370  	}
   371  
   372  	epl := len(entry.Path)
   373  	if (entry.ContentType == ManifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
   374  		if mt.loadSubTrie(entry, quitC) != nil {
   375  			return
   376  		}
   377  		entry.subtrie.deleteEntry(path[epl:], quitC)
   378  		entry.Hash = ""
   379  //如果子树少于2个元素,则删除它
   380  		cnt, lastentry := entry.subtrie.getCountLast()
   381  		if cnt < 2 {
   382  			if lastentry != nil {
   383  				lastentry.Path = entry.Path + lastentry.Path
   384  			}
   385  			mt.entries[b] = lastentry
   386  		}
   387  	}
   388  }
   389  
   390  func (mt *manifestTrie) recalcAndStore() error {
   391  	if mt.ref != nil {
   392  		return nil
   393  	}
   394  
   395  	var buffer bytes.Buffer
   396  	buffer.WriteString(`{"entries":[`)
   397  
   398  	list := &Manifest{}
   399  	for _, entry := range &mt.entries {
   400  		if entry != nil {
   401  if entry.Hash == "" { //托多:平行化
   402  				err := entry.subtrie.recalcAndStore()
   403  				if err != nil {
   404  					return err
   405  				}
   406  				entry.Hash = entry.subtrie.ref.Hex()
   407  			}
   408  			list.Entries = append(list.Entries, entry.ManifestEntry)
   409  		}
   410  
   411  	}
   412  
   413  	manifest, err := json.Marshal(list)
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	sr := bytes.NewReader(manifest)
   419  	ctx := context.TODO()
   420  	addr, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted)
   421  	if err2 != nil {
   422  		return err2
   423  	}
   424  	err2 = wait(ctx)
   425  	mt.ref = addr
   426  	return err2
   427  }
   428  
   429  func (mt *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
   430  	if entry.ManifestEntry.Access != nil {
   431  		if mt.decrypt == nil {
   432  			return errors.New("dont have decryptor")
   433  		}
   434  
   435  		err := mt.decrypt(&entry.ManifestEntry)
   436  		if err != nil {
   437  			return err
   438  		}
   439  	}
   440  
   441  	if entry.subtrie == nil {
   442  		hash := common.Hex2Bytes(entry.Hash)
   443  		entry.subtrie, err = loadManifest(context.TODO(), mt.fileStore, hash, quitC, mt.decrypt)
   444  entry.Hash = "" //可能不匹配,应重新计算
   445  	}
   446  	return
   447  }
   448  
   449  func (mt *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
   450  	plen := len(prefix)
   451  	var start, stop int
   452  	if plen == 0 {
   453  		start = 0
   454  		stop = 256
   455  	} else {
   456  		start = int(prefix[0])
   457  		stop = start
   458  	}
   459  
   460  	for i := start; i <= stop; i++ {
   461  		select {
   462  		case <-quitC:
   463  			return fmt.Errorf("aborted")
   464  		default:
   465  		}
   466  		entry := mt.entries[i]
   467  		if entry != nil {
   468  			epl := len(entry.Path)
   469  			if entry.ContentType == ManifestType {
   470  				l := plen
   471  				if epl < l {
   472  					l = epl
   473  				}
   474  				if prefix[:l] == entry.Path[:l] {
   475  					err := mt.loadSubTrie(entry, quitC)
   476  					if err != nil {
   477  						return err
   478  					}
   479  					err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb)
   480  					if err != nil {
   481  						return err
   482  					}
   483  				}
   484  			} else {
   485  				if (epl >= plen) && (prefix == entry.Path[:plen]) {
   486  					cb(entry, rp+entry.Path[plen:])
   487  				}
   488  			}
   489  		}
   490  	}
   491  	return nil
   492  }
   493  
   494  func (mt *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
   495  	return mt.listWithPrefixInt(prefix, "", quitC, cb)
   496  }
   497  
   498  func (mt *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
   499  	log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
   500  
   501  	if len(path) == 0 {
   502  		return mt.entries[256], 0
   503  	}
   504  
   505  //查看第一个字符是否在清单项中
   506  	b := path[0]
   507  	entry = mt.entries[b]
   508  	if entry == nil {
   509  		return mt.entries[256], 0
   510  	}
   511  
   512  	epl := len(entry.Path)
   513  	log.Trace(fmt.Sprintf("path = %v  entry.Path = %v  epl = %v", path, entry.Path, epl))
   514  	if len(path) <= epl {
   515  		if entry.Path[:len(path)] == path {
   516  			if entry.ContentType == ManifestType {
   517  				err := mt.loadSubTrie(entry, quitC)
   518  				if err == nil && entry.subtrie != nil {
   519  					subentries := entry.subtrie.entries
   520  					for i := 0; i < len(subentries); i++ {
   521  						sub := subentries[i]
   522  						if sub != nil && sub.Path == "" {
   523  							return sub, len(path)
   524  						}
   525  					}
   526  				}
   527  				entry.Status = http.StatusMultipleChoices
   528  			}
   529  			pos = len(path)
   530  			return
   531  		}
   532  		return nil, 0
   533  	}
   534  	if path[:epl] == entry.Path {
   535  		log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
   536  //子条目是清单、加载子条目
   537  		if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) {
   538  			err := mt.loadSubTrie(entry, quitC)
   539  			if err != nil {
   540  				return nil, 0
   541  			}
   542  			sub, pos := entry.subtrie.findPrefixOf(path[epl:], quitC)
   543  			if sub != nil {
   544  				entry = sub
   545  				pos += epl
   546  				return sub, pos
   547  			} else if path == entry.Path {
   548  				entry.Status = http.StatusMultipleChoices
   549  			}
   550  
   551  		} else {
   552  //条目不是清单,请将其返回
   553  			if path != entry.Path {
   554  				return nil, 0
   555  			}
   556  		}
   557  	}
   558  	return nil, 0
   559  }
   560  
   561  //文件系统清单始终包含规范化路径
   562  //没有前导或尾随斜杠,内部只有单个斜杠
   563  func RegularSlashes(path string) (res string) {
   564  	for i := 0; i < len(path); i++ {
   565  		if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) {
   566  			res = res + path[i:i+1]
   567  		}
   568  	}
   569  	if (len(res) > 0) && (res[len(res)-1] == '/') {
   570  		res = res[:len(res)-1]
   571  	}
   572  	return
   573  }
   574  
   575  func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
   576  	path := RegularSlashes(spath)
   577  	var pos int
   578  	quitC := make(chan bool)
   579  	entry, pos = mt.findPrefixOf(path, quitC)
   580  	return entry, path[:pos]
   581  }
   582