chitchat/client/main.go

167 lines
2.8 KiB
Go
Raw Normal View History

2025-01-05 16:28:42 +00:00
package main
import (
2025-01-06 11:03:58 +00:00
"bytes"
2025-01-05 16:28:42 +00:00
"fmt"
2025-01-06 11:03:58 +00:00
"io"
"math/rand/v2"
"net/http"
2025-01-05 16:28:42 +00:00
"os"
2025-01-06 11:03:58 +00:00
"strings"
"time"
2025-01-05 16:28:42 +00:00
)
2025-01-06 11:03:58 +00:00
/*
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:<temporary-id>
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
}
}
2025-01-05 16:28:42 +00:00
func run() error {
2025-01-06 11:03:58 +00:00
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 {
}
2025-01-05 16:28:42 +00:00
return nil
}
func main() {
err := run()
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
}