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 }