Beta Release
This commit is contained in:
parent
c1f7e8ae91
commit
5f07ea41d2
110
README.md
Normal file
110
README.md
Normal file
@ -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 <quest> <ship> <Args.Arg0> <Args.Arg1> ...`
|
||||||
|
|
||||||
|
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 <quest>`
|
||||||
|
|
||||||
|
And quests can be validated (just run through the the parser without executing it) by issuing:
|
||||||
|
`ncpt -c <quest>`
|
||||||
|
|
||||||
|
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 <quest>
|
||||||
|
Validate that the given quest is _c_orrect
|
||||||
|
-C <ship>
|
||||||
|
Validate that the given ship is _C_orrect
|
||||||
|
-e <quest>
|
||||||
|
Edit the given quest
|
||||||
|
-E <ship>
|
||||||
|
Edit the given ship
|
||||||
|
-H <ship>
|
||||||
|
Edit the hold for the given ship
|
||||||
|
-h <ship> <key>
|
||||||
|
Output the value of <key> in the given ship's hold
|
||||||
|
-d string
|
||||||
|
The configuration directory to use (default ".ncpt")
|
||||||
|
-v Run in Verbose mode
|
||||||
|
```
|
@ -20,6 +20,7 @@ const (
|
|||||||
MODE_EDIT_HOLD
|
MODE_EDIT_HOLD
|
||||||
MODE_LIST_QUESTS
|
MODE_LIST_QUESTS
|
||||||
MODE_LIST_SHIPS
|
MODE_LIST_SHIPS
|
||||||
|
MODE_OUTPUT_HOLD_VALUE
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppState struct {
|
type AppState struct {
|
||||||
@ -49,13 +50,14 @@ func NewApp() *AppState {
|
|||||||
func (a *AppState) initialize() error {
|
func (a *AppState) initialize() error {
|
||||||
flag.StringVar(&a.ConfDir, "d", ".ncpt", "The configuration directory to use")
|
flag.StringVar(&a.ConfDir, "d", ".ncpt", "The configuration directory to use")
|
||||||
flag.BoolVar(&a.Verbose, "v", false, "Run in Verbose mode")
|
flag.BoolVar(&a.Verbose, "v", false, "Run in Verbose mode")
|
||||||
validateQuest := flag.String("c", "", "Validate the given quest is _c_orrect")
|
validateQuest := flag.String("c", "", "Validate that the given quest is _c_orrect")
|
||||||
validateShip := flag.String("C", "", "Validate the given ship is _C_orrect")
|
validateShip := flag.String("C", "", "Validate that the given ship is _C_orrect")
|
||||||
editQuest := flag.String("e", "", "Edit the given quest")
|
editQuest := flag.String("e", "", "Edit the given quest")
|
||||||
editShip := flag.String("E", "", "Edit the given ship")
|
editShip := flag.String("E", "", "Edit the given ship")
|
||||||
listQuestsMode := flag.Bool("l", false, "List all available Quests")
|
listQuestsMode := flag.Bool("l", false, "List available Quests")
|
||||||
listShipsMode := flag.Bool("L", false, "List all available Ships")
|
listShipsMode := flag.Bool("L", false, "List available Ships")
|
||||||
editHold := flag.String("H", "", "Edit the hold for the given ship")
|
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()
|
flag.Parse()
|
||||||
a.Parms = flag.Args()
|
a.Parms = flag.Args()
|
||||||
@ -87,6 +89,9 @@ func (a *AppState) initialize() error {
|
|||||||
} else if *editHold != "" {
|
} else if *editHold != "" {
|
||||||
a.Mode = MODE_EDIT_HOLD
|
a.Mode = MODE_EDIT_HOLD
|
||||||
a.Ship = data.NewShip(a.ConfDir, *editHold)
|
a.Ship = data.NewShip(a.ConfDir, *editHold)
|
||||||
|
} else if *outputHoldValue != "" {
|
||||||
|
a.Mode = MODE_OUTPUT_HOLD_VALUE
|
||||||
|
a.Ship = data.NewShip(a.ConfDir, *outputHoldValue)
|
||||||
} else {
|
} else {
|
||||||
a.Mode = MODE_RUN
|
a.Mode = MODE_RUN
|
||||||
}
|
}
|
||||||
@ -111,6 +116,8 @@ func (a *AppState) run() int {
|
|||||||
return a.listQuests(a.Parms)
|
return a.listQuests(a.Parms)
|
||||||
case MODE_LIST_SHIPS:
|
case MODE_LIST_SHIPS:
|
||||||
return a.listShips(a.Parms)
|
return a.listShips(a.Parms)
|
||||||
|
case MODE_OUTPUT_HOLD_VALUE:
|
||||||
|
return a.outputHoldValue(a.Parms)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return a.runQuest(a.Parms)
|
return a.runQuest(a.Parms)
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package main
|
|
@ -65,3 +65,25 @@ func (a *AppState) editHold(parms []string) int {
|
|||||||
}
|
}
|
||||||
return 0
|
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
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ type Ship struct {
|
|||||||
Hold map[string]string `json:"-"` // Where dynamic values are stored
|
Hold map[string]string `json:"-"` // Where dynamic values are stored
|
||||||
Args map[string]string `json:"-"` // Arguments passed in from the command line
|
Args map[string]string `json:"-"` // Arguments passed in from the command line
|
||||||
Raw []byte `json:"-"`
|
Raw []byte `json:"-"`
|
||||||
|
Deliver string `json:"-"`
|
||||||
loaded bool `json:"-"`
|
loaded bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,16 +138,32 @@ func (s *Ship) Sail(q *Quest) int {
|
|||||||
cli.PrintErr(err.Error())
|
cli.PrintErr(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
fmt.Println(string(rbody))
|
|
||||||
err = s.SaveHold()
|
err = s.SaveHold()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cli.PrintErr(err.Error())
|
cli.PrintErr(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
if err = s.StandAndDeliver(q, rbody); err != nil {
|
||||||
|
cli.PrintErr(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
return 0
|
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 {
|
func (s *Ship) Plunder(q *Quest, body []byte) error {
|
||||||
plunder, ok := s.PlunderRules[q.Name]
|
plunder, ok := s.PlunderRules[q.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -161,7 +178,6 @@ func (s *Ship) Plunder(q *Quest, body []byte) error {
|
|||||||
s.Hold[k] = val
|
s.Hold[k] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user