first poc client
This commit is contained in:
parent
0c3842b90c
commit
9d47fc3282
5 changed files with 181 additions and 2 deletions
148
client/main.go
148
client/main.go
|
@ -1,11 +1,159 @@
|
|||
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:<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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
27
client/server.go
Normal file
27
client/server.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package main
|
||||
|
||||
type Server struct {
|
||||
}
|
||||
|
||||
// Checks if the storage has an element with the id.
|
||||
// Returns [ErrNotExists] if the element doesn't exist.
|
||||
func (s *Server) Has(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Retreive an element from the storage.
|
||||
// Returns [ErrNotExists] if the element doesn't exist.
|
||||
func (s *Server) Get(id string) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Store an element in the storage.
|
||||
func (s *Server) Put(id string, element []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete an element from the storage.
|
||||
// Returns [ErrNotExists] if the elment doesn't exist.
|
||||
func (s *Server) Delete(id string) error {
|
||||
return nil
|
||||
}
|
2
go.mod
2
go.mod
|
@ -1,3 +1,3 @@
|
|||
module git.1e99.eu/1e99/chitchat
|
||||
|
||||
go 1.23.4
|
||||
go 1.23.3
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
@ -56,6 +57,7 @@ func StoreHandler(store storage.Store, idRegex *regexp.Regexp, maxSize int) http
|
|||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Put %s = %s\n", id, string(data))
|
||||
err = store.Put(id, data)
|
||||
switch {
|
||||
case err != nil:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package storage
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
func NewMemStore() Store {
|
||||
s := &memStore{
|
||||
|
|
Loading…
Reference in a new issue