go_sysutils/net/main.go

200 lines
4.2 KiB
Go

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
}
}
}