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  }