package data import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "os" "text/template" "git.bullercodeworks.com/brian/netcaptain/internal/cli" ) type Ship struct { Name string `json:"-"` Dir string `json:"-"` Verbose bool `json:"-"` Crew map[string]string `json:"crew"` // Static Members of the Ship PlunderRules map[string]map[string]string `json:"plunder"` // Definitions for storing dynamic values 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:"-"` } func NewShip(dir, nm string) *Ship { return &Ship{ Name: nm, Dir: dir, Crew: make(map[string]string), PlunderRules: make(map[string]map[string]string), Args: make(map[string]string), Hold: make(map[string]string), } } func (s *Ship) Load() error { if !s.Exists() { return errors.New("Ship File not Found") } var err error s.Raw, err = ioutil.ReadFile(s.FilePath()) if err != nil { return err } // Parse 'Raw' into Crew and Plunder json.Unmarshal(s.Raw, &s) for quest, questRules := range s.PlunderRules { for key, val := range questRules { ruleName := quest + "." + key t, err := template.New(ruleName).Parse(val) if err != nil { return errors.New(fmt.Sprintf("Error parsing plunder rule: %s", ruleName)) } var tpl bytes.Buffer err = t.Execute(&tpl, s) if err != nil { return errors.New(fmt.Sprintf("Error executing plunder rule: %s\n->%s", ruleName, err.Error())) } } } err = s.LoadHold() if err != nil { return err } s.loaded = true return nil } func (s *Ship) LoadArgs(parms []string) { for k, v := range parms { s.Args[fmt.Sprintf("Arg%d", k)] = v } } func (s *Ship) Exists() bool { return cli.FileExists(s.FilePath()) } func (s *Ship) HoldExists() bool { return cli.FileExists(s.HoldFilePath()) } func (s *Ship) FilePath() string { return fmt.Sprintf("%s/ships/%s.json", s.Dir, s.Name) } func (s *Ship) HoldFilePath() string { return fmt.Sprintf("%s/holds/%s.json", s.Dir, s.Name) } func (s *Ship) IsValid() bool { return s.loaded } func (s *Ship) Sail(q *Quest) int { // Set up the Quest if !cli.FileExists(q.FilePath()) { cli.PrintErr(fmt.Sprintf("Quest file (%s) not found", q.Name)) return 1 } data, err := ioutil.ReadFile(q.FilePath()) if err != nil { cli.PrintErr(fmt.Sprintf("Error reading quest file (%s)", q.Name)) return 1 } q.Raw = string(data) t, err := template.New(s.Name + "." + q.Name).Parse(q.Raw) if err != nil { cli.PrintErr(fmt.Sprintf("Error parsing Quest as template: %s", err.Error())) return 1 } var tpl bytes.Buffer err = t.Execute(&tpl, s) if err != nil { cli.PrintErr(fmt.Sprintf("Error executing Quest template: %s\n->%s", q.Name, err.Error())) return 1 } q.Processed = tpl.String() q.loaded = true resp, err := q.Completer() if err != nil { cli.PrintErr(err.Error()) return 1 } defer resp.Body.Close() rbody, err := ioutil.ReadAll(resp.Body) if err != nil { cli.PrintErr(err.Error()) return 1 } // Check if we need to plunder from this quest if err = s.Plunder(q, rbody); err != nil { cli.PrintErr(err.Error()) return 1 } 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 { return nil } for k, v := range plunder { buff := bytes.NewBuffer(body) var result map[string]interface{} json.NewDecoder(buff).Decode(&result) switch val := result[v].(type) { case string: s.Hold[k] = val } } return nil } /* Hold Functions */ func (s *Ship) LoadHold() error { hold, err := ioutil.ReadFile(s.HoldFilePath()) if err != nil { f, err := os.OpenFile(s.HoldFilePath(), os.O_CREATE|os.O_WRONLY, 0644) defer f.Close() return err } json.NewDecoder(bytes.NewBuffer(hold)).Decode(&s.Hold) return nil } func (s *Ship) SaveHold() error { f, err := os.OpenFile(s.HoldFilePath(), os.O_RDWR|os.O_TRUNC, 0644) if err != nil { return err } defer f.Close() enc := json.NewEncoder(f) enc.Encode(s.Hold) return nil }