swarm/storage/mru: Renamed rest of MRU references
This commit is contained in:
parent
b35622cf3c
commit
83705ef6aa
@ -207,25 +207,25 @@ var (
|
|||||||
Name: "compressed",
|
Name: "compressed",
|
||||||
Usage: "Prints encryption keys in compressed form",
|
Usage: "Prints encryption keys in compressed form",
|
||||||
}
|
}
|
||||||
SwarmResourceNameFlag = cli.StringFlag{
|
SwarmFeedNameFlag = cli.StringFlag{
|
||||||
Name: "name",
|
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",
|
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",
|
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",
|
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",
|
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,
|
CustomHelpTemplate: helpTemplate,
|
||||||
Name: "resource",
|
Name: "feed",
|
||||||
Usage: "(Advanced) Create and update Mutable Resources",
|
Usage: "(Advanced) Create and update Swarm Feeds",
|
||||||
ArgsUsage: "<create|update|info>",
|
ArgsUsage: "<create|update|info>",
|
||||||
Description: "Works with Mutable Resource Updates",
|
Description: "Works with Swarm Feeds",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []cli.Command{
|
||||||
{
|
{
|
||||||
Action: resourceCreate,
|
Action: feedCreateManifest,
|
||||||
CustomHelpTemplate: helpTemplate,
|
CustomHelpTemplate: helpTemplate,
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "creates and publishes a new Mutable Resource manifest",
|
Usage: "creates and publishes a new Feed manifest",
|
||||||
Description: `creates and publishes a new Mutable Resource manifest pointing to a specified user's updates about a particular topic.
|
Description: `creates and publishes a new Feed manifest pointing to a specified user's updates about a particular 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 --topic to set the topic to an arbitrary binary hex string.
|
||||||
* use --name to set the topic to a human-readable name.
|
* 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.
|
* 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
|
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,
|
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)`,
|
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,
|
CustomHelpTemplate: helpTemplate,
|
||||||
Name: "update",
|
Name: "update",
|
||||||
Usage: "updates the content of an existing Mutable Resource",
|
Usage: "updates the content of an existing Swarm Feed",
|
||||||
ArgsUsage: "<0x Hex data>",
|
ArgsUsage: "<0x Hex data>",
|
||||||
Description: `publishes a new update on the specified topic
|
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 --topic to set the topic to an arbitrary binary hex string.
|
||||||
* use --name to set the topic to a human-readable name.
|
* 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.
|
* 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
|
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
|
instead of using --topic / --name
|
||||||
`,
|
`,
|
||||||
Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag},
|
Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: resourceInfo,
|
Action: feedInfo,
|
||||||
CustomHelpTemplate: helpTemplate,
|
CustomHelpTemplate: helpTemplate,
|
||||||
Name: "info",
|
Name: "info",
|
||||||
Usage: "obtains information about an existing Mutable Resource",
|
Usage: "obtains information about an existing Swarm Feed",
|
||||||
Description: `obtains information about an existing Mutable Resource
|
Description: `obtains information about an existing Swarm Feed
|
||||||
The topic can be specified directly with the --topic flag as an hex string
|
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
|
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 --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,
|
The --user flag allows to refer to a user other than yourself. If not specified,
|
||||||
it will then default to your local account (--bzzaccount)
|
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
|
If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user
|
||||||
to refer to the resource`,
|
to refer to the feed`,
|
||||||
Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag, SwarmResourceUserFlag},
|
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
|
// 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 {
|
func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
|
||||||
// booting up the swarm node just as we do in bzzd action
|
// booting up the swarm node just as we do in bzzd action
|
||||||
bzzconfig, err := buildConfig(ctx)
|
bzzconfig, err := buildConfig(ctx)
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -36,8 +36,8 @@ func NewGenericSigner(ctx *cli.Context) mru.Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getTopic(ctx *cli.Context) (topic mru.Topic) {
|
func getTopic(ctx *cli.Context) (topic mru.Topic) {
|
||||||
var name = ctx.String(SwarmResourceNameFlag.Name)
|
var name = ctx.String(SwarmFeedNameFlag.Name)
|
||||||
var relatedTopic = ctx.String(SwarmResourceTopicFlag.Name)
|
var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name)
|
||||||
var relatedTopicBytes []byte
|
var relatedTopicBytes []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -55,35 +55,35 @@ func getTopic(ctx *cli.Context) (topic mru.Topic) {
|
|||||||
return topic
|
return topic
|
||||||
}
|
}
|
||||||
|
|
||||||
// swarm resource create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
|
// swarm feed create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
|
||||||
// swarm resource update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
|
// swarm feed update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
|
||||||
// swarm resource info <Manifest Address or ENS domain>
|
// swarm feed info <Manifest Address or ENS domain>
|
||||||
|
|
||||||
func resourceCreate(ctx *cli.Context) {
|
func feedCreateManifest(ctx *cli.Context) {
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = swarm.NewClient(bzzapi)
|
client = swarm.NewClient(bzzapi)
|
||||||
)
|
)
|
||||||
|
|
||||||
newResourceRequest := mru.NewFirstRequest(getTopic(ctx))
|
newFeedUpdateRequest := mru.NewFirstRequest(getTopic(ctx))
|
||||||
newResourceRequest.Feed.User = resourceGetUser(ctx)
|
newFeedUpdateRequest.Feed.User = feedGetUser(ctx)
|
||||||
|
|
||||||
manifestAddress, err := client.CreateResource(newResourceRequest)
|
manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error creating resource: %s", err.Error())
|
utils.Fatalf("Error creating feed manifest: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
|
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()
|
args := ctx.Args()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = swarm.NewClient(bzzapi)
|
client = swarm.NewClient(bzzapi)
|
||||||
manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name)
|
manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
@ -110,10 +110,10 @@ func resourceUpdate(ctx *cli.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve resource status and metadata out of the manifest
|
// Retrieve feed status and metadata out of the manifest
|
||||||
updateRequest, err = client.GetResourceMetadata(query, manifestAddressOrDomain)
|
updateRequest, err = client.GetFeedMetadata(query, manifestAddressOrDomain)
|
||||||
if err != nil {
|
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
|
// set the new data
|
||||||
@ -121,34 +121,34 @@ func resourceUpdate(ctx *cli.Context) {
|
|||||||
|
|
||||||
// sign update
|
// sign update
|
||||||
if err = updateRequest.Sign(signer); err != nil {
|
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
|
// post update
|
||||||
err = client.UpdateResource(updateRequest)
|
err = client.UpdateFeed(updateRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Error updating resource: %s", err.Error())
|
utils.Fatalf("Error updating feed: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceInfo(ctx *cli.Context) {
|
func feedInfo(ctx *cli.Context) {
|
||||||
var (
|
var (
|
||||||
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
client = swarm.NewClient(bzzapi)
|
client = swarm.NewClient(bzzapi)
|
||||||
manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name)
|
manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
|
||||||
)
|
)
|
||||||
|
|
||||||
var query *mru.Query
|
var query *mru.Query
|
||||||
if manifestAddressOrDomain == "" {
|
if manifestAddressOrDomain == "" {
|
||||||
query = new(mru.Query)
|
query = new(mru.Query)
|
||||||
query.Topic = getTopic(ctx)
|
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 {
|
if err != nil {
|
||||||
utils.Fatalf("Error retrieving resource metadata: %s", err.Error())
|
utils.Fatalf("Error retrieving feed metadata: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
encodedMetadata, err := metadata.MarshalJSON()
|
encodedMetadata, err := metadata.MarshalJSON()
|
||||||
@ -158,8 +158,8 @@ func resourceInfo(ctx *cli.Context) {
|
|||||||
fmt.Println(string(encodedMetadata))
|
fmt.Println(string(encodedMetadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceGetUser(ctx *cli.Context) common.Address {
|
func feedGetUser(ctx *cli.Context) common.Address {
|
||||||
var user = ctx.String(SwarmResourceUserFlag.Name)
|
var user = ctx.String(SwarmFeedUserFlag.Name)
|
||||||
if user != "" {
|
if user != "" {
|
||||||
return common.HexToAddress(user)
|
return common.HexToAddress(user)
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,12 @@ import (
|
|||||||
swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
|
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 {
|
srv := testutil.NewTestSwarmServer(t, func(api *api.API) testutil.TestServer {
|
||||||
return swarmhttp.NewServer(api, "")
|
return swarmhttp.NewServer(api, "")
|
||||||
}, nil)
|
}, nil)
|
||||||
log.Info("starting 1 node cluster")
|
log.Info("starting a test swarm server")
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
|
|
||||||
// create a private key file for signing
|
// create a private key file for signing
|
||||||
@ -77,13 +77,13 @@ func TestCLIResourceUpdate(t *testing.T) {
|
|||||||
flags := []string{
|
flags := []string{
|
||||||
"--bzzapi", srv.URL,
|
"--bzzapi", srv.URL,
|
||||||
"--bzzaccount", pkfile.Name(),
|
"--bzzaccount", pkfile.Name(),
|
||||||
"resource", "update",
|
"feed", "update",
|
||||||
"--topic", topic.Hex(),
|
"--topic", topic.Hex(),
|
||||||
"--name", name,
|
"--name", name,
|
||||||
hexData}
|
hexData}
|
||||||
|
|
||||||
// create an update and expect an exit without errors
|
// 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 := runSwarm(t, flags...)
|
||||||
cmd.ExpectExit()
|
cmd.ExpectExit()
|
||||||
|
|
||||||
@ -100,17 +100,17 @@ func TestCLIResourceUpdate(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// View configures whose updates we will be looking up.
|
// Feed configures whose updates we will be looking up.
|
||||||
view := mru.Feed{
|
feed := mru.Feed{
|
||||||
Topic: topic,
|
Topic: topic,
|
||||||
User: address,
|
User: address,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a query to get the latest update
|
// Build a query to get the latest update
|
||||||
query := mru.NewQueryLatest(&view, lookup.NoClue)
|
query := mru.NewQueryLatest(&feed, lookup.NoClue)
|
||||||
|
|
||||||
// retrieve content!
|
// retrieve content!
|
||||||
reader, err := client.GetResource(query, "")
|
reader, err := client.QueryFeed(query, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -128,12 +128,12 @@ func TestCLIResourceUpdate(t *testing.T) {
|
|||||||
// Now retrieve info for the next update
|
// Now retrieve info for the next update
|
||||||
flags = []string{
|
flags = []string{
|
||||||
"--bzzapi", srv.URL,
|
"--bzzapi", srv.URL,
|
||||||
"resource", "info",
|
"feed", "info",
|
||||||
"--topic", topic.Hex(),
|
"--topic", topic.Hex(),
|
||||||
"--user", address.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...)
|
cmd = runSwarm(t, flags...)
|
||||||
_, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout
|
_, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout
|
||||||
cmd.ExpectExit()
|
cmd.ExpectExit()
|
||||||
@ -145,28 +145,28 @@ func TestCLIResourceUpdate(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the retrieved view is the same
|
// make sure the retrieved Feed is the same
|
||||||
if request.Feed != view {
|
if request.Feed != feed {
|
||||||
t.Fatalf("Expected view to be: %s, got %s", view, request.Feed)
|
t.Fatalf("Expected feed to be: %s, got %s", feed, request.Feed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test publishing a manifest
|
// test publishing a manifest
|
||||||
flags = []string{
|
flags = []string{
|
||||||
"--bzzapi", srv.URL,
|
"--bzzapi", srv.URL,
|
||||||
"--bzzaccount", pkfile.Name(),
|
"--bzzaccount", pkfile.Name(),
|
||||||
"resource", "create",
|
"feed", "create",
|
||||||
"--topic", topic.Hex(),
|
"--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...)
|
cmd = runSwarm(t, flags...)
|
||||||
_, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout
|
_, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout
|
||||||
cmd.ExpectExit()
|
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
|
// 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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
113
swarm/api/api.go
113
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
|
it is the public interface of the FileStore which is included in the ethereum stack
|
||||||
*/
|
*/
|
||||||
type API struct {
|
type API struct {
|
||||||
resource *mru.Handler
|
feeds *mru.Handler
|
||||||
fileStore *storage.FileStore
|
fileStore *storage.FileStore
|
||||||
dns Resolver
|
dns Resolver
|
||||||
Decryptor func(context.Context, string) DecryptFunc
|
Decryptor func(context.Context, string) DecryptFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAPI the api constructor initialises a new API instance.
|
// 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{
|
self = &API{
|
||||||
fileStore: fileStore,
|
fileStore: fileStore,
|
||||||
dns: dns,
|
dns: dns,
|
||||||
resource: resourceHandler,
|
feeds: feedsHandler,
|
||||||
Decryptor: func(ctx context.Context, credentials string) DecryptFunc {
|
Decryptor: func(ctx context.Context, credentials string) DecryptFunc {
|
||||||
return self.doDecrypt(ctx, credentials, pk)
|
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)
|
return a.Get(ctx, decrypt, adr, entry.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to do some extra work if this is a mutable resource manifest
|
// we need to do some extra work if this is a Feed manifest
|
||||||
if entry.ContentType == ResourceContentType {
|
if entry.ContentType == FeedContentType {
|
||||||
if entry.ResourceView == nil {
|
if entry.Feed == nil {
|
||||||
return reader, mimeType, status, nil, fmt.Errorf("Cannot decode ResourceView in manifest")
|
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 {
|
if err != nil {
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
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
|
return reader, mimeType, status, nil, err
|
||||||
}
|
}
|
||||||
// get the data of the update
|
// get the data of the update
|
||||||
_, rsrcData, err := a.resource.GetContent(entry.ResourceView)
|
_, rsrcData, err := a.feeds.GetContent(entry.Feed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
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
|
return reader, mimeType, status, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,18 +429,18 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
apiGetInvalid.Inc(1)
|
apiGetInvalid.Inc(1)
|
||||||
status = http.StatusUnprocessableEntity
|
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
|
return reader, mimeType, status, nil, err
|
||||||
}
|
}
|
||||||
manifestAddr = storage.Address(decodedMultihash)
|
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
|
// get the manifest the multihash digest points to
|
||||||
trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt)
|
trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
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
|
return reader, mimeType, status, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,13 +450,13 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
|
|||||||
if entry == nil {
|
if entry == nil {
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
err = fmt.Errorf("manifest (resource multihash) entry for '%s' not found", path)
|
err = fmt.Errorf("manifest (feed update multihash) entry for '%s' not found", path)
|
||||||
log.Trace("manifest (resource multihash) entry not found", "key", manifestAddr, "path", path)
|
log.Trace("manifest (feed update multihash) entry not found", "key", manifestAddr, "path", path)
|
||||||
return reader, mimeType, status, nil, err
|
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
|
// get the key the manifest entry points to and serve it if it's unambiguous
|
||||||
contentAddr = common.Hex2Bytes(entry.Hash)
|
contentAddr = common.Hex2Bytes(entry.Hash)
|
||||||
status = entry.Status
|
status = entry.Status
|
||||||
@ -956,68 +956,67 @@ func (a *API) BuildDirectoryTree(ctx context.Context, mhash string, nameresolver
|
|||||||
return addr, manifestEntryMap, nil
|
return addr, manifestEntryMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceLookup finds Swarm Feeds at specific periods and versions
|
// FeedsLookup finds Swarm Feeds Updates at specific points in time, or the latest update
|
||||||
func (a *API) ResourceLookup(ctx context.Context, query *mru.Query) ([]byte, error) {
|
func (a *API) FeedsLookup(ctx context.Context, query *mru.Query) ([]byte, error) {
|
||||||
_, err := a.resource.Lookup(ctx, query)
|
_, err := a.feeds.Lookup(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var data []byte
|
var data []byte
|
||||||
_, data, err = a.resource.GetContent(&query.Feed)
|
_, data, err = a.feeds.GetContent(&query.Feed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceNewRequest creates a Request object to update a specific mutable resource
|
// FeedsNewRequest creates a Request object to update a specific Feed
|
||||||
func (a *API) ResourceNewRequest(ctx context.Context, view *mru.Feed) (*mru.Request, error) {
|
func (a *API) FeedsNewRequest(ctx context.Context, feed *mru.Feed) (*mru.Request, error) {
|
||||||
return a.resource.NewRequest(ctx, view)
|
return a.feeds.NewRequest(ctx, feed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceUpdate updates a Mutable Resource with arbitrary data.
|
// FeedsUpdate publishes a new update on the given Feed
|
||||||
// Upon retrieval the update will be retrieved verbatim as bytes.
|
func (a *API) FeedsUpdate(ctx context.Context, request *mru.Request) (storage.Address, error) {
|
||||||
func (a *API) ResourceUpdate(ctx context.Context, request *mru.Request) (storage.Address, error) {
|
return a.feeds.Update(ctx, request)
|
||||||
return a.resource.Update(ctx, request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceHashSize returned the size of the digest produced by the Mutable Resource hashing function
|
// FeedsHashSize returned the size of the digest produced by Swarm Feeds' hashing function
|
||||||
func (a *API) ResourceHashSize() int {
|
func (a *API) FeedsHashSize() int {
|
||||||
return a.resource.HashSize
|
return a.feeds.HashSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrCannotLoadResourceManifest is returned when looking up a resource manifest fails
|
// ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails
|
||||||
var ErrCannotLoadResourceManifest = errors.New("Cannot load resource manifest")
|
var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest")
|
||||||
|
|
||||||
// ErrNotAResourceManifest is returned when the address provided returned something other than a valid manifest
|
// ErrNotAFeedManifest is returned when the address provided returned something other than a valid manifest
|
||||||
var ErrNotAResourceManifest = errors.New("Not a resource 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.
|
// ResolveFeedManifest retrieves the Feed manifest for the given address, and returns the referenced Feed.
|
||||||
func (a *API) ResolveResourceManifest(ctx context.Context, addr storage.Address) (*mru.Feed, error) {
|
func (a *API) ResolveFeedManifest(ctx context.Context, addr storage.Address) (*mru.Feed, error) {
|
||||||
trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt)
|
trie, err := loadManifest(ctx, a.fileStore, addr, nil, NOOPDecrypt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrCannotLoadResourceManifest
|
return nil, ErrCannotLoadFeedManifest
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, _ := trie.getEntry("")
|
entry, _ := trie.getEntry("")
|
||||||
if entry.ContentType != ResourceContentType {
|
if entry.ContentType != FeedContentType {
|
||||||
return nil, ErrNotAResourceManifest
|
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
|
// ErrCannotResolveFeedURI is returned when the ENS resolver is not able to translate a name to a Feed
|
||||||
var ErrCannotResolveResourceURI = errors.New("Cannot resolve Resource URI")
|
var ErrCannotResolveFeedURI = errors.New("Cannot resolve Feed URI")
|
||||||
|
|
||||||
// ErrCannotResolveResourceView is returned when values provided are not enough or invalid to recreate a
|
// ErrCannotResolveFeed is returned when values provided are not enough or invalid to recreate a
|
||||||
// resource view out of them.
|
// Feed out of them.
|
||||||
var ErrCannotResolveResourceView = errors.New("Cannot resolve resource view")
|
var ErrCannotResolveFeed = errors.New("Cannot resolve Feed")
|
||||||
|
|
||||||
// ResolveResourceView attempts to extract View information out of the manifest, if provided
|
// ResolveFeed attempts to extract Feed information out of the manifest, if provided
|
||||||
// If not, it attempts to extract the View out of a set of key-value pairs
|
// If not, it attempts to extract the Feed out of a set of key-value pairs
|
||||||
func (a *API) ResolveResourceView(ctx context.Context, uri *URI, values mru.Values) (*mru.Feed, error) {
|
func (a *API) ResolveFeed(ctx context.Context, uri *URI, values mru.Values) (*mru.Feed, error) {
|
||||||
var view *mru.Feed
|
var feed *mru.Feed
|
||||||
var err error
|
var err error
|
||||||
if uri.Addr != "" {
|
if uri.Addr != "" {
|
||||||
// resolve the content key.
|
// resolve the content key.
|
||||||
@ -1025,25 +1024,25 @@ func (a *API) ResolveResourceView(ctx context.Context, uri *URI, values mru.Valu
|
|||||||
if manifestAddr == nil {
|
if manifestAddr == nil {
|
||||||
manifestAddr, err = a.Resolve(ctx, uri.Addr)
|
manifestAddr, err = a.Resolve(ctx, uri.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrCannotResolveResourceURI
|
return nil, ErrCannotResolveFeedURI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the resource view from the manifest
|
// get the Feed from the manifest
|
||||||
view, err = a.ResolveResourceManifest(ctx, manifestAddr)
|
feed, err = a.ResolveFeedManifest(ctx, manifestAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
} else {
|
||||||
var v mru.Feed
|
var v mru.Feed
|
||||||
if err := v.FromValues(values); err != nil {
|
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
|
// MimeOctetStream default value of http Content-Type header
|
||||||
|
@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error)
|
|||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNoResourceUpdatesFound is returned when Swarm cannot find updates of the given resource
|
// ErrNoFeedUpdatesFound is returned when Swarm cannot find updates of the given feed
|
||||||
var ErrNoResourceUpdatesFound = errors.New("No updates found for this resource")
|
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
|
// CreateFeedWithManifest creates a Feed Manifest, initializing it with the provided
|
||||||
// data. Data is interpreted as multihash or not depending on the multihash parameter.
|
// data
|
||||||
// startTime=0 means "now"
|
// Returns the resulting Feed Manifest address that you can use to include in an ENS Resolver (setContent)
|
||||||
// Returns the resulting Mutable Resource manifest address that you can use to include in an ENS Resolver (setContent)
|
// or reference future updates (Client.UpdateFeed)
|
||||||
// or reference future updates (Client.UpdateResource)
|
func (c *Client) CreateFeedWithManifest(request *mru.Request) (string, error) {
|
||||||
func (c *Client) CreateResource(request *mru.Request) (string, error) {
|
responseStream, err := c.updateFeed(request, true)
|
||||||
responseStream, err := c.updateResource(request, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -628,18 +627,18 @@ func (c *Client) CreateResource(request *mru.Request) (string, error) {
|
|||||||
return manifestAddress, nil
|
return manifestAddress, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateResource allows you to set a new version of your content
|
// UpdateFeed allows you to set a new version of your content
|
||||||
func (c *Client) UpdateResource(request *mru.Request) error {
|
func (c *Client) UpdateFeed(request *mru.Request) error {
|
||||||
_, err := c.updateResource(request, false)
|
_, err := c.updateFeed(request, false)
|
||||||
return err
|
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)
|
URL, err := url.Parse(c.Gateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
URL.Path = "/bzz-resource:/"
|
URL.Path = "/bzz-feed:/"
|
||||||
values := URL.Query()
|
values := URL.Query()
|
||||||
body := request.AppendValues(values)
|
body := request.AppendValues(values)
|
||||||
if createManifest {
|
if createManifest {
|
||||||
@ -660,23 +659,23 @@ func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.R
|
|||||||
return res.Body, nil
|
return res.Body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResource returns a byte stream with the raw content of the resource
|
// QueryFeed returns a byte stream with the raw content of the feed update
|
||||||
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver
|
// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
|
||||||
// points to that address
|
// points to that address
|
||||||
func (c *Client) GetResource(query *mru.Query, manifestAddressOrDomain string) (io.ReadCloser, error) {
|
func (c *Client) QueryFeed(query *mru.Query, manifestAddressOrDomain string) (io.ReadCloser, error) {
|
||||||
return c.getResource(query, manifestAddressOrDomain, false)
|
return c.queryFeed(query, manifestAddressOrDomain, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getResource returns a byte stream with the raw content of the resource
|
// queryFeed returns a byte stream with the raw content of the feed update
|
||||||
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver
|
// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
|
||||||
// points to that address
|
// points to that address
|
||||||
// meta set to true will instruct the node return resource metainformation instead
|
// meta set to true will instruct the node return Feed metainformation instead
|
||||||
func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) {
|
func (c *Client) queryFeed(query *mru.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) {
|
||||||
URL, err := url.Parse(c.Gateway)
|
URL, err := url.Parse(c.Gateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
URL.Path = "/bzz-resource:/" + manifestAddressOrDomain
|
URL.Path = "/bzz-feed:/" + manifestAddressOrDomain
|
||||||
values := URL.Query()
|
values := URL.Query()
|
||||||
if query != nil {
|
if query != nil {
|
||||||
query.AppendValues(values) //adds query parameters
|
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.StatusOK {
|
||||||
if res.StatusCode == http.StatusNotFound {
|
if res.StatusCode == http.StatusNotFound {
|
||||||
return nil, ErrNoResourceUpdatesFound
|
return nil, ErrNoFeedUpdatesFound
|
||||||
}
|
}
|
||||||
errorMessageBytes, err := ioutil.ReadAll(res.Body)
|
errorMessageBytes, err := ioutil.ReadAll(res.Body)
|
||||||
var errorMessage string
|
var errorMessage string
|
||||||
@ -701,18 +700,18 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m
|
|||||||
} else {
|
} else {
|
||||||
errorMessage = string(errorMessageBytes)
|
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
|
return res.Body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResourceMetadata returns a structure that describes the Mutable Resource
|
// GetFeedMetadata returns a structure that describes the referenced Feed status
|
||||||
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver
|
// manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
|
||||||
// points to that address
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -369,12 +369,12 @@ func newTestSigner() (*mru.GenericSigner, error) {
|
|||||||
return mru.NewGenericSigner(privKey), nil
|
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
|
// 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
|
// and raw retrieve of that hash should return the data
|
||||||
func TestClientCreateResourceMultihash(t *testing.T) {
|
func TestClientCreateFeedMultihash(t *testing.T) {
|
||||||
|
|
||||||
signer, _ := newTestSigner()
|
signer, _ := newTestSigner()
|
||||||
|
|
||||||
@ -393,7 +393,7 @@ func TestClientCreateResourceMultihash(t *testing.T) {
|
|||||||
s := common.FromHex(swarmHash)
|
s := common.FromHex(swarmHash)
|
||||||
mh := multihash.ToMultihash(s)
|
mh := multihash.ToMultihash(s)
|
||||||
|
|
||||||
// our mutable resource topic
|
// our feed topic
|
||||||
topic, _ := mru.NewTopic("foo.eth", nil)
|
topic, _ := mru.NewTopic("foo.eth", nil)
|
||||||
|
|
||||||
createRequest := mru.NewFirstRequest(topic)
|
createRequest := mru.NewFirstRequest(topic)
|
||||||
@ -403,26 +403,26 @@ func TestClientCreateResourceMultihash(t *testing.T) {
|
|||||||
t.Fatalf("Error signing update: %s", err)
|
t.Fatalf("Error signing update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceManifestHash, err := client.CreateResource(createRequest)
|
feedManifestHash, err := client.CreateFeedWithManifest(createRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating resource: %s", err)
|
t.Fatalf("Error creating feed manifest: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd"
|
correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
|
||||||
if resourceManifestHash != correctManifestAddrHex {
|
if feedManifestHash != correctManifestAddrHex {
|
||||||
t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash)
|
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
|
// Check we get a not found error when trying to get feed updates with a made-up manifest
|
||||||
_, err = client.GetResource(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
|
_, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
|
||||||
if err != ErrNoResourceUpdatesFound {
|
if err != ErrNoFeedUpdatesFound {
|
||||||
t.Fatalf("Expected to receive ErrNoResourceUpdatesFound error. Got: %s", err)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Error retrieving resource: %s", err)
|
t.Fatalf("Error retrieving feed updates: %s", err)
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
gotData, err := ioutil.ReadAll(reader)
|
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.
|
// TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client.
|
||||||
func TestClientCreateUpdateResource(t *testing.T) {
|
func TestClientCreateUpdateFeed(t *testing.T) {
|
||||||
|
|
||||||
signer, _ := newTestSigner()
|
signer, _ := newTestSigner()
|
||||||
|
|
||||||
@ -444,10 +444,10 @@ func TestClientCreateUpdateResource(t *testing.T) {
|
|||||||
client := NewClient(srv.URL)
|
client := NewClient(srv.URL)
|
||||||
defer srv.Close()
|
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...")
|
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)
|
topic, _ := mru.NewTopic("El Quijote", nil)
|
||||||
createRequest := mru.NewFirstRequest(topic)
|
createRequest := mru.NewFirstRequest(topic)
|
||||||
|
|
||||||
@ -456,16 +456,16 @@ func TestClientCreateUpdateResource(t *testing.T) {
|
|||||||
t.Fatalf("Error signing update: %s", err)
|
t.Fatalf("Error signing update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceManifestHash, err := client.CreateResource(createRequest)
|
feedManifestHash, err := client.CreateFeedWithManifest(createRequest)
|
||||||
|
|
||||||
correctManifestAddrHex := "fcb8e75f53e480e197c083ad1976d265674d0ce776f2bf359c09c413fb5230b8"
|
correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882"
|
||||||
if resourceManifestHash != correctManifestAddrHex {
|
if feedManifestHash != correctManifestAddrHex {
|
||||||
t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Error retrieving resource: %s", err)
|
t.Fatalf("Error retrieving feed updates: %s", err)
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
gotData, err := ioutil.ReadAll(reader)
|
gotData, err := ioutil.ReadAll(reader)
|
||||||
@ -479,7 +479,7 @@ func TestClientCreateUpdateResource(t *testing.T) {
|
|||||||
// define different data
|
// define different data
|
||||||
databytes = []byte("... no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero ...")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Error retrieving update request template: %s", err)
|
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)
|
t.Fatalf("Error signing update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = client.UpdateResource(updateRequest); err != nil {
|
if err = client.UpdateFeed(updateRequest); err != nil {
|
||||||
t.Fatalf("Error updating resource: %s", err)
|
t.Fatalf("Error updating feed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err = client.GetResource(nil, correctManifestAddrHex)
|
reader, err = client.QueryFeed(nil, correctManifestAddrHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error retrieving resource: %s", err)
|
t.Fatalf("Error retrieving feed updates: %s", err)
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
gotData, err = ioutil.ReadAll(reader)
|
gotData, err = ioutil.ReadAll(reader)
|
||||||
@ -506,17 +506,17 @@ func TestClientCreateUpdateResource(t *testing.T) {
|
|||||||
t.Fatalf("Expected: %v, got %v", databytes, gotData)
|
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,
|
Topic: topic,
|
||||||
User: signer.Address(),
|
User: signer.Address(),
|
||||||
}
|
}
|
||||||
|
|
||||||
lookupParams := mru.NewQueryLatest(view, lookup.NoClue)
|
lookupParams := mru.NewQueryLatest(feed, lookup.NoClue)
|
||||||
reader, err = client.GetResource(lookupParams, "")
|
reader, err = client.QueryFeed(lookupParams, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error retrieving resource: %s", err)
|
t.Fatalf("Error retrieving feed updates: %s", err)
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
gotData, err = ioutil.ReadAll(reader)
|
gotData, err = ioutil.ReadAll(reader)
|
||||||
|
@ -31,7 +31,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -145,13 +144,13 @@ func NewServer(api *api.API, corsString string) *Server {
|
|||||||
defaultMiddlewares...,
|
defaultMiddlewares...,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
mux.Handle("/bzz-resource:/", methodHandler{
|
mux.Handle("/bzz-feed:/", methodHandler{
|
||||||
"GET": Adapt(
|
"GET": Adapt(
|
||||||
http.HandlerFunc(server.HandleGetResource),
|
http.HandlerFunc(server.HandleGetFeed),
|
||||||
defaultMiddlewares...,
|
defaultMiddlewares...,
|
||||||
),
|
),
|
||||||
"POST": Adapt(
|
"POST": Adapt(
|
||||||
http.HandlerFunc(server.HandlePostResource),
|
http.HandlerFunc(server.HandlePostFeed),
|
||||||
defaultMiddlewares...,
|
defaultMiddlewares...,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
@ -458,44 +457,13 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprint(w, newKey)
|
fmt.Fprint(w, newKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses a resource update post url to corresponding action
|
// Handles feed manifest creation and feed updates
|
||||||
// possible combinations:
|
// The POST request admits a JSON structure as defined in the feeds package: `feeds.updateRequestJSON`
|
||||||
// / add multihash update to existing hash
|
// 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
|
||||||
// /raw add raw update to existing hash
|
func (s *Server) HandlePostFeed(w http.ResponseWriter, r *http.Request) {
|
||||||
// /# 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) {
|
|
||||||
ruid := GetRUID(r.Context())
|
ruid := GetRUID(r.Context())
|
||||||
uri := GetURI(r.Context())
|
uri := GetURI(r.Context())
|
||||||
log.Debug("handle.post.resource", "ruid", ruid)
|
log.Debug("handle.post.feed", "ruid", ruid)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Creation and update must send mru.updateRequestJSON JSON structure
|
// Creation and update must send mru.updateRequestJSON JSON structure
|
||||||
@ -505,19 +473,19 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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
|
if err != nil { // couldn't parse query string or retrieve manifest
|
||||||
getFail.Inc(1)
|
getFail.Inc(1)
|
||||||
httpStatus := http.StatusBadRequest
|
httpStatus := http.StatusBadRequest
|
||||||
if err == api.ErrCannotLoadResourceManifest || err == api.ErrCannotResolveResourceURI {
|
if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI {
|
||||||
httpStatus = http.StatusNotFound
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateRequest mru.Request
|
var updateRequest mru.Request
|
||||||
updateRequest.Feed = *view
|
updateRequest.Feed = *feed
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
|
|
||||||
if err := updateRequest.FromValues(query, body); err != nil { // decodes request from query parameters
|
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() {
|
if updateRequest.IsUpdate() {
|
||||||
// Verify that the signature is intact and that the signer is authorized
|
// Verify that the signature is intact and that the signer is authorized
|
||||||
// to update this resource
|
// to update this feed
|
||||||
// Check this early, to avoid creating a resource and then not being able to set its first update.
|
// Check this early, to avoid creating a feed and then not being able to set its first update.
|
||||||
if err = updateRequest.Verify(); err != nil {
|
if err = updateRequest.Verify(); err != nil {
|
||||||
RespondError(w, r, err.Error(), http.StatusForbidden)
|
RespondError(w, r, err.Error(), http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = s.api.ResourceUpdate(r.Context(), &updateRequest)
|
_, err = s.api.FeedsUpdate(r.Context(), &updateRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, r, err.Error(), http.StatusInternalServerError)
|
RespondError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -541,16 +509,16 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if query.Get("manifest") == "1" {
|
if query.Get("manifest") == "1" {
|
||||||
// we create a manifest so we can retrieve the resource with bzz:// later
|
// we create a manifest so we can retrieve feed updates with bzz:// later
|
||||||
// this manifest has a special "resource type" manifest, and saves the
|
// this manifest has a special "feed type" manifest, and saves the
|
||||||
// resource view ID used to retrieve the resource later
|
// feed identification used to retrieve feed updates later
|
||||||
m, err := s.api.NewResourceManifest(r.Context(), &updateRequest.Feed)
|
m, err := s.api.NewFeedManifest(r.Context(), &updateRequest.Feed)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
// the key to the manifest will be passed back to the client
|
// 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
|
// the manifest key can be set as content in the resolver of the ENS name
|
||||||
outdata, err := json.Marshal(m)
|
outdata, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -563,41 +531,49 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve Swarm Feeds:
|
// HandleGetFeed retrieves Swarm Feeds updates:
|
||||||
// bzz-resource://<id> - get latest update
|
// bzz-feed://<manifest address or ENS name> - get latest feed update, given a manifest address
|
||||||
// bzz-resource://<id>/?period=n - get latest update on period n
|
// - or -
|
||||||
// bzz-resource://<id>/?period=n&version=m - get update version m of period n
|
// specify user + topic (optional), subtopic name (optional) directly, without manifest:
|
||||||
// bzz-resource://<id>/meta - get metadata and next version information
|
// bzz-feed://?user=0x...&topic=0x...&name=subtopic name
|
||||||
// <id> = ens name or hash
|
// topic defaults to 0x000... if not specified.
|
||||||
// TODO: Enable pass maxPeriod parameter
|
// name defaults to empty string if not specified.
|
||||||
func (s *Server) HandleGetResource(w http.ResponseWriter, r *http.Request) {
|
// 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())
|
ruid := GetRUID(r.Context())
|
||||||
uri := GetURI(r.Context())
|
uri := GetURI(r.Context())
|
||||||
log.Debug("handle.get.resource", "ruid", ruid)
|
log.Debug("handle.get.feed", "ruid", ruid)
|
||||||
var err error
|
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
|
if err != nil { // couldn't parse query string or retrieve manifest
|
||||||
getFail.Inc(1)
|
getFail.Inc(1)
|
||||||
httpStatus := http.StatusBadRequest
|
httpStatus := http.StatusBadRequest
|
||||||
if err == api.ErrCannotLoadResourceManifest || err == api.ErrCannotResolveResourceURI {
|
if err == api.ErrCannotLoadFeedManifest || err == api.ErrCannotResolveFeedURI {
|
||||||
httpStatus = http.StatusNotFound
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if the query specifies period and version or it is a metadata query
|
// determine if the query specifies period and version or it is a metadata query
|
||||||
if r.URL.Query().Get("meta") == "1" {
|
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 {
|
if err != nil {
|
||||||
getFail.Inc(1)
|
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
|
return
|
||||||
}
|
}
|
||||||
rawResponse, err := unsignedUpdateRequest.MarshalJSON()
|
rawResponse, err := unsignedUpdateRequest.MarshalJSON()
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
w.Header().Add("Content-type", "application/json")
|
w.Header().Add("Content-type", "application/json")
|
||||||
@ -606,28 +582,28 @@ func (s *Server) HandleGetResource(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lookupParams := &mru.Query{Feed: *view}
|
lookupParams := &mru.Query{Feed: *feed}
|
||||||
if err = lookupParams.FromValues(r.URL.Query()); err != nil { // parse period, version
|
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
|
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
|
// any error from the switch statement will end up here
|
||||||
if err != nil {
|
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)
|
RespondError(w, r, err2.Error(), code)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// All ok, serve the retrieved update
|
// 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)
|
w.Header().Set("Content-Type", api.MimeOctetStream)
|
||||||
http.ServeContent(w, r, "", time.Now(), bytes.NewReader(data))
|
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
|
code := 0
|
||||||
defaultErr := fmt.Errorf("%s: %v", supErr, err)
|
defaultErr := fmt.Errorf("%s: %v", supErr, err)
|
||||||
rsrcErr, ok := err.(*mru.Error)
|
rsrcErr, ok := err.(*mru.Error)
|
||||||
|
@ -58,47 +58,6 @@ func init() {
|
|||||||
log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
|
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 {
|
func serverFunc(api *api.API) testutil.TestServer {
|
||||||
return NewServer(api, "")
|
return NewServer(api, "")
|
||||||
}
|
}
|
||||||
@ -111,12 +70,12 @@ func newTestSigner() (*mru.GenericSigner, error) {
|
|||||||
return mru.NewGenericSigner(privKey), nil
|
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
|
// 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
|
// and raw retrieve of that hash should return the data
|
||||||
func TestBzzResourceMultihash(t *testing.T) {
|
func TestBzzFeedMultihash(t *testing.T) {
|
||||||
|
|
||||||
signer, _ := newTestSigner()
|
signer, _ := newTestSigner()
|
||||||
|
|
||||||
@ -154,7 +113,7 @@ func TestBzzResourceMultihash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -182,12 +141,12 @@ func TestBzzResourceMultihash(t *testing.T) {
|
|||||||
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd"
|
correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
|
||||||
if rsrcResp.Hex() != correctManifestAddrHex {
|
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)
|
testBzzUrl = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
||||||
resp, err = http.Get(testBzzUrl)
|
resp, err = http.Get(testBzzUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -207,7 +166,7 @@ func TestBzzResourceMultihash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test Swarm Feeds using the raw update methods
|
// Test Swarm Feeds using the raw update methods
|
||||||
func TestBzzResource(t *testing.T) {
|
func TestBzzFeed(t *testing.T) {
|
||||||
srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
|
srv := testutil.NewTestSwarmServer(t, serverFunc, nil)
|
||||||
signer, _ := newTestSigner()
|
signer, _ := newTestSigner()
|
||||||
|
|
||||||
@ -234,8 +193,8 @@ func TestBzzResource(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates resource and sets update 1
|
// creates feed and sets update 1
|
||||||
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -262,9 +221,9 @@ func TestBzzResource(t *testing.T) {
|
|||||||
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd"
|
correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
|
||||||
if rsrcResp.Hex() != correctManifestAddrHex {
|
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
|
// get the manifest
|
||||||
@ -289,12 +248,12 @@ func TestBzzResource(t *testing.T) {
|
|||||||
if len(manifest.Entries) != 1 {
|
if len(manifest.Entries) != 1 {
|
||||||
t.Fatalf("Manifest has %d entries", len(manifest.Entries))
|
t.Fatalf("Manifest has %d entries", len(manifest.Entries))
|
||||||
}
|
}
|
||||||
correctViewHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d"
|
correctFeedHex := "0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d"
|
||||||
if manifest.Entries[0].ResourceView.Hex() != correctViewHex {
|
if manifest.Entries[0].Feed.Hex() != correctFeedHex {
|
||||||
t.Fatalf("Expected manifest Resource View '%s', got '%s'", correctViewHex, manifest.Entries[0].ResourceView.Hex())
|
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)
|
testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
||||||
resp, err = http.Get(testBzzUrl)
|
resp, err = http.Get(testBzzUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -302,7 +261,7 @@ func TestBzzResource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode == http.StatusOK {
|
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)
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -310,21 +269,21 @@ func TestBzzResource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get non-existent name, should fail
|
// 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)
|
resp, err = http.Get(testBzzResUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusNotFound {
|
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()
|
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)
|
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)
|
resp, err = http.Get(testBzzResUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -346,15 +305,15 @@ func TestBzzResource(t *testing.T) {
|
|||||||
srv.CurrentTime++
|
srv.CurrentTime++
|
||||||
log.Info("update 2")
|
log.Info("update 2")
|
||||||
|
|
||||||
// 1.- get metadata about this resource
|
// 1.- get metadata about this Feed
|
||||||
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 + "?meta=1")
|
resp, err = http.Get(testBzzResUrl + "?meta=1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
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)
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -362,13 +321,13 @@ func TestBzzResource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
updateRequest = &mru.Request{}
|
updateRequest = &mru.Request{}
|
||||||
if err = updateRequest.UnmarshalJSON(b); err != nil {
|
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)
|
updateRequest.SetData(update2Data)
|
||||||
if err = updateRequest.Sign(signer); err != nil {
|
if err = updateRequest.Sign(signer); err != nil {
|
||||||
t.Fatal(err)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -385,9 +344,9 @@ func TestBzzResource(t *testing.T) {
|
|||||||
t.Fatalf("Update returned %s", resp.Status)
|
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")
|
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)
|
resp, err = http.Get(testBzzResUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -408,13 +367,13 @@ func TestBzzResource(t *testing.T) {
|
|||||||
log.Info("get first update in update1Timestamp via direct query")
|
log.Info("get first update in update1Timestamp via direct query")
|
||||||
query := mru.NewQuery(&updateRequest.Feed, update1Timestamp, lookup.NoClue)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
values := urlq.Query()
|
values := urlq.Query()
|
||||||
query.AppendValues(values) // this adds view query parameters
|
query.AppendValues(values) // this adds feed query parameters
|
||||||
urlq.RawQuery = values.Encode()
|
urlq.RawQuery = values.Encode()
|
||||||
resp, err = http.Get(urlq.String())
|
resp, err = http.Get(urlq.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,8 +35,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ManifestType = "application/bzz-manifest+json"
|
ManifestType = "application/bzz-manifest+json"
|
||||||
ResourceContentType = "application/bzz-resource"
|
FeedContentType = "application/bzz-feed"
|
||||||
|
|
||||||
manifestSizeLimit = 5 * 1024 * 1024
|
manifestSizeLimit = 5 * 1024 * 1024
|
||||||
)
|
)
|
||||||
@ -48,15 +48,15 @@ type Manifest struct {
|
|||||||
|
|
||||||
// ManifestEntry represents an entry in a swarm manifest
|
// ManifestEntry represents an entry in a swarm manifest
|
||||||
type ManifestEntry struct {
|
type ManifestEntry struct {
|
||||||
Hash string `json:"hash,omitempty"`
|
Hash string `json:"hash,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
ContentType string `json:"contentType,omitempty"`
|
ContentType string `json:"contentType,omitempty"`
|
||||||
Mode int64 `json:"mode,omitempty"`
|
Mode int64 `json:"mode,omitempty"`
|
||||||
Size int64 `json:"size,omitempty"`
|
Size int64 `json:"size,omitempty"`
|
||||||
ModTime time.Time `json:"mod_time,omitempty"`
|
ModTime time.Time `json:"mod_time,omitempty"`
|
||||||
Status int `json:"status,omitempty"`
|
Status int `json:"status,omitempty"`
|
||||||
Access *AccessEntry `json:"access,omitempty"`
|
Access *AccessEntry `json:"access,omitempty"`
|
||||||
ResourceView *mru.Feed `json:"resourceView,omitempty"`
|
Feed *mru.Feed `json:"feed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManifestList represents the result of listing files in a manifest
|
// 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
|
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
|
// 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
|
var manifest Manifest
|
||||||
entry := ManifestEntry{
|
entry := ManifestEntry{
|
||||||
ResourceView: view,
|
Feed: feed,
|
||||||
ContentType: ResourceContentType,
|
ContentType: FeedContentType,
|
||||||
}
|
}
|
||||||
manifest.Entries = append(manifest.Entries, entry)
|
manifest.Entries = append(manifest.Entries, entry)
|
||||||
data, err := json.Marshal(&manifest)
|
data, err := json.Marshal(&manifest)
|
||||||
|
@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) {
|
|||||||
|
|
||||||
// check the scheme is valid
|
// check the scheme is valid
|
||||||
switch uri.Scheme {
|
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:
|
default:
|
||||||
return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
|
return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
|
||||||
}
|
}
|
||||||
@ -108,8 +108,8 @@ func Parse(rawuri string) (*URI, error) {
|
|||||||
}
|
}
|
||||||
return uri, nil
|
return uri, nil
|
||||||
}
|
}
|
||||||
func (u *URI) Resource() bool {
|
func (u *URI) Feed() bool {
|
||||||
return u.Scheme == "bzz-resource"
|
return u.Scheme == "bzz-feed"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URI) Raw() bool {
|
func (u *URI) Raw() bool {
|
||||||
|
@ -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
|
- 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
|
keep track of syncing state across sessions, historical syncing state should survive restart
|
||||||
- extra data structures to support syncing should be kept at minimum
|
- 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
|
- 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.
|
Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention.
|
||||||
|
@ -30,8 +30,8 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// tests that the content address validator correctly checks the data
|
// tests that the content address validator correctly checks the data
|
||||||
// tests that resource update chunks are passed through content address validator
|
// tests that Feed update chunks are passed through content address validator
|
||||||
// the test checking the resouce update validator internal correctness is found in resource_test.go
|
// the test checking the resouce update validator internal correctness is found in storage/feeds/handler_test.go
|
||||||
func TestValidator(t *testing.T) {
|
func TestValidator(t *testing.T) {
|
||||||
// set up localstore
|
// set up localstore
|
||||||
datadir, err := ioutil.TempDir("", "storage-testvalidator")
|
datadir, err := ioutil.TempDir("", "storage-testvalidator")
|
||||||
|
@ -26,7 +26,7 @@ The Feed Update data is:
|
|||||||
updatedata = Feed|Epoch|data
|
updatedata = Feed|Epoch|data
|
||||||
|
|
||||||
The full update data that goes in the chunk payload is:
|
The full update data that goes in the chunk payload is:
|
||||||
resourcedata|sign(resourcedata)
|
updatedata|sign(updatedata)
|
||||||
|
|
||||||
Structure Summary:
|
Structure Summary:
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ const (
|
|||||||
ErrCnt
|
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 {
|
type Error struct {
|
||||||
code int
|
code int
|
||||||
err string
|
err string
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
// You should have received a copy of the GNU Lesser General Public License
|
// 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/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Handler is the API for Mutable Resources
|
// Handler is the API for Feeds
|
||||||
// It enables creating, updating, syncing and retrieving resources and their update data
|
// It enables creating, updating, syncing and retrieving feed updates and their data
|
||||||
package mru
|
package mru
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -265,7 +265,7 @@ func (h *Handler) Update(ctx context.Context, r *Request) (updateAddr storage.Ad
|
|||||||
// send the chunk
|
// send the chunk
|
||||||
h.chunkStore.Put(ctx, 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())
|
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) {
|
if feedUpdate != nil && r.Epoch.After(feedUpdate.Epoch) {
|
||||||
feedUpdate.Epoch = r.Epoch
|
feedUpdate.Epoch = r.Epoch
|
||||||
feedUpdate.data = make([]byte, len(r.data))
|
feedUpdate.data = make([]byte, len(r.data))
|
||||||
|
@ -396,7 +396,7 @@ func TestValidatorInStore(t *testing.T) {
|
|||||||
signer := newAliceSigner()
|
signer := newAliceSigner()
|
||||||
|
|
||||||
// set up localstore
|
// set up localstore
|
||||||
datadir, err := ioutil.TempDir("", "storage-testresourcevalidator")
|
datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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) {
|
func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) {
|
||||||
|
|
||||||
var fsClean func()
|
var fsClean func()
|
||||||
|
@ -228,7 +228,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) {
|
|||||||
var recovered Request
|
var recovered Request
|
||||||
recovered.fromChunk(chunk.Address(), chunk.Data())
|
recovered.fromChunk(chunk.Address(), chunk.Data())
|
||||||
if !reflect.DeepEqual(recovered, r) {
|
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 containing private key
|
||||||
signer := newAliceSigner()
|
signer := newAliceSigner()
|
||||||
|
|
||||||
// set up rpc and create resourcehandler
|
// set up rpc and create Feeds handler
|
||||||
_, _, teardownTest, err := setupTest(timeProvider, signer)
|
_, _, teardownTest, err := setupTest(timeProvider, signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -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
|
// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
|
||||||
self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams)
|
self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams)
|
||||||
|
|
||||||
var resourceHandler *mru.Handler
|
var feedsHandler *mru.Handler
|
||||||
rhparams := &mru.HandlerParams{}
|
fhParams := &mru.HandlerParams{}
|
||||||
|
|
||||||
resourceHandler = mru.NewHandler(rhparams)
|
feedsHandler = mru.NewHandler(fhParams)
|
||||||
resourceHandler.SetStore(self.netStore)
|
feedsHandler.SetStore(self.netStore)
|
||||||
|
|
||||||
lstore.Validators = []storage.ChunkValidator{
|
lstore.Validators = []storage.ChunkValidator{
|
||||||
storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)),
|
storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)),
|
||||||
resourceHandler,
|
feedsHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("Setup local storage")
|
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())
|
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)
|
self.sfs = fuse.NewSwarmFS(self.api)
|
||||||
log.Debug("Initialized FUSE filesystem")
|
log.Debug("Initialized FUSE filesystem")
|
||||||
|
@ -48,14 +48,14 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
|
|||||||
}
|
}
|
||||||
fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams())
|
fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams())
|
||||||
|
|
||||||
// mutable resources test setup
|
// Swarm Feeds test setup
|
||||||
resourceDir, err := ioutil.TempDir("", "swarm-resource-test")
|
feedsDir, err := ioutil.TempDir("", "swarm-feeds-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rhparams := &mru.HandlerParams{}
|
rhparams := &mru.HandlerParams{}
|
||||||
rh, err := mru.NewTestHandler(resourceDir, rhparams)
|
rh, err := mru.NewTestHandler(feedsDir, rhparams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
|
|||||||
srv.Close()
|
srv.Close()
|
||||||
rh.Close()
|
rh.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
os.RemoveAll(resourceDir)
|
os.RemoveAll(feedsDir)
|
||||||
},
|
},
|
||||||
CurrentTime: 42,
|
CurrentTime: 42,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user