package main import ( "bytes" "fmt" "io" "math/rand/v2" "net/http" "os" "strings" "time" ) /* Connect: 1. Client A: Create URL with public key and ID to reach on 2. Client B: Parses URL, generate AES key, upload key to storage 3. Client A: Polls for storage on server */ func get(id string) ([]byte, error) { res, err := http.Get(fmt.Sprintf("http://localhost:3000/store/%s", id)) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to get") } data, err := io.ReadAll(res.Body) if err != nil { return nil, err } return data, nil } func put(id string, data []byte) error { req, err := http.NewRequest( http.MethodPut, fmt.Sprintf("http://localhost:3000/store/%s", id), bytes.NewReader(data), ) if err != nil { return err } res, err := http.DefaultClient.Do(req) if err != nil { return err } defer res.Body.Close() if res.StatusCode != http.StatusNoContent { return fmt.Errorf("failed to get") } return nil } func randomId() string { var charset = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") runes := make([]rune, 512) for i := range runes { runes[i] = charset[rand.IntN(len(charset))] } return string(runes) } func connect() (string, string) { // link: chitchat: var selfId, partnerId string selfId = randomId() fmt.Printf("Your ID: %s\n", selfId) fmt.Printf("Partner ID: ") fmt.Scanln(&partnerId) partnerId = strings.TrimSpace(partnerId) return selfId, partnerId } func pollPartner(partnerId string) { var message string for { time.Sleep(5 * time.Second) data, err := get(partnerId) if err != nil { fmt.Printf("Failed to poll: %s\n", err) continue } partnerId, message, _ = strings.Cut(string(data), ":") fmt.Printf("%s\n", message) } } func pollInput(selfId string) { var message string for { fmt.Scanln(&message) nextId := randomId() data := fmt.Sprintf("%s:%s", nextId, message) err := put(selfId, []byte(data)) if err != nil { fmt.Printf("Failed to put: %s\n", err) continue } selfId = nextId } } func run() error { selfId, partnerId := connect() if partnerId == "" { fmt.Printf("Waiting for partner to connect to you...\n") for { time.Sleep(5 * time.Second) data, err := get(selfId) if err != nil { fmt.Printf("Partner hasn't connected: %s\n", err) continue } partnerId = string(data) break } } else { err := put(partnerId, []byte(selfId)) if err != nil { return fmt.Errorf("failed to put next id: %w", err) } } fmt.Printf("Your ID: %s\n", selfId) fmt.Printf("Partner ID: %s\n", partnerId) fmt.Printf("Chat away!\n") go pollInput(partnerId) go pollPartner(selfId) for { } return nil } func main() { err := run() if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } }