// Package grpc provides gRPC client implementations for service clients. package grpc import ( "context" "fmt" authzv1 "git.dcentral.systems/toolz/goplt/api/proto/generated/authz/v1" "git.dcentral.systems/toolz/goplt/pkg/registry" "git.dcentral.systems/toolz/goplt/pkg/services" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) // AuthzClient implements AuthzServiceClient using gRPC. type AuthzClient struct { registry registry.ServiceRegistry conn *grpc.ClientConn client authzv1.AuthzServiceClient } // NewAuthzClient creates a new gRPC client for the Authz Service. func NewAuthzClient(reg registry.ServiceRegistry) (services.AuthzServiceClient, error) { client := &AuthzClient{ registry: reg, } return client, nil } // connect connects to the Authz Service. func (c *AuthzClient) connect(ctx context.Context) error { if c.conn != nil { return nil } instances, err := c.registry.Discover(ctx, "authz-service") if err != nil { return fmt.Errorf("failed to discover authz service: %w", err) } if len(instances) == 0 { return fmt.Errorf("no instances found for authz-service") } instance := instances[0] address := fmt.Sprintf("%s:%d", instance.Address, instance.Port) conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return fmt.Errorf("failed to connect to authz-service at %s: %w", address, err) } c.conn = conn c.client = authzv1.NewAuthzServiceClient(conn) return nil } // Authorize checks if a user has a specific permission and returns an error if not. func (c *AuthzClient) Authorize(ctx context.Context, userID, permission string) error { if err := c.connect(ctx); err != nil { return err } resp, err := c.client.Authorize(ctx, &authzv1.AuthorizeRequest{ UserId: userID, Permission: permission, }) if err != nil { return fmt.Errorf("authorize failed: %w", err) } if !resp.Authorized { return fmt.Errorf("unauthorized: %s", resp.Message) } return nil } // HasPermission checks if a user has a specific permission. func (c *AuthzClient) HasPermission(ctx context.Context, userID, permission string) (bool, error) { if err := c.connect(ctx); err != nil { return false, err } resp, err := c.client.HasPermission(ctx, &authzv1.HasPermissionRequest{ UserId: userID, Permission: permission, }) if err != nil { return false, fmt.Errorf("has permission check failed: %w", err) } return resp.HasPermission, nil } // GetUserPermissions returns all permissions for a user. func (c *AuthzClient) GetUserPermissions(ctx context.Context, userID string) ([]services.Permission, error) { if err := c.connect(ctx); err != nil { return nil, err } resp, err := c.client.GetUserPermissions(ctx, &authzv1.GetUserPermissionsRequest{ UserId: userID, }) if err != nil { return nil, fmt.Errorf("get user permissions failed: %w", err) } permissions := make([]services.Permission, 0, len(resp.Permissions)) for _, p := range resp.Permissions { permissions = append(permissions, services.Permission{ ID: p.Id, Code: p.Code, Name: p.Name, Description: p.Description, }) } return permissions, nil } // GetUserRoles returns all roles for a user. func (c *AuthzClient) GetUserRoles(ctx context.Context, userID string) ([]services.Role, error) { if err := c.connect(ctx); err != nil { return nil, err } resp, err := c.client.GetUserRoles(ctx, &authzv1.GetUserRolesRequest{ UserId: userID, }) if err != nil { return nil, fmt.Errorf("get user roles failed: %w", err) } roles := make([]services.Role, 0, len(resp.Roles)) for _, r := range resp.Roles { roles = append(roles, services.Role{ ID: r.Id, Name: r.Name, Description: r.Description, Permissions: r.Permissions, }) } return roles, nil }