I've started Go for the last couple of months and I decided to challenging small projects, so I created this proxy requests script.
It works well (in my opinion at least) but I'm looking for different ways of improving this further like being able to target all servers, or making this more concise and compact. To be honest I think it is readable but again that's my opinion. I'm looking for it to be peer reviewed with no holds barred critism of my code. Why? to learn new ways of improving my coding techniques and making it much more efficient.
If anyone wants to view the code feel free:
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
type frame struct {
context.Context
resp chan<- string
}
type frames chan frame
func main() {
var serverConns []frames
const totalServers = 10
for i := 0; i < 10; i++ {
serverID := i
conn := make(frames)
defer close(conn)
serverConns = append(serverConns, conn)
go func() {
// the server
for frame := range conn {
resps := []string{"banana", "apple", "guava"}
time.Sleep(50*time.Millisecond + time.Duration(rand.Intn(500))*time.Millisecond)
r := fmt.Sprint("server ", serverID, ": ", resps[rand.Intn(len(resps))])
select {
case <-frame.Done():
case frame.resp <- r:
}
}
}()
}
// the proxy
const maxFanout = 3
var conns []frames
connIDs := rand.Perm(len(serverConns))[:totalServers/2]
for _, connID := range connIDs {
fmt.Println("selected server:", connID)
conns = append(conns, serverConns[connID])
}
fanoutConn := make(frames)
go func() {
for p := range fanoutConn {
ctx, cancel := context.WithCancel(p.Context)
firstResp := make(chan string)
for _, serverConn := range conns {
serverConn := serverConn
fwdframe := frame{
Context: ctx,
resp: firstResp,
}
go func() {
serverConn <- fwdframe
}()
}
response := <-firstResp
cancel()
p.resp <- response
}
}()
// the client
for {
r := make(chan string)
p := frame{
Context: context.Background(),
resp: r,
}
fanoutConn <- p
fmt.Println(<-r)
}
}