cmd.go 4.99 KB
Newer Older
keks's avatar
keks committed
1 2 3 4
package adder

import (
	"fmt"
keks's avatar
keks committed
5
	"io"
keks's avatar
keks committed
6
	"strconv"
keks's avatar
keks committed
7 8
	"strings"
	"time"
keks's avatar
keks committed
9

tavit ohanian's avatar
tavit ohanian committed
10
	cmds "gitlab.dms3.io/dms3/public/go-dms3-cmds"
tavit ohanian's avatar
tavit ohanian committed
11
	"gitlab.dms3.io/dms3/public/go-dms3-cmds/cli"
keks's avatar
keks committed
12 13
)

keks's avatar
keks committed
14 15 16 17
// AddStatus describes the progress of the add operation
type AddStatus struct {
	// Current is the current value of the sum.
	Current int
keks's avatar
fmt  
keks committed
18

keks's avatar
keks committed
19 20 21 22
	// Left is how many summands are left
	Left int
}

keks's avatar
keks committed
23 24 25
// Define the root of the commands
var RootCmd = &cmds.Command{
	Subcommands: map[string]*cmds.Command{
keks's avatar
keks committed
26 27
		// the simplest way to make an adder
		"simpleAdd": &cmds.Command{
Steven Allen's avatar
Steven Allen committed
28 29
			Arguments: []cmds.Argument{
				cmds.StringArg("summands", true, true, "values that are supposed to be summed"),
keks's avatar
keks committed
30
			},
31
			Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
keks's avatar
keks committed
32 33
				sum := 0

34
				for i, str := range req.Arguments {
keks's avatar
keks committed
35 36
					num, err := strconv.Atoi(str)
					if err != nil {
37
						return err
keks's avatar
keks committed
38 39 40
					}

					sum += num
keks's avatar
keks committed
41 42 43 44
					err = re.Emit(fmt.Sprintf("intermediate result: %d; %d left", sum, len(req.Arguments)-i-1))
					if err != nil {
						return err
					}
keks's avatar
keks committed
45 46
				}

keks's avatar
keks committed
47
				return re.Emit(fmt.Sprintf("total: %d", sum))
keks's avatar
keks committed
48 49
			},
		},
keks's avatar
keks committed
50 51
		// a bit more sophisticated
		"encodeAdd": &cmds.Command{
Steven Allen's avatar
Steven Allen committed
52 53
			Arguments: []cmds.Argument{
				cmds.StringArg("summands", true, true, "values that are supposed to be summed"),
keks's avatar
keks committed
54
			},
55
			Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
keks's avatar
keks committed
56 57
				sum := 0

58
				for i, str := range req.Arguments {
keks's avatar
keks committed
59 60
					num, err := strconv.Atoi(str)
					if err != nil {
61
						return err
keks's avatar
keks committed
62 63 64
					}

					sum += num
keks's avatar
keks committed
65
					err = re.Emit(&AddStatus{
keks's avatar
keks committed
66
						Current: sum,
67
						Left:    len(req.Arguments) - i - 1,
keks's avatar
keks committed
68
					})
keks's avatar
keks committed
69 70 71 72
					if err != nil {
						return err
					}

keks's avatar
keks committed
73 74
					time.Sleep(200 * time.Millisecond)
				}
75
				return nil
keks's avatar
keks committed
76 77 78 79
			},
			Type: &AddStatus{},
			Encoders: cmds.EncoderMap{
				// This defines how to encode these values as text. Other possible encodings are XML and JSON.
80
				cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
keks's avatar
keks committed
81 82 83 84
					s, ok := v.(*AddStatus)
					if !ok {
						return fmt.Errorf("cast error, got type %T", v)
					}
keks's avatar
fmt  
keks committed
85

keks's avatar
keks committed
86 87 88 89 90
					if s.Left == 0 {
						fmt.Fprintln(w, "total:", s.Current)
					} else {
						fmt.Fprintf(w, "intermediate result: %d; %d left\n", s.Current, s.Left)
					}
keks's avatar
fmt  
keks committed
91

keks's avatar
keks committed
92 93 94 95 96 97
					return nil
				}),
			},
		},
		// the best UX
		"postRunAdd": &cmds.Command{
Steven Allen's avatar
Steven Allen committed
98 99
			Arguments: []cmds.Argument{
				cmds.StringArg("summands", true, true, "values that are supposed to be summed"),
keks's avatar
keks committed
100 101
			},
			// this is the same as for encoderAdd
102
			Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
keks's avatar
keks committed
103 104
				sum := 0

105
				for i, str := range req.Arguments {
keks's avatar
keks committed
106 107
					num, err := strconv.Atoi(str)
					if err != nil {
108
						return err
keks's avatar
keks committed
109 110 111
					}

					sum += num
keks's avatar
keks committed
112
					err = re.Emit(&AddStatus{
keks's avatar
keks committed
113
						Current: sum,
114
						Left:    len(req.Arguments) - i - 1,
keks's avatar
keks committed
115
					})
keks's avatar
keks committed
116 117 118 119
					if err != nil {
						return err
					}

keks's avatar
keks committed
120 121
					time.Sleep(200 * time.Millisecond)
				}
122
				return nil
keks's avatar
keks committed
123 124 125
			},
			Type: &AddStatus{},
			PostRun: cmds.PostRunMap{
keks's avatar
keks committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139
				cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
					defer re.Close()
					defer fmt.Println()

					// length of line at last iteration
					var lastLen int

					for {
						v, err := res.Next()
						if err == io.EOF {
							return nil
						}
						if err != nil {
							return err
keks's avatar
keks committed
140
						}
keks's avatar
fmt  
keks committed
141

keks's avatar
keks committed
142 143 144 145 146 147 148 149 150
						fmt.Print("\r" + strings.Repeat(" ", lastLen))

						s := v.(*AddStatus)
						if s.Left > 0 {
							lastLen, _ = fmt.Printf("\rcalculation sum... current: %d; left: %d", s.Current, s.Left)
						} else {
							lastLen, _ = fmt.Printf("\rsum is %d.", s.Current)
						}
					}
keks's avatar
keks committed
151 152 153 154 155
				},
			},
		},
		// how to set program's return value
		"exitAdd": &cmds.Command{
Steven Allen's avatar
Steven Allen committed
156 157
			Arguments: []cmds.Argument{
				cmds.StringArg("summands", true, true, "values that are supposed to be summed"),
keks's avatar
keks committed
158 159
			},
			// this is the same as for encoderAdd
160
			Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
keks's avatar
keks committed
161 162
				sum := 0

163
				for i, str := range req.Arguments {
keks's avatar
keks committed
164 165
					num, err := strconv.Atoi(str)
					if err != nil {
166
						return err
keks's avatar
keks committed
167 168 169
					}

					sum += num
keks's avatar
keks committed
170
					err = re.Emit(&AddStatus{
keks's avatar
keks committed
171
						Current: sum,
172
						Left:    len(req.Arguments) - i - 1,
keks's avatar
keks committed
173
					})
keks's avatar
keks committed
174 175 176 177
					if err != nil {
						return err
					}

keks's avatar
keks committed
178 179
					time.Sleep(200 * time.Millisecond)
				}
180
				return nil
keks's avatar
keks committed
181 182 183
			},
			Type: &AddStatus{},
			PostRun: cmds.PostRunMap{
keks's avatar
keks committed
184
				cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
keks's avatar
keks committed
185
					clire := re.(cli.ResponseEmitter)
keks's avatar
keks committed
186
					defer fmt.Println()
keks's avatar
keks committed
187

keks's avatar
keks committed
188 189 190 191 192
					// length of line at last iteration
					var lastLen int

					var exit int
					defer func() {
Steven Allen's avatar
Steven Allen committed
193
						clire.SetStatus(exit)
keks's avatar
keks committed
194
					}()
keks's avatar
fmt  
keks committed
195

keks's avatar
keks committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
					for {
						v, err := res.Next()
						if err == io.EOF {
							return nil
						}
						if err != nil {
							return err
						}

						fmt.Print("\r" + strings.Repeat(" ", lastLen))

						s := v.(*AddStatus)
						if s.Left > 0 {
							lastLen, _ = fmt.Printf("\rcalculation sum... current: %d; left: %d", s.Current, s.Left)
						} else {
							lastLen, _ = fmt.Printf("\rsum is %d.", s.Current)
							exit = s.Current
						}
					}
keks's avatar
keks committed
215 216 217
				},
			},
		},
keks's avatar
keks committed
218 219
	},
}