initial commit
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | *_test.go | ||||||
							
								
								
									
										33
									
								
								ap_info.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								ap_info.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | package omadaapi | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"git.tordarus.net/tordarus/ezhttp" | ||||||
|  | 	"git.tordarus.net/tordarus/omada-api/model" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (api *Api) GetApInfo(siteID model.SiteID, macAddress string) (*model.ApInfo, error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("GET"), | ||||||
|  | 		ezhttp.AppendPath( | ||||||
|  | 			fmt.Sprintf("/openapi/v1/%s/sites/%s/aps/%s", | ||||||
|  | 				api.config.OmadaID, | ||||||
|  | 				siteID, | ||||||
|  | 				macAddress)), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.Response[model.ApInfo]](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &response.Result, nil | ||||||
|  | } | ||||||
							
								
								
									
										151
									
								
								api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								api.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | |||||||
|  | package omadaapi | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"git.tordarus.net/tordarus/ezhttp" | ||||||
|  | 	"git.tordarus.net/tordarus/omada-api/model" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Api struct { | ||||||
|  | 	tmpl *http.Request | ||||||
|  |  | ||||||
|  | 	config ApiConfig | ||||||
|  |  | ||||||
|  | 	accessToken  string | ||||||
|  | 	refreshToken string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ApiConfig struct { | ||||||
|  | 	BasePath     string | ||||||
|  | 	OmadaID      string | ||||||
|  | 	ClientID     string | ||||||
|  | 	ClientSecret string | ||||||
|  | 	Username     string | ||||||
|  | 	Password     string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewApi(config ApiConfig) (*Api, error) { | ||||||
|  | 	tmpl := ezhttp.Request(ezhttp.URL(config.BasePath)) | ||||||
|  |  | ||||||
|  | 	api := &Api{ | ||||||
|  | 		tmpl:   tmpl, | ||||||
|  | 		config: config, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	loginResponse, err := api.Login() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("login request failed: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if loginResponse.ErrorCode != 0 { | ||||||
|  | 		return nil, fmt.Errorf("login request failed: %s", loginResponse.Message) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	authCodeResponse, err := api.AuthCode(loginResponse.Result.CsrfToken, loginResponse.Result.SessionID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("auth code request failed: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if authCodeResponse.ErrorCode != 0 { | ||||||
|  | 		return nil, fmt.Errorf("auth code request failed: %s", authCodeResponse.Message) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	authTokenResponse, err := api.AuthToken(*authCodeResponse.Result) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("auth token request failed: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if authTokenResponse.ErrorCode != 0 { | ||||||
|  | 		return nil, fmt.Errorf("auth token request failed: %s", authTokenResponse.Message) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	api.accessToken = authTokenResponse.Result.AccessToken | ||||||
|  | 	api.refreshToken = authTokenResponse.Result.RefreshToken | ||||||
|  |  | ||||||
|  | 	api.tmpl = ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Headers("Authorization", "AccessToken="+api.accessToken), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	return api, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) Login() (*model.LoginResponse, error) { | ||||||
|  | 	reqBody := model.LoginRequest{ | ||||||
|  | 		Username: api.config.Username, | ||||||
|  | 		Password: api.config.Password, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("POST"), | ||||||
|  | 		ezhttp.AppendPath("/openapi/authorize/login"), | ||||||
|  | 		ezhttp.Query("client_id", api.config.ClientID, "omadac_id", api.config.OmadaID), | ||||||
|  | 		ezhttp.Body(ezhttp.JSON(reqBody)), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.LoginResponse](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) AuthCode(csrfToken, sessionID string) (*model.AuthCodeResponse, error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("POST"), | ||||||
|  | 		ezhttp.AppendPath("/openapi/authorize/code"), | ||||||
|  | 		ezhttp.Query("client_id", api.config.ClientID, "omadac_id", api.config.OmadaID, "response_type", "code"), | ||||||
|  | 		ezhttp.Headers("Csrf-Token", csrfToken, "Cookie", fmt.Sprintf("TPOMADA_SESSIONID=%s", sessionID)), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.AuthCodeResponse](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) AuthToken(authCode string) (*model.AuthTokenResponse, error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("POST"), | ||||||
|  | 		ezhttp.AppendPath("/openapi/authorize/token"), | ||||||
|  | 		ezhttp.Query( | ||||||
|  | 			"code", authCode, | ||||||
|  | 			"grant_type", "authorization_code", | ||||||
|  | 			"client_id", api.config.ClientID, | ||||||
|  | 			"client_secret", api.config.ClientSecret, | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.AuthTokenResponse](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								client.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | package omadaapi | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  |  | ||||||
|  | 	"git.tordarus.net/tordarus/ezhttp" | ||||||
|  | 	"git.tordarus.net/tordarus/omada-api/model" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (api *Api) GetClients(siteID model.SiteID) <-chan *model.Client { | ||||||
|  | 	out := make(chan *model.Client, 1000) | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		defer close(out) | ||||||
|  |  | ||||||
|  | 		for page := 1; ; page++ { | ||||||
|  | 			resp, err := api.getClients(page, siteID) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for _, v := range resp.Result.Data { | ||||||
|  | 				out <- &v | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if resp.Result.CurrentPage*resp.Result.CurrentSize >= resp.Result.TotalRows { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) getClients(page int, siteID model.SiteID) (*model.PagedResponse[model.Client], error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("GET"), | ||||||
|  | 		ezhttp.AppendPath(fmt.Sprintf("/openapi/v1/%s/sites/%s/clients", api.config.OmadaID, siteID)), | ||||||
|  | 		ezhttp.Query( | ||||||
|  | 			"page", strconv.Itoa(page), | ||||||
|  | 			"pageSize", "100", | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.PagedResponse[model.Client]](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								device.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								device.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | package omadaapi | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  |  | ||||||
|  | 	"git.tordarus.net/tordarus/ezhttp" | ||||||
|  | 	"git.tordarus.net/tordarus/omada-api/model" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (api *Api) GetDevices(siteID model.SiteID) <-chan *model.Device { | ||||||
|  | 	out := make(chan *model.Device, 1000) | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		defer close(out) | ||||||
|  |  | ||||||
|  | 		for page := 1; ; page++ { | ||||||
|  | 			resp, err := api.getDevices(page, siteID) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for _, v := range resp.Result.Data { | ||||||
|  | 				out <- &v | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if resp.Result.CurrentPage*resp.Result.CurrentSize >= resp.Result.TotalRows { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) getDevices(page int, siteID model.SiteID) (*model.PagedResponse[model.Device], error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("GET"), | ||||||
|  | 		ezhttp.AppendPath(fmt.Sprintf("/openapi/v1/%s/sites/%s/devices", api.config.OmadaID, siteID)), | ||||||
|  | 		ezhttp.Query( | ||||||
|  | 			"page", strconv.Itoa(page), | ||||||
|  | 			"pageSize", "100", | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.PagedResponse[model.Device]](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | module git.tordarus.net/tordarus/omada-api | ||||||
|  |  | ||||||
|  | go 1.23.0 | ||||||
|  |  | ||||||
|  | require git.tordarus.net/tordarus/ezhttp v0.0.3 | ||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | git.tordarus.net/tordarus/ezhttp v0.0.3 h1:K6IlLmqkAFUF68HJsOTKcP3ejco7qfm+MuEagohoouo= | ||||||
|  | git.tordarus.net/tordarus/ezhttp v0.0.3/go.mod h1:Zq9o0Hibny61GqSCwJHa0PfGjVoUFv/zt2PjiQHXvmY= | ||||||
							
								
								
									
										40
									
								
								model/ap_info.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								model/ap_info.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | import "encoding/json" | ||||||
|  |  | ||||||
|  | type ApInfo struct { | ||||||
|  | 	Type               string                `json:"type"` | ||||||
|  | 	MacAddress         string                `json:"mac"` | ||||||
|  | 	Name               string                `json:"name"` | ||||||
|  | 	IP                 string                `json:"ip"` | ||||||
|  | 	IPv6               []string              `json:"ipv6List"` | ||||||
|  | 	WlanGroupID        string                `json:"wlanId"` | ||||||
|  | 	WirelessUplinkInfo *ApWirelessUplinkInfo `json:"wirelessUplink"` | ||||||
|  | 	Model              string                `json:"model"` | ||||||
|  | 	FirmwareVersion    string                `json:"firmwareVersion"` | ||||||
|  | 	CpuUtil            int                   `json:"cpuUtil"` | ||||||
|  | 	MemUtil            int                   `json:"memoryUtil"` | ||||||
|  | 	UptimeSeconds      int                   `json:"uptimeLong"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (i ApInfo) String() string { | ||||||
|  | 	data, _ := json.MarshalIndent(i, "", "\t") | ||||||
|  | 	return string(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ApWirelessUplinkInfo struct { | ||||||
|  | 	UplinkMacAddress string `json:"uplinkMac"` | ||||||
|  | 	Name             string `json:"name"` | ||||||
|  | 	Channel          int    `json:"channel"` | ||||||
|  | 	SignalStrengh    int    `json:"rssi"` | ||||||
|  | 	SignalNoiseRatio int    `json:"snr"` | ||||||
|  | 	TransferRate     string `json:"txRate"` | ||||||
|  | 	TransferRateMbps int    `json:"txRateInt"` | ||||||
|  | 	ReceiveRate      string `json:"rxRate"` | ||||||
|  | 	ReceiveRateMbps  int    `json:"rxRateInt"` | ||||||
|  | 	UpBytes          int    `json:"upBytes"` | ||||||
|  | 	DownBytes        int    `json:"downBytes"` | ||||||
|  | 	UpPackets        int    `json:"upPackets"` | ||||||
|  | 	DownPackets      int    `json:"downPackets"` | ||||||
|  | 	Activity         int    `json:"activity"` | ||||||
|  | } | ||||||
							
								
								
									
										209
									
								
								model/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								model/client.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,209 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | import "encoding/json" | ||||||
|  |  | ||||||
|  | type Client struct { | ||||||
|  | 	ID                        string                      `json:"id"` | ||||||
|  | 	MacAddress                string                      `json:"mac"` | ||||||
|  | 	Name                      string                      `json:"name"` | ||||||
|  | 	Hostname                  string                      `json:"hostName"` | ||||||
|  | 	Vendor                    string                      `json:"vendor"` | ||||||
|  | 	DeviceType                string                      `json:"deviceType"` | ||||||
|  | 	DeviceCategory            string                      `json:"deviceCategory"` | ||||||
|  | 	OsName                    string                      `json:"osName"` | ||||||
|  | 	IP                        string                      `json:"ip"` | ||||||
|  | 	IPv6List                  []string                    `json:"ipv6List"` | ||||||
|  | 	ConnectionType            ConnectionType              `json:"connectType"` | ||||||
|  | 	ConnectionDevType         ConnectionDeviceType        `json:"connectDevType"` | ||||||
|  | 	ConnectedToWirelessRouter bool                        `json:"connectedToWirelessRouter"` | ||||||
|  | 	Wireless                  bool                        `json:"wireless"` | ||||||
|  | 	SSID                      string                      `json:"ssid"` | ||||||
|  | 	SignalLevel               int                         `json:"signalLevel"` | ||||||
|  | 	HealthScore               int                         `json:"healthScore"` | ||||||
|  | 	SignalRank                int                         `json:"signalRank"` | ||||||
|  | 	WifiMode                  WifiMode                    `json:"wifiMode"` | ||||||
|  | 	ApName                    string                      `json:"apName"` | ||||||
|  | 	ApMac                     string                      `json:"apMac"` | ||||||
|  | 	RadioID                   RadioID                     `json:"radioId"` | ||||||
|  | 	Channel                   int                         `json:"channel"` | ||||||
|  | 	ReceiveRateKbits          int                         `json:"rxRate"` | ||||||
|  | 	TransferRateKbits         int                         `json:"txRate"` | ||||||
|  | 	PowerSave                 bool                        `json:"powerSave"` | ||||||
|  | 	SignalStrengh             int                         `json:"rssi"` | ||||||
|  | 	SignalNoiseRatio          int                         `json:"snr"` | ||||||
|  | 	SwitchMac                 string                      `json:"switchMac"` | ||||||
|  | 	SwitchName                string                      `json:"switchName"` | ||||||
|  | 	GatewayMac                string                      `json:"gatewayMac"` | ||||||
|  | 	GatewayName               string                      `json:"gatewayName"` | ||||||
|  | 	VLanID                    int                         `json:"vid"` | ||||||
|  | 	NetworkName               string                      `json:"networkName"` | ||||||
|  | 	Dot1xIdentity             string                      `json:"dot1xIdentity"` | ||||||
|  | 	Dot1xVlan                 int                         `json:"dot1xVlan"` | ||||||
|  | 	Port                      int                         `json:"port"` | ||||||
|  | 	LagID                     int                         `json:"lagId"` | ||||||
|  | 	Activity                  int                         `json:"activity"` | ||||||
|  | 	TrafficDownBytes          int                         `json:"trafficDown"` | ||||||
|  | 	TrafficUpBytes            int                         `json:"trafficUp"` | ||||||
|  | 	UptimeSeconds             int                         `json:"uptime"` | ||||||
|  | 	LastSeen                  int                         `json:"lastSeen"` | ||||||
|  | 	AuthStatus                AuthStatus                  `json:"authStatus"` | ||||||
|  | 	Blocked                   bool                        `json:"blocked"` | ||||||
|  | 	Guest                     bool                        `json:"guest"` | ||||||
|  | 	Active                    bool                        `json:"active"` | ||||||
|  | 	Manager                   bool                        `json:"manager"` | ||||||
|  | 	IpSetting                 *ClientIpSetting            `json:"ipSetting"` | ||||||
|  | 	DownPacket                int                         `json:"downPacket"` | ||||||
|  | 	UpPacket                  int                         `json:"upPacket"` | ||||||
|  | 	RateLimit                 *ClientRateLimit            `json:"rateLimit"` | ||||||
|  | 	ClientLockToApSetting     *ClientLockToApSetting      `json:"clientLockToApSetting"` | ||||||
|  | 	MultiLink                 []*ClientMultiFrequencyInfo `json:"multiLink"` | ||||||
|  | 	Unit                      int                         `json:"unit"` | ||||||
|  | 	StandardPort              string                      `json:"standardPort"` | ||||||
|  | 	BlockDisable              bool                        `json:"blockDisable"` | ||||||
|  | 	DhcpLeaseTimeSeconds      int                         `json:"dhcpLeaseTime"` | ||||||
|  | 	SystemName                string                      `json:"systemName"` | ||||||
|  | 	Description               string                      `json:"description"` | ||||||
|  | 	Capabilities              []string                    `json:"capabilities"` | ||||||
|  | 	ClientStat                *ClientStat                 `json:"clientStat"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c Client) String() string { | ||||||
|  | 	data, _ := json.MarshalIndent(c, "", "\t") | ||||||
|  | 	return string(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ConnectionType int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	ConnectionTypeWirelessGuest ConnectionType = iota | ||||||
|  | 	ConnectionTypeWirelessUser | ||||||
|  | 	ConnectionTypeWiredUser | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type ConnectionDeviceType string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	ConnectionDeviceTypeAP      ConnectionDeviceType = "ap" | ||||||
|  | 	ConnectionDeviceTypeSwitch  ConnectionDeviceType = "switch" | ||||||
|  | 	ConnectionDeviceTypeGateway ConnectionDeviceType = "gateway" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type WifiMode int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	WifiMode11a WifiMode = iota | ||||||
|  | 	WifiMode11b | ||||||
|  | 	WifiMode11g | ||||||
|  | 	WifiMode11na | ||||||
|  | 	WifiMode11ng | ||||||
|  | 	WifiMode11ac | ||||||
|  | 	WifiMode11axa | ||||||
|  | 	WifiMode11axg | ||||||
|  | 	WifiMode11beg | ||||||
|  | 	WifiMode11bea | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type RadioID int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	RadioID_2_4G RadioID = iota | ||||||
|  | 	RadioID_5G   RadioID = iota | ||||||
|  | 	RadioID_5G2  RadioID = iota | ||||||
|  | 	RadioID_6G   RadioID = iota | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type AuthStatus int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	AuthStatusConnected AuthStatus = iota | ||||||
|  | 	AuthStatusPending | ||||||
|  | 	AuthStatusAuthorized | ||||||
|  | 	AuthStatusAuthFree | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type ClientIpSetting struct { | ||||||
|  | 	UseFixedAddr bool   `json:"useFixedAddr"` | ||||||
|  | 	NetID        string `json:"netId"` | ||||||
|  | 	IP           string `json:"ip"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ClientRateLimit struct { | ||||||
|  | 	Mode               RateLimitMode    `json:"mode"` | ||||||
|  | 	RateLimitProfileID string           `json:"rateLimitProfileId"` | ||||||
|  | 	CustomRateLimit    *CustomRateLimit `json:"customRateLimit"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type RateLimitMode int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	RateLimitModeCustom RateLimitMode = iota | ||||||
|  | 	RateLimitModeProfile | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type CustomRateLimit struct { | ||||||
|  | 	UpEnable   bool      `json:"upEnable"` | ||||||
|  | 	UpUnit     SpeedUnit `json:"upUnit"` | ||||||
|  | 	UpLimit    int       `json:"upLimit"` | ||||||
|  | 	DownEnable bool      `json:"downEnable"` | ||||||
|  | 	DownUnit   SpeedUnit `json:"downUnit"` | ||||||
|  | 	DownLimit  int       `json:"downLimit"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type SpeedUnit int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	SpeedUnitKbps SpeedUnit = iota | ||||||
|  | 	SpeedUnitMbps | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type ClientLockToApSetting struct { | ||||||
|  | 	Enable bool           `json:"enable"` | ||||||
|  | 	APs    []*ApBriefInfo `json:"aps"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ApBriefInfo struct { | ||||||
|  | 	Name       string `json:"name"` | ||||||
|  | 	MacAddress string `json:"mac"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ClientMultiFrequencyInfo struct { | ||||||
|  | 	RadioID            int      `json:"radioId"` | ||||||
|  | 	WifiMode           WifiMode `json:"wifiMode"` | ||||||
|  | 	Channel            int      `json:"channel"` | ||||||
|  | 	ReceiveRateKbits   int      `json:"rxRate"` | ||||||
|  | 	TransferRateKbits  int      `json:"txRate"` | ||||||
|  | 	PowerSave          bool     `json:"powerSave"` | ||||||
|  | 	SignalStrengh      int      `json:"rssi"` | ||||||
|  | 	SignalNoiseRatio   int      `json:"snr"` | ||||||
|  | 	SignalLevel        int      `json:"signalLevel"` | ||||||
|  | 	SignalRank         int      `json:"signalRank"` | ||||||
|  | 	UpPacket           int      `json:"upPacket"` | ||||||
|  | 	DownPacket         int      `json:"downPacket"` | ||||||
|  | 	TrafficDownBytes   int      `json:"trafficDown"` | ||||||
|  | 	TrafficUpBytes     int      `json:"trafficUp"` | ||||||
|  | 	Activity           int      `json:"activity"` | ||||||
|  | 	SignalLevelAndRank int      `json:"signalLevelAndRank"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ClientStat struct { | ||||||
|  | 	Total            int `json:"total"` | ||||||
|  | 	Wireless         int `json:"wireless"` | ||||||
|  | 	Wired            int `json:"wired"` | ||||||
|  | 	Num2G            int `json:"num2g"` | ||||||
|  | 	Num5G            int `json:"num5g"` | ||||||
|  | 	Num6G            int `json:"num6g"` | ||||||
|  | 	NumUser          int `json:"numUser"` | ||||||
|  | 	NumGuest         int `json:"numGuest"` | ||||||
|  | 	NumWirelessUser  int `json:"numWirelessUser"` | ||||||
|  | 	NumWirelessGuest int `json:"numWirelessGuest"` | ||||||
|  | 	Num2gUser        int `json:"num2gUser"` | ||||||
|  | 	Num5gUser        int `json:"num5gUser"` | ||||||
|  | 	Num6gUser        int `json:"num6gUser"` | ||||||
|  | 	Num2gGuest       int `json:"num2gGuest"` | ||||||
|  | 	Num5gGuest       int `json:"num5gGuest"` | ||||||
|  | 	Num6gGuest       int `json:"num6gGuest"` | ||||||
|  | 	Poor             int `json:"poor"` | ||||||
|  | 	Fair             int `json:"fair"` | ||||||
|  | 	NoData           int `json:"noData"` | ||||||
|  | 	Good             int `json:"good"` | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								model/device.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								model/device.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Device struct { | ||||||
|  | 	MacAddress       string       `json:"mac"` | ||||||
|  | 	Name             string       `json:"name"` | ||||||
|  | 	Type             DeviceType   `json:"type"` | ||||||
|  | 	Subtype          string       `json:"subtype"` | ||||||
|  | 	DeviceSeriesType int          `json:"deviceSeriesType"` | ||||||
|  | 	Model            string       `json:"model"` | ||||||
|  | 	IP               string       `json:"ip"` | ||||||
|  | 	IPv6             []string     `json:"ipv6"` | ||||||
|  | 	Uptime           string       `json:"uptime"` | ||||||
|  | 	Status           DeviceStatus `json:"status"` | ||||||
|  | 	LastSeen         int          `json:"lastSeen"` | ||||||
|  | 	CpuUtil          int          `json:"cpuUtil"` | ||||||
|  | 	MemUtil          int          `json:"memUtil"` | ||||||
|  | 	SerialNumber     string       `json:"sn"` | ||||||
|  | 	LicenseStatus    int          `json:"licenseStatus"` | ||||||
|  | 	TagName          string       `json:"tagName"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d Device) String() string { | ||||||
|  | 	data, _ := json.MarshalIndent(d, "", "\t") | ||||||
|  | 	return string(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type DeviceStatus int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	DeviceStatusDisconnected DeviceStatus = iota | ||||||
|  | 	DeviceStatusConnected | ||||||
|  | 	DeviceStatusPending | ||||||
|  | 	DeviceStatusHeartbeatMissed | ||||||
|  | 	DeviceStatusIsolated | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type DeviceType string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	DeviceTypeAP DeviceType = "ap" | ||||||
|  | ) | ||||||
							
								
								
									
										26
									
								
								model/login.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								model/login.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | type LoginRequest struct { | ||||||
|  | 	Username string `json:"username"` | ||||||
|  | 	Password string `json:"password"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type LoginResponse Response[LoginResponseResult] | ||||||
|  | type LoginResponseResult struct { | ||||||
|  | 	CsrfToken string `json:"csrfToken"` | ||||||
|  | 	SessionID string `json:"sessionId"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type AuthCodeResponse struct { | ||||||
|  | 	ErrorCode int     `json:"errorCode"` | ||||||
|  | 	Message   string  `json:"msg"` | ||||||
|  | 	Result    *string `json:"result"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type AuthTokenResponse Response[AuthTokenResponseResult] | ||||||
|  | type AuthTokenResponseResult struct { | ||||||
|  | 	AccessToken  string `json:"accessToken"` | ||||||
|  | 	TokenType    string `json:"tokenType"` | ||||||
|  | 	ExpiresIn    int    `json:"expiresIn"` | ||||||
|  | 	RefreshToken string `json:"refreshToken"` | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								model/response.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								model/response.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | type Response[T any] struct { | ||||||
|  | 	ErrorCode int    `json:"errorCode"` | ||||||
|  | 	Message   string `json:"msg"` | ||||||
|  | 	Result    T      `json:"result"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type PagedResponse[T any] Response[PagedResponseResult[T]] | ||||||
|  | type PagedResponseResult[T any] struct { | ||||||
|  | 	TotalRows   int `json:"totalRows"` | ||||||
|  | 	CurrentPage int `json:"currentPage"` | ||||||
|  | 	CurrentSize int `json:"currentSize"` | ||||||
|  | 	Data        []T `json:"data"` | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								model/site.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								model/site.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | package model | ||||||
|  |  | ||||||
|  | import "encoding/json" | ||||||
|  |  | ||||||
|  | type SiteID string | ||||||
|  | type Site struct { | ||||||
|  | 	ID        SiteID   `json:"siteId"` | ||||||
|  | 	Name      string   `json:"name"` | ||||||
|  | 	TagIDs    []string `json:"tagIds"` | ||||||
|  | 	Region    string   `json:"region"` | ||||||
|  | 	TimeZone  string   `json:"timeZone"` | ||||||
|  | 	Scenario  string   `json:"scenario"` | ||||||
|  | 	Longitude float64  `json:"longitude"` | ||||||
|  | 	Latitude  float64  `json:"latitude"` | ||||||
|  | 	Address   string   `json:"address"` | ||||||
|  | 	Type      int      `json:"type,omitempty"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s Site) String() string { | ||||||
|  | 	data, _ := json.MarshalIndent(s, "", "\t") | ||||||
|  | 	return string(data) | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								site.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								site.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | package omadaapi | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  |  | ||||||
|  | 	"git.tordarus.net/tordarus/ezhttp" | ||||||
|  | 	"git.tordarus.net/tordarus/omada-api/model" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (api *Api) GetSites() <-chan *model.Site { | ||||||
|  | 	out := make(chan *model.Site, 1000) | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		defer close(out) | ||||||
|  |  | ||||||
|  | 		for page := 1; ; page++ { | ||||||
|  | 			resp, err := api.getSites(page) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for _, v := range resp.Result.Data { | ||||||
|  | 				out <- &v | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if resp.Result.CurrentPage*resp.Result.CurrentSize >= resp.Result.TotalRows { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (api *Api) getSites(page int) (*model.PagedResponse[model.Site], error) { | ||||||
|  | 	req := ezhttp.Request( | ||||||
|  | 		ezhttp.Template(api.tmpl), | ||||||
|  | 		ezhttp.Method("GET"), | ||||||
|  | 		ezhttp.AppendPath(fmt.Sprintf("/openapi/v1/%s/sites", api.config.OmadaID)), | ||||||
|  | 		ezhttp.Query( | ||||||
|  | 			"page", strconv.Itoa(page), | ||||||
|  | 			"pageSize", "100", | ||||||
|  | 		), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	resp, err := ezhttp.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer resp.Body.Close() | ||||||
|  |  | ||||||
|  | 	response, err := ezhttp.ParseJsonResponse[model.PagedResponse[model.Site]](resp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return response, nil | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user