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