95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
|
package netgear
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"git.wbrawner.com/wbrawner/ntgr/internal/netrc"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
)
|
||
|
|
||
|
type DeviceList struct {
|
||
|
NumberOfDevices int `json:"numberOfDevices"`
|
||
|
Mode string `json:"mode"`
|
||
|
ConnDevices []struct {
|
||
|
CheckDev int `json:"checkDev"`
|
||
|
Mac string `json:"mac"`
|
||
|
Scene string `json:"scene"`
|
||
|
Mark string `json:"mark"`
|
||
|
Connection string `json:"connection"`
|
||
|
Priority int `json:"priority"`
|
||
|
PriorityStr string `json:"priorityStr"`
|
||
|
CurBarDownStr string `json:"curBarDownStr"`
|
||
|
CurBarUpStr string `json:"curBarUpStr"`
|
||
|
DownloadSpeedStr string `json:"downloadSpeedStr"`
|
||
|
UploadSpeedStr string `json:"uploadSpeedStr"`
|
||
|
Type string `json:"type"`
|
||
|
Model string `json:"model"`
|
||
|
Name string `json:"name"`
|
||
|
IP string `json:"ip"`
|
||
|
} `json:"connDevices"`
|
||
|
}
|
||
|
|
||
|
// login will attempt to authenticate with the router to perform a subsequent
|
||
|
// request. That request can be executed in the onSuccess function
|
||
|
func login[T interface{}](credentials netrc.NetrcCredential, onSuccess func(netrc.NetrcCredential) T) T {
|
||
|
req, err := http.NewRequest("GET", credentials.HttpHost(), nil)
|
||
|
if err != nil {
|
||
|
log.Fatalln("Failed to create request")
|
||
|
}
|
||
|
req.Header.Set(
|
||
|
"Authorization",
|
||
|
fmt.Sprintf("Basic %s", credentials.Base64()),
|
||
|
)
|
||
|
res, err := http.DefaultClient.Do(req)
|
||
|
if err != nil {
|
||
|
log.Fatalln("Failed to send first login request")
|
||
|
}
|
||
|
if res.StatusCode == 200 {
|
||
|
return onSuccess(credentials)
|
||
|
}
|
||
|
// if the first login attempt fails, it'll return an XSRF_TOKEN cookie
|
||
|
// that we'll need to set for the second request. it's only needed for
|
||
|
// the login request to succeed, and subsequent requests won't need it
|
||
|
// anymore
|
||
|
req.Header.Set(
|
||
|
"Cookie",
|
||
|
res.Header.Get("Set-Cookie"),
|
||
|
)
|
||
|
res, err = http.DefaultClient.Do(req)
|
||
|
if err != nil || res.StatusCode != 200 {
|
||
|
log.Fatalln("Failed to send second login request")
|
||
|
}
|
||
|
return onSuccess(credentials)
|
||
|
}
|
||
|
|
||
|
func ListDevices(credentials netrc.NetrcCredential) DeviceList {
|
||
|
log.Println("loading device list...")
|
||
|
req, err := http.NewRequest("GET", credentials.HttpHostWithPath("/ajax/devices_table_result"), nil)
|
||
|
if err != nil {
|
||
|
log.Fatalln("Failed to create request")
|
||
|
}
|
||
|
req.Header.Set(
|
||
|
"Authorization",
|
||
|
fmt.Sprintf("Basic %s", credentials.Base64()),
|
||
|
)
|
||
|
res, err := http.DefaultClient.Do(req)
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed to list devices: %v\n", err)
|
||
|
}
|
||
|
if res.StatusCode != 200 {
|
||
|
// if loading the device list fails, then we need to log in
|
||
|
// first
|
||
|
log.Println("listing devices failed, attempting login")
|
||
|
return login(credentials, ListDevices)
|
||
|
}
|
||
|
defer res.Body.Close()
|
||
|
body, err := io.ReadAll(res.Body)
|
||
|
var devices DeviceList
|
||
|
if err = json.Unmarshal(body, &devices); err != nil {
|
||
|
log.Fatalln("Failed to parse JSON response from router")
|
||
|
}
|
||
|
return devices
|
||
|
}
|