github.com/XinFinOrg/xdcchain@v1.1.0/cmd/swarm/feeds.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 // Command feed allows the user to create and update signed Swarm feeds 18 package main 19 20 import ( 21 "fmt" 22 "strings" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/common/hexutil" 26 "github.com/ethereum/go-ethereum/crypto" 27 28 "github.com/ethereum/go-ethereum/cmd/utils" 29 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 30 "github.com/ethereum/go-ethereum/swarm/storage/feed" 31 "gopkg.in/urfave/cli.v1" 32 ) 33 34 var feedCommand = cli.Command{ 35 CustomHelpTemplate: helpTemplate, 36 Name: "feed", 37 Usage: "(Advanced) Create and update Swarm Feeds", 38 ArgsUsage: "<create|update|info>", 39 Description: "Works with Swarm Feeds", 40 Subcommands: []cli.Command{ 41 { 42 Action: feedCreateManifest, 43 CustomHelpTemplate: helpTemplate, 44 Name: "create", 45 Usage: "creates and publishes a new feed manifest", 46 Description: `creates and publishes a new feed manifest pointing to a specified user's updates about a particular topic. 47 The feed topic can be built in the following ways: 48 * use --topic to set the topic to an arbitrary binary hex string. 49 * use --name to set the topic to a human-readable name. 50 For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. 51 * use both --topic and --name to create named subtopics. 52 For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning 53 this feed tracks a discussion about that contract. 54 The --user flag allows to have this manifest refer to a user other than yourself. If not specified, 55 it will then default to your local account (--bzzaccount)`, 56 Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, 57 }, 58 { 59 Action: feedUpdate, 60 CustomHelpTemplate: helpTemplate, 61 Name: "update", 62 Usage: "updates the content of an existing Swarm Feed", 63 ArgsUsage: "<0x Hex data>", 64 Description: `publishes a new update on the specified topic 65 The feed topic can be built in the following ways: 66 * use --topic to set the topic to an arbitrary binary hex string. 67 * use --name to set the topic to a human-readable name. 68 For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture. 69 * use both --topic and --name to create named subtopics. 70 For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning 71 this feed tracks a discussion about that contract. 72 73 If you have a manifest, you can specify it with --manifest to refer to the feed, 74 instead of using --topic / --name 75 `, 76 Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag}, 77 }, 78 { 79 Action: feedInfo, 80 CustomHelpTemplate: helpTemplate, 81 Name: "info", 82 Usage: "obtains information about an existing Swarm feed", 83 Description: `obtains information about an existing Swarm feed 84 The topic can be specified directly with the --topic flag as an hex string 85 If no topic is specified, the default topic (zero) will be used 86 The --name flag can be used to specify subtopics with a specific name. 87 The --user flag allows to refer to a user other than yourself. If not specified, 88 it will then default to your local account (--bzzaccount) 89 If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user 90 to refer to the feed`, 91 Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag}, 92 }, 93 }, 94 } 95 96 func NewGenericSigner(ctx *cli.Context) feed.Signer { 97 return feed.NewGenericSigner(getPrivKey(ctx)) 98 } 99 100 func getTopic(ctx *cli.Context) (topic feed.Topic) { 101 var name = ctx.String(SwarmFeedNameFlag.Name) 102 var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name) 103 var relatedTopicBytes []byte 104 var err error 105 106 if relatedTopic != "" { 107 relatedTopicBytes, err = hexutil.Decode(relatedTopic) 108 if err != nil { 109 utils.Fatalf("Error parsing topic: %s", err) 110 } 111 } 112 113 topic, err = feed.NewTopic(name, relatedTopicBytes) 114 if err != nil { 115 utils.Fatalf("Error parsing topic: %s", err) 116 } 117 return topic 118 } 119 120 // swarm feed create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]] 121 // swarm feed update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false] 122 // swarm feed info <Manifest Address or ENS domain> 123 124 func feedCreateManifest(ctx *cli.Context) { 125 var ( 126 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 127 client = swarm.NewClient(bzzapi) 128 ) 129 130 newFeedUpdateRequest := feed.NewFirstRequest(getTopic(ctx)) 131 newFeedUpdateRequest.Feed.User = feedGetUser(ctx) 132 133 manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest) 134 if err != nil { 135 utils.Fatalf("Error creating feed manifest: %s", err.Error()) 136 return 137 } 138 fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up) 139 140 } 141 142 func feedUpdate(ctx *cli.Context) { 143 args := ctx.Args() 144 145 var ( 146 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 147 client = swarm.NewClient(bzzapi) 148 manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) 149 ) 150 151 if len(args) < 1 { 152 fmt.Println("Incorrect number of arguments") 153 cli.ShowCommandHelpAndExit(ctx, "update", 1) 154 return 155 } 156 157 signer := NewGenericSigner(ctx) 158 159 data, err := hexutil.Decode(args[0]) 160 if err != nil { 161 utils.Fatalf("Error parsing data: %s", err.Error()) 162 return 163 } 164 165 var updateRequest *feed.Request 166 var query *feed.Query 167 168 if manifestAddressOrDomain == "" { 169 query = new(feed.Query) 170 query.User = signer.Address() 171 query.Topic = getTopic(ctx) 172 } 173 174 // Retrieve a feed update request 175 updateRequest, err = client.GetFeedRequest(query, manifestAddressOrDomain) 176 if err != nil { 177 utils.Fatalf("Error retrieving feed status: %s", err.Error()) 178 } 179 180 // Check that the provided signer matches the request to sign 181 if updateRequest.User != signer.Address() { 182 utils.Fatalf("Signer address does not match the update request") 183 } 184 185 // set the new data 186 updateRequest.SetData(data) 187 188 // sign update 189 if err = updateRequest.Sign(signer); err != nil { 190 utils.Fatalf("Error signing feed update: %s", err.Error()) 191 } 192 193 // post update 194 err = client.UpdateFeed(updateRequest) 195 if err != nil { 196 utils.Fatalf("Error updating feed: %s", err.Error()) 197 return 198 } 199 } 200 201 func feedInfo(ctx *cli.Context) { 202 var ( 203 bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") 204 client = swarm.NewClient(bzzapi) 205 manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name) 206 ) 207 208 var query *feed.Query 209 if manifestAddressOrDomain == "" { 210 query = new(feed.Query) 211 query.Topic = getTopic(ctx) 212 query.User = feedGetUser(ctx) 213 } 214 215 metadata, err := client.GetFeedRequest(query, manifestAddressOrDomain) 216 if err != nil { 217 utils.Fatalf("Error retrieving feed metadata: %s", err.Error()) 218 return 219 } 220 encodedMetadata, err := metadata.MarshalJSON() 221 if err != nil { 222 utils.Fatalf("Error encoding metadata to JSON for display:%s", err) 223 } 224 fmt.Println(string(encodedMetadata)) 225 } 226 227 func feedGetUser(ctx *cli.Context) common.Address { 228 var user = ctx.String(SwarmFeedUserFlag.Name) 229 if user != "" { 230 return common.HexToAddress(user) 231 } 232 pk := getPrivKey(ctx) 233 if pk == nil { 234 utils.Fatalf("Cannot read private key. Must specify --user or --bzzaccount") 235 } 236 return crypto.PubkeyToAddress(pk.PublicKey) 237 238 }