2021-02-25 09:04:39 +01:00
|
|
|
package fbx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-02-26 08:15:12 +01:00
|
|
|
"io"
|
2021-02-25 09:04:39 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/trazfr/freebox-exporter/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
errAuthRequired = errors.New("auth_required")
|
|
|
|
errInvalidToken = errors.New("invalid_token")
|
|
|
|
)
|
|
|
|
|
|
|
|
type FreeboxHttpClient struct {
|
2021-02-26 08:15:12 +01:00
|
|
|
client http.Client
|
|
|
|
ctx context.Context
|
|
|
|
decoder func(io.Reader, interface{}) error
|
2021-02-25 09:04:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type FreeboxHttpClientCallback func(*http.Request)
|
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
func jsonDecoder(reader io.Reader, out interface{}) error {
|
|
|
|
return json.NewDecoder(reader).Decode(out)
|
|
|
|
}
|
|
|
|
func jsonDebugDecoder(reader io.Reader, out interface{}) error {
|
|
|
|
data, err := ioutil.ReadAll(reader)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-27 21:36:56 +01:00
|
|
|
log.Debug.Println("HTTP result:", string(data))
|
2021-02-26 08:15:12 +01:00
|
|
|
return jsonDecoder(bytes.NewBuffer(data), out)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFreeboxHttpClient(debug bool) *FreeboxHttpClient {
|
|
|
|
result := &FreeboxHttpClient{
|
2021-02-25 09:04:39 +01:00
|
|
|
client: http.Client{
|
|
|
|
Transport: &http.Transport{
|
2021-02-27 11:15:08 +01:00
|
|
|
TLSClientConfig: newTLSConfig(),
|
|
|
|
MaxIdleConnsPerHost: 10,
|
|
|
|
IdleConnTimeout: 10 * time.Minute,
|
2021-02-25 09:04:39 +01:00
|
|
|
},
|
|
|
|
Timeout: 10 * time.Second,
|
|
|
|
},
|
2021-02-26 08:15:12 +01:00
|
|
|
ctx: context.Background(),
|
|
|
|
decoder: jsonDecoder,
|
|
|
|
}
|
|
|
|
|
|
|
|
if debug {
|
|
|
|
log.Debug.Println("Debug enabled")
|
|
|
|
result.decoder = jsonDebugDecoder
|
2021-02-25 09:04:39 +01:00
|
|
|
}
|
2021-02-26 08:15:12 +01:00
|
|
|
|
|
|
|
return result
|
2021-02-25 09:04:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FreeboxHttpClient) Get(url string, out interface{}, callbacks ...FreeboxHttpClientCallback) error {
|
|
|
|
req, err := http.NewRequestWithContext(f.ctx, "GET", url, nil)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, cb := range callbacks {
|
|
|
|
cb(req)
|
|
|
|
}
|
|
|
|
return f.do(req, out)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FreeboxHttpClient) Post(url string, in interface{}, out interface{}, callbacks ...FreeboxHttpClientCallback) error {
|
|
|
|
buffer := new(bytes.Buffer)
|
|
|
|
if err := json.NewEncoder(buffer).Encode(in); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(f.ctx, "POST", url, buffer)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
for _, cb := range callbacks {
|
|
|
|
cb(req)
|
|
|
|
}
|
|
|
|
return f.do(req, out)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *FreeboxHttpClient) do(req *http.Request, out interface{}) error {
|
2021-02-27 21:36:56 +01:00
|
|
|
log.Debug.Println("HTTP request:", req.Method, req.URL.Path)
|
|
|
|
|
2021-02-25 09:04:39 +01:00
|
|
|
res, err := f.client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-26 08:15:12 +01:00
|
|
|
defer res.Body.Close()
|
2021-02-25 09:04:39 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
r := struct {
|
|
|
|
Success bool `json:"success"`
|
|
|
|
Message string `json:"msg"`
|
|
|
|
ErrorCode string `json:"error_code"`
|
|
|
|
Result interface{} `json:"result"`
|
|
|
|
}{
|
|
|
|
Result: out,
|
|
|
|
}
|
2021-02-26 08:15:12 +01:00
|
|
|
if err := f.decoder(res.Body, &r); err != nil {
|
2021-02-25 09:04:39 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if r.Success == false {
|
|
|
|
switch r.ErrorCode {
|
|
|
|
case errAuthRequired.Error():
|
|
|
|
return errAuthRequired
|
|
|
|
case errInvalidToken.Error():
|
|
|
|
return errInvalidToken
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("%s %s error_code=%s msg=%s", req.Method, req.URL, r.ErrorCode, r.Message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|