github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/swarm/api/api.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"net/http"
    23  	"regexp"
    24  	"strings"
    25  	"sync"
    26  
    27  	"github.com/atheioschain/go-atheios/common"
    28  	"github.com/atheioschain/go-atheios/logger"
    29  	"github.com/atheioschain/go-atheios/logger/glog"
    30  	"github.com/atheioschain/go-atheios/swarm/storage"
    31  )
    32  
    33  var (
    34  	hashMatcher      = regexp.MustCompile("^[0-9A-Fa-f]{64}")
    35  	slashes          = regexp.MustCompile("/+")
    36  	domainAndVersion = regexp.MustCompile("[@:;,]+")
    37  )
    38  
    39  type Resolver interface {
    40  	Resolve(string) (common.Hash, error)
    41  }
    42  
    43  /*
    44  Api implements webserver/file system related content storage and retrieval
    45  on top of the dpa
    46  it is the public interface of the dpa which is included in the ethereum stack
    47  */
    48  type Api struct {
    49  	dpa *storage.DPA
    50  	dns Resolver
    51  }
    52  
    53  //the api constructor initialises
    54  func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
    55  	self = &Api{
    56  		dpa: dpa,
    57  		dns: dns,
    58  	}
    59  	return
    60  }
    61  
    62  // DPA reader API
    63  func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader {
    64  	return self.dpa.Retrieve(key)
    65  }
    66  
    67  func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
    68  	return self.dpa.Store(data, size, wg, nil)
    69  }
    70  
    71  type ErrResolve error
    72  
    73  // DNS Resolver
    74  func (self *Api) Resolve(hostPort string, nameresolver bool) (storage.Key, error) {
    75  	glog.V(logger.Detail).Infof("Resolving : %v", hostPort)
    76  	if hashMatcher.MatchString(hostPort) || self.dns == nil {
    77  		glog.V(logger.Detail).Infof("host is a contentHash: '%v'", hostPort)
    78  		return storage.Key(common.Hex2Bytes(hostPort)), nil
    79  	}
    80  	if !nameresolver {
    81  		return nil, fmt.Errorf("'%s' is not a content hash value.", hostPort)
    82  	}
    83  	contentHash, err := self.dns.Resolve(hostPort)
    84  	if err != nil {
    85  		err = ErrResolve(err)
    86  		glog.V(logger.Warn).Infof("DNS error : %v", err)
    87  	}
    88  	glog.V(logger.Detail).Infof("host lookup: %v -> %v", err)
    89  	return contentHash[:], err
    90  }
    91  func Parse(uri string) (hostPort, path string) {
    92  	if uri == "" {
    93  		return
    94  	}
    95  	parts := slashes.Split(uri, 3)
    96  	var i int
    97  	if len(parts) == 0 {
    98  		return
    99  	}
   100  	// beginning with slash is now optional
   101  	for len(parts[i]) == 0 {
   102  		i++
   103  	}
   104  	hostPort = parts[i]
   105  	for i < len(parts)-1 {
   106  		i++
   107  		if len(path) > 0 {
   108  			path = path + "/" + parts[i]
   109  		} else {
   110  			path = parts[i]
   111  		}
   112  	}
   113  	glog.V(logger.Debug).Infof("host: '%s', path '%s' requested.", hostPort, path)
   114  	return
   115  }
   116  
   117  func (self *Api) parseAndResolve(uri string, nameresolver bool) (key storage.Key, hostPort, path string, err error) {
   118  	hostPort, path = Parse(uri)
   119  	//resolving host and port
   120  	contentHash, err := self.Resolve(hostPort, nameresolver)
   121  	glog.V(logger.Debug).Infof("Resolved '%s' to contentHash: '%s', path: '%s'", uri, contentHash, path)
   122  	return contentHash[:], hostPort, path, err
   123  }
   124  
   125  // Put provides singleton manifest creation on top of dpa store
   126  func (self *Api) Put(content, contentType string) (string, error) {
   127  	r := strings.NewReader(content)
   128  	wg := &sync.WaitGroup{}
   129  	key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  	manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
   134  	r = strings.NewReader(manifest)
   135  	key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
   136  	if err != nil {
   137  		return "", err
   138  	}
   139  	wg.Wait()
   140  	return key.String(), nil
   141  }
   142  
   143  // Get uses iterative manifest retrieval and prefix matching
   144  // to resolve path to content using dpa retrieve
   145  // it returns a section reader, mimeType, status and an error
   146  func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionReader, mimeType string, status int, err error) {
   147  	key, _, path, err := self.parseAndResolve(uri, nameresolver)
   148  	if err != nil {
   149  		return nil, "", 500, fmt.Errorf("can't resolve: %v", err)
   150  	}
   151  
   152  	quitC := make(chan bool)
   153  	trie, err := loadManifest(self.dpa, key, quitC)
   154  	if err != nil {
   155  		glog.V(logger.Warn).Infof("loadManifestTrie error: %v", err)
   156  		return
   157  	}
   158  
   159  	glog.V(logger.Detail).Infof("getEntry(%s)", path)
   160  
   161  	entry, _ := trie.getEntry(path)
   162  
   163  	if entry != nil {
   164  		key = common.Hex2Bytes(entry.Hash)
   165  		status = entry.Status
   166  		mimeType = entry.ContentType
   167  		glog.V(logger.Detail).Infof("content lookup key: '%v' (%v)", key, mimeType)
   168  		reader = self.dpa.Retrieve(key)
   169  	} else {
   170  		status = http.StatusNotFound
   171  		err = fmt.Errorf("manifest entry for '%s' not found", path)
   172  		glog.V(logger.Warn).Infof("%v", err)
   173  	}
   174  	return
   175  }
   176  
   177  func (self *Api) Modify(uri, contentHash, contentType string, nameresolver bool) (newRootHash string, err error) {
   178  	root, _, path, err := self.parseAndResolve(uri, nameresolver)
   179  	if err != nil {
   180  		return "", fmt.Errorf("can't resolve: %v", err)
   181  	}
   182  
   183  	quitC := make(chan bool)
   184  	trie, err := loadManifest(self.dpa, root, quitC)
   185  	if err != nil {
   186  		return
   187  	}
   188  
   189  	if contentHash != "" {
   190  		entry := &manifestTrieEntry{
   191  			Path:        path,
   192  			Hash:        contentHash,
   193  			ContentType: contentType,
   194  		}
   195  		trie.addEntry(entry, quitC)
   196  	} else {
   197  		trie.deleteEntry(path, quitC)
   198  	}
   199  
   200  	err = trie.recalcAndStore()
   201  	if err != nil {
   202  		return
   203  	}
   204  	return trie.hash.String(), nil
   205  }