github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/cmd/swarm/manifest.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of go-wtc.
     3  //
     4  // go-wtc is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-wtc 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-wtc. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Command  MANIFEST update
    18  package main
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"mime"
    24  	"path/filepath"
    25  	"strings"
    26  
    27  	"github.com/wtc/go-wtc/cmd/utils"
    28  	"github.com/wtc/go-wtc/swarm/api"
    29  	swarm "github.com/wtc/go-wtc/swarm/api/client"
    30  	"gopkg.in/urfave/cli.v1"
    31  )
    32  
    33  func add(ctx *cli.Context) {
    34  	args := ctx.Args()
    35  	if len(args) < 3 {
    36  		utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
    37  	}
    38  
    39  	var (
    40  		mhash = args[0]
    41  		path  = args[1]
    42  		hash  = args[2]
    43  
    44  		ctype        string
    45  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
    46  		mroot        api.Manifest
    47  	)
    48  
    49  	if len(args) > 3 {
    50  		ctype = args[3]
    51  	} else {
    52  		ctype = mime.TypeByExtension(filepath.Ext(path))
    53  	}
    54  
    55  	newManifest := addEntryToManifest(ctx, mhash, path, hash, ctype)
    56  	fmt.Println(newManifest)
    57  
    58  	if !wantManifest {
    59  		// Print the manifest. This is the only output to stdout.
    60  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
    61  		fmt.Println(string(mrootJSON))
    62  		return
    63  	}
    64  }
    65  
    66  func update(ctx *cli.Context) {
    67  
    68  	args := ctx.Args()
    69  	if len(args) < 3 {
    70  		utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
    71  	}
    72  
    73  	var (
    74  		mhash = args[0]
    75  		path  = args[1]
    76  		hash  = args[2]
    77  
    78  		ctype        string
    79  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
    80  		mroot        api.Manifest
    81  	)
    82  	if len(args) > 3 {
    83  		ctype = args[3]
    84  	} else {
    85  		ctype = mime.TypeByExtension(filepath.Ext(path))
    86  	}
    87  
    88  	newManifest := updateEntryInManifest(ctx, mhash, path, hash, ctype)
    89  	fmt.Println(newManifest)
    90  
    91  	if !wantManifest {
    92  		// Print the manifest. This is the only output to stdout.
    93  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
    94  		fmt.Println(string(mrootJSON))
    95  		return
    96  	}
    97  }
    98  
    99  func remove(ctx *cli.Context) {
   100  	args := ctx.Args()
   101  	if len(args) < 2 {
   102  		utils.Fatalf("Need atleast two arguments <MHASH> <path>")
   103  	}
   104  
   105  	var (
   106  		mhash = args[0]
   107  		path  = args[1]
   108  
   109  		wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
   110  		mroot        api.Manifest
   111  	)
   112  
   113  	newManifest := removeEntryFromManifest(ctx, mhash, path)
   114  	fmt.Println(newManifest)
   115  
   116  	if !wantManifest {
   117  		// Print the manifest. This is the only output to stdout.
   118  		mrootJSON, _ := json.MarshalIndent(mroot, "", "  ")
   119  		fmt.Println(string(mrootJSON))
   120  		return
   121  	}
   122  }
   123  
   124  func addEntryToManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
   125  
   126  	var (
   127  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   128  		client           = swarm.NewClient(bzzapi)
   129  		longestPathEntry = api.ManifestEntry{}
   130  	)
   131  
   132  	mroot, err := client.DownloadManifest(mhash)
   133  	if err != nil {
   134  		utils.Fatalf("Manifest download failed: %v", err)
   135  	}
   136  
   137  	//TODO: check if the "hash" to add is valid and present in swarm
   138  	_, err = client.DownloadManifest(hash)
   139  	if err != nil {
   140  		utils.Fatalf("Hash to add is not present: %v", err)
   141  	}
   142  
   143  	// See if we path is in this Manifest or do we have to dig deeper
   144  	for _, entry := range mroot.Entries {
   145  		if path == entry.Path {
   146  			utils.Fatalf("Path %s already present, not adding anything", path)
   147  		} else {
   148  			if entry.ContentType == "application/bzz-manifest+json" {
   149  				prfxlen := strings.HasPrefix(path, entry.Path)
   150  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   151  					longestPathEntry = entry
   152  				}
   153  			}
   154  		}
   155  	}
   156  
   157  	if longestPathEntry.Path != "" {
   158  		// Load the child Manifest add the entry there
   159  		newPath := path[len(longestPathEntry.Path):]
   160  		newHash := addEntryToManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
   161  
   162  		// Replace the hash for parent Manifests
   163  		newMRoot := &api.Manifest{}
   164  		for _, entry := range mroot.Entries {
   165  			if longestPathEntry.Path == entry.Path {
   166  				entry.Hash = newHash
   167  			}
   168  			newMRoot.Entries = append(newMRoot.Entries, entry)
   169  		}
   170  		mroot = newMRoot
   171  	} else {
   172  		// Add the entry in the leaf Manifest
   173  		newEntry := api.ManifestEntry{
   174  			Hash:        hash,
   175  			Path:        path,
   176  			ContentType: ctype,
   177  		}
   178  		mroot.Entries = append(mroot.Entries, newEntry)
   179  	}
   180  
   181  	newManifestHash, err := client.UploadManifest(mroot)
   182  	if err != nil {
   183  		utils.Fatalf("Manifest upload failed: %v", err)
   184  	}
   185  	return newManifestHash
   186  
   187  }
   188  
   189  func updateEntryInManifest(ctx *cli.Context, mhash, path, hash, ctype string) string {
   190  
   191  	var (
   192  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   193  		client           = swarm.NewClient(bzzapi)
   194  		newEntry         = api.ManifestEntry{}
   195  		longestPathEntry = api.ManifestEntry{}
   196  	)
   197  
   198  	mroot, err := client.DownloadManifest(mhash)
   199  	if err != nil {
   200  		utils.Fatalf("Manifest download failed: %v", err)
   201  	}
   202  
   203  	//TODO: check if the "hash" with which to update is valid and present in swarm
   204  
   205  	// See if we path is in this Manifest or do we have to dig deeper
   206  	for _, entry := range mroot.Entries {
   207  		if path == entry.Path {
   208  			newEntry = entry
   209  		} else {
   210  			if entry.ContentType == "application/bzz-manifest+json" {
   211  				prfxlen := strings.HasPrefix(path, entry.Path)
   212  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   213  					longestPathEntry = entry
   214  				}
   215  			}
   216  		}
   217  	}
   218  
   219  	if longestPathEntry.Path == "" && newEntry.Path == "" {
   220  		utils.Fatalf("Path %s not present in the Manifest, not setting anything", path)
   221  	}
   222  
   223  	if longestPathEntry.Path != "" {
   224  		// Load the child Manifest add the entry there
   225  		newPath := path[len(longestPathEntry.Path):]
   226  		newHash := updateEntryInManifest(ctx, longestPathEntry.Hash, newPath, hash, ctype)
   227  
   228  		// Replace the hash for parent Manifests
   229  		newMRoot := &api.Manifest{}
   230  		for _, entry := range mroot.Entries {
   231  			if longestPathEntry.Path == entry.Path {
   232  				entry.Hash = newHash
   233  			}
   234  			newMRoot.Entries = append(newMRoot.Entries, entry)
   235  
   236  		}
   237  		mroot = newMRoot
   238  	}
   239  
   240  	if newEntry.Path != "" {
   241  		// Replace the hash for leaf Manifest
   242  		newMRoot := &api.Manifest{}
   243  		for _, entry := range mroot.Entries {
   244  			if newEntry.Path == entry.Path {
   245  				myEntry := api.ManifestEntry{
   246  					Hash:        hash,
   247  					Path:        entry.Path,
   248  					ContentType: ctype,
   249  				}
   250  				newMRoot.Entries = append(newMRoot.Entries, myEntry)
   251  			} else {
   252  				newMRoot.Entries = append(newMRoot.Entries, entry)
   253  			}
   254  		}
   255  		mroot = newMRoot
   256  	}
   257  
   258  	newManifestHash, err := client.UploadManifest(mroot)
   259  	if err != nil {
   260  		utils.Fatalf("Manifest upload failed: %v", err)
   261  	}
   262  	return newManifestHash
   263  }
   264  
   265  func removeEntryFromManifest(ctx *cli.Context, mhash, path string) string {
   266  
   267  	var (
   268  		bzzapi           = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
   269  		client           = swarm.NewClient(bzzapi)
   270  		entryToRemove    = api.ManifestEntry{}
   271  		longestPathEntry = api.ManifestEntry{}
   272  	)
   273  
   274  	mroot, err := client.DownloadManifest(mhash)
   275  	if err != nil {
   276  		utils.Fatalf("Manifest download failed: %v", err)
   277  	}
   278  
   279  	// See if we path is in this Manifest or do we have to dig deeper
   280  	for _, entry := range mroot.Entries {
   281  		if path == entry.Path {
   282  			entryToRemove = entry
   283  		} else {
   284  			if entry.ContentType == "application/bzz-manifest+json" {
   285  				prfxlen := strings.HasPrefix(path, entry.Path)
   286  				if prfxlen && len(path) > len(longestPathEntry.Path) {
   287  					longestPathEntry = entry
   288  				}
   289  			}
   290  		}
   291  	}
   292  
   293  	if longestPathEntry.Path == "" && entryToRemove.Path == "" {
   294  		utils.Fatalf("Path %s not present in the Manifest, not removing anything", path)
   295  	}
   296  
   297  	if longestPathEntry.Path != "" {
   298  		// Load the child Manifest remove the entry there
   299  		newPath := path[len(longestPathEntry.Path):]
   300  		newHash := removeEntryFromManifest(ctx, longestPathEntry.Hash, newPath)
   301  
   302  		// Replace the hash for parent Manifests
   303  		newMRoot := &api.Manifest{}
   304  		for _, entry := range mroot.Entries {
   305  			if longestPathEntry.Path == entry.Path {
   306  				entry.Hash = newHash
   307  			}
   308  			newMRoot.Entries = append(newMRoot.Entries, entry)
   309  		}
   310  		mroot = newMRoot
   311  	}
   312  
   313  	if entryToRemove.Path != "" {
   314  		// remove the entry in this Manifest
   315  		newMRoot := &api.Manifest{}
   316  		for _, entry := range mroot.Entries {
   317  			if entryToRemove.Path != entry.Path {
   318  				newMRoot.Entries = append(newMRoot.Entries, entry)
   319  			}
   320  		}
   321  		mroot = newMRoot
   322  	}
   323  
   324  	newManifestHash, err := client.UploadManifest(mroot)
   325  	if err != nil {
   326  		utils.Fatalf("Manifest upload failed: %v", err)
   327  	}
   328  	return newManifestHash
   329  }