From 737e4268fcf23312d404399980b0a05031e0da3a Mon Sep 17 00:00:00 2001 From: Stefan Hoffmann Date: Sat, 6 Feb 2021 22:32:24 +0100 Subject: [PATCH] added first support for config file --- example.config.json | 15 ++++++ main.go | 126 ++++++++++++++++---------------------------- types.go | 48 +++++++++++++++++ 3 files changed, 109 insertions(+), 80 deletions(-) create mode 100644 example.config.json diff --git a/example.config.json b/example.config.json new file mode 100644 index 0000000..2a300a8 --- /dev/null +++ b/example.config.json @@ -0,0 +1,15 @@ +{ + "unms": { + "active": "true", + "unmsAPIUrl": "https://unifi.freifunk-troisdorf.de/v2.1", + "APItoken": "API TOKEN", + "devicesURL": "https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api/raw/branch/master/" + }, + "unifi": { + "active": "true", + "APIUrl": "https://unifi.freifunk-troisdorf.de:8443", + "user": "APIuser", + "password": "PASSWORD", + "ucDevicesURL": "https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api/raw/branch/master/" + } +} \ No newline at end of file diff --git a/main.go b/main.go index 8c82485..74b9baa 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "log" "net/http" "net/http/cookiejar" + "os" "strconv" "strings" "time" @@ -17,74 +18,41 @@ import ( _ "git.nils.zone/nils/prettify" ) -// types - const ( - baseURL = "https://unifi.freifunk-troisdorf.de/v2.1" - ucBaseURL = "https://unifi.freifunk-troisdorf.de:8443" - iso8601 = "2006-01-02T15:04:05-0700" + iso8601 = "2006-01-02T15:04:05-0700" ) // flags -var token = flag.String("token", "", "Defines the x-auth-token") -var ucUser = flag.String("ucUser", "", "Defines the Unifi API User") -var ucPass = flag.String("ucPass", "", "Defines the Unifi API Password") +var configPath = flag.String("configPath", "config.json", "Path to config.json") var version = "development" -var delay time.Duration = 60 * time.Second +var delay time.Duration = 5 * time.Second func main() { log.Printf("starting version %s...\n", version) // parse all flags flag.Parse() + c := loadConfig(*configPath) // check if flags are set - if *token == "" { - log.Fatalln("Please specify an API token via the flag '-token'") + if *configPath == "" { + log.Fatalln("Please specify path to config.json flag '-configPath'") } - if *ucPass == "" { - log.Fatalln("Please specify an API Password via the flag '-ucPass'") - } - if *ucUser == "" { - log.Fatalln("Please specify an API User via the flag '-ucUser'") - } - // start API processing (runs in a loop) - go processAPIs() + go processAPIs(c) // start webserver on Port 3000 serveJSON() } -//switch Unifi AP Mod IDs to Names -func lookupModels(model string) string { - switch model { - case "BZ2", "U2S48", "U2Sv2": - return "Unifi AP" - case "BZ2LR", "U2L48", "U2Lv2": - return "UniFi AP-LR" - case "U7E", "U7Ev2": - return "UniFi AP-AC" - case "U7HD", "U7SHD": - return "UniFi AP-HD" - case "UXSDM": - return "UniFi AP-BaseStationXG" - case "UCMSH": - return "AP-MeshXG" - case "U7MP": - return "AP-AC-Mesh-Pro" - case "U7LR": - return "UniFi AP-AC-LR" - case "U7LT": - return "UniFi AP-AC-Lite" - case "U7P": - return "UniFi AP-Pro" - case "U7MSH": - return "UniFi AP-AC-Mesh" - case "U7PG2": - return "UniFi AP-AC-Pro" - default: - return "Unifi Gerät" +func loadConfig(file string) Config { + var config Config + configFile, err := os.Open(file) + if err != nil { + log.Fatalln(err) } + jsonParse := json.NewDecoder(configFile) + jsonParse.Decode(&config) + return config } //int to bool converter @@ -96,27 +64,27 @@ func itob(i int) bool { } //Unifi Controller API processing -func processUcAPIs() ([]node, []link) { +func processUcAPIs(c Config) ([]node, []link) { //get list of Unifi devices to display var nodes []node var links []link - d, err := getDevices("ucDevices.json") + d, err := getDevices(c, "ucDevices.json") if err != nil { log.Fatalln(err) } //call Unifi Controller - ucAPI := newAPI(*ucUser, *ucPass, ucBaseURL) + ucAPI := newAPI(c.Unifi.User, c.Unifi.Password, c.Unifi.APIURL) //login ucAPI.ucLogin() //get all Sites from Controller sites, err := ucAPI.ucGetSites() if err != nil { - panic(err) + log.Fatalln(err) } //get all devices in all sites devices, err := ucAPI.ucGetDevices(sites) if err != nil { - panic(err) + log.Fatalln(err) } //build nodes struct @@ -135,11 +103,11 @@ func processUcAPIs() ([]node, []link) { load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64) if err != nil { - panic(err) + log.Fatalln(err) } mem, err := strconv.ParseFloat(currentDevice.Sysstats.Memory, 64) if err != nil { - panic(err) + log.Fatalln(err) } nodes = append(nodes, node{ @@ -180,12 +148,12 @@ func processUcAPIs() ([]node, []link) { } //UNMS API processing (Richtfunk) -func processUNMSAPI() ([]node, []link) { +func processUNMSAPI(c Config) ([]node, []link) { // Variables for runtime var links []link var nodes []node - d, err := getDevices("devices.json") + d, err := getDevices(c, "devices.json") if err != nil { log.Fatalln(err) } @@ -193,7 +161,7 @@ func processUNMSAPI() ([]node, []link) { // API CALL 1 log.Println("calling API 1") var u []unifiAPIResponse - err = callUnifiAPI("/devices", &u) + err = callUnifiAPI(c, "/devices", &u) if err != nil { log.Fatalln(err) } @@ -217,13 +185,13 @@ func processUNMSAPI() ([]node, []link) { // API CALL 2 log.Println("calling API 2 for device", d.Devices[i].Name) var details unifiAPIDetails - callUnifiAPI("/devices/erouters/"+dev.Identification.ID, &details) + callUnifiAPI(c, "/devices/erouters/"+dev.Identification.ID, &details) // END OF API CALL 2 // API CALL 3 log.Println("calling API 3 for device", d.Devices[i].Name) var airmaxes []unifiAPIAirmax - callUnifiAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes) + callUnifiAPI(c, "/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes) // check if remote mac address is part of our published network for i := range airmaxes { if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) == true { @@ -270,14 +238,14 @@ func processUNMSAPI() ([]node, []link) { return nodes, links } -func processAPIs() { +func processAPIs(c Config) { tick := time.Tick(delay) for range tick { var nodes []node var links []link - unmsNodes, unmsLinks := processUNMSAPI() - ucNodes, ucLinks := processUcAPIs() + unmsNodes, unmsLinks := processUNMSAPI(c) + ucNodes, ucLinks := processUcAPIs(c) nodes = append(nodes, unmsNodes...) nodes = append(nodes, ucNodes...) links = append(links, unmsLinks...) @@ -311,43 +279,41 @@ func getFile(url string) []byte { return byteValue } -func getDevices(file string) (devices, error) { +func getDevices(c Config, file string) (devices, error) { // get devices from JSON file - jsonFile := getFile("https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api/raw/branch/master/" + file) + jsonFile := getFile(c.Unms.DevicesURL + file) // read file to bytes // variable for d var d devices // unmarshal to struct - json.Unmarshal(jsonFile, &d) + err := json.Unmarshal(jsonFile, &d) + if err != nil { + fmt.Println("can´t get devices file from " + c.Unms.DevicesURL) + log.Fatal(err) + } return d, nil } -func callUnifiAPI(url string, i interface{}) error { - request, err := http.NewRequest(http.MethodGet, baseURL+url, nil) +func callUnifiAPI(c Config, url string, i interface{}) error { + request, err := http.NewRequest(http.MethodGet, c.Unms.UnmsAPIURL+url, nil) if err != nil { - return errors.New(fmt.Sprint("can't set request", baseURL+url)) + return errors.New(fmt.Sprint("can't set request", c.Unms.UnmsAPIURL+url)) } - request.Header.Set("x-auth-token", *token) + request.Header.Set("x-auth-token", c.Unms.APItoken) client := &http.Client{} response, err := client.Do(request) if err != nil { - return fmt.Errorf("can't get request %s with x-auth-token %s", baseURL+url, *token) + return fmt.Errorf("can't get request %s with x-auth-token %s", c.Unms.UnmsAPIURL+url, c.Unms.APItoken) + } + if response.StatusCode != 200 { + log.Fatalln("Can´t call UNMS API, check token and URL. HTTP Status: ", response.StatusCode) } - data, err := ioutil.ReadAll(response.Body) defer response.Body.Close() if err != nil { return fmt.Errorf("can't read response body: %+v", response.Body) } - // try to fetch errors - var a apiResponse - json.Unmarshal(data, &a) - - if a.StatusCode != 0 { - return fmt.Errorf("got following errorcode from API: %d %s %s", a.StatusCode, a.Error, a.Message) - } - // no error occurred, unmarshal to struct json.Unmarshal(data, &i) return nil diff --git a/types.go b/types.go index 069e28c..c152b25 100644 --- a/types.go +++ b/types.go @@ -10,6 +10,22 @@ import ( "time" ) +type Config struct { + Unms struct { + Active string `json:"active"` + UnmsAPIURL string `json:"unmsAPIUrl"` + APItoken string `json:"APItoken"` + DevicesURL string `json:"devicesURL"` + } `json:"unms"` + Unifi struct { + Active string `json:"active"` + APIURL string `json:"APIUrl"` + User string `json:"user"` + Password string `json:"password"` + UCDevicesURL string `json:"ucDevicesURL"` + } `json:"unifi"` +} + type device struct { Name string `json:"name"` MAC string `json:"mac"` @@ -178,3 +194,35 @@ type ucAPIData struct { baseURL string client *http.Client } + +//switch Unifi AP Mod IDs to Names +func lookupModels(model string) string { + switch model { + case "BZ2", "U2S48", "U2Sv2": + return "Unifi AP" + case "BZ2LR", "U2L48", "U2Lv2": + return "UniFi AP-LR" + case "U7E", "U7Ev2": + return "UniFi AP-AC" + case "U7HD", "U7SHD": + return "UniFi AP-HD" + case "UXSDM": + return "UniFi AP-BaseStationXG" + case "UCMSH": + return "AP-MeshXG" + case "U7MP": + return "AP-AC-Mesh-Pro" + case "U7LR": + return "UniFi AP-AC-LR" + case "U7LT": + return "UniFi AP-AC-Lite" + case "U7P": + return "UniFi AP-Pro" + case "U7MSH": + return "UniFi AP-AC-Mesh" + case "U7PG2": + return "UniFi AP-AC-Pro" + default: + return "Unifi Gerät" + } +}