package main import ( "bytes" _ "encoding/csv" "fmt" "os" "strconv" "strings" "github.com/jszwec/csvutil" "r00t2.io/sysutils/net/ports" "r00t2.io/sysutils/net/protos" "r00t2.io/sysutils/paths" ) // I really don't get all the slobbering over interfaces. They seem... pointless. // Because now I have to write multiple parsers with largely duplicate code. // Massive code duplication is, apparently, Idiomatic Go(TM). // I miss python. func parsePort(src *[]byte, dst []ports.IPPort, outBytes *[]byte) (err error) { var tName string var varName string var s string var buf bytes.Buffer var allports []string buf.Write([]byte("package ports\n\n")) if err = csvutil.Unmarshal(*src, &dst); err != nil { return } buf.Write([]byte("var (\n")) for _, i := range dst { // tName = fmt.Sprintf("%v", i.ServiceName) tName = strings.ToLower(i.ServiceName) varName = fmt.Sprintf("RegisteredPort_%v%v", tName, int(i.Number)) s = fmt.Sprintf("\t%v := %#v\n", varName, &i) buf.Write([]byte(s)) } buf.Write([]byte(")\n\n")) // Write the easy collections. buf.Write([]byte("var (\n")) buf.Write([]byte("\tAllRegisteredPorts []*IPPort = {\n")) for _, i := range allports { buf.Write([]byte(fmt.Sprintf("\t\t%v,\n", i))) } buf.Write([]byte(")\n\n)\n")) *outBytes = buf.Bytes() return } func parseProto(src *[]byte, dst []protos.IPProto, outBytes *[]byte) (err error) { var tName string var varName string var s string var buf bytes.Buffer var allprotos []string buf.Write([]byte("package protos\n\n")) if err = csvutil.Unmarshal(*src, &dst); err != nil { return } buf.Write([]byte("var (\n")) for _, i := range dst { tName = fmt.Sprintf("%v", i.Name) varName = fmt.Sprintf("RegisteredProto%v%v", tName, strconv.Itoa(int(i.Number))) allprotos = append(allprotos, varName) s = fmt.Sprintf("\t%v := %#v\n", varName, &i) buf.Write([]byte(s)) } buf.Write([]byte(")\n\n")) // Write the easy collections. buf.Write([]byte("var (\n")) buf.Write([]byte("\tAllRegisteredProtos []*IPProto = {\n")) for _, i := range allprotos { buf.Write([]byte(fmt.Sprintf("\t\t%v,\n", i))) } buf.Write([]byte(")\n\n)\n")) *outBytes = buf.Bytes() return } func write(path string, b []byte) (err error) { if err = paths.RealPath(&path); err != nil { return } if err = os.WriteFile(path, b, 0644); err != nil { return } return } func main() { var dlbytes *[]byte // This is the raw downloaded CSV. // var rows [][]string // This is the parsed CSV. var err error urls := map[string]map[string]string{ // Protos needs to be first so ports can reference them. // TODO. "protos": { "url": protosUrl, "file": protosFile, }, "ports": { "url": portsUrl, "file": portsFile, }, } rendered := map[string]*[]byte{ "protos": &[]byte{}, "ports": &[]byte{}, } for t, d := range urls { var url string var fpath string var ok bool if url, ok = d["url"]; !ok { fmt.Printf("URL does not exist for %v; skipping.\n", t) continue } if fpath, ok = d["file"]; !ok { fmt.Printf("File path does not exist for %v; skipping.\n", t) continue } else { if err = paths.RealPath(&fpath); err != nil { fmt.Printf("Cannot resolve file path for %v; skipping.\n", t) continue } } if dlbytes, err = download(url); err != nil { fmt.Printf("Could not download '%v' for %v (skipping):\n", url, t) fmt.Println(err) continue } // I *could* set up a variable that refers to the proper func and set that func in an if block above... // But then I'd have to use reflection and it gets gross and hacky. This is a lot more performant even though it's a lot // more verbose. Write it once, run it many times... if t == "ports" { var objs []ports.IPPort if err = parsePort(dlbytes, objs, rendered[t]); err != nil { fmt.Printf("Could not parse %v (skipping):\n", t) fmt.Println(err) continue } } else { // t == "proto" var objs []protos.IPProto if err = parseProto(dlbytes, objs, rendered[t]); err != nil { fmt.Printf("Could not parse %v (skipping):\n", t) fmt.Println(err) continue } } if err = write(fpath, *rendered[t]); err != nil { fmt.Printf("Could not write to '%v' for %v (skipping):\n", fpath, t) fmt.Println(err) continue } } }