2020-02-11 14:46:58 +01:00
|
|
|
package rpc
|
|
|
|
|
|
|
|
import (
|
2020-02-12 13:55:04 +01:00
|
|
|
// "io"
|
|
|
|
"bufio"
|
2020-02-11 14:46:58 +01:00
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/rpc"
|
2020-02-12 13:55:04 +01:00
|
|
|
"os"
|
|
|
|
"strings"
|
2020-02-13 23:57:56 +01:00
|
|
|
"sync"
|
2020-02-11 14:46:58 +01:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2020-02-12 11:20:15 +01:00
|
|
|
type Rán struct {
|
|
|
|
clients []*rpc.Client
|
|
|
|
task FlutTask
|
|
|
|
}
|
|
|
|
|
2020-02-13 23:57:56 +01:00
|
|
|
// SummonRán sets up the RPC master, accepting connections at addres (":1234")
|
|
|
|
// Connects calls methods on each client's rpc provider, killing all clients
|
|
|
|
// when stopChan is closed.
|
|
|
|
func SummonRán(address string, stopChan chan bool, wg *sync.WaitGroup) *Rán {
|
2020-02-12 11:20:15 +01:00
|
|
|
r := new(Rán)
|
2020-02-11 14:46:58 +01:00
|
|
|
|
|
|
|
l, err := net.Listen("tcp", address)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
fmt.Printf("[rán] rpc server listening on %s\n", l.Addr())
|
|
|
|
|
2020-02-12 11:20:15 +01:00
|
|
|
// serve tcp port, handshake
|
2020-02-11 14:46:58 +01:00
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
conn, err := l.Accept()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
client := rpc.NewClient(conn)
|
2020-02-12 11:20:15 +01:00
|
|
|
r.clients = append(r.clients, client)
|
|
|
|
fmt.Printf("[rán] client connected (%v). current clients: %v\n",
|
|
|
|
conn.RemoteAddr(), len(r.clients))
|
2020-02-11 14:46:58 +01:00
|
|
|
|
2020-02-12 11:20:15 +01:00
|
|
|
if (r.task != FlutTask{}) {
|
|
|
|
ack := FlutAck{}
|
|
|
|
err = client.Call("Hevring.Flut", r.task, &ack)
|
|
|
|
if err != nil || !ack.Ok {
|
|
|
|
log.Printf("[rán] client didn't accept task")
|
|
|
|
}
|
2020-02-11 14:46:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// poll clients
|
|
|
|
go func() {
|
|
|
|
for {
|
2020-02-12 11:20:15 +01:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
2020-02-11 14:46:58 +01:00
|
|
|
|
|
|
|
var clients []*rpc.Client
|
2020-02-12 11:20:15 +01:00
|
|
|
for _, c := range r.clients {
|
2020-02-11 14:46:58 +01:00
|
|
|
status := FlutAck{}
|
2020-02-13 23:57:56 +01:00
|
|
|
err := c.Call("Hevring.Status", 0, &status)
|
|
|
|
if err == nil && status.Ok {
|
2020-02-11 14:46:58 +01:00
|
|
|
clients = append(clients, c)
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 11:20:15 +01:00
|
|
|
if len(r.clients) != len(clients) {
|
|
|
|
fmt.Printf("[rán] client disconnected. current clients: %v\n", len(clients))
|
|
|
|
}
|
|
|
|
r.clients = clients
|
2020-02-11 14:46:58 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-02-12 13:55:04 +01:00
|
|
|
// REPL to change tasks without loosing clients
|
|
|
|
go func() {
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
for scanner.Scan() {
|
|
|
|
input := strings.Split(scanner.Text(), " ")
|
|
|
|
cmd := strings.ToLower(input[0])
|
|
|
|
args := input[1:]
|
|
|
|
if cmd == "stop" {
|
|
|
|
for _, c := range r.clients {
|
|
|
|
ack := FlutAck{}
|
|
|
|
c.Call("Hevring.Stop", 0, &ack) // @speed: async
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if cmd == "img" && len(args) > 0 {
|
|
|
|
// // @incomplete
|
|
|
|
// path := args[0]
|
|
|
|
// img := readImage(path)
|
|
|
|
// offset := image.Pt(0, 0)
|
|
|
|
// if len(args) == 3 {
|
|
|
|
// x := strconv.Atoi(args[1])
|
|
|
|
// y := strconv.Atoi(args[2])
|
|
|
|
// offset = image.Pt(x, y)
|
|
|
|
// }
|
|
|
|
// task := FlutTask{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// kill clients on exit
|
|
|
|
go func() {
|
2020-02-13 23:57:56 +01:00
|
|
|
<-stopChan
|
|
|
|
for _, c := range r.clients {
|
|
|
|
ack := FlutAck{}
|
|
|
|
c.Call("Hevring.Die", 0, &ack) // @speed: async
|
2020-02-12 13:55:04 +01:00
|
|
|
}
|
2020-02-13 23:57:56 +01:00
|
|
|
wg.Done()
|
2020-02-12 13:55:04 +01:00
|
|
|
}()
|
2020-02-11 14:46:58 +01:00
|
|
|
|
2020-02-12 11:20:15 +01:00
|
|
|
return r
|
2020-02-11 14:46:58 +01:00
|
|
|
}
|
|
|
|
|
2020-02-13 23:57:56 +01:00
|
|
|
// SetTask assigns a FlutTask to Rán, distributing it to all clients
|
2020-02-14 12:39:16 +01:00
|
|
|
func (r *Rán) SetTask(img *image.NRGBA, offset image.Point, address string, maxConns int) {
|
2020-02-12 11:20:15 +01:00
|
|
|
// @incomplete: smart task creation:
|
|
|
|
// fetch server state & sample foreign activity in image regions. assign
|
|
|
|
// subregions to clients (per connection), considering their bandwidth.
|
|
|
|
|
2020-02-14 12:39:16 +01:00
|
|
|
r.task = FlutTask{address, maxConns, img, offset, true}
|
2020-02-12 11:20:15 +01:00
|
|
|
for _, c := range r.clients {
|
|
|
|
ack := FlutAck{}
|
|
|
|
// @speed: should send tasks async
|
|
|
|
err := c.Call("Hevring.Flut", r.task, &ack)
|
|
|
|
if err != nil || !ack.Ok {
|
|
|
|
log.Printf("[rán] client didn't accept task")
|
|
|
|
}
|
|
|
|
}
|
2020-02-11 14:46:58 +01:00
|
|
|
}
|