116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
var mu sync.Mutex
|
|
var me string
|
|
var hashToDomain map[string]string
|
|
var peerHashes []string
|
|
var kvstore map[string]string
|
|
|
|
func sha256sum(s string) string {
|
|
// Get the sha256sum of string as a hex string
|
|
b := sha256.Sum256([]byte(s))
|
|
return hex.EncodeToString(b[:])
|
|
}
|
|
|
|
func addPeer(peer string) error {
|
|
// Try to peer with another server
|
|
peerHash := sha256sum(peer)
|
|
// Check if already peered
|
|
mu.Lock()
|
|
_, ok := hashToDomain[peerHash]
|
|
mu.Unlock()
|
|
if ok {
|
|
return nil
|
|
}
|
|
mu.Lock()
|
|
hashToDomain[peerHash] = peer
|
|
mu.Unlock()
|
|
|
|
// Try request to peer
|
|
log.Printf("%s trying to peer with %s", me, peer)
|
|
resp, err := http.Get(peer + "/peer?peer=" + me)
|
|
if err != nil {
|
|
// Request failed, delete peer
|
|
mu.Lock()
|
|
delete(hashToDomain, peerHash)
|
|
mu.Unlock()
|
|
return err
|
|
}
|
|
|
|
log.Printf("%s successfully peered with %s", me, peer)
|
|
mu.Lock()
|
|
peerHashes = append(peerHashes, peerHash)
|
|
sort.Sort(sort.StringSlice(peerHashes))
|
|
mu.Unlock()
|
|
// Read response body
|
|
defer resp.Body.Close()
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Try adding all peers of this peer
|
|
newPeers := strings.Split(string(body), "\n")
|
|
for _, newPeer := range newPeers[:len(newPeers)-1] {
|
|
go addPeer(newPeer)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func peerHandler(w http.ResponseWriter, r *http.Request) {
|
|
// Handle incoming peer requests
|
|
r.ParseForm()
|
|
peer := r.Form.Get("peer")
|
|
if peer == "" {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
go addPeer(peer)
|
|
for _, p := range hashToDomain {
|
|
fmt.Fprintf(w, "%s\n", p)
|
|
}
|
|
}
|
|
|
|
func getHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
}
|
|
|
|
func setHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
}
|
|
|
|
func main() {
|
|
bindAddr := flag.String("b", ":4200", "bind address")
|
|
domain := flag.String("d", "http://localhost:4200", "full domain name")
|
|
peer := flag.String("i", "", "initial peer")
|
|
flag.Parse()
|
|
|
|
log.Printf("Starting %s %s %s", *bindAddr, *domain, *peer)
|
|
|
|
// Record myself
|
|
me = *domain
|
|
peerHashes = append(peerHashes, sha256sum(me))
|
|
hashToDomain = map[string]string{peerHashes[0]: me}
|
|
|
|
if *peer != "" {
|
|
go addPeer(*peer)
|
|
}
|
|
|
|
http.HandleFunc("/peer", peerHandler)
|
|
http.HandleFunc("/get", getHandler)
|
|
http.HandleFunc("/set", setHandler)
|
|
log.Fatal(http.ListenAndServe(*bindAddr, nil))
|
|
}
|