Implement service layer #3

Merged
krendelhoff merged 5 commits from phase-3-service-layer into master 2025-08-22 16:40:01 +03:00
2 changed files with 102 additions and 0 deletions
Showing only changes of commit f38aa214d2 - Show all commits

View file

@ -0,0 +1,16 @@
package service
import "hash-of-wisdom/internal/pow/challenge"
// generatorAdapter adapts the real challenge.Generator to our interface
type generatorAdapter struct {
generator *challenge.Generator
}
func NewGeneratorAdapter(generator *challenge.Generator) ChallengeGenerator {
return &generatorAdapter{generator: generator}
}
func (a *generatorAdapter) GenerateChallenge() (*challenge.Challenge, error) {
return a.generator.GenerateChallenge()
}

View file

@ -0,0 +1,86 @@
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)
}