Implement service layer #3
16
internal/service/adapters.go
Normal file
16
internal/service/adapters.go
Normal 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()
|
||||
}
|
||||
86
internal/service/wisdom.go
Normal file
86
internal/service/wisdom.go
Normal 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)
|
||||
}
|
||||
Loading…
Reference in a new issue