evcc-io/cmd/detect/tasks/http.go
2025-02-28 16:59:15 +01:00

133 lines
2.2 KiB
Go

package tasks
import (
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/jq"
"github.com/itchyny/gojq"
)
const Http TaskType = "http"
func init() {
registry.Add(Http, HttpHandlerFactory)
}
type HttpResult struct {
Jq interface{}
}
func HttpHandlerFactory(conf map[string]interface{}) (TaskHandler, error) {
handler := HttpHandler{
Schema: "http",
Method: "GET",
Codes: []int{200},
Header: map[string]string{
"Content-type": "application/json",
},
Timeout: 3 * timeout,
}
err := util.DecodeOther(conf, &handler)
switch handler.Schema {
case "http":
handler.Port = 80
case "https":
handler.Port = 443
}
if handler.Jq != "" {
query, err := gojq.Parse(handler.Jq)
if err != nil {
return nil, fmt.Errorf("invalid jq query: %s (%s)", handler.Jq, err)
}
handler.query = query
}
return &handler, err
}
type HttpHandler struct {
query *gojq.Query
Port int
Schema, Method, Path string
Codes []int
Header map[string]string
ResponseHeader map[string]string
Jq string
Timeout time.Duration
}
func (h *HttpHandler) Test(log *util.Logger, in ResultDetails) []ResultDetails {
port := in.Port
if port == 0 {
port = h.Port
}
if port == 0 {
panic("http: invalid port")
}
uri := fmt.Sprintf("%s://%s:%d/%s", h.Schema, in.IP, port, strings.TrimLeft(h.Path, "/"))
req, err := http.NewRequest(strings.ToUpper(h.Method), uri, nil)
if err != nil {
return nil
}
client := http.Client{
Timeout: h.Timeout,
}
resp, err := client.Do(req)
if err != nil {
return nil
}
defer resp.Body.Close()
if len(h.Codes) > 0 {
var status bool
for _, code := range h.Codes {
if resp.StatusCode == code {
status = true
break
}
}
if !status {
return nil
}
}
for k, v := range h.ResponseHeader {
if resp.Header.Get(k) != v {
return nil
}
}
var res HttpResult
if h.query != nil {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil
}
val, err := jq.Query(h.query, body)
res.Jq = val
if val == nil || err != nil {
return nil
}
}
out := in
out.Port = port
return []ResultDetails{out}
}