mirror of
https://github.com/datarhei/core.git
synced 2025-10-07 17:01:01 +08:00
159 lines
3.0 KiB
Go
159 lines
3.0 KiB
Go
package srt
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/datarhei/core/v16/session"
|
|
srt "github.com/datarhei/gosrt"
|
|
)
|
|
|
|
type client struct {
|
|
conn srt.Conn
|
|
id string
|
|
createdAt time.Time
|
|
|
|
txbytes uint64
|
|
rxbytes uint64
|
|
|
|
collector session.Collector
|
|
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
func newClient(conn srt.Conn, id string, collector session.Collector) *client {
|
|
c := &client{
|
|
conn: conn,
|
|
id: id,
|
|
createdAt: time.Now(),
|
|
|
|
collector: collector,
|
|
}
|
|
|
|
var ctx context.Context
|
|
ctx, c.cancel = context.WithCancel(context.Background())
|
|
|
|
go c.ticker(ctx)
|
|
|
|
return c
|
|
}
|
|
|
|
func (c *client) ticker(ctx context.Context) {
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
stats := &srt.Statistics{}
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
c.conn.Stats(stats)
|
|
|
|
rxbytes := stats.Accumulated.ByteRecv
|
|
txbytes := stats.Accumulated.ByteSent
|
|
|
|
c.collector.Ingress(c.id, int64(rxbytes-c.rxbytes))
|
|
c.collector.Egress(c.id, int64(txbytes-c.txbytes))
|
|
|
|
c.txbytes = txbytes
|
|
c.rxbytes = rxbytes
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *client) Close() {
|
|
c.cancel()
|
|
c.conn.Close()
|
|
c.collector.Close(c.id)
|
|
}
|
|
|
|
// channel represents a stream that is sent to the server
|
|
type channel struct {
|
|
pubsub srt.PubSub
|
|
collector session.Collector
|
|
path string
|
|
|
|
publisher *client
|
|
subscriber map[string]*client
|
|
lock sync.RWMutex
|
|
|
|
isProxy bool
|
|
}
|
|
|
|
func newChannel(conn srt.Conn, resource string, isProxy bool, identity string, collector session.Collector) *channel {
|
|
ch := &channel{
|
|
pubsub: srt.NewPubSub(srt.PubSubConfig{}),
|
|
path: resource,
|
|
publisher: newClient(conn, resource, collector),
|
|
subscriber: make(map[string]*client),
|
|
collector: collector,
|
|
isProxy: isProxy,
|
|
}
|
|
|
|
addr := conn.RemoteAddr().String()
|
|
ip, _, _ := net.SplitHostPort(addr)
|
|
|
|
if collector.IsCollectableIP(ip) {
|
|
extra := map[string]interface{}{
|
|
"name": identity,
|
|
"method": "publish",
|
|
}
|
|
collector.RegisterAndActivate(resource, resource, resource, addr)
|
|
collector.Extra(resource, extra)
|
|
}
|
|
|
|
return ch
|
|
}
|
|
|
|
func (ch *channel) Close() {
|
|
if ch.publisher == nil {
|
|
return
|
|
}
|
|
|
|
ch.publisher.Close()
|
|
ch.publisher = nil
|
|
}
|
|
|
|
func (ch *channel) AddSubscriber(conn srt.Conn, resource, identity string) string {
|
|
addr := conn.RemoteAddr().String()
|
|
ip, _, _ := net.SplitHostPort(addr)
|
|
|
|
client := newClient(conn, addr, ch.collector)
|
|
|
|
if ch.collector.IsCollectableIP(ip) {
|
|
extra := map[string]interface{}{
|
|
"name": identity,
|
|
"method": "play",
|
|
}
|
|
ch.collector.RegisterAndActivate(addr, resource, resource, addr)
|
|
ch.collector.Extra(addr, extra)
|
|
}
|
|
|
|
ch.lock.Lock()
|
|
ch.subscriber[addr] = client
|
|
ch.lock.Unlock()
|
|
|
|
return addr
|
|
}
|
|
|
|
func (ch *channel) RemoveSubscriber(id string) {
|
|
ch.lock.Lock()
|
|
defer ch.lock.Unlock()
|
|
|
|
client := ch.subscriber[id]
|
|
if client != nil {
|
|
delete(ch.subscriber, id)
|
|
client.Close()
|
|
}
|
|
|
|
// If this is a proxied channel and the last subscriber leaves,
|
|
// close the channel.
|
|
if len(ch.subscriber) == 0 && ch.isProxy {
|
|
ch.Close()
|
|
}
|
|
}
|