Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
83705ef6
Commit
83705ef6
authored
Sep 30, 2018
by
Javier Peletier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
swarm/storage/mru: Renamed rest of MRU references
parent
b35622cf
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
315 additions
and
382 deletions
+315
-382
main.go
cmd/swarm/main.go
+33
-33
mru.go
cmd/swarm/mru.go
+26
-26
mru_test.go
cmd/swarm/mru_test.go
+17
-17
api.go
swarm/api/api.go
+56
-57
client.go
swarm/api/client/client.go
+28
-29
client_test.go
swarm/api/client/client_test.go
+35
-35
server.go
swarm/api/http/server.go
+50
-74
server_test.go
swarm/api/http/server_test.go
+30
-71
manifest.go
swarm/api/manifest.go
+15
-15
uri.go
swarm/api/uri.go
+3
-3
README.md
swarm/network/README.md
+1
-1
localstore_test.go
swarm/storage/localstore_test.go
+2
-2
doc.go
swarm/storage/mru/doc.go
+1
-1
error.go
swarm/storage/mru/error.go
+1
-1
handler.go
swarm/storage/mru/handler.go
+3
-3
handler_test.go
swarm/storage/mru/handler_test.go
+2
-2
request_test.go
swarm/storage/mru/request_test.go
+2
-2
swarm.go
swarm/swarm.go
+6
-6
http.go
swarm/testutil/http.go
+4
-4
No files found.
cmd/swarm/main.go
View file @
83705ef6
...
@@ -207,25 +207,25 @@ var (
...
@@ -207,25 +207,25 @@ var (
Name
:
"compressed"
,
Name
:
"compressed"
,
Usage
:
"Prints encryption keys in compressed form"
,
Usage
:
"Prints encryption keys in compressed form"
,
}
}
Swarm
Resource
NameFlag
=
cli
.
StringFlag
{
Swarm
Feed
NameFlag
=
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"
,
}
}
Swarm
Resource
TopicFlag
=
cli
.
StringFlag
{
Swarm
Feed
TopicFlag
=
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"
,
}
}
Swarm
Resource
DataOnCreateFlag
=
cli
.
StringFlag
{
Swarm
Feed
DataOnCreateFlag
=
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"
,
}
}
Swarm
Resource
ManifestFlag
=
cli
.
StringFlag
{
Swarm
Feed
ManifestFlag
=
cli
.
StringFlag
{
Name
:
"manifest"
,
Name
:
"manifest"
,
Usage
:
"Refers to the
resource
through a manifest"
,
Usage
:
"Refers to the
feed
through a manifest"
,
}
}
Swarm
Resource
UserFlag
=
cli
.
StringFlag
{
Swarm
Feed
UserFlag
=
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() {
...
@@ -346,62 +346,62 @@ func init() {
},
},
{
{
CustomHelpTemplate
:
helpTemplate
,
CustomHelpTemplate
:
helpTemplate
,
Name
:
"
resource
"
,
Name
:
"
feed
"
,
Usage
:
"(Advanced) Create and update
Mutable Resource
s"
,
Usage
:
"(Advanced) Create and update
Swarm Feed
s"
,
ArgsUsage
:
"<create|update|info>"
,
ArgsUsage
:
"<create|update|info>"
,
Description
:
"Works with
Mutable Resource Update
s"
,
Description
:
"Works with
Swarm Feed
s"
,
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
th
e Mutable Resource
tracks a discussion about that contract.
th
is 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
{
Swarm
ResourceNameFlag
,
SwarmResourceTopicFlag
,
SwarmResource
UserFlag
},
Flags
:
[]
cli
.
Flag
{
Swarm
FeedNameFlag
,
SwarmFeedTopicFlag
,
SwarmFeed
UserFlag
},
},
},
{
{
Action
:
resource
Update
,
Action
:
feed
Update
,
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
th
e Mutable Resource
tracks a discussion about that contract.
th
is 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
{
Swarm
ResourceManifestFlag
,
SwarmResourceNameFlag
,
SwarmResource
TopicFlag
},
Flags
:
[]
cli
.
Flag
{
Swarm
FeedManifestFlag
,
SwarmFeedNameFlag
,
SwarmFeed
TopicFlag
},
},
},
{
{
Action
:
resource
Info
,
Action
:
feed
Info
,
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
{
Swarm
ResourceManifestFlag
,
SwarmResourceNameFlag
,
SwarmResourceTopicFlag
,
SwarmResource
UserFlag
},
Flags
:
[]
cli
.
Flag
{
Swarm
FeedManifestFlag
,
SwarmFeedNameFlag
,
SwarmFeedTopicFlag
,
SwarmFeed
UserFlag
},
},
},
},
},
},
},
...
@@ -738,7 +738,7 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr
...
@@ -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
)
...
...
cmd/swarm/mru.go
View file @
83705ef6
...
@@ -14,7 +14,7 @@
...
@@ -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 {
...
@@ -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
(
Swarm
Resource
NameFlag
.
Name
)
var
name
=
ctx
.
String
(
Swarm
Feed
NameFlag
.
Name
)
var
relatedTopic
=
ctx
.
String
(
Swarm
Resource
TopicFlag
.
Name
)
var
relatedTopic
=
ctx
.
String
(
Swarm
Feed
TopicFlag
.
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) {
...
@@ -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
)
)
)
new
Resourc
eRequest
:=
mru
.
NewFirstRequest
(
getTopic
(
ctx
))
new
FeedUpdat
eRequest
:=
mru
.
NewFirstRequest
(
getTopic
(
ctx
))
new
ResourceRequest
.
Feed
.
User
=
resource
GetUser
(
ctx
)
new
FeedUpdateRequest
.
Feed
.
User
=
feed
GetUser
(
ctx
)
manifestAddress
,
err
:=
client
.
Create
Resource
(
newResourc
eRequest
)
manifestAddress
,
err
:=
client
.
Create
FeedWithManifest
(
newFeedUpdat
eRequest
)
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
resource
Update
(
ctx
*
cli
.
Context
)
{
func
feed
Update
(
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
(
Swarm
Resource
ManifestFlag
.
Name
)
manifestAddressOrDomain
=
ctx
.
String
(
Swarm
Feed
ManifestFlag
.
Name
)
)
)
if
len
(
args
)
<
1
{
if
len
(
args
)
<
1
{
...
@@ -110,10 +110,10 @@ func resourceUpdate(ctx *cli.Context) {
...
@@ -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
.
Get
Resource
Metadata
(
query
,
manifestAddressOrDomain
)
updateRequest
,
err
=
client
.
Get
Feed
Metadata
(
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) {
...
@@ -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
.
Update
Resource
(
updateRequest
)
err
=
client
.
Update
Feed
(
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
resource
Info
(
ctx
*
cli
.
Context
)
{
func
feed
Info
(
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
(
Swarm
Resource
ManifestFlag
.
Name
)
manifestAddressOrDomain
=
ctx
.
String
(
Swarm
Feed
ManifestFlag
.
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
=
resource
GetUser
(
ctx
)
query
.
User
=
feed
GetUser
(
ctx
)
}
}
metadata
,
err
:=
client
.
Get
Resource
Metadata
(
query
,
manifestAddressOrDomain
)
metadata
,
err
:=
client
.
Get
Feed
Metadata
(
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) {
...
@@ -158,8 +158,8 @@ func resourceInfo(ctx *cli.Context) {
fmt
.
Println
(
string
(
encodedMetadata
))
fmt
.
Println
(
string
(
encodedMetadata
))
}
}
func
resource
GetUser
(
ctx
*
cli
.
Context
)
common
.
Address
{
func
feed
GetUser
(
ctx
*
cli
.
Context
)
common
.
Address
{
var
user
=
ctx
.
String
(
Swarm
Resource
UserFlag
.
Name
)
var
user
=
ctx
.
String
(
Swarm
Feed
UserFlag
.
Name
)
if
user
!=
""
{
if
user
!=
""
{
return
common
.
HexToAddress
(
user
)
return
common
.
HexToAddress
(
user
)
}
}
...
...
cmd/swarm/mru_test.go
View file @
83705ef6
...
@@ -38,12 +38,12 @@ import (
...
@@ -38,12 +38,12 @@ import (
swarmhttp
"github.com/ethereum/go-ethereum/swarm/api/http"
swarmhttp
"github.com/ethereum/go-ethereum/swarm/api/http"
)
)
func
TestCLI
Resource
Update
(
t
*
testing
.
T
)
{
func
TestCLI
Feed
Update
(
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 clust
er"
)
log
.
Info
(
"starting
a test swarm serv
er"
)
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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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
)
}
}
...
...
swarm/api/api.go
View file @
83705ef6
...
@@ -235,18 +235,18 @@ on top of the FileStore
...
@@ -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
,
resource
Handler
*
mru
.
Handler
,
pk
*
ecdsa
.
PrivateKey
)
(
self
*
API
)
{
func
NewAPI
(
fileStore
*
storage
.
FileStore
,
dns
Resolver
,
feeds
Handler
*
mru
.
Handler
,
pk
*
ecdsa
.
PrivateKey
)
(
self
*
API
)
{
self
=
&
API
{
self
=
&
API
{
fileStore
:
fileStore
,
fileStore
:
fileStore
,
dns
:
dns
,
dns
:
dns
,
resource
:
resource
Handler
,
feeds
:
feeds
Handler
,
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
...
@@ -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
==
Resource
ContentType
{
if
entry
.
ContentType
==
Feed
ContentType
{
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
resourc
e content error: %v"
,
err
))
log
.
Debug
(
fmt
.
Sprintf
(
"get
feed updat
e 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
resourc
e content error: %v"
,
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"get
feed updat
e 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
...
@@ -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 i
s multihash"
,
"key"
,
manifestAddr
)
log
.
Trace
(
"
feed update contain
s 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 (
resourc
e multihash) error: %v"
,
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"loadManifestTrie (
feed updat
e 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
...
@@ -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 (
resourc
e multihash) entry for '%s' not found"
,
path
)
err
=
fmt
.
Errorf
(
"manifest (
feed updat
e multihash) entry for '%s' not found"
,
path
)
log
.
Trace
(
"manifest (
resourc
e multihash) entry not found"
,
"key"
,
manifestAddr
,
"path"
,
path
)
log
.
Trace
(
"manifest (
feed updat
e 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
...
@@ -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
)
Resource
Lookup
(
ctx
context
.
Context
,
query
*
mru
.
Query
)
([]
byte
,
error
)
{
func
(
a
*
API
)
Feeds
Lookup
(
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
)
Resource
HashSize
()
int
{
func
(
a
*
API
)
Feeds
HashSize
()
int
{
return
a
.
resource
.
HashSize
return
a
.
feeds
.
HashSize
}
}
// ErrCannotLoad
ResourceManifest is returned when looking up a resource
manifest fails
// ErrCannotLoad
FeedManifest is returned when looking up a feeds
manifest fails
var
ErrCannotLoad
ResourceManifest
=
errors
.
New
(
"Cannot load resource
manifest"
)
var
ErrCannotLoad
FeedManifest
=
errors
.
New
(
"Cannot load feed
manifest"
)
// ErrNotA
Resource
Manifest is returned when the address provided returned something other than a valid manifest
// ErrNotA
Feed
Manifest is returned when the address provided returned something other than a valid manifest
var
ErrNotA
ResourceManifest
=
errors
.
New
(
"Not a resource
manifest"
)
var
ErrNotA
FeedManifest
=
errors
.
New
(
"Not a feed
manifest"
)
// Resolve
ResourceManifest retrieves the Mutable Resource manifest for the given address, and returns the Resource's view ID
.
// Resolve
FeedManifest retrieves the Feed manifest for the given address, and returns the referenced Feed
.
func
(
a
*
API
)
Resolve
Resource
Manifest
(
ctx
context
.
Context
,
addr
storage
.
Address
)
(
*
mru
.
Feed
,
error
)
{
func
(
a
*
API
)
Resolve
Feed
Manifest
(
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
,
ErrCannotLoad
Resource
Manifest
return
nil
,
ErrCannotLoad
Feed
Manifest
}
}
entry
,
_
:=
trie
.
getEntry
(
""
)
entry
,
_
:=
trie
.
getEntry
(
""
)
if
entry
.
ContentType
!=
Resource
ContentType
{
if
entry
.
ContentType
!=
Feed
ContentType
{
return
nil
,
ErrNotA
Resource
Manifest
return
nil
,
ErrNotA
Feed
Manifest
}
}
return
entry
.
ResourceView
,
nil
return
entry
.
Feed
,
nil
}
}
// ErrCannotResolve
ResourceURI is returned when the ENS resolver is not able to translate a name to a resource
// ErrCannotResolve
FeedURI is returned when the ENS resolver is not able to translate a name to a Feed
var
ErrCannotResolve
ResourceURI
=
errors
.
New
(
"Cannot resolve Resource
URI"
)
var
ErrCannotResolve
FeedURI
=
errors
.
New
(
"Cannot resolve Feed
URI"
)
// ErrCannotResolve
ResourceView
is returned when values provided are not enough or invalid to recreate a
// ErrCannotResolve
Feed
is returned when values provided are not enough or invalid to recreate a
//
resource view
out of them.
//
Feed
out of them.
var
ErrCannotResolve
ResourceView
=
errors
.
New
(
"Cannot resolve resource view
"
)
var
ErrCannotResolve
Feed
=
errors
.
New
(
"Cannot resolve Feed
"
)
// Resolve
ResourceView attempts to extract View
information out of the manifest, if provided
// Resolve
Feed 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
)
Resolve
ResourceView
(
ctx
context
.
Context
,
uri
*
URI
,
values
mru
.
Values
)
(
*
mru
.
Feed
,
error
)
{
func
(
a
*
API
)
Resolve
Feed
(
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
...
@@ -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
,
ErrCannotResolve
Resource
URI
return
nil
,
ErrCannotResolve
Feed
URI
}
}
}
}
// get the
resource view
from the manifest
// get the
Feed
from the manifest
view
,
err
=
a
.
ResolveResource
Manifest
(
ctx
,
manifestAddr
)
feed
,
err
=
a
.
ResolveFeed
Manifest
(
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
,
ErrCannotResolve
ResourceView
return
nil
,
ErrCannotResolve
Feed
}
}
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
...
...
swarm/api/client/client.go
View file @
83705ef6
...
@@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error)
...
@@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error)
return
string
(
data
),
nil
return
string
(
data
),
nil
}
}
// ErrNo
ResourceUpdatesFound is returned when Swarm cannot find updates of the given resource
// ErrNo
FeedUpdatesFound is returned when Swarm cannot find updates of the given feed
var
ErrNo
ResourceUpdatesFound
=
errors
.
New
(
"No updates found for this resource
"
)
var
ErrNo
FeedUpdatesFound
=
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) {
...
@@ -628,18 +627,18 @@ func (c *Client) CreateResource(request *mru.Request) (string, error) {
return
manifestAddress
,
nil
return
manifestAddress
,
nil
}
}
// Update
Resource
allows you to set a new version of your content
// Update
Feed
allows you to set a new version of your content
func
(
c
*
Client
)
Update
Resource
(
request
*
mru
.
Request
)
error
{
func
(
c
*
Client
)
Update
Feed
(
request
*
mru
.
Request
)
error
{
_
,
err
:=
c
.
update
Resource
(
request
,
false
)
_
,
err
:=
c
.
update
Feed
(
request
,
false
)
return
err
return
err
}
}
func
(
c
*
Client
)
update
Resource
(
request
*
mru
.
Request
,
createManifest
bool
)
(
io
.
ReadCloser
,
error
)
{
func
(
c
*
Client
)
update
Feed
(
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
...
@@ -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 resourc
e
//
QueryFeed returns a byte stream with the raw content of the feed updat
e
// manifestAddressOrDomain is the address you obtained in Create
Resource
or an ENS domain whose Resolver
// manifestAddressOrDomain is the address you obtained in Create
FeedWithManifest
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 resourc
e
//
queryFeed returns a byte stream with the raw content of the feed updat
e
// manifestAddressOrDomain is the address you obtained in Create
Resource
or an ENS domain whose Resolver
// manifestAddressOrDomain is the address you obtained in Create
FeedWithManifest
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
...
@@ -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
,
ErrNo
Resource
UpdatesFound
return
nil
,
ErrNo
Feed
UpdatesFound
}
}
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
...
@@ -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
}
}
// Get
ResourceMetadata returns a structure that describes the Mutable Resource
// Get
FeedMetadata returns a structure that describes the referenced Feed status
// manifestAddressOrDomain is the address you obtained in Create
Resource
or an ENS domain whose Resolver
// manifestAddressOrDomain is the address you obtained in Create
FeedWithManifest
or an ENS domain whose Resolver
// points to that address
// points to that address
func
(
c
*
Client
)
Get
Resource
Metadata
(
query
*
mru
.
Query
,
manifestAddressOrDomain
string
)
(
*
mru
.
Request
,
error
)
{
func
(
c
*
Client
)
Get
Feed
Metadata
(
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
}
}
...
...
swarm/api/client/client_test.go
View file @
83705ef6
...
@@ -369,12 +369,12 @@ func newTestSigner() (*mru.GenericSigner, error) {
...
@@ -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 typ
es with bzz:// scheme
// test the transparent resolving of multihash
feed updat
es 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
TestClientCreate
Resource
Multihash
(
t
*
testing
.
T
)
{
func
TestClientCreate
Feed
Multihash
(
t
*
testing
.
T
)
{
signer
,
_
:=
newTestSigner
()
signer
,
_
:=
newTestSigner
()
...
@@ -393,7 +393,7 @@ func TestClientCreateResourceMultihash(t *testing.T) {
...
@@ -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) {
...
@@ -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
resource
ManifestHash
!=
correctManifestAddrHex
{
if
feed
ManifestHash
!=
correctManifestAddrHex
{
t
.
Fatalf
(
"Response
resource manifest mismatch, expected '%s', got '%s'"
,
correctManifestAddrHex
,
resource
ManifestHash
)
t
.
Fatalf
(
"Response
feed manifest mismatch, expected '%s', got '%s'"
,
correctManifestAddrHex
,
feed
ManifestHash
)
}
}
// 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
!=
ErrNo
Resource
UpdatesFound
{
if
err
!=
ErrNo
Feed
UpdatesFound
{
t
.
Fatalf
(
"Expected to receive ErrNo
Resource
UpdatesFound error. Got: %s"
,
err
)
t
.
Fatalf
(
"Expected to receive ErrNo
Feed
UpdatesFound 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) {
...
@@ -435,8 +435,8 @@ func TestClientCreateResourceMultihash(t *testing.T) {
}
}
// TestClientCreateUpdate
Resource will check that mutable resource
s can be created and updated via the HTTP client.
// TestClientCreateUpdate
Feed will check that feed
s can be created and updated via the HTTP client.
func
TestClientCreateUpdate
Resource
(
t
*
testing
.
T
)
{
func
TestClientCreateUpdate
Feed
(
t
*
testing
.
T
)
{
signer
,
_
:=
newTestSigner
()
signer
,
_
:=
newTestSigner
()
...
@@ -444,10 +444,10 @@ func TestClientCreateUpdateResource(t *testing.T) {
...
@@ -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
resourc
e
// set raw data for the
feed updat
e
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) {
...
@@ -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
resource
ManifestHash
!=
correctManifestAddrHex
{
if
feed
ManifestHash
!=
correctManifestAddrHex
{
t
.
Fatalf
(
"Response
resource manifest mismatch, expected '%s', got '%s'"
,
correctManifestAddrHex
,
resource
ManifestHash
)
t
.
Fatalf
(
"Response
feed manifest mismatch, expected '%s', got '%s'"
,
correctManifestAddrHex
,
feed
ManifestHash
)
}
}
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) {
...
@@ -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
.
Get
Resource
Metadata
(
nil
,
correctManifestAddrHex
)
updateRequest
,
err
:=
client
.
Get
Feed
Metadata
(
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) {
...
@@ -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
.
Update
Resource
(
updateRequest
);
err
!=
nil
{
if
err
=
client
.
Update
Feed
(
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) {
...
@@ -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
)
...
...
swarm/api/http/server.go
View file @
83705ef6
...
@@ -31,7 +31,6 @@ import (
...
@@ -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 {
...
@@ -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
.
HandleGet
Resource
),
http
.
HandlerFunc
(
server
.
HandleGet
Feed
),
defaultMiddlewares
...
,
defaultMiddlewares
...
,
),
),
"POST"
:
Adapt
(
"POST"
:
Adapt
(
http
.
HandlerFunc
(
server
.
HandlePost
Resource
),
http
.
HandlerFunc
(
server
.
HandlePost
Feed
),
defaultMiddlewares
...
,
defaultMiddlewares
...
,
),
),
})
})
...
@@ -458,44 +457,13 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) {
...
@@ -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) {
...
@@ -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
.
ErrCannotLoad
ResourceManifest
||
err
==
api
.
ErrCannotResolveResource
URI
{
if
err
==
api
.
ErrCannotLoad
FeedManifest
||
err
==
api
.
ErrCannotResolveFeed
URI
{
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) {
...
@@ -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
.
Resource
Update
(
r
.
Context
(),
&
updateRequest
)
_
,
err
=
s
.
api
.
Feeds
Update
(
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) {
...
@@ -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
.
New
Resource
Manifest
(
r
.
Context
(),
&
updateRequest
.
Feed
)
m
,
err
:=
s
.
api
.
New
Feed
Manifest
(
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) {
...
@@ -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
.
ErrCannotLoad
ResourceManifest
||
err
==
api
.
ErrCannotResolveResource
URI
{
if
err
==
api
.
ErrCannotLoad
FeedManifest
||
err
==
api
.
ErrCannotResolveFeed
URI
{
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
UpdateR
equest: %v"
,
err
),
http
.
StatusInternalServerError
)
RespondError
(
w
,
r
,
fmt
.
Sprintf
(
"cannot encode unsigned
feed update r
equest: %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) {
...
@@ -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 resourc
e request:%s"
,
err
),
http
.
StatusBadRequest
)
RespondError
(
w
,
r
,
fmt
.
Sprintf
(
"invalid
feed updat
e request:%s"
,
err
),
http
.
StatusBadRequest
)
return
return
}
}
data
,
err
:=
s
.
api
.
Resource
Lookup
(
r
.
Context
(),
lookupParams
)
data
,
err
:=
s
.
api
.
Feeds
Lookup
(
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
.
translate
ResourceError
(
w
,
r
,
"mutable resource
lookup fail"
,
err
)
code
,
err2
:=
s
.
translate
FeedError
(
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
)
translate
Resource
Error
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
supErr
string
,
err
error
)
(
int
,
error
)
{
func
(
s
*
Server
)
translate
Feed
Error
(
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
)
...
...
swarm/api/http/server_test.go
View file @
83705ef6
...
@@ -58,47 +58,6 @@ func init() {
...
@@ -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) {
...
@@ -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 typ
es with bzz:// scheme
// test the transparent resolving of multihash
-containing feed updat
es 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
TestBzz
Resource
Multihash
(
t
*
testing
.
T
)
{
func
TestBzz
Feed
Multihash
(
t
*
testing
.
T
)
{
signer
,
_
:=
newTestSigner
()
signer
,
_
:=
newTestSigner
()
...
@@ -154,7 +113,7 @@ func TestBzzResourceMultihash(t *testing.T) {
...
@@ -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) {
...
@@ -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
resourc
e resolve
// get bzz manifest transparent
feed updat
e 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) {
...
@@ -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
TestBzz
Resource
(
t
*
testing
.
T
)
{
func
TestBzz
Feed
(
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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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
))
}
}
correct
View
Hex
:=
"0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d"
correct
Feed
Hex
:=
"0x666f6f2e65746800000000000000000000000000000000000000000000000000c96aaa54e2d44c299564da76e1cd3184a2386b8d"
if
manifest
.
Entries
[
0
]
.
ResourceView
.
Hex
()
!=
correctView
Hex
{
if
manifest
.
Entries
[
0
]
.
Feed
.
Hex
()
!=
correctFeed
Hex
{
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
resourc
e resolve
// get bzz manifest transparent
feed updat
e 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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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) {
...
@@ -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
{
...
...
swarm/api/manifest.go
View file @
83705ef6
...
@@ -36,7 +36,7 @@ import (
...
@@ -36,7 +36,7 @@ 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
)
)
...
@@ -56,7 +56,7 @@ type ManifestEntry struct {
...
@@ -56,7 +56,7 @@ type ManifestEntry struct {
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,
...
@@ -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 Update
s from the bzz: scheme
// Manifest hack for supporting
Feed
s 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
)
New
ResourceManifest
(
ctx
context
.
Context
,
view
*
mru
.
Feed
)
(
storage
.
Address
,
error
)
{
func
(
a
*
API
)
New
FeedManifest
(
ctx
context
.
Context
,
feed
*
mru
.
Feed
)
(
storage
.
Address
,
error
)
{
var
manifest
Manifest
var
manifest
Manifest
entry
:=
ManifestEntry
{
entry
:=
ManifestEntry
{
ResourceView
:
view
,
Feed
:
feed
,
ContentType
:
Resource
ContentType
,
ContentType
:
Feed
ContentType
,
}
}
manifest
.
Entries
=
append
(
manifest
.
Entries
,
entry
)
manifest
.
Entries
=
append
(
manifest
.
Entries
,
entry
)
data
,
err
:=
json
.
Marshal
(
&
manifest
)
data
,
err
:=
json
.
Marshal
(
&
manifest
)
...
...
swarm/api/uri.go
View file @
83705ef6
...
@@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) {
...
@@ -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) {
...
@@ -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
{
...
...
swarm/network/README.md
View file @
83705ef6
...
@@ -57,7 +57,7 @@ receipts for a deleted chunk easily to refute their challenge.
...
@@ -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.
...
...
swarm/storage/localstore_test.go
View file @
83705ef6
...
@@ -30,8 +30,8 @@ var (
...
@@ -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"
)
...
...
swarm/storage/mru/doc.go
View file @
83705ef6
...
@@ -26,7 +26,7 @@ The Feed Update data is:
...
@@ -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(resourc
edata)
updatedata|sign(updat
edata)
Structure Summary:
Structure Summary:
...
...
swarm/storage/mru/error.go
View file @
83705ef6
...
@@ -35,7 +35,7 @@ const (
...
@@ -35,7 +35,7 @@ const (
ErrCnt
ErrCnt
)
)
// Error is a the typed error object used for
Mutable Resource
s
// Error is a the typed error object used for
Swarm Feed
s
type
Error
struct
{
type
Error
struct
{
code
int
code
int
err
string
err
string
...
...
swarm/storage/mru/handler.go
View file @
83705ef6
...
@@ -14,8 +14,8 @@
...
@@ -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 Resource
s
// Handler is the API for
Feed
s
// 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
...
@@ -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
resourc
es map cache entry if the new update is older than the one we have, if we have it.
// update our
feed updat
es 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
))
...
...
swarm/storage/mru/handler_test.go
View file @
83705ef6
...
@@ -396,7 +396,7 @@ func TestValidatorInStore(t *testing.T) {
...
@@ -396,7 +396,7 @@ func TestValidatorInStore(t *testing.T) {
signer
:=
newAliceSigner
()
signer
:=
newAliceSigner
()
// set up localstore
// set up localstore
datadir
,
err
:=
ioutil
.
TempDir
(
""
,
"storage-test
resource
validator"
)
datadir
,
err
:=
ioutil
.
TempDir
(
""
,
"storage-test
feeds
validator"
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
...
@@ -463,7 +463,7 @@ func TestValidatorInStore(t *testing.T) {
...
@@ -463,7 +463,7 @@ func TestValidatorInStore(t *testing.T) {
}
}
}
}
// create rpc and
resourceh
andler
// create rpc and
Feeds H
andler
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
()
...
...
swarm/storage/mru/request_test.go
View file @
83705ef6
...
@@ -228,7 +228,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) {
...
@@ -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) {
...
@@ -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
resource
handler
// 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
)
...
...
swarm/swarm.go
View file @
83705ef6
...
@@ -186,15 +186,15 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e
...
@@ -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
resource
Handler
*
mru
.
Handler
var
feeds
Handler
*
mru
.
Handler
rhp
arams
:=
&
mru
.
HandlerParams
{}
fhP
arams
:=
&
mru
.
HandlerParams
{}
resourceHandler
=
mru
.
NewHandler
(
rhp
arams
)
feedsHandler
=
mru
.
NewHandler
(
fhP
arams
)
resource
Handler
.
SetStore
(
self
.
netStore
)
feeds
Handler
.
SetStore
(
self
.
netStore
)
lstore
.
Validators
=
[]
storage
.
ChunkValidator
{
lstore
.
Validators
=
[]
storage
.
ChunkValidator
{
storage
.
NewContentAddressValidator
(
storage
.
MakeHashFunc
(
storage
.
DefaultHash
)),
storage
.
NewContentAddressValidator
(
storage
.
MakeHashFunc
(
storage
.
DefaultHash
)),
resource
Handler
,
feeds
Handler
,
}
}
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
...
@@ -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
,
resource
Handler
,
self
.
privateKey
)
self
.
api
=
api
.
NewAPI
(
self
.
fileStore
,
self
.
dns
,
feeds
Handler
,
self
.
privateKey
)
self
.
sfs
=
fuse
.
NewSwarmFS
(
self
.
api
)
self
.
sfs
=
fuse
.
NewSwarmFS
(
self
.
api
)
log
.
Debug
(
"Initialized FUSE filesystem"
)
log
.
Debug
(
"Initialized FUSE filesystem"
)
...
...
swarm/testutil/http.go
View file @
83705ef6
...
@@ -48,14 +48,14 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
...
@@ -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 resource
s test setup
//
Swarm Feed
s 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
(
resource
Dir
,
rhparams
)
rh
,
err
:=
mru
.
NewTestHandler
(
feeds
Dir
,
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
...
@@ -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
(
resource
Dir
)
os
.
RemoveAll
(
feeds
Dir
)
},
},
CurrentTime
:
42
,
CurrentTime
:
42
,
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment