cmd/stream.go
changeset 0 5abace724584
child 44 6da40ca4534c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/stream.go	Wed Apr 19 19:08:47 2017 +0200
@@ -0,0 +1,136 @@
+// Copyright © 2017 Mikael Berthe <mikael@lilotux.net>
+//
+// Licensed under the MIT license.
+// Please see the LICENSE file is this directory.
+
+package cmd
+
+import (
+	"errors"
+	"io"
+
+	"github.com/spf13/cobra"
+
+	"github.com/McKael/madon"
+)
+
+/*
+var streamOpts struct {
+	local bool
+}
+*/
+
+// streamCmd represents the stream command
+var streamCmd = &cobra.Command{
+	Use:   "stream [user|local|public|:HASHTAG]",
+	Short: "Listen to an event stream",
+	Long: `
+The stream command stays connected to the server and listen to a stream of
+events (user, local or federated).
+It can also get a hashtag-based stream if the keyword or prefixed with
+':' or '#'.`,
+	Example: `  madonctl stream           # User timeline stream
+  madonctl stream local     # Local timeline stream
+  madonctl stream public    # Public timeline stream
+  madonctl stream :mastodon # Hashtag
+  madonctl stream #madonctl`,
+	RunE:       streamRunE,
+	ValidArgs:  []string{"user", "public"},
+	ArgAliases: []string{"home"},
+}
+
+func init() {
+	RootCmd.AddCommand(streamCmd)
+
+	//streamCmd.Flags().BoolVar(&streamOpts.local, "local", false, "Events from the local instance")
+}
+
+func streamRunE(cmd *cobra.Command, args []string) error {
+	streamName := "user"
+	tag := ""
+
+	if len(args) > 0 {
+		if len(args) != 1 {
+			return errors.New("too many parameters")
+		}
+		arg := args[0]
+		switch arg {
+		case "", "user":
+		case "public":
+			streamName = arg
+		case "local":
+			streamName = "public:local"
+		default:
+			if arg[0] != ':' && arg[0] != '#' {
+				return errors.New("invalid argument")
+			}
+			streamName = "hashtag"
+			tag = arg[1:]
+			if len(tag) == 0 {
+				return errors.New("empty hashtag")
+			}
+		}
+	}
+
+	if err := madonInit(true); err != nil {
+		return err
+	}
+
+	evChan := make(chan madon.StreamEvent, 10)
+	stop := make(chan bool)
+	done := make(chan bool)
+
+	// StreamListener(name string, hashTag string, events chan<- madon.StreamEvent, stopCh <-chan bool, doneCh chan<- bool) error
+	err := gClient.StreamListener(streamName, tag, evChan, stop, done)
+	if err != nil {
+		errPrint("Error: %s", err.Error())
+		return nil
+	}
+
+	p, err := getPrinter()
+	if err != nil {
+		close(stop)
+		<-done
+		close(evChan)
+		return err
+	}
+
+LISTEN:
+	for {
+		select {
+		case _, ok := <-done:
+			if !ok { // done is closed, end of streaming
+				done = nil
+				break LISTEN
+			}
+		case ev := <-evChan:
+			switch ev.Event {
+			case "error":
+				if ev.Error != nil {
+					if ev.Error == io.ErrUnexpectedEOF {
+						errPrint("The stream connection was unexpectedly closed")
+						continue
+					}
+					errPrint("Error event: [%s] %s", ev.Event, ev.Error)
+					continue
+				}
+				errPrint("Event: [%s]", ev.Event)
+			case "update":
+				s := ev.Data.(madon.Status)
+				p.PrintObj(&s, nil, "")
+				continue
+			case "notification":
+				n := ev.Data.(madon.Notification)
+				p.PrintObj(&n, nil, "")
+				continue
+			case "delete":
+				// TODO PrintObj ?
+				errPrint("Event: [%s] Status %d was deleted", ev.Event, ev.Data.(int))
+			default:
+				errPrint("Unhandled event: [%s] %T", ev.Event, ev.Data)
+			}
+		}
+	}
+	close(evChan)
+	return nil
+}