Zippytal-Node/server.go
2022-08-28 22:17:30 +02:00

244 lines
6.2 KiB
Go

package localserver
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"path/filepath"
"sync"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
var logger *log.Logger = new(log.Logger)
var dbLogger *BadgerLogger = &BadgerLogger{
Logger: logger,
}
type BadgerLogger struct {
*log.Logger
}
func (b *BadgerLogger) Debugf(message string, data ...interface{}) {
b.Println(data...)
}
func (b *BadgerLogger) Errorf(message string, data ...interface{}) {
b.Println(data...)
}
func (b *BadgerLogger) Infof(message string, data ...interface{}) {
b.Println(data...)
}
func (b *BadgerLogger) Warningf(message string, data ...interface{}) {
b.Println(data...)
}
type (
LocalServerHandlerMiddleware interface {
Process(ctx context.Context, req *http.Request, w http.ResponseWriter) (err error)
}
SignalingClientManagerMiddleware interface {
Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error)
}
LocalServerHandler struct {
middlewares []LocalServerHandlerMiddleware
}
LocalServer struct {
ID string
GrpcClientManager *SignalingClientManager
}
SignalingClientManager struct {
GrpcConn grpc.ClientConnInterface
SignalingManagerClient SignalingServiceClient
GrpcLinkClient SignalingService_LinkClient
middlewares []SignalingClientManagerMiddleware
}
CustomMenuItem struct {
//MenuItem *systray.MenuItem
ID string
State bool
SubMenus []*CustomMenuItem
CallBack func(bool)
}
ReqType string
LocalServerRequest struct {
ReqType ReqType
Payload map[string]interface{}
}
)
func NewLocalServer(_ string, grpcAddr string, id string, token string) (localServer *LocalServer, err error) {
webRTCCallManager, err := NewWebRTCCallManager(id, token, NewWebrtcCallSoundManager(), NewWebrtcCallChatManager(), NewWebrtcCallVideoManager(), NewWebrtcCallFileManager())
if err != nil {
err = fmt.Errorf("error from call manager")
return
}
zoneManager, err := NewZoneManager(id, token)
if err != nil {
err = fmt.Errorf("error from zone manager")
return
}
webrtcFsManager, err := NewWebrtcFsManager(NewP2PFSDatachannelManager())
if err != nil {
err = fmt.Errorf("error from fs manager")
return
}
webrtcGrpcMiddleware := NewWebRTCGrpcMiddleware(webRTCCallManager)
ZoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager)
webrtcFsMiddleware := NewWebRTCFsMiddleware(webrtcFsManager)
signalingClientManager, err := NewGrpcClientManager(grpcAddr, id, webrtcGrpcMiddleware, ZoneGrpcMiddleware)
if err != nil {
return
}
webrtcGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
webRTCCallManager.stream = signalingClientManager.GrpcLinkClient
zoneManager.stream = signalingClientManager.GrpcLinkClient
webrtcFsMiddleware.stream = signalingClientManager.GrpcLinkClient
webrtcFsManager.stream = signalingClientManager.GrpcLinkClient
ZoneGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient
localServer = &LocalServer{
ID: id,
GrpcClientManager: signalingClientManager,
}
return
}
func NewGrpcClientManager(addr string, id string, middleware ...SignalingClientManagerMiddleware) (signalingClientManager *SignalingClientManager, err error) {
conn, signalingClient, signalingLinkClient, err := NewGrpcConn(addr, id)
if err != nil {
return
}
signalingClientManager = &SignalingClientManager{
GrpcConn: conn,
SignalingManagerClient: signalingClient,
GrpcLinkClient: signalingLinkClient,
middlewares: middleware,
}
return
}
func NewGrpcConn(addr string, id string) (conn grpc.ClientConnInterface, signalingClient SignalingServiceClient, signalingLinkClient SignalingService_LinkClient, err error) {
var cert = filepath.Join("config", "fullchain.pem")
creds, err := credentials.NewClientTLSFromFile(cert, "dev.zippytal.com")
if err != nil {
fmt.Println("there")
return
}
var opts []grpc.DialOption = []grpc.DialOption{grpc.WithTransportCredentials(creds)}
conn, err = grpc.Dial(addr, opts...)
if err != nil {
fmt.Println("over there")
return
}
signalingClient = NewSignalingServiceClient(conn)
signalingLinkClient, err = signalingClient.Link(context.Background())
if err != nil {
fmt.Println("really there")
logger.Println(err)
return
}
payload := map[string]any{
"init": "init",
}
bs, err := json.Marshal(payload)
if err != nil {
logger.Println(err)
return
}
if err = signalingLinkClient.Send(&SignalingMessage{
Type: "init",
From: id,
To: "server",
Payload: bs,
}); err != nil {
return
}
return
}
func NewLocalServerHandler(middlewares ...LocalServerHandlerMiddleware) (localServerHandler *LocalServerHandler) {
localServerHandler = &LocalServerHandler{
middlewares: middlewares,
}
return
}
func (lsh *LocalServerHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
wg, done, errCh := &sync.WaitGroup{}, make(chan struct{}), make(chan error)
for _, middleware := range lsh.middlewares {
wg.Add(1)
go func(m LocalServerHandlerMiddleware) {
err := m.Process(req.Context(), req, w)
if err != nil {
errCh <- err
}
wg.Done()
}(middleware)
}
go func() {
wg.Wait()
done <- struct{}{}
}()
select {
case <-req.Context().Done():
case <-done:
case err := <-errCh:
logger.Println(err)
}
}
func (gcm *SignalingClientManager) Handle(ctx context.Context) (err error) {
done, errCh := make(chan struct{}), make(chan error)
go func() {
wg := new(sync.WaitGroup)
for {
res, err := gcm.GrpcLinkClient.Recv()
if err != nil {
errCh <- err
return
}
for _, middleware := range gcm.middlewares {
wg.Add(1)
go func(m SignalingClientManagerMiddleware) {
defer wg.Done()
if err := m.Process(ctx, res, gcm.GrpcLinkClient); err != nil {
logger.Println(err)
}
}(middleware)
}
wg.Wait()
}
}()
select {
case <-gcm.GrpcLinkClient.Context().Done():
logger.Println("grpc context")
err = gcm.GrpcLinkClient.Context().Err()
return
case <-ctx.Done():
logger.Println("app context")
err = ctx.Err()
return
case <-done:
logger.Println("done")
return
case err = <-errCh:
logger.Println("done with error")
if closeErr := gcm.GrpcLinkClient.CloseSend(); closeErr != nil {
return closeErr
}
return
}
}