[PHASE-7] Implement the client
This commit is contained in:
parent
e9f60136ef
commit
18ae8b3bc2
134
cmd/client/main.go
Normal file
134
cmd/client/main.go
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"hash-of-wisdom/internal/pow/challenge"
|
||||
"hash-of-wisdom/internal/pow/solver"
|
||||
"hash-of-wisdom/internal/protocol"
|
||||
)
|
||||
|
||||
func main() {
|
||||
serverAddr := flag.String("addr", "localhost:8080", "server address")
|
||||
flag.Parse()
|
||||
|
||||
fmt.Printf("Connecting to Word of Wisdom server at %s\n", *serverAddr)
|
||||
|
||||
// Step 1: Get challenge
|
||||
challengeResp, err := requestChallenge(*serverAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to get challenge: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Received challenge with difficulty %d\n", challengeResp.Challenge.Difficulty)
|
||||
|
||||
// Step 2: Solve challenge
|
||||
fmt.Println("Solving challenge...")
|
||||
start := time.Now()
|
||||
|
||||
s := solver.NewSolver()
|
||||
solution, err := s.Solve(context.Background(), challengeResp.Challenge)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to solve challenge: %v", err)
|
||||
}
|
||||
|
||||
solveTime := time.Since(start)
|
||||
fmt.Printf("Challenge solved in %v with nonce %d\n", solveTime, solution.Nonce)
|
||||
|
||||
// Step 3: Submit solution and get quote
|
||||
err = submitSolution(*serverAddr, challengeResp.Challenge, solution.Nonce)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to submit solution: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func requestChallenge(serverAddr string) (*protocol.ChallengeResponse, error) {
|
||||
// Connect with timeout
|
||||
conn, err := net.DialTimeout("tcp", serverAddr, 5*time.Second)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Request challenge
|
||||
fmt.Println("Requesting challenge...")
|
||||
challengeReq := &protocol.ChallengeRequest{}
|
||||
if err := challengeReq.Encode(conn); err != nil {
|
||||
return nil, fmt.Errorf("failed to send challenge request: %w", err)
|
||||
}
|
||||
|
||||
// Receive challenge
|
||||
decoder := protocol.NewMessageDecoder()
|
||||
msg, err := decoder.Decode(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to receive challenge: %w", err)
|
||||
}
|
||||
|
||||
if msg.Type != protocol.ChallengeResponseType {
|
||||
return nil, fmt.Errorf("unexpected response type: %v", msg.Type)
|
||||
}
|
||||
|
||||
// Parse challenge
|
||||
challengeResp := &protocol.ChallengeResponse{}
|
||||
if err := challengeResp.Decode(msg.PayloadStream); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse challenge: %w", err)
|
||||
}
|
||||
|
||||
return challengeResp, nil
|
||||
}
|
||||
|
||||
func submitSolution(serverAddr string, chall *challenge.Challenge, nonce uint64) error {
|
||||
// Connect with timeout
|
||||
conn, err := net.DialTimeout("tcp", serverAddr, 5*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Submit solution
|
||||
solutionReq := &protocol.SolutionRequest{
|
||||
Challenge: *chall,
|
||||
Nonce: nonce,
|
||||
}
|
||||
|
||||
fmt.Println("Submitting solution...")
|
||||
if err := solutionReq.Encode(conn); err != nil {
|
||||
return fmt.Errorf("failed to send solution: %w", err)
|
||||
}
|
||||
|
||||
// Receive quote or error
|
||||
decoder := protocol.NewMessageDecoder()
|
||||
msg, err := decoder.Decode(conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to receive response: %w", err)
|
||||
}
|
||||
|
||||
switch msg.Type {
|
||||
case protocol.QuoteResponseType:
|
||||
solutionResp := &protocol.SolutionResponse{}
|
||||
if err := solutionResp.Decode(msg.PayloadStream); err != nil {
|
||||
return fmt.Errorf("failed to parse quote: %w", err)
|
||||
}
|
||||
fmt.Printf("\nQuote received:\n\"%s\"\n— %s\n", solutionResp.Quote.Text, solutionResp.Quote.Author)
|
||||
case protocol.ErrorResponseType:
|
||||
errorResp := &protocol.ErrorResponse{}
|
||||
if err := errorResp.Decode(msg.PayloadStream); err != nil {
|
||||
fmt.Println("Error: Contact administrator")
|
||||
return nil
|
||||
}
|
||||
if errorResp.Code == protocol.ErrServerError {
|
||||
fmt.Println("Error: Contact administrator")
|
||||
} else {
|
||||
fmt.Printf("Error: %s\n", errorResp.Message)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unexpected response type: %v", msg.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue