chore: refactor plugin structure (#18335)
This commit is contained in:
parent
9127e1a913
commit
07fa1b64f8
127 changed files with 861 additions and 938 deletions
164
plugin/socket.go
Normal file
164
plugin/socket.go
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/plugin/pipeline"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/transport"
|
||||
)
|
||||
|
||||
const retryDelay = 5 * time.Second
|
||||
|
||||
// Socket implements websocket request provider
|
||||
type Socket struct {
|
||||
*getter
|
||||
*request.Helper
|
||||
log *util.Logger
|
||||
url string
|
||||
headers map[string]string
|
||||
pipeline *pipeline.Pipeline
|
||||
val *util.Monitor[[]byte]
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("ws", NewSocketPluginFromConfig)
|
||||
registry.Add("websocket", NewSocketPluginFromConfig)
|
||||
}
|
||||
|
||||
// NewSocketPluginFromConfig creates a HTTP provider
|
||||
func NewSocketPluginFromConfig(other map[string]interface{}) (Plugin, error) {
|
||||
cc := struct {
|
||||
URI string
|
||||
Headers map[string]string
|
||||
pipeline.Settings `mapstructure:",squash"`
|
||||
Scale float64
|
||||
Insecure bool
|
||||
Auth Auth
|
||||
Timeout time.Duration
|
||||
}{
|
||||
Headers: make(map[string]string),
|
||||
Scale: 1,
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := util.NewLogger("ws")
|
||||
|
||||
url := util.DefaultScheme(cc.URI, "ws")
|
||||
if url != cc.URI {
|
||||
log.WARN.Printf("missing scheme for %s, assuming ws", cc.URI)
|
||||
}
|
||||
|
||||
p := &Socket{
|
||||
log: log,
|
||||
Helper: request.NewHelper(log),
|
||||
url: url,
|
||||
headers: cc.Headers,
|
||||
val: util.NewMonitor[[]byte](cc.Timeout),
|
||||
}
|
||||
|
||||
p.getter = defaultGetters(p, cc.Scale)
|
||||
|
||||
// handle basic auth
|
||||
if cc.Auth.Type != "" {
|
||||
basicAuth := transport.BasicAuthHeader(cc.Auth.User, cc.Auth.Password)
|
||||
log.Redact(basicAuth)
|
||||
|
||||
p.headers["Authorization"] = basicAuth
|
||||
}
|
||||
|
||||
// ignore the self signed certificate
|
||||
if cc.Insecure {
|
||||
p.Client.Transport = request.NewTripper(log, transport.Insecure())
|
||||
}
|
||||
|
||||
var err error
|
||||
if p.pipeline, err = pipeline.New(log, cc.Settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
errC := make(chan error, 1)
|
||||
go p.run(errC)
|
||||
|
||||
if cc.Timeout > 0 {
|
||||
select {
|
||||
case <-p.val.Done():
|
||||
case <-time.After(cc.Timeout):
|
||||
return nil, api.ErrTimeout
|
||||
case err := <-errC:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Socket) run(errC chan error) {
|
||||
var once sync.Once
|
||||
|
||||
headers := make(http.Header)
|
||||
for k, v := range p.headers {
|
||||
headers.Set(k, v)
|
||||
}
|
||||
|
||||
opts := &websocket.DialOptions{
|
||||
HTTPHeader: headers,
|
||||
}
|
||||
|
||||
for {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), request.Timeout)
|
||||
conn, _, err := websocket.Dial(ctx, p.url, opts)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
// handle initial connection error immediately
|
||||
once.Do(func() { errC <- err })
|
||||
|
||||
p.log.ERROR.Println(err)
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
for {
|
||||
_, b, err := conn.Read(context.Background())
|
||||
if err != nil {
|
||||
p.log.TRACE.Println("read:", err)
|
||||
_ = conn.Close(websocket.StatusAbnormalClosure, "done")
|
||||
break
|
||||
}
|
||||
|
||||
p.log.TRACE.Printf("recv: %s", b)
|
||||
|
||||
if v, err := p.pipeline.Process(b); err == nil {
|
||||
p.val.Set(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ Getters = (*Socket)(nil)
|
||||
|
||||
// StringGetter sends string request
|
||||
func (p *Socket) StringGetter() (func() (string, error), error) {
|
||||
return func() (string, error) {
|
||||
val, err := p.val.Get()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := knownErrors(val); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(val), nil
|
||||
}, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue