diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc235d6 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# netcaptain +Sail the treacherous seas of the internet. + +Netcaptain assists you in building and making HTTP requests. + +## Vernacular: +### Quest - An internet adventure +Held in the `quests` directory under the given config directory, a quest will look something like this (we'll call this `quest` `auth`): +``` +POST {{ .Crew.BaseURL }}/api/v1.0/auth +{"email":"{{.Args.Arg0}}","password":"{{.Args.Arg1}}"} +``` +Or something like this (and this `quest` will be `lookup`): +``` +Authorization: Bearer {{ .Hold.Token }} +GET http://192.168.86.197:8080/api/v1.0/lookup/book/{{ .Args.Arg0 }} +``` +As you can see, support for `go` templates is built in. While executing the template, the captain will load as much information as can be loaded. + +In the examples above we can see these variables: +* `.Crew.*` +* `.Hold.*` +* `.Args.Arg*` + +The `Crew` and the `Hold` are loaded if the captain is given a ship to sail. (A ship need not be specified if one named `default` exists in the given configuration.) + +`Args` values are loaded at runtime by arguments passed on the command line in addition to the quest and ship. + +That is: +`ncpt ...` + +And for example: +`ncpt lookup enterprise Search+Term` +Will take the ship `enterprise` and go on the `lookup` quest providing: +* `Args.Arg0` = `Search+Term` + +On the other hand, if `enterprise` is not the name of a defined ship, then you will go on the `lookup` quest providing: +* `Args.Arg0` = `enterprise` +* `Args.Arg1` = `Search+Term` + +In this second case, if a `default` ship exists, it will be sailed, whether it contains anything to be used or not. + +Quests can be easily edited in whatever editor you have defined in `EDITOR` by issuing: +`ncpt -e ` + +And quests can be validated (just run through the the parser without executing it) by issuing: +`ncpt -c ` + +And all available quests can be listed by issuing: +`ncpt -l` + +### Ship - A Crew, and rules for Plunder and Delivery +Held in the `ships` directory under the given config directory, a ship will look something like this: +``` +{ + "crew": { + "BaseURL": "http://192.168.86.197:8080" + }, + "plunder": { + "auth": { + "token": "token" + }, + "ddg-search": { + "image": "Image", + "result": "Abstract" + } + } +} +``` +Here we have a `Crew` some rules for `Plunder`, and a rule for `Deliver`. + +The `Crew` is simple, we have a single Crew Member: `BaseURL`. Looking at the first Quest up above (`auth`): +``` +POST {{ .Crew.BaseURL }}/api/v1.0/auth +{"email":"{{.Args.Arg0}}","password":"{{.Args.Arg1}}"} +``` +So, when we pursue the `auth` quest using this `ship`, the `BaseURL` variable will be replaced with the given Crew member: `http://192.168.86.197:8080`) + +The `Plunder` takes a little more explanation. Here we have defined a rule for plundering the `auth` `Quest`. It's basically saying "Upon completing the `auth` quest, I expect to receive `json` that contains, at the first level of the response, a `token` value. Store that value in the `Hold` under the name `token`." + +The second `Plunder` rule will trigger on a Quest named `ddg-search`. It's going to pull a couple of values out of the top level of the response: +* `Image` stored in the ship `Hold` as `image` and +* `Abstract` stored in the ship `Hold` as `result` + +Currently, only top-level values in JSON responses can be plundered. + +### Hold - Where Plunder is Stored +These are simple JSON files that act as key-value stores for anything plundered. + +## Usage of ncpt: +``` +Usage of ncpt: + -l List available Quests + -L List available Ships + -c + Validate that the given quest is _c_orrect + -C + Validate that the given ship is _C_orrect + -e + Edit the given quest + -E + Edit the given ship + -H + Edit the hold for the given ship + -h + Output the value of in the given ship's hold + -d string + The configuration directory to use (default ".ncpt") + -v Run in Verbose mode +``` diff --git a/cmd/ncpt/app.go b/cmd/ncpt/app.go index 521303d..8510a18 100644 --- a/cmd/ncpt/app.go +++ b/cmd/ncpt/app.go @@ -20,6 +20,7 @@ const ( MODE_EDIT_HOLD MODE_LIST_QUESTS MODE_LIST_SHIPS + MODE_OUTPUT_HOLD_VALUE ) type AppState struct { @@ -49,13 +50,14 @@ func NewApp() *AppState { func (a *AppState) initialize() error { flag.StringVar(&a.ConfDir, "d", ".ncpt", "The configuration directory to use") flag.BoolVar(&a.Verbose, "v", false, "Run in Verbose mode") - validateQuest := flag.String("c", "", "Validate the given quest is _c_orrect") - validateShip := flag.String("C", "", "Validate the given ship is _C_orrect") + validateQuest := flag.String("c", "", "Validate that the given quest is _c_orrect") + validateShip := flag.String("C", "", "Validate that the given ship is _C_orrect") editQuest := flag.String("e", "", "Edit the given quest") editShip := flag.String("E", "", "Edit the given ship") - listQuestsMode := flag.Bool("l", false, "List all available Quests") - listShipsMode := flag.Bool("L", false, "List all available Ships") + listQuestsMode := flag.Bool("l", false, "List available Quests") + listShipsMode := flag.Bool("L", false, "List available Ships") editHold := flag.String("H", "", "Edit the hold for the given ship") + outputHoldValue := flag.String("h", "", "Output the given value from the given ship's hold") flag.Parse() a.Parms = flag.Args() @@ -87,6 +89,9 @@ func (a *AppState) initialize() error { } else if *editHold != "" { a.Mode = MODE_EDIT_HOLD a.Ship = data.NewShip(a.ConfDir, *editHold) + } else if *outputHoldValue != "" { + a.Mode = MODE_OUTPUT_HOLD_VALUE + a.Ship = data.NewShip(a.ConfDir, *outputHoldValue) } else { a.Mode = MODE_RUN } @@ -111,6 +116,8 @@ func (a *AppState) run() int { return a.listQuests(a.Parms) case MODE_LIST_SHIPS: return a.listShips(a.Parms) + case MODE_OUTPUT_HOLD_VALUE: + return a.outputHoldValue(a.Parms) default: return a.runQuest(a.Parms) diff --git a/cmd/ncpt/app_cmds.go b/cmd/ncpt/app_cmds.go deleted file mode 100644 index 06ab7d0..0000000 --- a/cmd/ncpt/app_cmds.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/cmd/ncpt/app_ship_cmds.go b/cmd/ncpt/app_ship_cmds.go index 2ebdfa3..d6b2536 100644 --- a/cmd/ncpt/app_ship_cmds.go +++ b/cmd/ncpt/app_ship_cmds.go @@ -65,3 +65,25 @@ func (a *AppState) editHold(parms []string) int { } return 0 } + +func (a *AppState) outputHoldValue(parms []string) int { + if a.Ship == nil { + cli.PrintErr("Ship name must be provided.") + return 1 + } + if err := a.Ship.Load(); err != nil { + cli.PrintErr(err.Error()) + return 1 + } + if len(parms) == 0 { + cli.PrintErr("Hold key must be provided.") + return 1 + } + v, ok := a.Ship.Hold[parms[0]] + if !ok { + cli.PrintErr(fmt.Sprintf("No value for '%s' found", parms[0])) + return 1 + } + fmt.Println(v) + return 0 +} diff --git a/internal/data/ship.go b/internal/data/ship.go index ded63fe..9b2f436 100644 --- a/internal/data/ship.go +++ b/internal/data/ship.go @@ -21,6 +21,7 @@ type Ship struct { Hold map[string]string `json:"-"` // Where dynamic values are stored Args map[string]string `json:"-"` // Arguments passed in from the command line Raw []byte `json:"-"` + Deliver string `json:"-"` loaded bool `json:"-"` } @@ -137,16 +138,32 @@ func (s *Ship) Sail(q *Quest) int { cli.PrintErr(err.Error()) return 1 } - fmt.Println(string(rbody)) err = s.SaveHold() if err != nil { cli.PrintErr(err.Error()) return 1 } - + if err = s.StandAndDeliver(q, rbody); err != nil { + cli.PrintErr(err.Error()) + return 1 + } return 0 } +func (s *Ship) StandAndDeliver(q *Quest, body []byte) error { + if s.Deliver == "" { + fmt.Println(string(body)) + } else { + v, ok := s.Hold[s.Deliver] + if ok { + fmt.Println(v) + } else { + fmt.Printf("No value for %s in Hold\n", s.Deliver) + } + } + return nil +} + func (s *Ship) Plunder(q *Quest, body []byte) error { plunder, ok := s.PlunderRules[q.Name] if !ok { @@ -161,7 +178,6 @@ func (s *Ship) Plunder(q *Quest, body []byte) error { s.Hold[k] = val } } - return nil }