hash-of-wisdom/internal/service/wisdom.go

87 lines
2 KiB
Go

package service
import (
"context"
"errors"
"fmt"
"hash-of-wisdom/internal/pow/challenge"
"hash-of-wisdom/internal/quotes"
)
var (
ErrResourceRequired = errors.New("resource is required")
ErrUnsupportedResource = errors.New("unsupported resource")
ErrSolutionRequired = errors.New("solution is required")
ErrInvalidChallenge = errors.New("invalid challenge")
ErrInvalidSolution = errors.New("invalid proof of work solution")
)
type ChallengeGenerator interface {
GenerateChallenge() (*challenge.Challenge, error)
}
type ChallengeVerifier interface {
VerifyChallenge(ch *challenge.Challenge) error
}
type QuoteService interface {
GetRandomQuote(ctx context.Context) (*quotes.Quote, error)
}
type WisdomService struct {
challengeGenerator ChallengeGenerator
challengeVerifier ChallengeVerifier
quoteService QuoteService
}
func NewWisdomService(
generator ChallengeGenerator,
verifier ChallengeVerifier,
quoteService QuoteService,
) *WisdomService {
return &WisdomService{
challengeGenerator: generator,
challengeVerifier: verifier,
quoteService: quoteService,
}
}
func (s *WisdomService) GenerateChallenge(ctx context.Context, resource string) (*challenge.Challenge, error) {
if resource == "" {
return nil, ErrResourceRequired
}
if resource != "quotes" {
return nil, ErrUnsupportedResource
}
ch, err := s.challengeGenerator.GenerateChallenge()
if err != nil {
return nil, fmt.Errorf("failed to generate challenge: %w", err)
}
return ch, nil
}
func (s *WisdomService) VerifySolution(ctx context.Context, solution *challenge.Solution) error {
if solution == nil {
return ErrSolutionRequired
}
// Verify challenge authenticity and expiration
if err := s.challengeVerifier.VerifyChallenge(&solution.Challenge); err != nil {
return fmt.Errorf("%w: %v", ErrInvalidChallenge, err)
}
// Verify PoW solution
if !solution.Verify() {
return ErrInvalidSolution
}
return nil
}
func (s *WisdomService) GetQuote(ctx context.Context) (*quotes.Quote, error) {
return s.quoteService.GetRandomQuote(ctx)
}