Files
monibuca/plugin.go
langhuihui 0efbe886c8 update
2024-03-22 15:43:09 +08:00

178 lines
4.0 KiB
Go

package m7s
import (
"context"
"crypto/tls"
"log/slog"
"net"
"path/filepath"
"reflect"
"runtime"
"strings"
"sync"
"github.com/logrusorgru/aurora/v4"
"m7s.live/m7s/v5/pkg/config"
"m7s.live/m7s/v5/pkg/util"
)
type PluginMeta struct {
Name string
Version string //插件版本
Type reflect.Type
}
type IPlugin interface {
OnInit()
OnEvent(any)
}
type IPublishPlugin interface {
OnStopPublish(*Publisher, error)
}
type ITCPPlugin interface {
OnTCPConnect(*net.TCPConn)
}
var plugins []PluginMeta
func InstallPlugin[C IPlugin](options ...any) error {
var c C
t := reflect.TypeOf(c).Elem()
meta := PluginMeta{
Name: t.Name(),
Type: t,
}
_, pluginFilePath, _, _ := runtime.Caller(1)
configDir := filepath.Dir(pluginFilePath)
if _, after, found := strings.Cut(configDir, "@"); found {
meta.Version = after
} else {
meta.Version = pluginFilePath
}
plugins = append(plugins, meta)
return nil
}
func sendPromiseToServer[T any](server *Server, value T) error {
promise := util.NewPromise(value)
server.EventBus <- promise
<-promise.Done()
return context.Cause(promise.Context)
}
type Plugin struct {
Disabled bool
Meta *PluginMeta
context.Context `json:"-" yaml:"-"`
context.CancelCauseFunc `json:"-" yaml:"-"`
Config struct {
config.Publish
config.Subscribe
config.HTTP
config.Quic
config.TCP
config.Pull
config.Push
}
Publishers []*Publisher
*slog.Logger
handler IPlugin
server *Server
sync.RWMutex
}
func (p *Plugin) OnInit() {
var err error
httpConf := p.Config.HTTP
defer httpConf.StopListen()
if httpConf.ListenAddrTLS != "" && (httpConf.ListenAddrTLS != p.server.Config.ListenAddrTLS) {
go func() {
p.Info("https listen at ", "addr", aurora.Blink(httpConf.ListenAddrTLS))
p.CancelCauseFunc(httpConf.ListenTLS())
}()
}
if httpConf.ListenAddr != "" && (httpConf.ListenAddr != p.server.Config.ListenAddr) {
go func() {
p.Info("http listen at ", "addr", aurora.Blink(httpConf.ListenAddr))
p.CancelCauseFunc(httpConf.Listen())
}()
}
tcpConf := p.Config.TCP
tcphandler, ok := p.handler.(ITCPPlugin)
if !ok {
tcphandler = p
}
count := p.Config.TCP.ListenNum
if count == 0 {
count = runtime.NumCPU()
}
if p.Config.TCP.ListenAddr != "" {
l, err := net.Listen("tcp", tcpConf.ListenAddr)
if err != nil {
p.Error("tcp listen error", "addr", tcpConf.ListenAddr, "error", err)
p.CancelCauseFunc(err)
return
}
defer l.Close()
p.Info("tcp listen at ", "addr", aurora.Blink(tcpConf.ListenAddr))
for i := 0; i < count; i++ {
go tcpConf.Listen(l, tcphandler.OnTCPConnect)
}
}
if tcpConf.ListenAddrTLS != "" {
keyPair, _ := tls.X509KeyPair(config.LocalCert, config.LocalKey)
if tcpConf.CertFile != "" || tcpConf.KeyFile != "" {
keyPair, err = tls.LoadX509KeyPair(tcpConf.CertFile, tcpConf.KeyFile)
}
if err != nil {
p.Error("LoadX509KeyPair", "error", err)
p.CancelCauseFunc(err)
return
}
l, err := tls.Listen("tcp", tcpConf.ListenAddrTLS, &tls.Config{
Certificates: []tls.Certificate{keyPair},
})
if err != nil {
p.Error("tls tcp listen error", "addr", tcpConf.ListenAddrTLS, "error", err)
p.CancelCauseFunc(err)
return
}
defer l.Close()
p.Info("tls tcp listen at ", "addr", aurora.Blink(tcpConf.ListenAddrTLS))
for i := 0; i < count; i++ {
go tcpConf.Listen(l, tcphandler.OnTCPConnect)
}
}
select {
case <-p.Done():
return
}
}
func (p *Plugin) OnEvent(event any) {
}
func (p *Plugin) OnTCPConnect(conn *net.TCPConn) {
p.handler.OnEvent(conn)
}
func (p *Plugin) Publish(streamPath string) (publisher *Publisher, err error) {
publisher = &Publisher{Publish: p.Config.Publish}
publisher.Init(p, streamPath)
publisher.Subscribers = make(map[*Subscriber]struct{})
err = sendPromiseToServer(p.server, publisher)
return
}
func (p *Plugin) Subscribe(streamPath string) (subscriber *Subscriber, err error) {
subscriber = &Subscriber{Subscribe: p.Config.Subscribe}
subscriber.Init(p, streamPath)
err = sendPromiseToServer(p.server, subscriber)
return
}