package rpc import ( "crypto/tls" "crypto/x509" "fmt" "net" "os" "gitlink.org.cn/cloudream/common/pkgs/async" "gitlink.org.cn/cloudream/common/pkgs/logger" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) type ServerEventChan = async.UnboundChannel[RPCServerEvent] type RPCServerEvent interface { IsRPCServerEvent() } type ExitEvent struct { RPCServerEvent Err error } type Config struct { Listen string `json:"listen"` RootCA string `json:"rootCA"` ServerCert string `json:"serverCert"` ServerKey string `json:"serverKey"` } type ServerBase struct { cfg Config grpcSvr *grpc.Server srvImpl any svcDesc *grpc.ServiceDesc rootCA *x509.CertPool serverCert tls.Certificate accessTokenAuthAPIs map[string]bool tokenVerifier AccessTokenVerifier noAuthAPIs map[string]bool } func NewServerBase(cfg Config, srvImpl any, svcDesc *grpc.ServiceDesc, accessTokenAuthAPIs []string, tokenVerifier AccessTokenVerifier, noAuthAPIs []string) *ServerBase { tokenAuthAPIs := make(map[string]bool) for _, api := range accessTokenAuthAPIs { tokenAuthAPIs[api] = true } noAuths := make(map[string]bool) for _, api := range noAuthAPIs { noAuths[api] = true } return &ServerBase{ cfg: cfg, srvImpl: srvImpl, svcDesc: svcDesc, accessTokenAuthAPIs: tokenAuthAPIs, tokenVerifier: tokenVerifier, noAuthAPIs: noAuths, } } func (s *ServerBase) Start() *ServerEventChan { ch := async.NewUnboundChannel[RPCServerEvent]() go func() { svrCert, err := tls.LoadX509KeyPair(s.cfg.ServerCert, s.cfg.ServerKey) if err != nil { logger.Warnf("load server cert: %v", err) ch.Send(&ExitEvent{Err: err}) return } s.serverCert = svrCert rootCA, err := os.ReadFile(s.cfg.RootCA) if err != nil { logger.Warnf("load root ca: %v", err) ch.Send(&ExitEvent{Err: err}) return } s.rootCA = x509.NewCertPool() if !s.rootCA.AppendCertsFromPEM(rootCA) { logger.Warnf("load root ca: failed to parse root ca") ch.Send(&ExitEvent{Err: fmt.Errorf("failed to parse root ca")}) return } logger.Infof("start serving rpc at: %v", s.cfg.Listen) lis, err := net.Listen("tcp", s.cfg.Listen) if err != nil { ch.Send(&ExitEvent{Err: err}) return } s.grpcSvr = grpc.NewServer( grpc.Creds(credentials.NewTLS(&tls.Config{ GetConfigForClient: s.tlsConfigSelector, })), grpc.UnaryInterceptor(s.authUnary), grpc.StreamInterceptor(s.authStream), ) s.grpcSvr.RegisterService(s.svcDesc, s.srvImpl) err = s.grpcSvr.Serve(lis) ch.Send(&ExitEvent{Err: err}) }() return ch } func (s *ServerBase) Stop() { if s.grpcSvr != nil { s.grpcSvr.Stop() } }