Move code into packages

This commit is contained in:
Ingo Oppermann
2023-05-10 20:41:04 +02:00
parent 862c36c9e6
commit d214607ff8
14 changed files with 361 additions and 287 deletions

View File

@@ -1,15 +1,11 @@
package cluster package cluster
import ( import (
"bytes"
"context" "context"
"encoding/json"
"fmt"
"io"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/datarhei/core/v16/cluster/client"
httpapi "github.com/datarhei/core/v16/http/api" httpapi "github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/http/errorhandler" "github.com/datarhei/core/v16/http/errorhandler"
"github.com/datarhei/core/v16/http/handler/util" "github.com/datarhei/core/v16/http/handler/util"
@@ -17,7 +13,6 @@ import (
mwlog "github.com/datarhei/core/v16/http/middleware/log" mwlog "github.com/datarhei/core/v16/http/middleware/log"
"github.com/datarhei/core/v16/http/validator" "github.com/datarhei/core/v16/http/validator"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/restream/app"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
@@ -42,27 +37,6 @@ type APIConfig struct {
Logger log.Logger Logger log.Logger
} }
type JoinRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
RaftAddress string `json:"raft_address"`
}
type LeaveRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
}
type AddProcessRequest struct {
Origin string `json:"origin"`
Config app.Config `json:"config"`
}
type RemoveProcessRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
}
func NewAPI(config APIConfig) (API, error) { func NewAPI(config APIConfig) (API, error) {
a := &api{ a := &api{
id: config.ID, id: config.ID,
@@ -105,7 +79,7 @@ func NewAPI(config APIConfig) (API, error) {
a.router.Logger.SetOutput(httplog.NewWrapper(a.logger)) a.router.Logger.SetOutput(httplog.NewWrapper(a.logger))
a.router.POST("/v1/join", func(c echo.Context) error { a.router.POST("/v1/join", func(c echo.Context) error {
r := JoinRequest{} r := client.JoinRequest{}
if err := util.ShouldBindJSON(c, &r); err != nil { if err := util.ShouldBindJSON(c, &r); err != nil {
return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err) return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err)
@@ -127,7 +101,7 @@ func NewAPI(config APIConfig) (API, error) {
}) })
a.router.POST("/v1/leave", func(c echo.Context) error { a.router.POST("/v1/leave", func(c echo.Context) error {
r := LeaveRequest{} r := client.LeaveRequest{}
if err := util.ShouldBindJSON(c, &r); err != nil { if err := util.ShouldBindJSON(c, &r); err != nil {
return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err) return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err)
@@ -161,7 +135,7 @@ func NewAPI(config APIConfig) (API, error) {
}) })
a.router.POST("/v1/process", func(c echo.Context) error { a.router.POST("/v1/process", func(c echo.Context) error {
r := AddProcessRequest{} r := client.AddProcessRequest{}
if err := util.ShouldBindJSON(c, &r); err != nil { if err := util.ShouldBindJSON(c, &r); err != nil {
return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err) return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err)
@@ -183,7 +157,7 @@ func NewAPI(config APIConfig) (API, error) {
}) })
a.router.POST("/v1/process/:id", func(c echo.Context) error { a.router.POST("/v1/process/:id", func(c echo.Context) error {
r := RemoveProcessRequest{} r := client.RemoveProcessRequest{}
if err := util.ShouldBindJSON(c, &r); err != nil { if err := util.ShouldBindJSON(c, &r); err != nil {
return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err) return httpapi.Err(http.StatusBadRequest, "Invalid JSON", "%s", err)
@@ -220,141 +194,3 @@ func (a *api) Start() error {
func (a *api) Shutdown(ctx context.Context) error { func (a *api) Shutdown(ctx context.Context) error {
return a.router.Shutdown(ctx) return a.router.Shutdown(ctx)
} }
type APIClient struct {
Address string
Client *http.Client
}
func (c *APIClient) CoreAPIAddress() (string, error) {
data, err := c.call(http.MethodGet, "/core", "", nil)
if err != nil {
return "", err
}
var address string
err = json.Unmarshal(data, &address)
if err != nil {
return "", err
}
return address, nil
}
func (c *APIClient) Join(r JoinRequest) error {
data, err := json.Marshal(&r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/join", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) Leave(r LeaveRequest) error {
data, err := json.Marshal(&r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/leave", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) AddProcess(r AddProcessRequest) error {
data, err := json.Marshal(r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/process", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) RemoveProcess(r RemoveProcessRequest) error {
data, err := json.Marshal(r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/process/"+r.ID, "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) Snapshot() (io.ReadCloser, error) {
return c.stream(http.MethodGet, "/snapshot", "", nil)
}
func (c *APIClient) stream(method, path, contentType string, data io.Reader) (io.ReadCloser, error) {
if len(c.Address) == 0 {
return nil, fmt.Errorf("no address defined")
}
address := "http://" + c.Address + "/v1" + path
req, err := http.NewRequest(method, address, data)
if err != nil {
return nil, err
}
if method == "POST" || method == "PUT" {
req.Header.Add("Content-Type", contentType)
}
status, body, err := c.request(req)
if err != nil {
return nil, err
}
if status < 200 || status >= 300 {
e := httpapi.Error{}
defer body.Close()
x, _ := io.ReadAll(body)
json.Unmarshal(x, &e)
return nil, e
}
return body, nil
}
func (c *APIClient) call(method, path, contentType string, data io.Reader) ([]byte, error) {
body, err := c.stream(method, path, contentType, data)
if err != nil {
return nil, err
}
defer body.Close()
x, _ := io.ReadAll(body)
return x, nil
}
func (c *APIClient) request(req *http.Request) (int, io.ReadCloser, error) {
if c.Client == nil {
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
}
c.Client = &http.Client{
Transport: tr,
Timeout: 5 * time.Second,
}
}
resp, err := c.Client.Do(req)
if err != nil {
return -1, nil, err
}
return resp.StatusCode, resp.Body, nil
}

172
cluster/client/client.go Normal file
View File

@@ -0,0 +1,172 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
httpapi "github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/restream/app"
)
type JoinRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
RaftAddress string `json:"raft_address"`
}
type LeaveRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
}
type AddProcessRequest struct {
Origin string `json:"origin"`
Config app.Config `json:"config"`
}
type RemoveProcessRequest struct {
Origin string `json:"origin"`
ID string `json:"id"`
}
type APIClient struct {
Address string
Client *http.Client
}
func (c *APIClient) CoreAPIAddress() (string, error) {
data, err := c.call(http.MethodGet, "/core", "", nil)
if err != nil {
return "", err
}
var address string
err = json.Unmarshal(data, &address)
if err != nil {
return "", err
}
return address, nil
}
func (c *APIClient) Join(r JoinRequest) error {
data, err := json.Marshal(&r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/join", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) Leave(r LeaveRequest) error {
data, err := json.Marshal(&r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/leave", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) AddProcess(r AddProcessRequest) error {
data, err := json.Marshal(r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/process", "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) RemoveProcess(r RemoveProcessRequest) error {
data, err := json.Marshal(r)
if err != nil {
return err
}
_, err = c.call(http.MethodPost, "/process/"+r.ID, "application/json", bytes.NewReader(data))
return err
}
func (c *APIClient) Snapshot() (io.ReadCloser, error) {
return c.stream(http.MethodGet, "/snapshot", "", nil)
}
func (c *APIClient) stream(method, path, contentType string, data io.Reader) (io.ReadCloser, error) {
if len(c.Address) == 0 {
return nil, fmt.Errorf("no address defined")
}
address := "http://" + c.Address + "/v1" + path
req, err := http.NewRequest(method, address, data)
if err != nil {
return nil, err
}
if method == "POST" || method == "PUT" {
req.Header.Add("Content-Type", contentType)
}
status, body, err := c.request(req)
if err != nil {
return nil, err
}
if status < 200 || status >= 300 {
e := httpapi.Error{}
defer body.Close()
x, _ := io.ReadAll(body)
json.Unmarshal(x, &e)
return nil, e
}
return body, nil
}
func (c *APIClient) call(method, path, contentType string, data io.Reader) ([]byte, error) {
body, err := c.stream(method, path, contentType, data)
if err != nil {
return nil, err
}
defer body.Close()
x, _ := io.ReadAll(body)
return x, nil
}
func (c *APIClient) request(req *http.Request) (int, io.ReadCloser, error) {
if c.Client == nil {
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
}
c.Client = &http.Client{
Transport: tr,
Timeout: 5 * time.Second,
}
}
resp, err := c.Client.Do(req)
if err != nil {
return -1, nil, err
}
return resp.StatusCode, resp.Body, nil
}

View File

@@ -5,7 +5,6 @@ import (
"context" "context"
"encoding/gob" "encoding/gob"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
gonet "net" gonet "net"
@@ -16,6 +15,11 @@ import (
"sync" "sync"
"time" "time"
apiclient "github.com/datarhei/core/v16/cluster/client"
"github.com/datarhei/core/v16/cluster/forwarder"
raftlogger "github.com/datarhei/core/v16/cluster/logger"
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/cluster/store"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/net" "github.com/datarhei/core/v16/net"
"github.com/datarhei/core/v16/restream/app" "github.com/datarhei/core/v16/restream/app"
@@ -46,8 +50,6 @@ import (
** all these endpoints will forward the request to the leader. ** all these endpoints will forward the request to the leader.
*/ */
var ErrNodeNotFound = errors.New("node not found")
type Cluster interface { type Cluster interface {
// Address returns the raft address of this node // Address returns the raft address of this node
Address() string Address() string
@@ -71,7 +73,7 @@ type Cluster interface {
AddProcess(origin string, config *app.Config) error AddProcess(origin string, config *app.Config) error
RemoveProcess(origin, id string) error RemoveProcess(origin, id string) error
ProxyReader() ProxyReader ProxyReader() proxy.ProxyReader
} }
type Peer struct { type Peer struct {
@@ -113,7 +115,7 @@ type cluster struct {
peers []Peer peers []Peer
store Store store store.Store
reassertLeaderCh chan chan error reassertLeaderCh chan chan error
cancelLeaderShip context.CancelFunc cancelLeaderShip context.CancelFunc
@@ -124,9 +126,9 @@ type cluster struct {
shutdownCh chan struct{} shutdownCh chan struct{}
shutdownLock sync.Mutex shutdownLock sync.Mutex
forwarder Forwarder forwarder forwarder.Forwarder
api API api API
proxy Proxy proxy proxy.Proxy
coreAddress string coreAddress string
@@ -135,7 +137,7 @@ type cluster struct {
isLeader bool isLeader bool
leaderLock sync.Mutex leaderLock sync.Mutex
nodes map[string]Node nodes map[string]proxy.Node
nodesLock sync.RWMutex nodesLock sync.RWMutex
} }
@@ -153,7 +155,7 @@ func New(config ClusterConfig) (Cluster, error) {
leaveCh: make(chan struct{}), leaveCh: make(chan struct{}),
shutdownCh: make(chan struct{}), shutdownCh: make(chan struct{}),
nodes: map[string]Node{}, nodes: map[string]proxy.Node{},
} }
u, err := url.Parse(config.CoreAPIAddress) u, err := url.Parse(config.CoreAPIAddress)
@@ -173,7 +175,7 @@ func New(config ClusterConfig) (Cluster, error) {
c.logger = log.New("") c.logger = log.New("")
} }
store, err := NewStore() store, err := store.NewStore()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -195,7 +197,7 @@ func New(config ClusterConfig) (Cluster, error) {
c.api = api c.api = api
proxy, err := NewProxy(ProxyConfig{ nodeproxy, err := proxy.NewProxy(proxy.ProxyConfig{
ID: c.id, ID: c.id,
Name: c.name, Name: c.name,
IPLimiter: config.IPLimiter, IPLimiter: config.IPLimiter,
@@ -206,15 +208,15 @@ func New(config ClusterConfig) (Cluster, error) {
return nil, err return nil, err
} }
go func(proxy Proxy) { go func(nodeproxy proxy.Proxy) {
proxy.Start() nodeproxy.Start()
}(proxy) }(nodeproxy)
c.proxy = proxy c.proxy = nodeproxy
go c.trackNodeChanges() go c.trackNodeChanges()
if forwarder, err := NewForwarder(ForwarderConfig{ if forwarder, err := forwarder.New(forwarder.ForwarderConfig{
ID: c.id, ID: c.id,
Logger: c.logger.WithField("logname", "forwarder"), Logger: c.logger.WithField("logname", "forwarder"),
}); err != nil { }); err != nil {
@@ -299,7 +301,7 @@ func (c *cluster) CoreAPIAddress(raftAddress string) (string, error) {
return "", err return "", err
} }
client := APIClient{ client := apiclient.APIClient{
Address: addr, Address: addr,
} }
@@ -494,7 +496,7 @@ func (c *cluster) Join(origin, id, raftAddress, peerAddress string) error {
return fmt.Errorf("peer API doesn't respond: %w", err) return fmt.Errorf("peer API doesn't respond: %w", err)
} }
node := NewNode(address) node := proxy.NewNode(address)
err = node.Connect() err = node.Connect()
if err != nil { if err != nil {
return fmt.Errorf("couldn't connect to peer: %w", err) return fmt.Errorf("couldn't connect to peer: %w", err)
@@ -640,7 +642,7 @@ func (c *cluster) trackNodeChanges() {
continue continue
} }
node := NewNode(address) node := proxy.NewNode(address)
err = node.Connect() err = node.Connect()
if err != nil { if err != nil {
c.logger.Warn().WithError(err).WithFields(log.Fields{ c.logger.Warn().WithError(err).WithFields(log.Fields{
@@ -745,14 +747,14 @@ func (c *cluster) startRaft(fsm raft.FSM, bootstrap, recover bool, peers []Peer,
c.logger.Debug().Log("address: %s", addr) c.logger.Debug().Log("address: %s", addr)
transport, err := raft.NewTCPTransportWithLogger(c.raftAddress, addr, 3, 10*time.Second, NewLogger(c.logger, hclog.Debug).Named("raft-transport")) transport, err := raft.NewTCPTransportWithLogger(c.raftAddress, addr, 3, 10*time.Second, raftlogger.New(c.logger, hclog.Debug).Named("raft-transport"))
if err != nil { if err != nil {
return err return err
} }
c.raftTransport = transport c.raftTransport = transport
snapshotLogger := NewLogger(c.logger, hclog.Debug).Named("raft-snapshot") snapshotLogger := raftlogger.New(c.logger, hclog.Debug).Named("raft-snapshot")
snapshots, err := raft.NewFileSnapshotStoreWithLogger(c.path, 3, snapshotLogger) snapshots, err := raft.NewFileSnapshotStoreWithLogger(c.path, 3, snapshotLogger)
if err != nil { if err != nil {
return err return err
@@ -787,7 +789,7 @@ func (c *cluster) startRaft(fsm raft.FSM, bootstrap, recover bool, peers []Peer,
cfg := raft.DefaultConfig() cfg := raft.DefaultConfig()
cfg.LocalID = raft.ServerID(c.id) cfg.LocalID = raft.ServerID(c.id)
cfg.Logger = NewLogger(c.logger, hclog.Debug).Named("raft") cfg.Logger = raftlogger.New(c.logger, hclog.Debug).Named("raft")
hasState, err := raft.HasExistingState(logStore, stableStore, snapshots) hasState, err := raft.HasExistingState(logStore, stableStore, snapshots)
if err != nil { if err != nil {
@@ -823,7 +825,7 @@ func (c *cluster) startRaft(fsm raft.FSM, bootstrap, recover bool, peers []Peer,
c.logger.Debug().Log("raft node bootstrapped") c.logger.Debug().Log("raft node bootstrapped")
} else { } else {
// Recover cluster // Recover cluster
fsm, err := NewStore() fsm, err := store.NewStore()
if err != nil { if err != nil {
return err return err
} }
@@ -919,9 +921,9 @@ func (c *cluster) AddProcess(origin string, config *app.Config) error {
return c.forwarder.AddProcess(origin, config) return c.forwarder.AddProcess(origin, config)
} }
cmd := &command{ cmd := &store.Command{
Operation: opAddProcess, Operation: store.OpAddProcess,
Data: &addProcessCommand{ Data: &store.CommandAddProcess{
Config: *config, Config: *config,
}, },
} }
@@ -934,9 +936,9 @@ func (c *cluster) RemoveProcess(origin, id string) error {
return c.forwarder.RemoveProcess(origin, id) return c.forwarder.RemoveProcess(origin, id)
} }
cmd := &command{ cmd := &store.Command{
Operation: opRemoveProcess, Operation: store.OpRemoveProcess,
Data: &removeProcessCommand{ Data: &store.CommandRemoveProcess{
ID: id, ID: id,
}, },
} }
@@ -944,7 +946,7 @@ func (c *cluster) RemoveProcess(origin, id string) error {
return c.applyCommand(cmd) return c.applyCommand(cmd)
} }
func (c *cluster) applyCommand(cmd *command) error { func (c *cluster) applyCommand(cmd *store.Command) error {
b, err := json.Marshal(cmd) b, err := json.Marshal(cmd)
if err != nil { if err != nil {
return err return err
@@ -1076,6 +1078,6 @@ func (c *cluster) sentinel() {
} }
} }
func (c *cluster) ProxyReader() ProxyReader { func (c *cluster) ProxyReader() proxy.ProxyReader {
return c.proxy.Reader() return c.proxy.Reader()
} }

View File

@@ -1,4 +1,4 @@
package cluster package forwarder
import ( import (
"fmt" "fmt"
@@ -7,6 +7,7 @@ import (
"sync" "sync"
"time" "time"
apiclient "github.com/datarhei/core/v16/cluster/client"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/restream/app" "github.com/datarhei/core/v16/restream/app"
) )
@@ -27,7 +28,7 @@ type forwarder struct {
id string id string
lock sync.RWMutex lock sync.RWMutex
client APIClient client apiclient.APIClient
logger log.Logger logger log.Logger
} }
@@ -37,7 +38,7 @@ type ForwarderConfig struct {
Logger log.Logger Logger log.Logger
} }
func NewForwarder(config ForwarderConfig) (Forwarder, error) { func New(config ForwarderConfig) (Forwarder, error) {
f := &forwarder{ f := &forwarder{
id: config.ID, id: config.ID,
logger: config.Logger, logger: config.Logger,
@@ -57,7 +58,7 @@ func NewForwarder(config ForwarderConfig) (Forwarder, error) {
Timeout: 5 * time.Second, Timeout: 5 * time.Second,
} }
f.client = APIClient{ f.client = apiclient.APIClient{
Client: client, Client: client,
} }
@@ -86,7 +87,7 @@ func (f *forwarder) Join(origin, id, raftAddress, peerAddress string) error {
origin = f.id origin = f.id
} }
r := JoinRequest{ r := apiclient.JoinRequest{
Origin: origin, Origin: origin,
ID: id, ID: id,
RaftAddress: raftAddress, RaftAddress: raftAddress,
@@ -99,7 +100,7 @@ func (f *forwarder) Join(origin, id, raftAddress, peerAddress string) error {
f.lock.RUnlock() f.lock.RUnlock()
if len(peerAddress) != 0 { if len(peerAddress) != 0 {
client = APIClient{ client = apiclient.APIClient{
Address: peerAddress, Address: peerAddress,
Client: f.client.Client, Client: f.client.Client,
} }
@@ -113,7 +114,7 @@ func (f *forwarder) Leave(origin, id string) error {
origin = f.id origin = f.id
} }
r := LeaveRequest{ r := apiclient.LeaveRequest{
Origin: origin, Origin: origin,
ID: id, ID: id,
} }
@@ -140,7 +141,7 @@ func (f *forwarder) AddProcess(origin string, config *app.Config) error {
origin = f.id origin = f.id
} }
r := AddProcessRequest{ r := apiclient.AddProcessRequest{
Origin: origin, Origin: origin,
Config: *config, Config: *config,
} }
@@ -161,7 +162,7 @@ func (f *forwarder) RemoveProcess(origin, id string) error {
origin = f.id origin = f.id
} }
r := RemoveProcessRequest{ r := apiclient.RemoveProcessRequest{
Origin: origin, Origin: origin,
ID: id, ID: id,
} }

View File

@@ -8,6 +8,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/restream/app" "github.com/datarhei/core/v16/restream/app"
) )
@@ -471,7 +472,7 @@ func (c *cluster) doRebalance() {
} }
// normalizeProcessesAndResources normalizes the CPU and memory consumption of the processes and resources in-place. // normalizeProcessesAndResources normalizes the CPU and memory consumption of the processes and resources in-place.
func normalizeProcessesAndResources(processes []ProcessConfig, resources map[string]NodeResources) { func normalizeProcessesAndResources(processes []proxy.ProcessConfig, resources map[string]proxy.NodeResources) {
maxNCPU := .0 maxNCPU := .0
maxMemTotal := .0 maxMemTotal := .0
@@ -520,7 +521,7 @@ func normalizeProcessesAndResources(processes []ProcessConfig, resources map[str
// synchronize returns a list of operations in order to adjust the "have" list to the "want" list // synchronize returns a list of operations in order to adjust the "have" list to the "want" list
// with taking the available resources on each node into account. // with taking the available resources on each node into account.
func synchronize(want []app.Config, have []ProcessConfig, resources map[string]NodeResources) []interface{} { func synchronize(want []app.Config, have []proxy.ProcessConfig, resources map[string]proxy.NodeResources) []interface{} {
normalizeProcessesAndResources(have, resources) normalizeProcessesAndResources(have, resources)
// A map from the process ID to the process config of the processes // A map from the process ID to the process config of the processes
@@ -535,7 +536,7 @@ func synchronize(want []app.Config, have []ProcessConfig, resources map[string]N
// Now we iterate through the processes we actually have running on the nodes // Now we iterate through the processes we actually have running on the nodes
// and remove them from the wantMap. We also make sure that they are running. // and remove them from the wantMap. We also make sure that they are running.
// If a process is not on the wantMap, it will be deleted from the nodes. // If a process is not on the wantMap, it will be deleted from the nodes.
haveAfterRemove := []ProcessConfig{} haveAfterRemove := []proxy.ProcessConfig{}
for _, p := range have { for _, p := range have {
if _, ok := wantMap[p.Config.ID]; !ok { if _, ok := wantMap[p.Config.ID]; !ok {
@@ -664,7 +665,7 @@ type referenceAffinityNodeCount struct {
count uint64 count uint64
} }
func createReferenceAffinityMap(processes []ProcessConfig) map[string][]referenceAffinityNodeCount { func createReferenceAffinityMap(processes []proxy.ProcessConfig) map[string][]referenceAffinityNodeCount {
referenceAffinityMap := map[string][]referenceAffinityNodeCount{} referenceAffinityMap := map[string][]referenceAffinityNodeCount{}
for _, p := range processes { for _, p := range processes {
if len(p.Config.Reference) == 0 { if len(p.Config.Reference) == 0 {
@@ -709,11 +710,11 @@ func createReferenceAffinityMap(processes []ProcessConfig) map[string][]referenc
// rebalance returns a list of operations that will move running processes away from nodes // rebalance returns a list of operations that will move running processes away from nodes
// that are overloaded. // that are overloaded.
func rebalance(have []ProcessConfig, resources map[string]NodeResources) []interface{} { func rebalance(have []proxy.ProcessConfig, resources map[string]proxy.NodeResources) []interface{} {
normalizeProcessesAndResources(have, resources) normalizeProcessesAndResources(have, resources)
// Group the processes by node // Group the processes by node
processNodeMap := map[string][]ProcessConfig{} processNodeMap := map[string][]proxy.ProcessConfig{}
for _, p := range have { for _, p := range have {
processNodeMap[p.NodeID] = append(processNodeMap[p.NodeID], p) processNodeMap[p.NodeID] = append(processNodeMap[p.NodeID], p)

View File

@@ -3,13 +3,14 @@ package cluster
import ( import (
"testing" "testing"
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/restream/app" "github.com/datarhei/core/v16/restream/app"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNormalize(t *testing.T) { func TestNormalize(t *testing.T) {
have := []ProcessConfig{ have := []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -23,7 +24,7 @@ func TestNormalize(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 2, NCPU: 2,
CPU: 7, CPU: 7,
@@ -40,7 +41,7 @@ func TestNormalize(t *testing.T) {
normalizeProcessesAndResources(have, resources) normalizeProcessesAndResources(have, resources)
require.Equal(t, []ProcessConfig{ require.Equal(t, []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -54,7 +55,7 @@ func TestNormalize(t *testing.T) {
}, },
}, have) }, have)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 2, NCPU: 2,
CPU: 7, CPU: 7,
@@ -72,7 +73,7 @@ func TestNormalize(t *testing.T) {
// test idempotency // test idempotency
normalizeProcessesAndResources(have, resources) normalizeProcessesAndResources(have, resources)
require.Equal(t, []ProcessConfig{ require.Equal(t, []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -86,7 +87,7 @@ func TestNormalize(t *testing.T) {
}, },
}, have) }, have)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 2, NCPU: 2,
CPU: 7, CPU: 7,
@@ -111,9 +112,9 @@ func TestSynchronizeAdd(t *testing.T) {
}, },
} }
have := []ProcessConfig{} have := []proxy.ProcessConfig{}
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 7, CPU: 7,
@@ -145,7 +146,7 @@ func TestSynchronizeAdd(t *testing.T) {
}, },
}, stack) }, stack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 17, CPU: 17,
@@ -181,7 +182,7 @@ func TestSynchronizeAddReferenceAffinity(t *testing.T) {
}, },
} }
have := []ProcessConfig{ have := []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -196,7 +197,7 @@ func TestSynchronizeAddReferenceAffinity(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 1, CPU: 1,
@@ -239,9 +240,9 @@ func TestSynchronizeAddLimit(t *testing.T) {
}, },
} }
have := []ProcessConfig{} have := []proxy.ProcessConfig{}
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 81, CPU: 81,
@@ -273,7 +274,7 @@ func TestSynchronizeAddLimit(t *testing.T) {
}, },
}, stack) }, stack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 81, CPU: 81,
@@ -302,9 +303,9 @@ func TestSynchronizeAddNoResourcesCPU(t *testing.T) {
}, },
} }
have := []ProcessConfig{} have := []proxy.ProcessConfig{}
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 81, CPU: 81,
@@ -342,9 +343,9 @@ func TestSynchronizeAddNoResourcesMemory(t *testing.T) {
}, },
} }
have := []ProcessConfig{} have := []proxy.ProcessConfig{}
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 81, CPU: 81,
@@ -380,9 +381,9 @@ func TestSynchronizeAddNoLimits(t *testing.T) {
}, },
} }
have := []ProcessConfig{} have := []proxy.ProcessConfig{}
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 81, CPU: 81,
@@ -414,7 +415,7 @@ func TestSynchronizeAddNoLimits(t *testing.T) {
func TestSynchronizeRemove(t *testing.T) { func TestSynchronizeRemove(t *testing.T) {
want := []app.Config{} want := []app.Config{}
have := []ProcessConfig{ have := []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -428,7 +429,7 @@ func TestSynchronizeRemove(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 7, CPU: 7,
@@ -456,7 +457,7 @@ func TestSynchronizeRemove(t *testing.T) {
}, },
}, stack) }, stack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 7, CPU: 7,
@@ -485,7 +486,7 @@ func TestSynchronizeAddRemove(t *testing.T) {
}, },
} }
have := []ProcessConfig{ have := []proxy.ProcessConfig{
{ {
NodeID: "node2", NodeID: "node2",
Order: "start", Order: "start",
@@ -499,7 +500,7 @@ func TestSynchronizeAddRemove(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 7, CPU: 7,
@@ -535,7 +536,7 @@ func TestSynchronizeAddRemove(t *testing.T) {
}, },
}, stack) }, stack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 17, CPU: 17,
@@ -556,7 +557,7 @@ func TestSynchronizeAddRemove(t *testing.T) {
} }
func TestRebalanceNothingToDo(t *testing.T) { func TestRebalanceNothingToDo(t *testing.T) {
processes := []ProcessConfig{ processes := []proxy.ProcessConfig{
{ {
NodeID: "node1", NodeID: "node1",
Order: "start", Order: "start",
@@ -581,7 +582,7 @@ func TestRebalanceNothingToDo(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 42, CPU: 42,
@@ -606,7 +607,7 @@ func TestRebalanceNothingToDo(t *testing.T) {
} }
func TestRebalanceOverload(t *testing.T) { func TestRebalanceOverload(t *testing.T) {
processes := []ProcessConfig{ processes := []proxy.ProcessConfig{
{ {
NodeID: "node1", NodeID: "node1",
Order: "start", Order: "start",
@@ -642,7 +643,7 @@ func TestRebalanceOverload(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 91, CPU: 91,
@@ -675,7 +676,7 @@ func TestRebalanceOverload(t *testing.T) {
}, },
}, opStack) }, opStack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 74, CPU: 74,
@@ -696,7 +697,7 @@ func TestRebalanceOverload(t *testing.T) {
} }
func TestRebalanceSkip(t *testing.T) { func TestRebalanceSkip(t *testing.T) {
processes := []ProcessConfig{ processes := []proxy.ProcessConfig{
{ {
NodeID: "node1", NodeID: "node1",
Order: "start", Order: "start",
@@ -732,7 +733,7 @@ func TestRebalanceSkip(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 91, CPU: 91,
@@ -773,7 +774,7 @@ func TestRebalanceSkip(t *testing.T) {
}, },
}, opStack) }, opStack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 91, CPU: 91,
@@ -794,7 +795,7 @@ func TestRebalanceSkip(t *testing.T) {
} }
func TestRebalanceReferenceAffinity(t *testing.T) { func TestRebalanceReferenceAffinity(t *testing.T) {
processes := []ProcessConfig{ processes := []proxy.ProcessConfig{
{ {
NodeID: "node1", NodeID: "node1",
Order: "start", Order: "start",
@@ -856,7 +857,7 @@ func TestRebalanceReferenceAffinity(t *testing.T) {
}, },
} }
resources := map[string]NodeResources{ resources := map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 90, CPU: 90,
@@ -898,7 +899,7 @@ func TestRebalanceReferenceAffinity(t *testing.T) {
}, },
}, opStack) }, opStack)
require.Equal(t, map[string]NodeResources{ require.Equal(t, map[string]proxy.NodeResources{
"node1": { "node1": {
NCPU: 1, NCPU: 1,
CPU: 89, CPU: 89,
@@ -927,7 +928,7 @@ func TestRebalanceReferenceAffinity(t *testing.T) {
} }
func TestCreateReferenceAffinityNodeMap(t *testing.T) { func TestCreateReferenceAffinityNodeMap(t *testing.T) {
processes := []ProcessConfig{ processes := []proxy.ProcessConfig{
{ {
NodeID: "node1", NodeID: "node1",
Order: "start", Order: "start",

View File

@@ -1,4 +1,4 @@
package cluster package logger
import ( import (
"io" "io"
@@ -19,7 +19,7 @@ type hclogger struct {
args []interface{} args []interface{}
} }
func NewLogger(logger log.Logger, lvl hclog.Level) hclog.Logger { func New(logger log.Logger, lvl hclog.Level) hclog.Logger {
return &hclogger{ return &hclogger{
logger: logger, logger: logger,
level: lvl, level: lvl,

View File

@@ -1,4 +1,4 @@
package cluster package proxy
import ( import (
"context" "context"
@@ -375,6 +375,13 @@ func (n *node) IPs() []string {
} }
func (n *node) ID() string { func (n *node) ID() string {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return ""
}
return n.peer.ID() return n.peer.ID()
} }
@@ -383,7 +390,7 @@ func (n *node) Files() NodeFiles {
defer n.stateLock.RUnlock() defer n.stateLock.RUnlock()
state := NodeFiles{ state := NodeFiles{
ID: n.peer.ID(), ID: n.ID(),
LastUpdate: n.lastUpdate, LastUpdate: n.lastUpdate,
} }
@@ -400,7 +407,7 @@ func (n *node) State() NodeState {
defer n.stateLock.RUnlock() defer n.stateLock.RUnlock()
state := NodeState{ state := NodeState{
ID: n.peer.ID(), ID: n.ID(),
LastContact: n.lastContact, LastContact: n.lastContact,
State: n.state.String(), State: n.state.String(),
Latency: time.Duration(n.latency * float64(time.Second)), Latency: time.Duration(n.latency * float64(time.Second)),
@@ -445,6 +452,10 @@ func (n *node) files() {
n.peerLock.RLock() n.peerLock.RLock()
defer n.peerLock.RUnlock() defer n.peerLock.RUnlock()
if n.peer == nil {
return
}
files, err := n.peer.MemFSList("name", "asc") files, err := n.peer.MemFSList("name", "asc")
if err != nil { if err != nil {
return return
@@ -461,6 +472,10 @@ func (n *node) files() {
n.peerLock.RLock() n.peerLock.RLock()
defer n.peerLock.RUnlock() defer n.peerLock.RUnlock()
if n.peer == nil {
return
}
files, err := n.peer.DiskFSList("name", "asc") files, err := n.peer.DiskFSList("name", "asc")
if err != nil { if err != nil {
return return
@@ -480,6 +495,10 @@ func (n *node) files() {
n.peerLock.RLock() n.peerLock.RLock()
defer n.peerLock.RUnlock() defer n.peerLock.RUnlock()
if n.peer == nil {
return
}
files, err := n.peer.RTMPChannels() files, err := n.peer.RTMPChannels()
if err != nil { if err != nil {
return return
@@ -500,6 +519,10 @@ func (n *node) files() {
n.peerLock.RLock() n.peerLock.RLock()
defer n.peerLock.RUnlock() defer n.peerLock.RUnlock()
if n.peer == nil {
return
}
files, err := n.peer.SRTChannels() files, err := n.peer.SRTChannels()
if err != nil { if err != nil {
return return
@@ -570,6 +593,10 @@ func (n *node) GetFile(path string) (io.ReadCloser, error) {
n.peerLock.RLock() n.peerLock.RLock()
defer n.peerLock.RUnlock() defer n.peerLock.RUnlock()
if n.peer == nil {
return nil, fmt.Errorf("not connected")
}
if prefix == "mem" { if prefix == "mem" {
return n.peer.MemFSGetFile(path) return n.peer.MemFSGetFile(path)
} else if prefix == "disk" { } else if prefix == "disk" {
@@ -580,6 +607,13 @@ func (n *node) GetFile(path string) (io.ReadCloser, error) {
} }
func (n *node) ProcessList() ([]ProcessConfig, error) { func (n *node) ProcessList() ([]ProcessConfig, error) {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return nil, fmt.Errorf("not connected")
}
list, err := n.peer.ProcessList(nil, []string{ list, err := n.peer.ProcessList(nil, []string{
"state", "state",
"config", "config",
@@ -613,6 +647,13 @@ func (n *node) ProcessList() ([]ProcessConfig, error) {
} }
func (n *node) ProcessAdd(config *app.Config) error { func (n *node) ProcessAdd(config *app.Config) error {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return fmt.Errorf("not connected")
}
cfg := httpapi.ProcessConfig{} cfg := httpapi.ProcessConfig{}
cfg.Unmarshal(config) cfg.Unmarshal(config)
@@ -620,13 +661,34 @@ func (n *node) ProcessAdd(config *app.Config) error {
} }
func (n *node) ProcessStart(id string) error { func (n *node) ProcessStart(id string) error {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return fmt.Errorf("not connected")
}
return n.peer.ProcessCommand(id, "start") return n.peer.ProcessCommand(id, "start")
} }
func (n *node) ProcessStop(id string) error { func (n *node) ProcessStop(id string) error {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return fmt.Errorf("not connected")
}
return n.peer.ProcessCommand(id, "stop") return n.peer.ProcessCommand(id, "stop")
} }
func (n *node) ProcessDelete(id string) error { func (n *node) ProcessDelete(id string) error {
n.peerLock.RLock()
defer n.peerLock.RUnlock()
if n.peer == nil {
return fmt.Errorf("not connected")
}
return n.peer.ProcessDelete(id) return n.peer.ProcessDelete(id)
} }

View File

@@ -1,7 +1,8 @@
package cluster package proxy
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"sync" "sync"
@@ -156,6 +157,8 @@ type proxy struct {
logger log.Logger logger log.Logger
} }
var ErrNodeNotFound = errors.New("node not found")
func NewProxy(config ProxyConfig) (Proxy, error) { func NewProxy(config ProxyConfig) (Proxy, error) {
p := &proxy{ p := &proxy{
id: config.ID, id: config.ID,

View File

@@ -1,4 +1,4 @@
package cluster package store
import ( import (
"encoding/json" "encoding/json"
@@ -21,25 +21,20 @@ type Store interface {
type operation string type operation string
const ( const (
opAddProcess operation = "addProcess" OpAddProcess operation = "addProcess"
opRemoveProcess operation = "removeProcess" OpRemoveProcess operation = "removeProcess"
) )
type command struct { type Command struct {
Operation operation Operation operation
Data interface{} Data interface{}
} }
type StoreNode struct { type CommandAddProcess struct {
ID string
Address string
}
type addProcessCommand struct {
app.Config app.Config
} }
type removeProcessCommand struct { type CommandRemoveProcess struct {
ID string ID string
} }
@@ -58,7 +53,7 @@ func NewStore() (Store, error) {
func (s *store) Apply(log *raft.Log) interface{} { func (s *store) Apply(log *raft.Log) interface{} {
fmt.Printf("a log entry came in (index=%d, term=%d): %s\n", log.Index, log.Term, string(log.Data)) fmt.Printf("a log entry came in (index=%d, term=%d): %s\n", log.Index, log.Term, string(log.Data))
c := command{} c := Command{}
err := json.Unmarshal(log.Data, &c) err := json.Unmarshal(log.Data, &c)
if err != nil { if err != nil {
@@ -70,17 +65,17 @@ func (s *store) Apply(log *raft.Log) interface{} {
fmt.Printf("op: %+v\n", c) fmt.Printf("op: %+v\n", c)
switch c.Operation { switch c.Operation {
case opAddProcess: case OpAddProcess:
b, _ := json.Marshal(c.Data) b, _ := json.Marshal(c.Data)
cmd := addProcessCommand{} cmd := CommandAddProcess{}
json.Unmarshal(b, &cmd) json.Unmarshal(b, &cmd)
s.lock.Lock() s.lock.Lock()
s.Process[cmd.ID] = cmd.Config s.Process[cmd.ID] = cmd.Config
s.lock.Unlock() s.lock.Unlock()
case opRemoveProcess: case OpRemoveProcess:
b, _ := json.Marshal(c.Data) b, _ := json.Marshal(c.Data)
cmd := removeProcessCommand{} cmd := CommandRemoveProcess{}
json.Unmarshal(b, &cmd) json.Unmarshal(b, &cmd)
s.lock.Lock() s.lock.Lock()

View File

@@ -5,7 +5,7 @@ import (
gofs "io/fs" gofs "io/fs"
"time" "time"
"github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/io/fs" "github.com/datarhei/core/v16/io/fs"
) )
@@ -17,10 +17,10 @@ type filesystem struct {
fs.Filesystem fs.Filesystem
name string name string
proxy cluster.ProxyReader proxy proxy.ProxyReader
} }
func NewClusterFS(name string, fs fs.Filesystem, proxy cluster.ProxyReader) Filesystem { func NewClusterFS(name string, fs fs.Filesystem, proxy proxy.ProxyReader) Filesystem {
if proxy == nil { if proxy == nil {
return fs return fs
} }

View File

@@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster"
"github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/http/api" "github.com/datarhei/core/v16/http/api"
"github.com/datarhei/core/v16/http/handler/util" "github.com/datarhei/core/v16/http/handler/util"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
@@ -15,7 +16,7 @@ import (
// The ClusterHandler type provides handler functions for manipulating the cluster config. // The ClusterHandler type provides handler functions for manipulating the cluster config.
type ClusterHandler struct { type ClusterHandler struct {
cluster cluster.Cluster cluster cluster.Cluster
proxy cluster.ProxyReader proxy proxy.ProxyReader
} }
// NewCluster return a new ClusterHandler type. You have to provide a cluster. // NewCluster return a new ClusterHandler type. You have to provide a cluster.

View File

@@ -11,7 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/session" "github.com/datarhei/core/v16/session"
@@ -58,7 +58,7 @@ type Config struct {
// with methods like tls.Config.SetSessionTicketKeys. // with methods like tls.Config.SetSessionTicketKeys.
TLSConfig *tls.Config TLSConfig *tls.Config
Proxy cluster.ProxyReader Proxy proxy.ProxyReader
} }
// Server represents a RTMP server // Server represents a RTMP server
@@ -93,7 +93,7 @@ type server struct {
channels map[string]*channel channels map[string]*channel
lock sync.RWMutex lock sync.RWMutex
proxy cluster.ProxyReader proxy proxy.ProxyReader
} }
// New creates a new RTMP server according to the given config // New creates a new RTMP server according to the given config
@@ -119,7 +119,7 @@ func New(config Config) (Server, error) {
} }
if s.proxy == nil { if s.proxy == nil {
s.proxy = cluster.NewNullProxyReader() s.proxy = proxy.NewNullProxyReader()
} }
s.server = &rtmp.Server{ s.server = &rtmp.Server{

View File

@@ -10,7 +10,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/datarhei/core/v16/cluster" "github.com/datarhei/core/v16/cluster/proxy"
"github.com/datarhei/core/v16/log" "github.com/datarhei/core/v16/log"
"github.com/datarhei/core/v16/session" "github.com/datarhei/core/v16/session"
srt "github.com/datarhei/gosrt" srt "github.com/datarhei/gosrt"
@@ -40,7 +40,7 @@ type Config struct {
SRTLogTopics []string SRTLogTopics []string
Proxy cluster.ProxyReader Proxy proxy.ProxyReader
} }
// Server represents a SRT server // Server represents a SRT server
@@ -77,7 +77,7 @@ type server struct {
srtlog map[string]*ring.Ring // Per logtopic a dedicated ring buffer srtlog map[string]*ring.Ring // Per logtopic a dedicated ring buffer
srtlogLock sync.RWMutex srtlogLock sync.RWMutex
proxy cluster.ProxyReader proxy proxy.ProxyReader
} }
func New(config Config) (Server, error) { func New(config Config) (Server, error) {
@@ -95,7 +95,7 @@ func New(config Config) (Server, error) {
} }
if s.proxy == nil { if s.proxy == nil {
s.proxy = cluster.NewNullProxyReader() s.proxy = proxy.NewNullProxyReader()
} }
if s.logger == nil { if s.logger == nil {