mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
cmd/swarm: manifest update: update default entry for non-encrypted uploads
This commit is contained in:
parent
d84dc3e2fc
commit
46d5ba723d
2 changed files with 162 additions and 8 deletions
|
|
@ -19,6 +19,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
|
@ -91,7 +92,13 @@ func manifestUpdate(ctx *cli.Context) {
|
||||||
utils.Fatalf("Too many entries in manifest %s", hash)
|
utils.Fatalf("Too many entries in manifest %s", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifest := updateEntryInManifest(client, mhash, path, m.Entries[0])
|
newManifest, _, defaultEntryUpdated := updateEntryInManifest(client, mhash, path, m.Entries[0], true)
|
||||||
|
if defaultEntryUpdated {
|
||||||
|
// Print informational message to stderr
|
||||||
|
// allowing the user to get the new manifest hash from stdout
|
||||||
|
// without the need to parse the complete output.
|
||||||
|
fmt.Fprintln(os.Stderr, "Manifest default entry is updated, too")
|
||||||
|
}
|
||||||
fmt.Println(newManifest)
|
fmt.Println(newManifest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +172,13 @@ func addEntryToManifest(client *swarm.Client, mhash, path string, entry api.Mani
|
||||||
return newManifestHash
|
return newManifestHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry) string {
|
// updateEntryInManifest updates an existing entry o path with a new one in the manifest with provided mhash
|
||||||
|
// finding the path recursively through all nested manifests. Argument isRoot is used for default
|
||||||
|
// entry update detection. If the updated entry has the same hash as the default entry, then the
|
||||||
|
// default entry in root manifest will be updated too.
|
||||||
|
// Returned values are the new manifest hash, hash of the entry that was replaced by the new entry and
|
||||||
|
// a a bool that is true if default entry is updated.
|
||||||
|
func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.ManifestEntry, isRoot bool) (newManifestHash, oldHash string, defaultEntryUpdated bool) {
|
||||||
var (
|
var (
|
||||||
newEntry = api.ManifestEntry{}
|
newEntry = api.ManifestEntry{}
|
||||||
longestPathEntry = api.ManifestEntry{}
|
longestPathEntry = api.ManifestEntry{}
|
||||||
|
|
@ -180,6 +193,9 @@ func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.M
|
||||||
for _, e := range mroot.Entries {
|
for _, e := range mroot.Entries {
|
||||||
if path == e.Path {
|
if path == e.Path {
|
||||||
newEntry = e
|
newEntry = e
|
||||||
|
// keep the reference of the hash of the entry that should be replaced
|
||||||
|
// for default entry detection
|
||||||
|
oldHash = e.Hash
|
||||||
} else {
|
} else {
|
||||||
if e.ContentType == api.ManifestType {
|
if e.ContentType == api.ManifestType {
|
||||||
prfxlen := strings.HasPrefix(path, e.Path)
|
prfxlen := strings.HasPrefix(path, e.Path)
|
||||||
|
|
@ -197,7 +213,8 @@ func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.M
|
||||||
if longestPathEntry.Path != "" {
|
if longestPathEntry.Path != "" {
|
||||||
// Load the child Manifest add the entry there
|
// Load the child Manifest add the entry there
|
||||||
newPath := path[len(longestPathEntry.Path):]
|
newPath := path[len(longestPathEntry.Path):]
|
||||||
newHash := updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry)
|
var newHash string
|
||||||
|
newHash, oldHash, _ = updateEntryInManifest(client, longestPathEntry.Hash, newPath, entry, false)
|
||||||
|
|
||||||
// Replace the hash for parent Manifests
|
// Replace the hash for parent Manifests
|
||||||
newMRoot := &api.Manifest{}
|
newMRoot := &api.Manifest{}
|
||||||
|
|
@ -211,13 +228,19 @@ func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.M
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
if newEntry.Path != "" {
|
// update the manifest if the new entry is found and
|
||||||
|
// check if default entry should be updated
|
||||||
|
if newEntry.Path != "" || isRoot {
|
||||||
// Replace the hash for leaf Manifest
|
// Replace the hash for leaf Manifest
|
||||||
newMRoot := &api.Manifest{}
|
newMRoot := &api.Manifest{}
|
||||||
for _, e := range mroot.Entries {
|
for _, e := range mroot.Entries {
|
||||||
if newEntry.Path == e.Path {
|
if newEntry.Path == e.Path {
|
||||||
entry.Path = e.Path
|
entry.Path = e.Path
|
||||||
newMRoot.Entries = append(newMRoot.Entries, entry)
|
newMRoot.Entries = append(newMRoot.Entries, entry)
|
||||||
|
} else if isRoot && e.Path == "" && e.Hash == oldHash {
|
||||||
|
entry.Path = e.Path
|
||||||
|
newMRoot.Entries = append(newMRoot.Entries, entry)
|
||||||
|
defaultEntryUpdated = true
|
||||||
} else {
|
} else {
|
||||||
newMRoot.Entries = append(newMRoot.Entries, e)
|
newMRoot.Entries = append(newMRoot.Entries, e)
|
||||||
}
|
}
|
||||||
|
|
@ -225,11 +248,11 @@ func updateEntryInManifest(client *swarm.Client, mhash, path string, entry api.M
|
||||||
mroot = newMRoot
|
mroot = newMRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
newManifestHash, err := client.UploadManifest(mroot, isEncrypted)
|
newManifestHash, err = client.UploadManifest(mroot, isEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Manifest upload failed: %v", err)
|
utils.Fatalf("Manifest upload failed: %v", err)
|
||||||
}
|
}
|
||||||
return newManifestHash
|
return newManifestHash, oldHash, defaultEntryUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
|
func removeEntryFromManifest(client *swarm.Client, mhash, path string) string {
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ func testManifestChange(t *testing.T, encrypt bool) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
humansManifestHash := runSwarmExpectHash(t,
|
indexManifestHash := runSwarmExpectHash(t,
|
||||||
"--bzzapi",
|
"--bzzapi",
|
||||||
cluster.Nodes[0].URL,
|
cluster.Nodes[0].URL,
|
||||||
"up",
|
"up",
|
||||||
|
|
@ -240,7 +240,7 @@ func testManifestChange(t *testing.T, encrypt bool) {
|
||||||
"update",
|
"update",
|
||||||
origManifestHash,
|
origManifestHash,
|
||||||
"index.html",
|
"index.html",
|
||||||
humansManifestHash,
|
indexManifestHash,
|
||||||
)
|
)
|
||||||
|
|
||||||
checkHashLength(t, newManifestHash, encrypt)
|
checkHashLength(t, newManifestHash, encrypt)
|
||||||
|
|
@ -269,6 +269,14 @@ func testManifestChange(t *testing.T, encrypt bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFile(t, client, newManifestHash, "index.html", indexData)
|
checkFile(t, client, newManifestHash, "index.html", indexData)
|
||||||
|
|
||||||
|
// check default entry change
|
||||||
|
// TODO: encrypted uploads generate manifest with default entry
|
||||||
|
// with different hash compared to the same file that is used
|
||||||
|
// for default entry.
|
||||||
|
if !encrypt {
|
||||||
|
checkFile(t, client, newManifestHash, "", indexData)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// upload a new file and use its manifest to change the file it the original manifest,
|
// upload a new file and use its manifest to change the file it the original manifest,
|
||||||
|
|
@ -394,6 +402,129 @@ func testManifestChange(t *testing.T, encrypt bool) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNestedDefaultEntryUpdate tests if the default entry is updated
|
||||||
|
// if the file in nested manifest used for it is also updated.
|
||||||
|
// TODO: create a similar test for encrypted uploads when it becomes
|
||||||
|
// functional.
|
||||||
|
func TestNestedDefaultEntryUpdate(t *testing.T) {
|
||||||
|
testNestedDefaultEntryUpdate(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNestedDefaultEntryUpdate(t *testing.T, encrypt bool) {
|
||||||
|
t.Parallel()
|
||||||
|
cluster := newTestCluster(t, 1)
|
||||||
|
defer cluster.Shutdown()
|
||||||
|
|
||||||
|
tmp, err := ioutil.TempDir("", "swarm-manifest-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
origDir := filepath.Join(tmp, "orig")
|
||||||
|
if err := os.Mkdir(origDir, 0777); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
indexData := []byte("<h1>Test</h1>")
|
||||||
|
indexDataFilename := filepath.Join(origDir, "index.html")
|
||||||
|
err = ioutil.WriteFile(indexDataFilename, indexData, 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Add another file with common prefix as the default entry to test updates of
|
||||||
|
// default entry with nested manifests.
|
||||||
|
err = ioutil.WriteFile(filepath.Join(origDir, "index.txt"), []byte("Test"), 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"--bzzapi",
|
||||||
|
cluster.Nodes[0].URL,
|
||||||
|
"--recursive",
|
||||||
|
"--defaultpath",
|
||||||
|
indexDataFilename,
|
||||||
|
"up",
|
||||||
|
origDir,
|
||||||
|
}
|
||||||
|
if encrypt {
|
||||||
|
args = append(args, "--encrypt")
|
||||||
|
}
|
||||||
|
|
||||||
|
origManifestHash := runSwarmExpectHash(t, args...)
|
||||||
|
|
||||||
|
checkHashLength(t, origManifestHash, encrypt)
|
||||||
|
|
||||||
|
client := swarm.NewClient(cluster.Nodes[0].URL)
|
||||||
|
|
||||||
|
newIndexData := []byte("<h1>Ethereum Swarm</h1>")
|
||||||
|
newIndexDataFilename := filepath.Join(tmp, "index.html")
|
||||||
|
err = ioutil.WriteFile(newIndexDataFilename, newIndexData, 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newIndexManifestHash := runSwarmExpectHash(t,
|
||||||
|
"--bzzapi",
|
||||||
|
cluster.Nodes[0].URL,
|
||||||
|
"up",
|
||||||
|
newIndexDataFilename,
|
||||||
|
)
|
||||||
|
|
||||||
|
newManifestHash := runSwarmExpectHash(t,
|
||||||
|
"--bzzapi",
|
||||||
|
cluster.Nodes[0].URL,
|
||||||
|
"manifest",
|
||||||
|
"update",
|
||||||
|
origManifestHash,
|
||||||
|
"index.html",
|
||||||
|
newIndexManifestHash,
|
||||||
|
)
|
||||||
|
|
||||||
|
checkHashLength(t, newManifestHash, encrypt)
|
||||||
|
|
||||||
|
newManifest := downloadManifest(t, client, newManifestHash, encrypt)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, e := range newManifest.Entries {
|
||||||
|
if e.Path == "index." {
|
||||||
|
found = true
|
||||||
|
newManifest = downloadManifest(t, client, e.Hash, encrypt)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatal("no index. path in new manifest")
|
||||||
|
}
|
||||||
|
|
||||||
|
found = false
|
||||||
|
for _, e := range newManifest.Entries {
|
||||||
|
if e.Path == "html" {
|
||||||
|
found = true
|
||||||
|
if e.Size != int64(len(newIndexData)) {
|
||||||
|
t.Errorf("expected index.html size %v, got %v", len(newIndexData), e.Size)
|
||||||
|
}
|
||||||
|
if e.ModTime.IsZero() {
|
||||||
|
t.Errorf("got zero mod time for index.html")
|
||||||
|
}
|
||||||
|
ct := "text/html; charset=utf-8"
|
||||||
|
if e.ContentType != ct {
|
||||||
|
t.Errorf("expected content type %q, got %q", ct, e.ContentType)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatal("no html in new manifest")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkFile(t, client, newManifestHash, "index.html", newIndexData)
|
||||||
|
|
||||||
|
// check default entry change
|
||||||
|
checkFile(t, client, newManifestHash, "", newIndexData)
|
||||||
|
}
|
||||||
|
|
||||||
func runSwarmExpectHash(t *testing.T, args ...string) (hash string) {
|
func runSwarmExpectHash(t *testing.T, args ...string) (hash string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
hashRegexp := `[a-f\d]{64,128}`
|
hashRegexp := `[a-f\d]{64,128}`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue