package localserver import ( "context" "crypto/x509" "encoding/json" "fmt" "io" "log" "net/http" "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{} } ) var dataPath = "" func NewLocalServer(grpcAddr uint, appDataPath, id, token string) (localServer *LocalServer, err error) { dataPath = appDataPath zoneManager, err := NewZoneManager(id, token) if err != nil { fmt.Println(err) return } chatManager, err := NewChatManager(id, token) if err != nil { fmt.Println(err) return } squadManager, err := NewSquadManager(id, token) if err != nil { fmt.Println(err) return } zoneGrpcMiddleware := NewZoneGrpcMiddleware(zoneManager) chatGrpcMiddleware := NewChatGrpcMiddleware(chatManager) squadGrpcMiddleware := NewSquadGrpcMiddleware(squadManager) signalingClientManager, err := NewGrpcClientManager(grpcAddr, id, zoneGrpcMiddleware, chatGrpcMiddleware, squadGrpcMiddleware) if err != nil { return } zoneManager.stream = signalingClientManager.GrpcLinkClient zoneGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient chatManager.stream = signalingClientManager.GrpcLinkClient chatGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient squadManager.stream = signalingClientManager.GrpcLinkClient squadGrpcMiddleware.stream = signalingClientManager.GrpcLinkClient localServer = &LocalServer{ ID: id, GrpcClientManager: signalingClientManager, } return } func NewGrpcClientManager(addr uint, id string, middleware ...SignalingClientManagerMiddleware) (signalingClientManager *SignalingClientManager, err error) { conn, signalingClient, signalingLinkClient, err := NewGrpcConn(fmt.Sprintf("dev.zippytal.com:%d", 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) { res, err := http.Get("https://dev.zippytal.com/certificate") if err != nil { return } bytes, err := io.ReadAll(res.Body) if err != nil { return } cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(bytes) { err = fmt.Errorf("certificate format not supported") return } creds := credentials.NewClientTLSFromCert(cp, "dev.zippytal.com") 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 } }