Skip to content

Commit

Permalink
what's new:
Browse files Browse the repository at this point in the history
- transport factory
  • Loading branch information
pieceowater committed Nov 30, 2024
1 parent 9ad1170 commit f730015
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 15 deletions.
12 changes: 7 additions & 5 deletions cmd/example/app.go → cmd/example/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@ import (
"google.golang.org/grpc"
)

// Entry point for the example application demonstrating how to use the gossiper package.
func main() {
// Создаём менеджер серверов
// Create a new server manager to manage multiple servers.
serverManager := gossiper.NewServerManager()

// Инициализация gRPC сервера
// Initialize the gRPC server.
grpcInitRoute := func(server *grpc.Server) {
// Пример: добавить маршруты
// Example: Add gRPC routes here.
}
serverManager.AddServer(gossiper.NewGRPCServ("50051", grpc.NewServer(), grpcInitRoute))

// Инициализация REST сервера
// Initialize the REST server.
restInitRoute := func(router *gin.Engine) {
// Define a health check endpoint.
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
}
serverManager.AddServer(gossiper.NewRESTServ("8080", gin.Default(), restInitRoute))

// Запуск всех серверов
// Start all servers.
serverManager.StartAll()
defer serverManager.StopAll()
}
54 changes: 54 additions & 0 deletions cmd/example/transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
gossiper "github.com/pieceowater-dev/lotof.lib.gossiper"
)

type SomeService struct {
transport gossiper.Transport
//client pb.SomeServiceClient // Add client as a property, generated from protobuf
}

func NewSomeService() *SomeService {
factory := gossiper.NewTransportFactory()
grpcTransport := factory.CreateTransport(
gossiper.GRPC,
"localhost:50051",
)

// Create the client only once and store it as a property
//clientConstructor := pb.NewSomeServiceClient
//client, err := grpcTransport.CreateClient(clientConstructor)
//if err != nil {
// log.Fatalf("Error creating client: %v", err)
//}

return &SomeService{
transport: grpcTransport,
//client: client,
}
}

//func (s *SomeService) Items() ([]any, error) {
// ctx := context.Background()
//
// // Send the request using the client stored in the SomeService instance
// response, err := s.transport.Send(
// ctx,
// s.client,
// "GetItems",
// &pb.GetItemsRequest{}, // Dynamic request for GetItems
// )
// if err != nil {
// log.Printf("Error sending request: %v", err)
// return nil, err
// }
//
// // Assert the response to the correct type
// res, ok := response.(*pb.GetItemsResponse)
// if !ok {
// return nil, errors.New("invalid response type from gRPC transport")
// }
//
// return res, nil
//}
30 changes: 21 additions & 9 deletions gossiper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package gossiper

import (
"github.com/gin-gonic/gin"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/db"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers"
grpcServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers/grpc"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers/rabbitmq"
rmqServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers/rabbitmq"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers/rest"
restServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/servers/rest"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/db"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/servers"
grpcServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/servers/grpc"
rmqServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/servers/rabbitmq"
restServ "github.com/pieceowater-dev/lotof.lib.gossiper/internal/servers/rest"
"github.com/pieceowater-dev/lotof.lib.gossiper/internal/transport"
"google.golang.org/grpc"
)

Expand Down Expand Up @@ -42,10 +41,10 @@ type ServerManager = servers.ServerManager
type GRPCServer = grpcServ.Server

// RESTServer represents a REST server instance.
type RESTServer = rest.Server
type RESTServer = restServ.Server

// RMQServer represents a RabbitMQ server instance.
type RMQServer = rabbitmq.Server
type RMQServer = rmqServ.Server

// NewServerManager creates a new instance of the server manager.
// The server manager is responsible for starting and stopping multiple server instances.
Expand Down Expand Up @@ -76,3 +75,16 @@ func NewRESTServ(port string, router *gin.Engine, initRoute func(router *gin.Eng
func NewRMQServ() *RMQServer {
return rmqServ.New()
}

type Transport = transport.Transport
type TransportType = transport.Type

const (
GRPC TransportType = transport.GRPC
)

type TransportFactory = transport.Factory

func NewTransportFactory() *TransportFactory {
return transport.NewFactory()
}
2 changes: 1 addition & 1 deletion internal/core/db/database.go → internal/db/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package db

import (
"fmt"
postgresql "github.com/pieceowater-dev/lotof.lib.gossiper/internal/core/db/pg"
postgresql "github.com/pieceowater-dev/lotof.lib.gossiper/internal/db/pg"
"gorm.io/gorm"
)

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
66 changes: 66 additions & 0 deletions internal/transport/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package transport

import (
"context"
"errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"reflect"
)

// GRPCTransport handles both client and server-side transport
type GRPCTransport struct {
address string
server *grpc.Server
}

func NewGRPCTransport(address string) *GRPCTransport {
return &GRPCTransport{address: address}
}

// CreateClient dynamically creates a gRPC client using the passed constructor.
func (g *GRPCTransport) CreateClient(clientConstructor any) (any, error) {
// Dial the gRPC connection.
conn, err := grpc.Dial(g.address, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, errors.New("failed to connect to gRPC server: " + err.Error())
}

// Use reflection to call the constructor function dynamically
constructorValue := reflect.ValueOf(clientConstructor)
if constructorValue.Kind() != reflect.Func {
return nil, errors.New("clientConstructor must be a function")
}

// Call the constructor to create the client (pass the connection as argument)
clientValues := constructorValue.Call([]reflect.Value{reflect.ValueOf(conn)})

// Ensure that the client creation was successful and return the client
if len(clientValues) > 0 {
return clientValues[0].Interface(), nil
}
return nil, errors.New("failed to create client")
}

// Send sends a dynamic gRPC request based on method name and request type
func (g *GRPCTransport) Send(ctx context.Context, client any, serviceMethod string, request any) (any, error) {
// Use reflection to get the method from the client dynamically
clientValue := reflect.ValueOf(client)
method := clientValue.MethodByName(serviceMethod)
if !method.IsValid() {
return nil, errors.New("invalid service method: " + serviceMethod)
}

// Ensure the request is passed as a reflect.Value
reqValue := reflect.ValueOf(request)
if reqValue.IsValid() {
// Call the method dynamically, passing the context and the request
returnValues := method.Call([]reflect.Value{reflect.ValueOf(ctx), reqValue})
if len(returnValues) > 1 && returnValues[1].Interface() != nil {
return nil, returnValues[1].Interface().(error)
}
// Return the response from the method call
return returnValues[0].Interface(), nil
}
return nil, errors.New("invalid request type for method")
}
29 changes: 29 additions & 0 deletions internal/transport/transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package transport

import "context"

type Transport interface {
CreateClient(clientConstructor any) (any, error)
Send(ctx context.Context, client any, serviceMethod string, request any) (any, error)
}

type Type string

const (
GRPC Type = "grpc"
)

type Factory struct{}

func NewFactory() *Factory {
return &Factory{}
}

func (f *Factory) CreateTransport(transportType Type, address string) Transport {
switch transportType {
case GRPC:
return NewGRPCTransport(address)
default:
return nil
}
}

0 comments on commit f730015

Please sign in to comment.