diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6aa6dea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/store \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bc25902 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module ntnu-hpc-club/flyio + +go 1.21.3 + +require github.com/jepsen-io/maelstrom/demo/go v0.0.0-20230918143807-815e8c3bd0a7 + +require github.com/google/uuid v1.3.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..285a2af --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jepsen-io/maelstrom/demo/go v0.0.0-20230918143807-815e8c3bd0a7 h1:uhFy3IVL82hhoz47LGFySnts2lXfChLYwRG0bjNXkz8= +github.com/jepsen-io/maelstrom/demo/go v0.0.0-20230918143807-815e8c3bd0a7/go.mod h1:i6aVIs5AIOOaQF1lAisBm7DDeWM1Iopf+26UxjagsCU= diff --git a/main.go b/main.go new file mode 100644 index 0000000..acfa2a8 --- /dev/null +++ b/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "encoding/json" + "errors" + "log" + "os" + + "github.com/google/uuid" + + maelstrom "github.com/jepsen-io/maelstrom/demo/go" +) + +func main() { + n := maelstrom.NewNode() + + var messages []int + var neighbors []string + + // body.type == "echo" + n.Handle("echo", func(msg maelstrom.Message) error { + // Unmarshal the message body as an loosely-typed map. + var body map[string]any + if err := json.Unmarshal(msg.Body, &body); err != nil { + return err + } + + // Update the message type to return back. + body["type"] = "echo_ok" + + // Echo the original message back with the updated message type. + return n.Reply(msg, body) + }) + + n.Handle("generate", func(msg maelstrom.Message) error { + var body map[string]any + if err := json.Unmarshal(msg.Body, &body); err != nil { + return err + } + + body["type"] = "generate_ok" + body["id"] = uuid.New().String() + + return n.Reply(msg, body) + }) + + n.Handle("broadcast", func(msg maelstrom.Message) error { + var body map[string]any + if err := json.Unmarshal(msg.Body, &body); err != nil { + return err + } + + message, ok := body["message"].(float64) + if !ok { + return errors.New("message is not an int") + } + + var alreadyHasMessage bool = false + for _, i := range messages { + if i == int(message) { + alreadyHasMessage = true + break + } + } + + if !alreadyHasMessage { + messages = append(messages, int(message)) + for _, neighbor := range neighbors { + if err := pollSend(n, neighbor, msg.Body); err != nil { + return err + } + } + } + + delete(body, "message") + body["type"] = "broadcast_ok" + + return n.Reply(msg, body) + }) + + n.Handle("read", func(msg maelstrom.Message) error { + var body map[string]any + if err := json.Unmarshal(msg.Body, &body); err != nil { + return err + } + + body["type"] = "read_ok" + body["messages"] = messages + + return n.Reply(msg, body) + }) + + n.Handle("topology", func(msg maelstrom.Message) error { + var body map[string]any + if err := json.Unmarshal(msg.Body, &body); err != nil { + return err + } + + topology := body["topology"].(map[string]interface{}) + almostneighbours := topology[n.ID()].([]interface{}) + neighbors = nil + for _, i := range almostneighbours { + neighbors = append(neighbors, i.(string)) + } + + body["type"] = "topology_ok" + delete(body, "topology") + + return n.Reply(msg, body) + }) + + if err := n.Run(); err != nil { + log.Printf("ERROR: %s", err) + os.Exit(1) + } +} + +func pollSend(n *maelstrom.Node, dest string, body any) error { + return n.RPC(dest, body, func(msg maelstrom.Message) error { + if msg.RPCError() != nil { + return pollSend(n, dest, body) + } + return nil + }) +}