github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:46</date>
    10  //</624342669920833536>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package api
    29  
    30  import (
    31  	"bytes"
    32  	"context"
    33  	"encoding/json"
    34  	"errors"
    35  	"fmt"
    36  	"io"
    37  	"net/http"
    38  	"strings"
    39  	"time"
    40  
    41  	"github.com/ethereum/go-ethereum/common"
    42  	"github.com/ethereum/go-ethereum/swarm/log"
    43  	"github.com/ethereum/go-ethereum/swarm/storage"
    44  )
    45  
    46  const (
    47  	ManifestType        = "application/bzz-manifest+json"
    48  	ResourceContentType = "application/bzz-resource"
    49  
    50  	manifestSizeLimit = 5 * 1024 * 1024
    51  )
    52  
    53  //
    54  type Manifest struct {
    55  	Entries []ManifestEntry `json:"entries,omitempty"`
    56  }
    57  
    58  //
    59  type ManifestEntry struct {
    60  	Hash        string       `json:"hash,omitempty"`
    61  	Path        string       `json:"path,omitempty"`
    62  	ContentType string       `json:"contentType,omitempty"`
    63  	Mode        int64        `json:"mode,omitempty"`
    64  	Size        int64        `json:"size,omitempty"`
    65  	ModTime     time.Time    `json:"mod_time,omitempty"`
    66  	Status      int          `json:"status,omitempty"`
    67  	Access      *AccessEntry `json:"access,omitempty"`
    68  }
    69  
    70  //
    71  type ManifestList struct {
    72  	CommonPrefixes []string         `json:"common_prefixes,omitempty"`
    73  	Entries        []*ManifestEntry `json:"entries,omitempty"`
    74  }
    75  
    76  //
    77  func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, error) {
    78  	var manifest Manifest
    79  	data, err := json.Marshal(&manifest)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	key, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt)
    84  	wait(ctx)
    85  	return key, err
    86  }
    87  
    88  //
    89  //
    90  func (a *API) NewResourceManifest(ctx context.Context, resourceAddr string) (storage.Address, error) {
    91  	var manifest Manifest
    92  	entry := ManifestEntry{
    93  		Hash:        resourceAddr,
    94  		ContentType: ResourceContentType,
    95  	}
    96  	manifest.Entries = append(manifest.Entries, entry)
    97  	data, err := json.Marshal(&manifest)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	key, _, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), false)
   102  	return key, err
   103  }
   104  
   105  //
   106  type ManifestWriter struct {
   107  	api   *API
   108  	trie  *manifestTrie
   109  	quitC chan bool
   110  }
   111  
   112  func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC chan bool) (*ManifestWriter, error) {
   113  	trie, err := loadManifest(ctx, a.fileStore, addr, quitC, NOOPDecrypt)
   114  	if err != nil {
   115  		return nil, fmt.Errorf("error loading manifest %s: %s", addr, err)
   116  	}
   117  	return &ManifestWriter{a, trie, quitC}, nil
   118  }
   119  
   120  //
   121  func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (key storage.Address, err error) {
   122  	entry := newManifestTrieEntry(e, nil)
   123  	if data != nil {
   124  		key, _, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted)
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  		entry.Hash = key.Hex()
   129  	}
   130  	if entry.Hash == "" {
   131  		return key, errors.New("missing entry hash")
   132  	}
   133  	m.trie.addEntry(entry, m.quitC)
   134  	return key, nil
   135  }
   136  
   137  //
   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  //
   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  //
   165  //
   166  var ErrSkipManifest = errors.New("skip this manifest")
   167  
   168  //
   169  //
   170  type WalkFn func(entry *ManifestEntry) error
   171  
   172  //
   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 //
   207  ref       storage.Address         //
   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, hash storage.Address, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //
   226  	log.Trace("manifest lookup", "key", hash)
   227  //
   228  	manifestReader, isEncrypted := fileStore.Retrieve(ctx, hash)
   229  	log.Trace("reader retrieved", "key", hash)
   230  	return readManifest(manifestReader, hash, fileStore, isEncrypted, quitC, decrypt)
   231  }
   232  
   233  func readManifest(mr storage.LazySectionReader, hash storage.Address, fileStore *storage.FileStore, isEncrypted bool, quitC chan bool, decrypt DecryptFunc) (trie *manifestTrie, err error) { //
   234  
   235  //
   236  	size, err := mr.Size(mr.Context(), quitC)
   237  if err != nil { //
   238  //
   239  		log.Trace("manifest not found", "key", hash)
   240  		err = fmt.Errorf("Manifest not Found")
   241  		return
   242  	}
   243  	if size > manifestSizeLimit {
   244  		log.Warn("manifest exceeds size limit", "key", hash, "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", "key", hash)
   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", "key", hash)
   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", hash.Log(), err)
   265  		log.Trace("malformed manifest", "key", hash)
   266  		return
   267  	}
   268  
   269  	log.Trace("manifest entries", "key", hash, "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 //
   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 //
   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  //
   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  	key, 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 = key
   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  			pos = epl
   557  		}
   558  	}
   559  	return nil, 0
   560  }
   561  
   562  //
   563  //
   564  func RegularSlashes(path string) (res string) {
   565  	for i := 0; i < len(path); i++ {
   566  		if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) {
   567  			res = res + path[i:i+1]
   568  		}
   569  	}
   570  	if (len(res) > 0) && (res[len(res)-1] == '/') {
   571  		res = res[:len(res)-1]
   572  	}
   573  	return
   574  }
   575  
   576  func (mt *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
   577  	path := RegularSlashes(spath)
   578  	var pos int
   579  	quitC := make(chan bool)
   580  	entry, pos = mt.findPrefixOf(path, quitC)
   581  	return entry, path[:pos]
   582  }
   583