diff options
-rw-r--r-- | cmd/swarm/main.go | 66 | ||||
-rw-r--r-- | cmd/swarm/mru.go | 52 | ||||
-rw-r--r-- | cmd/swarm/mru_test.go | 34 | ||||
-rw-r--r-- | swarm/api/api.go | 113 | ||||
-rw-r--r-- | swarm/api/client/client.go | 57 | ||||
-rw-r--r-- | swarm/api/client/client_test.go | 70 | ||||
-rw-r--r-- | swarm/api/http/server.go | 124 | ||||
-rw-r--r-- | swarm/api/http/server_test.go | 101 | ||||
-rw-r--r-- | swarm/api/manifest.go | 30 | ||||
-rw-r--r-- | swarm/api/uri.go | 6 | ||||
-rw-r--r-- | swarm/network/README.md | 2 | ||||
-rw-r--r-- | swarm/storage/localstore_test.go | 4 | ||||
-rw-r--r-- | swarm/storage/mru/doc.go | 2 | ||||
-rw-r--r-- | swarm/storage/mru/error.go | 2 | ||||
-rw-r--r-- | swarm/storage/mru/handler.go | 6 | ||||
-rw-r--r-- | swarm/storage/mru/handler_test.go | 4 | ||||
-rw-r--r-- | swarm/storage/mru/request_test.go | 4 | ||||
-rw-r--r-- | swarm/swarm.go | 12 | ||||
-rw-r--r-- | swarm/testutil/http.go | 8 |
19 files changed, 315 insertions, 382 deletions
diff --git a/cmd/swarm/main.go b/cmd/swarm/main.go index 5acf87c71..4c4dfceb7 100644 --- a/cmd/swarm/main.go +++ b/cmd/swarm/main.go @@ -207,25 +207,25 @@ var ( Name: "compressed", Usage: "Prints encryption keys in compressed form", } - SwarmResourceNameFlag = cli.StringFlag{ + SwarmFeedNameFlag = cli.StringFlag{ Name: "name", - Usage: "User-defined name for the new resource, limited to 32 characters. If combined with topic, the resource will be a subtopic with this name", + Usage: "User-defined name for the new feed, limited to 32 characters. If combined with topic, it will refer to a subtopic with this name", } - SwarmResourceTopicFlag = cli.StringFlag{ + SwarmFeedTopicFlag = cli.StringFlag{ Name: "topic", - Usage: "User-defined topic this resource is tracking, hex encoded. Limited to 64 hexadecimal characters", + Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters", } - SwarmResourceDataOnCreateFlag = cli.StringFlag{ + SwarmFeedDataOnCreateFlag = cli.StringFlag{ Name: "data", - Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x", + Usage: "Initializes the feed with the given hex-encoded data. Data must be prefixed by 0x", } - SwarmResourceManifestFlag = cli.StringFlag{ + SwarmFeedManifestFlag = cli.StringFlag{ Name: "manifest", - Usage: "Refers to the resource through a manifest", + Usage: "Refers to the feed through a manifest", } - SwarmResourceUserFlag = cli.StringFlag{ + SwarmFeedUserFlag = cli.StringFlag{ Name: "user", - Usage: "Indicates the user who updates the resource", + Usage: "Indicates the user who updates the feed", } ) @@ -346,62 +346,62 @@ func init() { }, { CustomHelpTemplate: helpTemplate, - Name: "resource", - Usage: "(Advanced) Create and update Mutable Resources", + Name: "feed", + Usage: "(Advanced) Create and update Swarm Feeds", ArgsUsage: "<create|update|info>", - Description: "Works with Mutable Resource Updates", + Description: "Works with Swarm Feeds", Subcommands: []cli.Command{ { - Action: resourceCreate, + Action: feedCreateManifest, CustomHelpTemplate: helpTemplate, Name: "create", - Usage: "creates and publishes a new Mutable Resource manifest", - Description: `creates and publishes a new Mutable Resource manifest pointing to a specified user's updates about a particular topic. - The resource topic can be built in the following ways: + Usage: "creates and publishes a new Feed manifest", + Description: `creates and publishes a new Feed manifest pointing to a specified user's updates about a particular topic. + The feed topic can be built in the following ways: * use --topic to set the topic to an arbitrary binary hex string. * use --name to set the topic to a human-readable name. - For example --name could be set to "profile-picture", meaning this Mutable Resource allows to get this user's current profile picture. + For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. * use both --topic and --name to create named subtopics. For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning - the Mutable Resource tracks a discussion about that contract. + this feed tracks a discussion about that contract. The --user flag allows to have this manifest refer to a user other than yourself. If not specified, it will then default to your local account (--bzzaccount)`, - Flags: []cli.Flag{SwarmResourceNameFlag, SwarmResourceTopicFlag, SwarmResourceUserFlag}, + Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, }, { - Action: resourceUpdate, + Action: feedUpdate, CustomHelpTemplate: helpTemplate, Name: "update", - Usage: "updates the content of an existing Mutable Resource", + Usage: "updates the content of an existing Swarm Feed", ArgsUsage: "<0x Hex data>", Description: `publishes a new update on the specified topic - The resource topic can be built in the following ways: + The feed topic can be built in the following ways: * use --topic to set the topic to an arbitrary binary hex string. * use --name to set the topic to a human-readable name. - For example --name could be set to "profile-picture", meaning this Mutable Resource allows to get this user's current profile picture. + For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. * use both --topic and --name to create named subtopics. For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning - the Mutable Resource tracks a discussion about that contract. + this feed tracks a discussion about that contract. - If you have a manifest, you can specify it with --manifest to refer to the resource, + If you have a manifest, you can specify it with --manifest to refer to the feed, instead of using --topic / --name `, - Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag}, + Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag}, }, { - Action: resourceInfo, + Action: feedInfo, CustomHelpTemplate: helpTemplate, Name: "info", - Usage: "obtains information about an existing Mutable Resource", - Description: `obtains information about an existing Mutable Resource + Usage: "obtains information about an existing Swarm Feed", + Description: `obtains information about an existing Swarm Feed The topic can be specified directly with the --topic flag as an hex string If no topic is specified, the default topic (zero) will be used The --name flag can be used to specify subtopics with a specific name. The --user flag allows to refer to a user other than yourself. If not specified, it will then default to your local account (--bzzaccount) If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user - to refer to the resource`, - Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag, SwarmResourceUserFlag}, + to refer to the feed`, + Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, }, }, }, @@ -738,7 +738,7 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr } // getPrivKey returns the private key of the specified bzzaccount -// Used only by client commands, such as `resource` +// Used only by client commands, such as `feed` func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { // booting up the swarm node just as we do in bzzd action bzzconfig, err := buildConfig(ctx) diff --git a/cmd/swarm/mru.go b/cmd/swarm/mru.go index afa73820f..6c6d44c0a 100644 --- a/cmd/swarm/mru.go +++ b/cmd/swarm/mru.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. -// Command resource allows the user to create and update signed Swarm Feeds +// Command feed allows the user to create and update signed Swarm Feeds package main import ( @@ -36,8 +36,8 @@ func NewGenericSigner(ctx *cli.Context) mru.Signer { } func getTopic(ctx *cli.Context) (topic mru.Topic) { - var name = ctx.String(SwarmResourceNameFlag.Name) - var relatedTopic = ctx.String(SwarmResourceTopicFlag.Name) + var name = ctx.String(SwarmFeedNameFlag.Name) + var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name) var relatedTopicBytes []byte var err error @@ -55,35 +55,35 @@ func getTopic(ctx *cli.Context) (topic mru.Topic) { return topic } -// swarm resource create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]] -// swarm resource update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false] -// swarm resource info <Manifest Address or ENS domain> +// swarm feed create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]] +// swarm feed update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false] +// swarm feed info <Manifest Address or ENS domain> -func resourceCreate(ctx *cli.Context) { +func feedCreateManifest(ctx *cli.Context) { var ( bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") client = swarm.NewClient(bzzapi) ) - newResourceRequest := mru.NewFirstRequest(getTopic(ctx)) - newResourceRequest.Feed.User = resourceGetUser(ctx) + newFeedUpdateRequest := mru.NewFirstRequest(getTopic(ctx)) + newFeedUpdateRequest.Feed.User = feedGetUser(ctx) - manifestAddress, err := client.CreateResource(newResourceRequest) + manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest) if err != nil { - utils.Fatalf("Error creating resource: %s", err.Error()) + utils.Fatalf("Error creating feed manifest: %s", err.Error()) return } fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up) } -func resourceUpdate(ctx *cli.Context) { +func feedUpdate(ctx *cli.Context) { args := ctx.Args() var ( bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") client = swarm.NewClient(bzzapi) - manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name) + manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) ) if len(args) < 1 { @@ -110,10 +110,10 @@ func resourceUpdate(ctx *cli.Context) { } - // Retrieve resource status and metadata out of the manifest - updateRequest, err = client.GetResourceMetadata(query, manifestAddressOrDomain) + // Retrieve feed status and metadata out of the manifest + updateRequest, err = client.GetFeedMetadata(query, manifestAddressOrDomain) if err != nil { - utils.Fatalf("Error retrieving resource status: %s", err.Error()) + utils.Fatalf("Error retrieving feed status: %s", err.Error()) } // set the new data @@ -121,34 +121,34 @@ func resourceUpdate(ctx *cli.Context) { // sign update if err = updateRequest.Sign(signer); err != nil { - utils.Fatalf("Error signing resource update: %s", err.Error()) + utils.Fatalf("Error signing feed update: %s", err.Error()) } // post update - err = client.UpdateResource(updateRequest) + err = client.UpdateFeed(updateRequest) if err != nil { - utils.Fatalf("Error updating resource: %s", err.Error()) + utils.Fatalf("Error updating feed: %s", err.Error()) return } } -func resourceInfo(ctx *cli.Context) { +func feedInfo(ctx *cli.Context) { var ( bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") client = swarm.NewClient(bzzapi) - manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name) + manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) ) var query *mru.Query if manifestAddressOrDomain == "" { query = new(mru.Query) query.Topic = getTopic(ctx) - query.User = resourceGetUser(ctx) + query.User = feedGetUser(ctx) } - metadata, err := client.GetResourceMetadata(query, manifestAddressOrDomain) + metadata, err := client.GetFeedMetadata(query, manifestAddressOrDomain) if err != nil { - utils.Fatalf("Error retrieving resource metadata: %s", err.Error()) + utils.Fatalf("Error retrieving feed metadata: %s", err.Error()) return } encodedMetadata, err := metadata.MarshalJSON() @@ -158,8 +158,8 @@ func resourceInfo(ctx *cli.Context) { fmt.Println(string(encodedMetadata)) } -func resourceGetUser(ctx *cli.Context) common.Address { - var user = ctx.String(SwarmResourceUserFlag.Name) +func feedGetUser(ctx *cli.Context) common.Address { + var user = ctx.String(SwarmFeedUserFlag.Name) if user != "" { return common.HexToAddress(user) } diff --git a/cmd/swarm/mru_test.go b/cmd/swarm/mru_test.go index c52097a6e..c0c43aca4 100644 --- a/cmd/swarm/mru_test.go +++ b/cmd/swarm/mru_test.go @@ -38,12 +38,12 @@ import ( swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" ) -func TestCLIResourceUpdate(t *testing.T) { +func TestCLIFeedUpdate(t *testing.T) { srv := testutil.NewTestSwarmServer(t, func(api *api.API) testutil.TestServer { return swarmhttp.NewServer(api, "") }, nil) - log.Info("starting 1 node cluster") + log.Info("starting a test swarm server") defer srv.Close() // create a private key file for signing @@ -77,13 +77,13 @@ func TestCLIResourceUpdate(t *testing.T) { flags := []string{ "--bzzapi", srv.URL, "--bzzaccount", pkfile.Name(), - "resource", "update", + "feed", "update", "--topic", topic.Hex(), "--name", name, hexData} // create an update and expect an exit without errors - log.Info(fmt.Sprintf("updating a resource with 'swarm resource update'")) + log.Info(fmt.Sprintf("updating a feed with 'swarm feed update'")) cmd := runSwarm(t, flags...) cmd.ExpectExit() @@ -100,17 +100,17 @@ func TestCLIResourceUpdate(t *testing.T) { t.Fatal(err) } - // View configures whose updates we will be looking up. - view := mru.Feed{ + // Feed configures whose updates we will be looking up. + feed := mru.Feed{ Topic: topic, User: address, } // Build a query to get the latest update - query := mru.NewQueryLatest(&view, lookup.NoClue) + query := mru.NewQueryLatest(&feed, lookup.NoClue) // retrieve content! - reader, err := client.GetResource(query, "") + reader, err := client.QueryFeed(query, "") if err != nil { t.Fatal(err) } @@ -128,12 +128,12 @@ func TestCLIResourceUpdate(t *testing.T) { // Now retrieve info for the next update flags = []string{ "--bzzapi", srv.URL, - "resource", "info", + "feed", "info", "--topic", topic.Hex(), "--user", address.Hex(), } - log.Info(fmt.Sprintf("getting resource info with 'swarm resource info'")) + log.Info(fmt.Sprintf("getting feed info with 'swarm feed info'")) cmd = runSwarm(t, flags...) _, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout cmd.ExpectExit() @@ -145,28 +145,28 @@ func TestCLIResourceUpdate(t *testing.T) { t.Fatal(err) } - // make sure the retrieved view is the same - if request.Feed != view { - t.Fatalf("Expected view to be: %s, got %s", view, request.Feed) + // make sure the retrieved Feed is the same + if request.Feed != feed { + t.Fatalf("Expected feed to be: %s, got %s", feed, request.Feed) } // test publishing a manifest flags = []string{ "--bzzapi", srv.URL, "--bzzaccount", pkfile.Name(), - "resource", "create", + "feed", "create", "--topic", topic.Hex(), } - log.Info(fmt.Sprintf("Publishing manifest with 'swarm resource create'")) + log.Info(fmt.Sprintf("Publishing manifest with 'swarm feed create'")) cmd = runSwarm(t, flags...) _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout cmd.ExpectExit() - manifestAddress := matches[0] // read the received resource manifest + manifestAddress := matches[0] // read the received feed manifest // now attempt to lookup the latest update using a manifest instead - reader, err = client.GetResource(nil, manifestAddress) + reader, err = client.QueryFeed(nil, manifestAddress) if err != nil { t.Fatal(err) } diff --git a/swarm/api/api.go b/swarm/api/api.go index e6b676dba..9b4571bee 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -235,18 +235,18 @@ on top of the FileStore it is the public interface of the FileStore which is included in the ethereum stack */ type API struct { - resource *mru.Handler + feeds *mru.Handler fileStore *storage.FileStore dns Resolver Decryptor func(context.Context, string) DecryptFunc } // NewAPI the api constructor initialises a new API instance. -func NewAPI(fileStore *storage.FileStore, dns Resolver, resourceHandler *mru.Handler, pk *ecdsa.PrivateKey) (self *API) { +func NewAPI(fileStore *storage.FileStore, dns Resolver, feedsHandler *mru.Handler, pk *ecdsa.PrivateKey) (self *API) { self = &API{ fileStore: fileStore, dns: dns, - resource: resourceHandler, + feeds: feedsHandler, Decryptor: func(ctx context.Context, credentials string) DecryptFunc { return self.doDecrypt(ctx, credentials, pk) }, @@ -403,24 +403,24 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage return a.Get(ctx, decrypt, adr, entry.Path) } - // we need to do some extra work if this is a mutable resource manifest - if entry.ContentType == ResourceContentType { - if entry.ResourceView == nil { - return reader, mimeType, status, nil, fmt.Errorf("Cannot decode ResourceView in manifest") + // we need to do some extra work if this is a Feed manifest + if entry.ContentType == FeedContentType { + if entry.Feed == nil { + return reader, mimeType, status, nil, fmt.Errorf("Cannot decode Feed in manifest") } - _, err := a.resource.Lookup(ctx, mru.NewQueryLatest(entry.ResourceView, lookup.NoClue)) + _, err := a.feeds.Lookup(ctx, mru.NewQueryLatest(entry.Feed, lookup.NoClue)) if err != nil { apiGetNotFound.Inc(1) status = http.StatusNotFound - log.Debug(fmt.Sprintf("get resource content error: %v", err)) + log.Debug(fmt.Sprintf("get feed update content error: %v", err)) return reader, mimeType, status, nil, err } // get the data of the update - _, rsrcData, err := a.resource.GetContent(entry.ResourceView) + _, rsrcData, err := a.feeds.GetContent(entry.Feed) if err != nil { apiGetNotFound.Inc(1) status = http.StatusNotFound - log.Warn(fmt.Sprintf("get resource content error: %v", err)) + log.Warn(fmt.Sprintf("get feed update content error: %v", err)) return reader, mimeType, status, nil, err } @@ -429,18 +429,18 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage if err != nil { apiGetInvalid.Inc(1) status = http.StatusUnprocessableEntity - log.Warn("invalid resource multihash", "err", err) + log.Warn("invalid multihash in feed update", "err", err) return reader, mimeType, status, nil, err } manifestAddr = storage.Address(decodedMultihash) - log.Trace("resource is multihash", "key", manifestAddr) + log.Trace("feed update contains multihash", "key", manifestAddr) // get the manifest the multihash digest points to trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt) if err != nil { apiGetNotFound.Inc(1) status = http.StatusNotFound - log.Warn(fmt.Sprintf("loadManifestTrie (resource multihash) error: %v", err)) + log.Warn(fmt.Sprintf("loadManifestTrie (feed update multihash) error: %v", err)) return reader, mimeType, status, nil, err } @@ -450,13 +450,13 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage if entry == nil { status = http.StatusNotFound apiGetNotFound.Inc(1) - err = fmt.Errorf("manifest (resource multihash) entry for '%s' not found", path) - log.Trace("manifest (resource multihash) entry not found", "key", manifestAddr, "path", path) + err = fmt.Errorf("manifest (feed update multihash) entry for '%s' not found", path) + log.Trace("manifest (feed update multihash) entry not found", "key", manifestAddr, "path", path) return reader, mimeType, status, nil, err } } - // regardless of resource update manifests or normal manifests we will converge at this point + // regardless of feed update manifests or normal manifests we will converge at this point // get the key the manifest entry points to and serve it if it's unambiguous contentAddr = common.Hex2Bytes(entry.Hash) status = entry.Status @@ -956,68 +956,67 @@ func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver return addr, manifestEntryMap, nil } -// ResourceLookup finds Swarm Feeds at specific periods and versions -func (a *API) ResourceLookup(ctx context.Context, query *mru.Query) ([]byte, error) { - _, err := a.resource.Lookup(ctx, query) +// FeedsLookup finds Swarm Feeds Updates at specific points in time, or the latest update +func (a *API) FeedsLookup(ctx context.Context, query *mru.Query) ([]byte, error) { + _, err := a.feeds.Lookup(ctx, query) if err != nil { return nil, err } var data []byte - _, data, err = a.resource.GetContent(&query.Feed) + _, data, err = a.feeds.GetContent(&query.Feed) if err != nil { return nil, err } return data, nil } -// ResourceNewRequest creates a Request object to update a specific mutable resource -func (a *API) ResourceNewRequest(ctx context.Context, view *mru.Feed) (*mru.Request, error) { - return a.resource.NewRequest(ctx, view) +// FeedsNewRequest creates a Request object to update a specific Feed +func (a *API) FeedsNewRequest(ctx context.Context, feed *mru.Feed) (*mru.Request, error) { + return a.feeds.NewRequest(ctx, feed) } -// ResourceUpdate updates a Mutable Resource with arbitrary data. -// Upon retrieval the update will be retrieved verbatim as bytes. -func (a *API) ResourceUpdate(ctx context.Context, request *mru.Request) (storage.Address, error) { - return a.resource.Update(ctx, request) +// FeedsUpdate publishes a new update on the given Feed +func (a *API) FeedsUpdate(ctx context.Context, request *mru.Request) (storage.Address, error) { + return a.feeds.Update(ctx, request) } -// ResourceHashSize returned the size of the digest produced by the Mutable Resource hashing function -func (a *API) ResourceHashSize() int { - return a.resource.HashSize +// FeedsHashSize returned the size of the digest produced by Swarm Feeds' hashing function +func (a *API) FeedsHashSize() int { + return a.feeds.HashSize } -// ErrCannotLoadResourceManifest is returned when looking up a resource manifest fails -var ErrCannotLoadResourceManifest = errors.New("Cannot load resource manifest") +// ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails +var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest") -// ErrNotAResourceManifest is returned when the address provided returned something other than a valid manifest -var ErrNotAResourceManifest = errors.New("Not a resource manifest") +// ErrNotAFeedManifest is returned when the address provided returned something other than a valid manifest +var ErrNotAFeedManifest = errors.New("Not a feed manifest") -// ResolveResourceManifest retrieves the Mutable Resource manifest for the given address, and returns the Resource's view ID. -func (a *API) ResolveResourceManifest(ctx context.Context, addr storage.Address) (*mru.Feed, error) { +// ResolveFeedManifest retrieves the Feed manifest for the given address, and returns the referenced Feed. +func (a *API) ResolveFeedManifest(ctx context.Context, addr storage.Address) (*mru.Feed, error) { trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt) if err != nil { - return nil, ErrCannotLoadResourceManifest + return nil, ErrCannotLoadFeedManifest } entry, _ := trie.getEntry("") - if entry.ContentType != ResourceContentType { - return nil, ErrNotAResourceManifest + if entry.ContentType != FeedContentType { + return nil, ErrNotAFeedManifest } - return entry.ResourceView, nil + return entry.Feed, nil } -// ErrCannotResolveResourceURI is returned when the ENS resolver is not able to translate a name to a resource -var ErrCannotResolveResourceURI = errors.New("Cannot resolve Resource URI") +// ErrCannotResolveFeedURI is returned when the ENS resolver is not able to translate a name to a Feed +var ErrCannotResolveFeedURI = errors.New("Cannot resolve Feed URI") -// ErrCannotResolveResourceView is returned when values provided are not enough or invalid to recreate a -// resource view out of them. -var ErrCannotResolveResourceView = errors.New("Cannot resolve resource view") +// ErrCannotResolveFeed is returned when values provided are not enough or invalid to recreate a +// Feed out of them. +var ErrCannotResolveFeed = errors.New("Cannot resolve Feed") -// ResolveResourceView attempts to extract View information out of the manifest, if provided -// If not, it attempts to extract the View out of a set of key-value pairs -func (a *API) ResolveResourceView(ctx context.Context, uri *URI, values mru.Values) (*mru.Feed, error) { - var view *mru.Feed +// ResolveFeed attempts to extract Feed information out of the manifest, if provided +// If not, it attempts to extract the Feed out of a set of key-value pairs +func (a *API) ResolveFeed(ctx context.Context, uri *URI, values mru.Values) (*mru.Feed, error) { + var feed *mru.Feed var err error if uri.Addr != "" { // resolve the content key. @@ -1025,25 +1024,25 @@ func (a *API) ResolveResourceView(ctx context.Context, uri *URI, values mru.Valu if manifestAddr == nil { manifestAddr, err = a.Resolve(ctx, uri.Addr) if err != nil { - return nil, ErrCannotResolveResourceURI + return nil, ErrCannotResolveFeedURI } } - // get the resource view from the manifest - view, err = a.ResolveResourceManifest(ctx, manifestAddr) + // get the Feed from the manifest + feed, err = a.ResolveFeedManifest(ctx, manifestAddr) if err != nil { return nil, err } - log.Debug("handle.get.resource: resolved", "manifestkey", manifestAddr, "view", view.Hex()) + log.Debug("handle.get.feed: resolved", "manifestkey", manifestAddr, "feed", feed.Hex()) } else { var v mru.Feed if err := v.FromValues(values); err != nil { - return nil, ErrCannotResolveResourceView + return nil, ErrCannotResolveFeed } - view = &v + feed = &v } - return view, nil + return feed, nil } // MimeOctetStream default value of http Content-Type header diff --git a/swarm/api/client/client.go b/swarm/api/client/client.go index 47a6980de..76ada1297 100644 --- a/swarm/api/client/client.go +++ b/swarm/api/client/client.go @@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error) return string(data), nil } -// ErrNoResourceUpdatesFound is returned when Swarm cannot find updates of the given resource -var ErrNoResourceUpdatesFound = errors.New("No updates found for this resource") +// ErrNoFeedUpdatesFound is returned when Swarm cannot find updates of the given feed +var ErrNoFeedUpdatesFound = errors.New("No updates found for this feed") -// CreateResource creates a Mutable Resource with the given name and frequency, initializing it with the provided -// data. Data is interpreted as multihash or not depending on the multihash parameter. -// startTime=0 means "now" -// Returns the resulting Mutable Resource manifest address that you can use to include in an ENS Resolver (setContent) -// or reference future updates (Client.UpdateResource) -func (c *Client) CreateResource(request *mru.Request) (string, error) { - responseStream, err := c.updateResource(request, true) +// CreateFeedWithManifest creates a Feed Manifest, initializing it with the provided +// data +// Returns the resulting Feed Manifest address that you can use to include in an ENS Resolver (setContent) +// or reference future updates (Client.UpdateFeed) +func (c *Client) CreateFeedWithManifest(request *mru.Request) (string, error) { + responseStream, err := c.updateFeed(request, true) if err != nil { return "", err } @@ -628,18 +627,18 @@ func (c *Client) CreateResource(request *mru.Request) (string, error) { return manifestAddress, nil } -// UpdateResource allows you to set a new version of your content -func (c *Client) UpdateResource(request *mru.Request) error { - _, err := c.updateResource(request, false) +// UpdateFeed allows you to set a new version of your content +func (c *Client) UpdateFeed(request *mru.Request) error { + _, err := c.updateFeed(request, false) return err } -func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.ReadCloser, error) { +func (c *Client) updateFeed(request *mru.Request, createManifest bool) (io.ReadCloser, error) { URL, err := url.Parse(c.Gateway) if err != nil { return nil, err } - URL.Path = "/bzz-resource:/" + URL.Path = "/bzz-feed:/" values := URL.Query() body := request.AppendValues(values) if createManifest { @@ -660,23 +659,23 @@ func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.R return res.Body, nil } -// GetResource returns a byte stream with the raw content of the resource -// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver +// QueryFeed returns a byte stream with the raw content of the feed update +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver // points to that address -func (c *Client) GetResource(query *mru.Query, manifestAddressOrDomain string) (io.ReadCloser, error) { - return c.getResource(query, manifestAddressOrDomain, false) +func (c *Client) QueryFeed(query *mru.Query, manifestAddressOrDomain string) (io.ReadCloser, error) { + return c.queryFeed(query, manifestAddressOrDomain, false) } -// getResource returns a byte stream with the raw content of the resource -// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver +// queryFeed returns a byte stream with the raw content of the feed update +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver // points to that address -// meta set to true will instruct the node return resource metainformation instead -func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) { +// meta set to true will instruct the node return Feed metainformation instead +func (c *Client) queryFeed(query *mru.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) { URL, err := url.Parse(c.Gateway) if err != nil { return nil, err } - URL.Path = "/bzz-resource:/" + manifestAddressOrDomain + URL.Path = "/bzz-feed:/" + manifestAddressOrDomain values := URL.Query() if query != nil { query.AppendValues(values) //adds query parameters @@ -692,7 +691,7 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m if res.StatusCode != http.StatusOK { if res.StatusCode == http.StatusNotFound { - return nil, ErrNoResourceUpdatesFound + return nil, ErrNoFeedUpdatesFound } errorMessageBytes, err := ioutil.ReadAll(res.Body) var errorMessage string @@ -701,18 +700,18 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m } else { errorMessage = string(errorMessageBytes) } - return nil, fmt.Errorf("Error retrieving resource: %s", errorMessage) + return nil, fmt.Errorf("Error retrieving feed updates: %s", errorMessage) } return res.Body, nil } -// GetResourceMetadata returns a structure that describes the Mutable Resource -// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver +// GetFeedMetadata returns a structure that describes the referenced Feed status +// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver // points to that address -func (c *Client) GetResourceMetadata(query *mru.Query, manifestAddressOrDomain string) (*mru.Request, error) { +func (c *Client) GetFeedMetadata(query *mru.Query, manifestAddressOrDomain string) (*mru.Request, error) { - responseStream, err := c.getResource(query, manifestAddressOrDomain, true) + responseStream, err := c.queryFeed(query, manifestAddressOrDomain, true) if err != nil { return nil, err } diff --git a/swarm/api/client/client_test.go b/swarm/api/client/client_test.go index c6ad0237b..fbc49a6e1 100644 --- a/swarm/api/client/client_test.go +++ b/swarm/api/client/client_test.go @@ -369,12 +369,12 @@ func newTestSigner() (*mru.GenericSigner, error) { return mru.NewGenericSigner(privKey), nil } -// test the transparent resolving of multihash resource types with bzz:// scheme +// test the transparent resolving of multihash feed updates with bzz:// scheme // -// first upload data, and store the multihash to the resulting manifest in a resource update +// first upload data, and store the multihash to the resulting manifest in a feed update // retrieving the update with the multihash should return the manifest pointing directly to the data // and raw retrieve of that hash should return the data -func TestClientCreateResourceMultihash(t *testing.T) { +func TestClientCreateFeedMultihash(t *testing.T) { signer, _ := newTestSigner() @@ -393,7 +393,7 @@ func TestClientCreateResourceMultihash(t *testing.T) { s := common.FromHex(swarmHash) mh := multihash.ToMultihash(s) - // our mutable resource topic + // our feed topic topic, _ := mru.NewTopic("foo.eth", nil) createRequest := mru.NewFirstRequest(topic) @@ -403,26 +403,26 @@ func TestClientCreateResourceMultihash(t *testing.T) { t.Fatalf("Error signing update: %s", err) } - resourceManifestHash, err := client.CreateResource(createRequest) + feedManifestHash, err := client.CreateFeedWithManifest(createRequest) if err != nil { - t.Fatalf("Error creating resource: %s", err) + t.Fatalf("Error creating feed manifest: %s", err) } - correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd" - if resourceManifestHash != correctManifestAddrHex { - t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash) + correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" + if feedManifestHash != correctManifestAddrHex { + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) } - // Check we get a not found error when trying to get the resource with a made-up manifest - _, err = client.GetResource(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") - if err != ErrNoResourceUpdatesFound { - t.Fatalf("Expected to receive ErrNoResourceUpdatesFound error. Got: %s", err) + // Check we get a not found error when trying to get feed updates with a made-up manifest + _, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + if err != ErrNoFeedUpdatesFound { + t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) } - reader, err := client.GetResource(nil, correctManifestAddrHex) + reader, err := client.QueryFeed(nil, correctManifestAddrHex) if err != nil { - t.Fatalf("Error retrieving resource: %s", err) + t.Fatalf("Error retrieving feed updates: %s", err) } defer reader.Close() gotData, err := ioutil.ReadAll(reader) @@ -435,8 +435,8 @@ func TestClientCreateResourceMultihash(t *testing.T) { } -// TestClientCreateUpdateResource will check that mutable resources can be created and updated via the HTTP client. -func TestClientCreateUpdateResource(t *testing.T) { +// TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client. +func TestClientCreateUpdateFeed(t *testing.T) { signer, _ := newTestSigner() @@ -444,10 +444,10 @@ func TestClientCreateUpdateResource(t *testing.T) { client := NewClient(srv.URL) defer srv.Close() - // set raw data for the resource + // set raw data for the feed update databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") - // our mutable resource name + // our feed topic name topic, _ := mru.NewTopic("El Quijote", nil) createRequest := mru.NewFirstRequest(topic) @@ -456,16 +456,16 @@ func TestClientCreateUpdateResource(t *testing.T) { t.Fatalf("Error signing update: %s", err) } - resourceManifestHash, err := client.CreateResource(createRequest) + feedManifestHash, err := client.CreateFeedWithManifest(createRequest) - correctManifestAddrHex := "fcb8e75f53e480e197c083ad1976d265674d0ce776f2bf359c09c413fb5230b8" - if resourceManifestHash != correctManifestAddrHex { - t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash) + correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882" + if feedManifestHash != correctManifestAddrHex { + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) } - reader, err := client.GetResource(nil, correctManifestAddrHex) + reader, err := client.QueryFeed(nil, correctManifestAddrHex) if err != nil { - t.Fatalf("Error retrieving resource: %s", err) + t.Fatalf("Error retrieving feed updates: %s", err) } defer reader.Close() gotData, err := ioutil.ReadAll(reader) @@ -479,7 +479,7 @@ func TestClientCreateUpdateResource(t *testing.T) { // define different data databytes = []byte("... no ha mucho tiempo que vivĂa un hidalgo de los de lanza en astillero ...") - updateRequest, err := client.GetResourceMetadata(nil, correctManifestAddrHex) + updateRequest, err := client.GetFeedMetadata(nil, correctManifestAddrHex) if err != nil { t.Fatalf("Error retrieving update request template: %s", err) } @@ -489,13 +489,13 @@ func TestClientCreateUpdateResource(t *testing.T) { t.Fatalf("Error signing update: %s", err) } - if err = client.UpdateResource(updateRequest); err != nil { - t.Fatalf("Error updating resource: %s", err) + if err = client.UpdateFeed(updateRequest); err != nil { + t.Fatalf("Error updating feed: %s", err) } - reader, err = client.GetResource(nil, correctManifestAddrHex) + reader, err = client.QueryFeed(nil, correctManifestAddrHex) if err != nil { - t.Fatalf("Error retrieving resource: %s", err) + t.Fatalf("Error retrieving feed updates: %s", err) } defer reader.Close() gotData, err = ioutil.ReadAll(reader) @@ -506,17 +506,17 @@ func TestClientCreateUpdateResource(t *testing.T) { t.Fatalf("Expected: %v, got %v", databytes, gotData) } - // now try retrieving resource without a manifest + // now try retrieving feed updates without a manifest - view := &mru.Feed{ + feed := &mru.Feed{ Topic: topic, User: signer.Address(), } - lookupParams := mru.NewQueryLatest(view, lookup.NoClue) - reader, err = client.GetResource(lookupParams, "") + lookupParams := mru.NewQueryLatest(feed, lookup.NoClue) + reader, err = client.QueryFeed(lookupParams, "") if err != nil { - t.Fatalf("Error retrieving resource: %s", err) + t.Fatalf("Error retrieving feed updates: %s", err) } defer reader.Close() gotData, err = ioutil.ReadAll(reader) diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 4c19dd6df..c5b3b564c 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -31,7 +31,6 @@ import ( "net/http" "os" "path" - "regexp" "strconv" "strings" "time" @@ -145,13 +144,13 @@ func NewServer(api *api.API, corsString string) *Server { defaultMiddlewares..., ), }) - mux.Handle("/bzz-resource:/", methodHandler{ + mux.Handle("/bzz-feed:/", methodHandler{ "GET": Adapt( - http.HandlerFunc(server.HandleGetResource), + http.HandlerFunc(server.HandleGetFeed), defaultMiddlewares..., ), "POST": Adapt( - http.HandlerFunc(server.HandlePostResource), + http.HandlerFunc(server.HandlePostFeed), defaultMiddlewares..., ), }) @@ -458,44 +457,13 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, newKey) } -// Parses a resource update post url to corresponding action -// possible combinations: -// / add multihash update to existing hash -// /raw add raw update to existing hash -// /# create new resource with first update as mulitihash -// /raw/# create new resource with first update raw -func resourcePostMode(path string) (isRaw bool, frequency uint64, err error) { - re, err := regexp.Compile("^(raw)?/?([0-9]+)?$") - if err != nil { - return isRaw, frequency, err - } - m := re.FindAllStringSubmatch(path, 2) - var freqstr = "0" - if len(m) > 0 { - if m[0][1] != "" { - isRaw = true - } - if m[0][2] != "" { - freqstr = m[0][2] - } - } else if len(path) > 0 { - return isRaw, frequency, fmt.Errorf("invalid path") - } - frequency, err = strconv.ParseUint(freqstr, 10, 64) - return isRaw, frequency, err -} - -// Handles creation of new mutable resources and adding updates to existing mutable resources -// There are two types of updates available, "raw" and "multihash." -// If the latter is used, a subsequent bzz:// GET call to the manifest of the resource will return -// the page that the multihash is pointing to, as if it held a normal swarm content manifest -// -// The POST request admits a JSON structure as defined in the mru package: `mru.updateRequestJSON` -// The requests can be to a) create a resource, b) update a resource or c) both a+b: create a resource and set the initial content -func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) { +// Handles feed manifest creation and feed updates +// The POST request admits a JSON structure as defined in the feeds package: `feeds.updateRequestJSON` +// The requests can be to a) create a feed manifest, b) update a feed or c) both a+b: create a feed manifest and publish a first update +func (s *Server) HandlePostFeed(w http.ResponseWriter, r *http.Request) { ruid := GetRUID(r.Context()) uri := GetURI(r.Context()) - log.Debug("handle.post.resource", "ruid", ruid) + log.Debug("handle.post.feed", "ruid", ruid) var err error // Creation and update must send mru.updateRequestJSON JSON structure @@ -505,19 +473,19 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) { return } - view, err := s.api.ResolveResourceView(r.Context(), uri, r.URL.Query()) + feed, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) if err != nil { // couldn't parse query string or retrieve manifest getFail.Inc(1) httpStatus := http.StatusBadRequest - if err == api.ErrCannotLoadResourceManifest || err == api.ErrCannotResolveResourceURI { + if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { httpStatus = http.StatusNotFound } - RespondError(w, r, fmt.Sprintf("cannot retrieve resource view: %s", err), httpStatus) + RespondError(w, r, fmt.Sprintf("cannot retrieve feed from manifest: %s", err), httpStatus) return } var updateRequest mru.Request - updateRequest.Feed = *view + updateRequest.Feed = *feed query := r.URL.Query() if err := updateRequest.FromValues(query, body); err != nil { // decodes request from query parameters @@ -527,13 +495,13 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) { if updateRequest.IsUpdate() { // Verify that the signature is intact and that the signer is authorized - // to update this resource - // Check this early, to avoid creating a resource and then not being able to set its first update. + // to update this feed + // Check this early, to avoid creating a feed and then not being able to set its first update. if err = updateRequest.Verify(); err != nil { RespondError(w, r, err.Error(), http.StatusForbidden) return } - _, err = s.api.ResourceUpdate(r.Context(), &updateRequest) + _, err = s.api.FeedsUpdate(r.Context(), &updateRequest) if err != nil { RespondError(w, r, err.Error(), http.StatusInternalServerError) return @@ -541,16 +509,16 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) { } if query.Get("manifest") == "1" { - // we create a manifest so we can retrieve the resource with bzz:// later - // this manifest has a special "resource type" manifest, and saves the - // resource view ID used to retrieve the resource later - m, err := s.api.NewResourceManifest(r.Context(), &updateRequest.Feed) + // we create a manifest so we can retrieve feed updates with bzz:// later + // this manifest has a special "feed type" manifest, and saves the + // feed identification used to retrieve feed updates later + m, err := s.api.NewFeedManifest(r.Context(), &updateRequest.Feed) if err != nil { - RespondError(w, r, fmt.Sprintf("failed to create resource manifest: %v", err), http.StatusInternalServerError) + RespondError(w, r, fmt.Sprintf("failed to create feed manifest: %v", err), http.StatusInternalServerError) return } // the key to the manifest will be passed back to the client - // the client can access the view directly through its resourceView member + // the client can access the Feed directly through its Feed member // the manifest key can be set as content in the resolver of the ENS name outdata, err := json.Marshal(m) if err != nil { @@ -563,41 +531,49 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) { } } -// Retrieve Swarm Feeds: -// bzz-resource://<id> - get latest update -// bzz-resource://<id>/?period=n - get latest update on period n -// bzz-resource://<id>/?period=n&version=m - get update version m of period n -// bzz-resource://<id>/meta - get metadata and next version information -// <id> = ens name or hash -// TODO: Enable pass maxPeriod parameter -func (s *Server) HandleGetResource(w http.ResponseWriter, r *http.Request) { +// HandleGetFeed retrieves Swarm Feeds updates: +// bzz-feed://<manifest address or ENS name> - get latest feed update, given a manifest address +// - or - +// specify user + topic (optional), subtopic name (optional) directly, without manifest: +// bzz-feed://?user=0x...&topic=0x...&name=subtopic name +// topic defaults to 0x000... if not specified. +// name defaults to empty string if not specified. +// thus, empty name and topic refers to the user's default feed. +// +// Optional parameters: +// time=xx - get the latest update before time (in epoch seconds) +// hint.time=xx - hint the lookup algorithm looking for updates at around that time +// hint.level=xx - hint the lookup algorithm looking for updates at around this frequency level +// meta=1 - get feed metadata and status information instead of performing a feed query +// NOTE: meta=1 will be deprecated in the near future +func (s *Server) HandleGetFeed(w http.ResponseWriter, r *http.Request) { ruid := GetRUID(r.Context()) uri := GetURI(r.Context()) - log.Debug("handle.get.resource", "ruid", ruid) + log.Debug("handle.get.feed", "ruid", ruid) var err error - view, err := s.api.ResolveResourceView(r.Context(), uri, r.URL.Query()) + feed, err := s.api.ResolveFeed(r.Context(), uri, r.URL.Query()) if err != nil { // couldn't parse query string or retrieve manifest getFail.Inc(1) httpStatus := http.StatusBadRequest - if err == api.ErrCannotLoadResourceManifest || err == api.ErrCannotResolveResourceURI { + if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI { httpStatus = http.StatusNotFound } - RespondError(w, r, fmt.Sprintf("cannot retrieve resource view: %s", err), httpStatus) + RespondError(w, r, fmt.Sprintf("cannot retrieve feed information from manifest: %s", err), httpStatus) return } // determine if the query specifies period and version or it is a metadata query if r.URL.Query().Get("meta") == "1" { - unsignedUpdateRequest, err := s.api.ResourceNewRequest(r.Context(), view) + unsignedUpdateRequest, err := s.api.FeedsNewRequest(r.Context(), feed) if err != nil { getFail.Inc(1) - RespondError(w, r, fmt.Sprintf("cannot retrieve resource metadata for view=%s: %s", view.Hex(), err), http.StatusNotFound) + RespondError(w, r, fmt.Sprintf("cannot retrieve feed metadata for feed=%s: %s", feed.Hex(), err), http.StatusNotFound) return } rawResponse, err := unsignedUpdateRequest.MarshalJSON() if err != nil { - RespondError(w, r, fmt.Sprintf("cannot encode unsigned UpdateRequest: %v", err), http.StatusInternalServerError) + RespondError(w, r, fmt.Sprintf("cannot encode unsigned feed update request: %v", err), http.StatusInternalServerError) return } w.Header().Add("Content-type", "application/json") @@ -606,28 +582,28 @@ func (s *Server) HandleGetResource(w http.ResponseWriter, r *http.Request) { return } - lookupParams := &mru.Query{Feed: *view} + lookupParams := &mru.Query{Feed: *feed} if err = lookupParams.FromValues(r.URL.Query()); err != nil { // parse period, version - RespondError(w, r, fmt.Sprintf("invalid mutable resource request:%s", err), http.StatusBadRequest) + RespondError(w, r, fmt.Sprintf("invalid feed update request:%s", err), http.StatusBadRequest) return } - data, err := s.api.ResourceLookup(r.Context(), lookupParams) + data, err := s.api.FeedsLookup(r.Context(), lookupParams) // any error from the switch statement will end up here if err != nil { - code, err2 := s.translateResourceError(w, r, "mutable resource lookup fail", err) + code, err2 := s.translateFeedError(w, r, "feed lookup fail", err) RespondError(w, r, err2.Error(), code) return } // All ok, serve the retrieved update - log.Debug("Found update", "view", view.Hex(), "ruid", ruid) + log.Debug("Found update", "feed", feed.Hex(), "ruid", ruid) w.Header().Set("Content-Type", api.MimeOctetStream) http.ServeContent(w, r, "", time.Now(), bytes.NewReader(data)) } -func (s *Server) translateResourceError(w http.ResponseWriter, r *http.Request, supErr string, err error) (int, error) { +func (s *Server) translateFeedError(w http.ResponseWriter, r *http.Request, supErr string, err error) (int, error) { code := 0 defaultErr := fmt.Errorf("%s: %v", supErr, err) rsrcErr, ok := err.(*mru.Error) diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go index 0855d30a2..a7c7e3003 100644 --- a/swarm/api/http/server_test.go +++ b/swarm/api/http/server_test.go @@ -58,47 +58,6 @@ func init() { log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) } -func TestResourcePostMode(t *testing.T) { - path := "" - errstr := "resourcePostMode for '%s' should be raw %v frequency %d, was raw %v, frequency %d" - r, f, err := resourcePostMode(path) - if err != nil { - t.Fatal(err) - } else if r || f != 0 { - t.Fatalf(errstr, path, false, 0, r, f) - } - - path = "raw" - r, f, err = resourcePostMode(path) - if err != nil { - t.Fatal(err) - } else if !r || f != 0 { - t.Fatalf(errstr, path, true, 0, r, f) - } - - path = "13" - r, f, err = resourcePostMode(path) - if err != nil { - t.Fatal(err) - } else if r || f == 0 { - t.Fatalf(errstr, path, false, 13, r, f) - } - - path = "raw/13" - r, f, err = resourcePostMode(path) - if err != nil { - t.Fatal(err) - } else if !r || f == 0 { - t.Fatalf(errstr, path, true, 13, r, f) - } - - path = "foo/13" - r, f, err = resourcePostMode(path) - if err == nil { - t.Fatal("resourcePostMode for 'foo/13' should fail, returned error nil") - } -} - func serverFunc(api *api.API) testutil.TestServer { return NewServer(api, "") } @@ -111,12 +70,12 @@ func newTestSigner() (*mru.GenericSigner, error) { return mru.NewGenericSigner(privKey), nil } -// test the transparent resolving of multihash resource types with bzz:// scheme +// test the transparent resolving of multihash-containing feed updates with bzz:// scheme // -// first upload data, and store the multihash to the resulting manifest in a resource update +// first upload data, and store the multihash to the resulting manifest in a feed update // retrieving the update with the multihash should return the manifest pointing directly to the data // and raw retrieve of that hash should return the data -func TestBzzResourceMultihash(t *testing.T) { +func TestBzzFeedMultihash(t *testing.T) { signer, _ := newTestSigner() @@ -154,7 +113,7 @@ func TestBzzResourceMultihash(t *testing.T) { } log.Info("added data", "manifest", string(b), "data", common.ToHex(mh)) - testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL)) + testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) if err != nil { t.Fatal(err) } @@ -182,12 +141,12 @@ func TestBzzResourceMultihash(t *testing.T) { t.Fatalf("data %s could not be unmarshaled: %v", b, err) } - correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd" + correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" if rsrcResp.Hex() != correctManifestAddrHex { - t.Fatalf("Response resource key mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) + t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) } - // get bzz manifest transparent resource resolve + // get bzz manifest transparent feed update resolve testBzzUrl = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp) resp, err = http.Get(testBzzUrl) if err != nil { @@ -207,7 +166,7 @@ func TestBzzResourceMultihash(t *testing.T) { } // Test Swarm Feeds using the raw update methods -func TestBzzResource(t *testing.T) { +func TestBzzFeed(t *testing.T) { srv := testutil.NewTestSwarmServer(t, serverFunc, nil) signer, _ := newTestSigner() @@ -234,8 +193,8 @@ func TestBzzResource(t *testing.T) { t.Fatal(err) } - // creates resource and sets update 1 - testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL)) + // creates feed and sets update 1 + testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) if err != nil { t.Fatal(err) } @@ -262,9 +221,9 @@ func TestBzzResource(t *testing.T) { t.Fatalf("data %s could not be unmarshaled: %v", b, err) } - correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd" + correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" if rsrcResp.Hex() != correctManifestAddrHex { - t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) + t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex()) } // get the manifest @@ -289,12 +248,12 @@ func TestBzzResource(t *testing.T) { if len(manifest.Entries) != 1 { t.Fatalf("Manifest has %d entries", len(manifest.Entries)) } - correctViewHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d" - if manifest.Entries[0].ResourceView.Hex() != correctViewHex { - t.Fatalf("Expected manifest Resource View '%s', got '%s'", correctViewHex, manifest.Entries[0].ResourceView.Hex()) + correctFeedHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d" + if manifest.Entries[0].Feed.Hex() != correctFeedHex { + t.Fatalf("Expected manifest Feed '%s', got '%s'", correctFeedHex, manifest.Entries[0].Feed.Hex()) } - // get bzz manifest transparent resource resolve + // get bzz manifest transparent feed update resolve testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp) resp, err = http.Get(testBzzUrl) if err != nil { @@ -302,7 +261,7 @@ func TestBzzResource(t *testing.T) { } defer resp.Body.Close() if resp.StatusCode == http.StatusOK { - t.Fatal("Expected error status since resource is not multihash. Received 200 OK") + t.Fatal("Expected error status since feed update does not contain multihash. Received 200 OK") } b, err = ioutil.ReadAll(resp.Body) if err != nil { @@ -310,21 +269,21 @@ func TestBzzResource(t *testing.T) { } // get non-existent name, should fail - testBzzResUrl := fmt.Sprintf("%s/bzz-resource:/bar", srv.URL) + testBzzResUrl := fmt.Sprintf("%s/bzz-feed:/bar", srv.URL) resp, err = http.Get(testBzzResUrl) if err != nil { t.Fatal(err) } if resp.StatusCode != http.StatusNotFound { - t.Fatalf("Expected get non-existent resource to fail with StatusNotFound (404), got %d", resp.StatusCode) + t.Fatalf("Expected get non-existent feed manifest to fail with StatusNotFound (404), got %d", resp.StatusCode) } resp.Body.Close() - // get latest update (1.1) through resource directly + // get latest update through bzz-feed directly log.Info("get update latest = 1.1", "addr", correctManifestAddrHex) - testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex) + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) resp, err = http.Get(testBzzResUrl) if err != nil { t.Fatal(err) @@ -346,15 +305,15 @@ func TestBzzResource(t *testing.T) { srv.CurrentTime++ log.Info("update 2") - // 1.- get metadata about this resource - testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s/", srv.URL, correctManifestAddrHex) + // 1.- get metadata about this Feed + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s/", srv.URL, correctManifestAddrHex) resp, err = http.Get(testBzzResUrl + "?meta=1") if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - t.Fatalf("Get resource metadata returned %s", resp.Status) + t.Fatalf("Get feed metadata returned %s", resp.Status) } b, err = ioutil.ReadAll(resp.Body) if err != nil { @@ -362,13 +321,13 @@ func TestBzzResource(t *testing.T) { } updateRequest = &mru.Request{} if err = updateRequest.UnmarshalJSON(b); err != nil { - t.Fatalf("Error decoding resource metadata: %s", err) + t.Fatalf("Error decoding feed metadata: %s", err) } updateRequest.SetData(update2Data) if err = updateRequest.Sign(signer); err != nil { t.Fatal(err) } - testUrl, err = url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL)) + testUrl, err = url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) if err != nil { t.Fatal(err) } @@ -385,9 +344,9 @@ func TestBzzResource(t *testing.T) { t.Fatalf("Update returned %s", resp.Status) } - // get latest update (1.2) through resource directly + // get latest update through bzz-feed directly log.Info("get update 1.2") - testBzzResUrl = fmt.Sprintf("%s/bzz-resource:/%s", srv.URL, correctManifestAddrHex) + testBzzResUrl = fmt.Sprintf("%s/bzz-feed:/%s", srv.URL, correctManifestAddrHex) resp, err = http.Get(testBzzResUrl) if err != nil { t.Fatal(err) @@ -408,13 +367,13 @@ func TestBzzResource(t *testing.T) { log.Info("get first update in update1Timestamp via direct query") query := mru.NewQuery(&updateRequest.Feed, update1Timestamp, lookup.NoClue) - urlq, err := url.Parse(fmt.Sprintf("%s/bzz-resource:/", srv.URL)) + urlq, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL)) if err != nil { t.Fatal(err) } values := urlq.Query() - query.AppendValues(values) // this adds view query parameters + query.AppendValues(values) // this adds feed query parameters urlq.RawQuery = values.Encode() resp, err = http.Get(urlq.String()) if err != nil { diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go index 9672ca540..f41a823bd 100644 --- a/swarm/api/manifest.go +++ b/swarm/api/manifest.go @@ -35,8 +35,8 @@ import ( ) const ( - ManifestType = "application/bzz-manifest+json" - ResourceContentType = "application/bzz-resource" + ManifestType = "application/bzz-manifest+json" + FeedContentType = "application/bzz-feed" manifestSizeLimit = 5 * 1024 * 1024 ) @@ -48,15 +48,15 @@ type Manifest struct { // ManifestEntry represents an entry in a swarm manifest type ManifestEntry struct { - Hash string `json:"hash,omitempty"` - Path string `json:"path,omitempty"` - ContentType string `json:"contentType,omitempty"` - Mode int64 `json:"mode,omitempty"` - Size int64 `json:"size,omitempty"` - ModTime time.Time `json:"mod_time,omitempty"` - Status int `json:"status,omitempty"` - Access *AccessEntry `json:"access,omitempty"` - ResourceView *mru.Feed `json:"resourceView,omitempty"` + Hash string `json:"hash,omitempty"` + Path string `json:"path,omitempty"` + ContentType string `json:"contentType,omitempty"` + Mode int64 `json:"mode,omitempty"` + Size int64 `json:"size,omitempty"` + ModTime time.Time `json:"mod_time,omitempty"` + Status int `json:"status,omitempty"` + Access *AccessEntry `json:"access,omitempty"` + Feed *mru.Feed `json:"feed,omitempty"` } // ManifestList represents the result of listing files in a manifest @@ -80,13 +80,13 @@ func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, return addr, err } -// Manifest hack for supporting Mutable Resource Updates from the bzz: scheme +// Manifest hack for supporting Feeds from the bzz: scheme // see swarm/api/api.go:API.Get() for more information -func (a *API) NewResourceManifest(ctx context.Context, view *mru.Feed) (storage.Address, error) { +func (a *API) NewFeedManifest(ctx context.Context, feed *mru.Feed) (storage.Address, error) { var manifest Manifest entry := ManifestEntry{ - ResourceView: view, - ContentType: ResourceContentType, + Feed: feed, + ContentType: FeedContentType, } manifest.Entries = append(manifest.Entries, entry) data, err := json.Marshal(&manifest) diff --git a/swarm/api/uri.go b/swarm/api/uri.go index 808517088..09cfa4502 100644 --- a/swarm/api/uri.go +++ b/swarm/api/uri.go @@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) { // check the scheme is valid switch uri.Scheme { - case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-resource": + case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed": default: return nil, fmt.Errorf("unknown scheme %q", u.Scheme) } @@ -108,8 +108,8 @@ func Parse(rawuri string) (*URI, error) { } return uri, nil } -func (u *URI) Resource() bool { - return u.Scheme == "bzz-resource" +func (u *URI) Feed() bool { + return u.Scheme == "bzz-feed" } func (u *URI) Raw() bool { diff --git a/swarm/network/README.md b/swarm/network/README.md index 0955fe94e..33d215c4b 100644 --- a/swarm/network/README.md +++ b/swarm/network/README.md @@ -57,7 +57,7 @@ receipts for a deleted chunk easily to refute their challenge. - syncing should be resilient to cut connections, metadata should be persisted that keep track of syncing state across sessions, historical syncing state should survive restart - extra data structures to support syncing should be kept at minimum -- syncing is organized separately for chunk types (resource update v content chunk) +- syncing is organized separately for chunk types (Swarm Feed Updates v regular content chunk) - various types of streams should have common logic abstracted Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention. diff --git a/swarm/storage/localstore_test.go b/swarm/storage/localstore_test.go index 814d270d3..b8eea4350 100644 --- a/swarm/storage/localstore_test.go +++ b/swarm/storage/localstore_test.go @@ -30,8 +30,8 @@ var ( ) // tests that the content address validator correctly checks the data -// tests that resource update chunks are passed through content address validator -// the test checking the resouce update validator internal correctness is found in resource_test.go +// tests that Feed update chunks are passed through content address validator +// the test checking the resouce update validator internal correctness is found in storage/feeds/handler_test.go func TestValidator(t *testing.T) { // set up localstore datadir, err := ioutil.TempDir("", "storage-testvalidator") diff --git a/swarm/storage/mru/doc.go b/swarm/storage/mru/doc.go index 2cf2d3757..7ffd4a3c6 100644 --- a/swarm/storage/mru/doc.go +++ b/swarm/storage/mru/doc.go @@ -26,7 +26,7 @@ The Feed Update data is: updatedata = Feed|Epoch|data The full update data that goes in the chunk payload is: -resourcedata|sign(resourcedata) +updatedata|sign(updatedata) Structure Summary: diff --git a/swarm/storage/mru/error.go b/swarm/storage/mru/error.go index 714426449..452cc80f0 100644 --- a/swarm/storage/mru/error.go +++ b/swarm/storage/mru/error.go @@ -35,7 +35,7 @@ const ( ErrCnt ) -// Error is a the typed error object used for Mutable Resources +// Error is a the typed error object used for Swarm Feeds type Error struct { code int err string diff --git a/swarm/storage/mru/handler.go b/swarm/storage/mru/handler.go index 3ddeaafae..cc0da7df9 100644 --- a/swarm/storage/mru/handler.go +++ b/swarm/storage/mru/handler.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -// Handler is the API for Mutable Resources -// It enables creating, updating, syncing and retrieving resources and their update data +// Handler is the API for Feeds +// It enables creating, updating, syncing and retrieving feed updates and their data package mru import ( @@ -265,7 +265,7 @@ func (h *Handler) Update(ctx context.Context, r *Request) (updateAddr storage.Ad // send the chunk h.chunkStore.Put(ctx, chunk) log.Trace("feed update", "updateAddr", r.idAddr, "epoch time", r.Epoch.Time, "epoch level", r.Epoch.Level, "data", chunk.Data()) - // update our resources map cache entry if the new update is older than the one we have, if we have it. + // update our feed updates map cache entry if the new update is older than the one we have, if we have it. if feedUpdate != nil && r.Epoch.After(feedUpdate.Epoch) { feedUpdate.Epoch = r.Epoch feedUpdate.data = make([]byte, len(r.data)) diff --git a/swarm/storage/mru/handler_test.go b/swarm/storage/mru/handler_test.go index 3bf2bda8b..b66ff0c80 100644 --- a/swarm/storage/mru/handler_test.go +++ b/swarm/storage/mru/handler_test.go @@ -396,7 +396,7 @@ func TestValidatorInStore(t *testing.T) { signer := newAliceSigner() // set up localstore - datadir, err := ioutil.TempDir("", "storage-testresourcevalidator") + datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator") if err != nil { t.Fatal(err) } @@ -463,7 +463,7 @@ func TestValidatorInStore(t *testing.T) { } } -// create rpc and resourcehandler +// create rpc and Feeds Handler func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) { var fsClean func() diff --git a/swarm/storage/mru/request_test.go b/swarm/storage/mru/request_test.go index 33e975756..515de651c 100644 --- a/swarm/storage/mru/request_test.go +++ b/swarm/storage/mru/request_test.go @@ -228,7 +228,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) { var recovered Request recovered.fromChunk(chunk.Address(), chunk.Data()) if !reflect.DeepEqual(recovered, r) { - t.Fatal("Expected recovered SignedResource update to equal the original one") + t.Fatal("Expected recovered Request update to equal the original one") } } @@ -248,7 +248,7 @@ func TestReverse(t *testing.T) { // signer containing private key signer := newAliceSigner() - // set up rpc and create resourcehandler + // set up rpc and create Feeds handler _, _, teardownTest, err := setupTest(timeProvider, signer) if err != nil { t.Fatal(err) diff --git a/swarm/swarm.go b/swarm/swarm.go index 0cd56d4eb..4d9bf724f 100644 --- a/swarm/swarm.go +++ b/swarm/swarm.go @@ -186,15 +186,15 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams) - var resourceHandler *mru.Handler - rhparams := &mru.HandlerParams{} + var feedsHandler *mru.Handler + fhParams := &mru.HandlerParams{} - resourceHandler = mru.NewHandler(rhparams) - resourceHandler.SetStore(self.netStore) + feedsHandler = mru.NewHandler(fhParams) + feedsHandler.SetStore(self.netStore) lstore.Validators = []storage.ChunkValidator{ storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)), - resourceHandler, + feedsHandler, } log.Debug("Setup local storage") @@ -210,7 +210,7 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e pss.SetHandshakeController(self.ps, pss.NewHandshakeParams()) } - self.api = api.NewAPI(self.fileStore, self.dns, resourceHandler, self.privateKey) + self.api = api.NewAPI(self.fileStore, self.dns, feedsHandler, self.privateKey) self.sfs = fuse.NewSwarmFS(self.api) log.Debug("Initialized FUSE filesystem") diff --git a/swarm/testutil/http.go b/swarm/testutil/http.go index 2309c39f0..2162da880 100644 --- a/swarm/testutil/http.go +++ b/swarm/testutil/http.go @@ -48,14 +48,14 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso } fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams()) - // mutable resources test setup - resourceDir, err := ioutil.TempDir("", "swarm-resource-test") + // Swarm Feeds test setup + feedsDir, err := ioutil.TempDir("", "swarm-feeds-test") if err != nil { t.Fatal(err) } rhparams := &mru.HandlerParams{} - rh, err := mru.NewTestHandler(resourceDir, rhparams) + rh, err := mru.NewTestHandler(feedsDir, rhparams) if err != nil { t.Fatal(err) } @@ -71,7 +71,7 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso srv.Close() rh.Close() os.RemoveAll(dir) - os.RemoveAll(resourceDir) + os.RemoveAll(feedsDir) }, CurrentTime: 42, } |