summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2023-05-21 23:49:03 +0300
committerPaul Buetow <paul@buetow.org>2023-05-21 23:49:03 +0300
commite958dc957a2339228bfe74865b4e1728484f4fd0 (patch)
tree186bdf561be5a122e122f94106fd2d82aece1fe3
parent6cd559398b5b1183c19ac0ab2b5840b02132489c (diff)
refactor config to separate package
-rw-r--r--internal/client.go10
-rw-r--r--internal/config/config.go (renamed from internal/config.go)42
-rw-r--r--internal/config/config_test.go (renamed from internal/config_test.go)36
-rw-r--r--internal/quorum.go12
-rw-r--r--internal/quorum_test.go44
-rw-r--r--internal/run.go7
-rw-r--r--internal/server.go8
-rw-r--r--internal/tcpserver.go18
-rw-r--r--internal/utils/string.go10
-rw-r--r--internal/utils/string_test.go11
-rw-r--r--internal/vote.go9
-rw-r--r--internal/vote_test.go10
12 files changed, 128 insertions, 89 deletions
diff --git a/internal/client.go b/internal/client.go
new file mode 100644
index 0000000..6775ab2
--- /dev/null
+++ b/internal/client.go
@@ -0,0 +1,10 @@
+package internal
+
+import (
+ "context"
+
+ "codeberg.org/snonux/gorum/internal/config"
+)
+
+func runClient(ctx context.Context, conf config.Config) {
+}
diff --git a/internal/config.go b/internal/config/config.go
index 21df3b9..1e2705c 100644
--- a/internal/config.go
+++ b/internal/config/config.go
@@ -1,4 +1,4 @@
-package internal
+package config
import (
"encoding/json"
@@ -7,40 +7,41 @@ import (
"log"
"net"
"os"
- "strings"
+
+ "codeberg.org/snonux/gorum/internal/utils"
)
-type config struct {
+type Config struct {
StateDir string
Address string
Participants []string
}
-func newConfig(configFile string) (config, error) {
- var config config
+func New(configFile string) (Config, error) {
+ var c Config
file, err := os.Open(configFile)
if err != nil {
- return config, err
+ return c, err
}
defer file.Close()
bytes, err := ioutil.ReadAll(file)
if err != nil {
- return config, err
+ return c, err
}
- err = json.Unmarshal(bytes, &config)
+ err = json.Unmarshal(bytes, &c)
if err != nil {
- return config, err
+ return c, err
}
- return config, nil
+ return c, nil
}
-func (c config) participantNumber(participant string) (int, error) {
+func (c Config) ParticipantNumber(participant string) (int, error) {
for i, participant_ := range c.Participants {
- if participant == stripPort(participant_) {
+ if participant == utils.StripPort(participant_) {
return i, nil
}
}
@@ -48,11 +49,11 @@ func (c config) participantNumber(participant string) (int, error) {
return 0, fmt.Errorf("participant %s not found", participant)
}
-func (c config) isParticipant(remoteAddr string) bool {
- remoteAddr = stripPort(remoteAddr)
+func (c Config) IsParticipant(remoteAddr string) bool {
+ remoteAddr = utils.StripPort(remoteAddr)
for _, participant := range c.Participants {
- if remoteAddr == stripPort(participant) {
+ if remoteAddr == utils.StripPort(participant) {
return true
}
}
@@ -60,11 +61,11 @@ func (c config) isParticipant(remoteAddr string) bool {
return false
}
-func (c config) isParticipantWithLookup(remoteAddr string, lookupIP func(string) ([]net.IP, error)) bool {
- remoteAddr = stripPort(remoteAddr)
+func (c Config) IsParticipantWithLookup(remoteAddr string, lookupIP func(string) ([]net.IP, error)) bool {
+ remoteAddr = utils.StripPort(remoteAddr)
for _, participant := range c.Participants {
- ips, err := lookupIP(stripPort(participant))
+ ips, err := lookupIP(utils.StripPort(participant))
if err != nil {
log.Println(err)
continue
@@ -79,8 +80,3 @@ func (c config) isParticipantWithLookup(remoteAddr string, lookupIP func(string)
return false
}
-
-func stripPort(addr string) string {
- parts := strings.Split(addr, ":")
- return parts[0]
-}
diff --git a/internal/config_test.go b/internal/config/config_test.go
index d1974b5..bccfb2e 100644
--- a/internal/config_test.go
+++ b/internal/config/config_test.go
@@ -1,4 +1,4 @@
-package internal
+package config
import (
"fmt"
@@ -6,16 +6,10 @@ import (
"testing"
)
-func TestStripPort(t *testing.T) {
- if "localhost" != stripPort("localhost:1234") {
- t.Errorf("Unable to split port from \"localhost:1234\"")
- }
-}
-
func TestParticipantNumber(t *testing.T) {
- config := config{Participants: []string{"localhost:1234", "hamburger:4321"}}
+ conf := Config{Participants: []string{"localhost:1234", "hamburger:4321"}}
- num, err := config.participantNumber("localhost")
+ num, err := conf.ParticipantNumber("localhost")
if err != nil {
t.Errorf(err.Error())
}
@@ -23,7 +17,7 @@ func TestParticipantNumber(t *testing.T) {
t.Errorf("localhost should be participant number 0 but is %d", num)
}
- num, err = config.participantNumber("hamburger")
+ num, err = conf.ParticipantNumber("hamburger")
if err != nil {
t.Errorf(err.Error())
}
@@ -31,28 +25,28 @@ func TestParticipantNumber(t *testing.T) {
t.Errorf("hamburger should be participant number 1 but is %d", num)
}
- _, err = config.participantNumber("doener")
+ _, err = conf.ParticipantNumber("doener")
if err == nil {
t.Errorf("doener is not a participant")
}
}
func TestIsParticipant(t *testing.T) {
- config := config{Participants: []string{"localhost:1234", "hamburger:4321"}}
+ conf := Config{Participants: []string{"localhost:1234", "hamburger:4321"}}
remoteAddr := "localhost:323232"
- if !config.isParticipant(remoteAddr) {
- t.Errorf("%s should be participant of %v", remoteAddr, config.Participants)
+ if !conf.IsParticipant(remoteAddr) {
+ t.Errorf("%s should be participant of %v", remoteAddr, conf.Participants)
}
remoteAddr = "foo.zone:2345"
- if config.isParticipant(remoteAddr) {
- t.Errorf("%s should not be participant of %v", remoteAddr, config.Participants)
+ if conf.IsParticipant(remoteAddr) {
+ t.Errorf("%s should not be participant of %v", remoteAddr, conf.Participants)
}
}
func TestIsParticipantWithLookup(t *testing.T) {
- config := config{Participants: []string{"localhost:1234", "hamburger:4321"}}
+ conf := Config{Participants: []string{"localhost:1234", "hamburger:4321"}}
lookupIP := func(addr string) ([]net.IP, error) {
switch addr {
@@ -66,12 +60,12 @@ func TestIsParticipantWithLookup(t *testing.T) {
}
remoteAddr := "127.0.0.1:323232"
- if !config.isParticipantWithLookup(remoteAddr, lookupIP) {
- t.Errorf("%s should be participant of %v", remoteAddr, config.Participants)
+ if !conf.IsParticipantWithLookup(remoteAddr, lookupIP) {
+ t.Errorf("%s should be participant of %v", remoteAddr, conf.Participants)
}
remoteAddr = "9.9.9.9:2345"
- if config.isParticipantWithLookup(remoteAddr, lookupIP) {
- t.Errorf("%s should not be participant of %v", remoteAddr, config.Participants)
+ if conf.IsParticipantWithLookup(remoteAddr, lookupIP) {
+ t.Errorf("%s should not be participant of %v", remoteAddr, conf.Participants)
}
}
diff --git a/internal/quorum.go b/internal/quorum.go
index 179efb1..b680378 100644
--- a/internal/quorum.go
+++ b/internal/quorum.go
@@ -4,6 +4,8 @@ import (
"fmt"
"log"
"sort"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
type quorumMap map[string]vote
@@ -18,15 +20,15 @@ func (q quorumMap) vote(v vote) {
q[v.from] = v
}
-func (q quorumMap) winner(config config) (string, error) {
- scores := q.score(config)
+func (q quorumMap) winner(conf config.Config) (string, error) {
+ scores := q.score(conf)
if len(scores) == 0 {
return "", fmt.Errorf("unable to find a winner, empty score list")
}
return scores[0].id, nil
}
-func (q quorumMap) score(config config) (scores []score) {
+func (q quorumMap) score(conf config.Config) (scores []score) {
scoreMap := make(map[string]int)
for _, vote := range q {
@@ -46,8 +48,8 @@ func (q quorumMap) score(config config) (scores []score) {
}
// Score tie, use participant number.
- i_, _ := config.participantNumber(scores[i].id)
- j_, _ := config.participantNumber(scores[j].id)
+ i_, _ := conf.ParticipantNumber(scores[i].id)
+ j_, _ := conf.ParticipantNumber(scores[j].id)
return i_ < j_
})
diff --git a/internal/quorum_test.go b/internal/quorum_test.go
index d4790f9..6da4956 100644
--- a/internal/quorum_test.go
+++ b/internal/quorum_test.go
@@ -3,29 +3,31 @@ package internal
import (
"testing"
"time"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
func TestScore(t *testing.T) {
quorum := make(quorumMap)
- config := config{Participants: []string{"foo:1234", "bar:4321", "baz:3444"}}
+ conf := config.Config{Participants: []string{"foo:1234", "bar:4321", "baz:3444"}}
- vote1 := newVote(config, "foo:334234", "foo bar\n")
+ vote1 := newVote(conf, "foo:334234", "foo bar\n")
vote1.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote1)
- vote2 := newVote(config, "bar:334234", "bar baz\n")
+ vote2 := newVote(conf, "bar:334234", "bar baz\n")
vote2.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote2)
- vote3_dup := newVote(config, "bar:33234", "bar baz\n")
+ vote3_dup := newVote(conf, "bar:33234", "bar baz\n")
vote3_dup.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote3_dup)
- vote4 := newVote(config, "baz:334234", "foo bar baz\n")
+ vote4 := newVote(conf, "baz:334234", "foo bar baz\n")
vote4.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote4)
- scores := quorum.score(config)
+ scores := quorum.score(conf)
if len(scores) != 3 {
t.Errorf("Expected scores to be of length 3: %v", scores)
}
@@ -36,16 +38,16 @@ func TestScore(t *testing.T) {
}
func TestTieScore(t *testing.T) {
- addVotes := func(config config, quorum quorumMap) {
- vote1 := newVote(config, "foo:334234", "foo bar baz\n")
+ addVotes := func(conf config.Config, quorum quorumMap) {
+ vote1 := newVote(conf, "foo:334234", "foo bar baz\n")
vote1.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote1)
- vote2 := newVote(config, "bar:334234", "foo bar baz\n")
+ vote2 := newVote(conf, "bar:334234", "foo bar baz\n")
vote2.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote2)
- vote3 := newVote(config, "baz:334234", "foo bar baz\n")
+ vote3 := newVote(conf, "baz:334234", "foo bar baz\n")
vote3.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote3)
}
@@ -53,10 +55,10 @@ func TestTieScore(t *testing.T) {
t.Run("First tie score test", func(t *testing.T) {
quorum := make(quorumMap)
// If it is a tie, the first particpant (here: "foo") will win.
- config := config{Participants: []string{"foo:1234", "bar:4321", "baz:3444"}}
+ conf := config.Config{Participants: []string{"foo:1234", "bar:4321", "baz:3444"}}
- addVotes(config, quorum)
- scores := quorum.score(config)
+ addVotes(conf, quorum)
+ scores := quorum.score(conf)
if len(scores) != 3 {
t.Errorf("Expected scores to be of length 3: %v", scores)
@@ -65,7 +67,7 @@ func TestTieScore(t *testing.T) {
t.Errorf("Expected score[0] to be {foo,3}: %v", scores[0])
}
- winner, _ := quorum.winner(config)
+ winner, _ := quorum.winner(conf)
if winner != "foo" {
t.Errorf("Expected the winner to be foo but is: %s", winner)
}
@@ -74,10 +76,10 @@ func TestTieScore(t *testing.T) {
t.Run("Second tie score test", func(t *testing.T) {
quorum := make(quorumMap)
// If it is a tie, the first particpant (here: "bar") will win.
- config := config{Participants: []string{"bar:1234", "foo:4321", "baz:3444"}}
+ conf := config.Config{Participants: []string{"bar:1234", "foo:4321", "baz:3444"}}
- addVotes(config, quorum)
- scores := quorum.score(config)
+ addVotes(conf, quorum)
+ scores := quorum.score(conf)
if len(scores) != 3 {
t.Errorf("Expected scores to be of length 3: %v", scores)
@@ -86,7 +88,7 @@ func TestTieScore(t *testing.T) {
t.Errorf("Expected score[0] to be {bar,3}: %v", scores[0])
}
- winner, _ := quorum.winner(config)
+ winner, _ := quorum.winner(conf)
if winner != "bar" {
t.Errorf("Expected the winner to be bar but is: %s", winner)
}
@@ -95,13 +97,13 @@ func TestTieScore(t *testing.T) {
func TestCleanExpired(t *testing.T) {
quorum := make(quorumMap)
- config := config{Participants: []string{"foo:1234", "bay:4321"}}
+ conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}}
- vote1 := newVote(config, "foo:334234", " foo bar baz bay\n")
+ vote1 := newVote(conf, "foo:334234", " foo bar baz bay\n")
vote1.expiresAt = time.Now().Add(1 * time.Hour)
quorum.vote(vote1)
- vote2 := newVote(config, "bar:334234", " foo bar baz bay\n")
+ vote2 := newVote(conf, "bar:334234", " foo bar baz bay\n")
vote2.expiresAt = time.Now()
quorum.vote(vote2)
diff --git a/internal/run.go b/internal/run.go
index a8be7ca..d575ded 100644
--- a/internal/run.go
+++ b/internal/run.go
@@ -2,13 +2,16 @@ package internal
import (
"context"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
func Run(ctx context.Context, configFile string) {
- config, err := newConfig(configFile)
+ conf, err := config.New(configFile)
if err != nil {
panic(err)
}
- runServer(ctx, config)
+ go runClient(ctx, conf)
+ runServer(ctx, conf)
}
diff --git a/internal/server.go b/internal/server.go
index 2024b88..e5e55d1 100644
--- a/internal/server.go
+++ b/internal/server.go
@@ -4,9 +4,11 @@ import (
"context"
"log"
"time"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
-func runServer(ctx context.Context, config config) {
+func runServer(ctx context.Context, conf config.Config) {
ch := make(chan vote)
quorum := make(quorumMap)
@@ -15,7 +17,7 @@ func runServer(ctx context.Context, config config) {
select {
case vote := <-ch:
quorum.vote(vote)
- winner, err := quorum.winner(config)
+ winner, err := quorum.winner(conf)
if err != nil {
log.Println(err.Error())
continue
@@ -29,7 +31,7 @@ func runServer(ctx context.Context, config config) {
}
}()
- if err := startTcpServer(ctx, config, ch); err != nil {
+ if err := startTcpServer(ctx, conf, ch); err != nil {
panic(err)
}
}
diff --git a/internal/tcpserver.go b/internal/tcpserver.go
index 024f563..0f9c006 100644
--- a/internal/tcpserver.go
+++ b/internal/tcpserver.go
@@ -6,16 +6,18 @@ import (
"fmt"
"log"
"net"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
-func startTcpServer(ctx context.Context, config config, ch chan<- vote) error {
- listener, err := net.Listen("tcp", config.Address)
+func startTcpServer(ctx context.Context, conf config.Config, ch chan<- vote) error {
+ listener, err := net.Listen("tcp", conf.Address)
if err != nil {
return fmt.Errorf("Error starting TCP server: %s", err.Error())
}
defer listener.Close()
- log.Printf("TCP server started on %s\n", config.Address)
+ log.Printf("TCP server started on %s\n", conf.Address)
for {
conn, err := listener.Accept()
@@ -24,18 +26,20 @@ func startTcpServer(ctx context.Context, config config, ch chan<- vote) error {
continue
}
- if !config.isParticipantWithLookup(conn.RemoteAddr().String(), net.LookupIP) {
+ if !conf.IsParticipantWithLookup(conn.RemoteAddr().String(), net.LookupIP) {
log.Printf("Denying connection, peer not a participant: %v\n", conn.RemoteAddr().String())
conn.Close()
continue
}
log.Printf("Client connected: %s\n", conn.RemoteAddr().String())
- go handleConnection(ctx, config, conn, ch)
+ go handleConnection(ctx, conf, conn, ch)
}
}
-func handleConnection(ctx context.Context, config config, conn net.Conn, ch chan<- vote) {
+func handleConnection(ctx context.Context, conf config.Config,
+ conn net.Conn, ch chan<- vote) {
+
defer conn.Close()
remoteAddr := conn.RemoteAddr().String()
@@ -53,7 +57,7 @@ func handleConnection(ctx context.Context, config config, conn net.Conn, ch chan
}
log.Printf("Received message from %s: %s", remoteAddr, message)
- ch <- newVote(config, remoteAddr, message)
+ ch <- newVote(conf, remoteAddr, message)
conn.Write([]byte(message))
}
diff --git a/internal/utils/string.go b/internal/utils/string.go
new file mode 100644
index 0000000..58456ff
--- /dev/null
+++ b/internal/utils/string.go
@@ -0,0 +1,10 @@
+package utils
+
+import (
+ "strings"
+)
+
+func StripPort(addr string) string {
+ parts := strings.Split(addr, ":")
+ return parts[0]
+}
diff --git a/internal/utils/string_test.go b/internal/utils/string_test.go
new file mode 100644
index 0000000..ca3c0dd
--- /dev/null
+++ b/internal/utils/string_test.go
@@ -0,0 +1,11 @@
+package utils
+
+import (
+ "testing"
+)
+
+func TestStripPort(t *testing.T) {
+ if "localhost" != StripPort("localhost:1234") {
+ t.Errorf("Unable to split port from \"localhost:1234\"")
+ }
+}
diff --git a/internal/vote.go b/internal/vote.go
index b2db2d9..a9c93f0 100644
--- a/internal/vote.go
+++ b/internal/vote.go
@@ -4,6 +4,9 @@ import (
"log"
"strings"
"time"
+
+ "codeberg.org/snonux/gorum/internal/config"
+ "codeberg.org/snonux/gorum/internal/utils"
)
const voteExpiry = 20 * time.Second
@@ -14,17 +17,17 @@ type vote struct {
expiresAt time.Time
}
-func newVote(config config, from, message string) vote {
+func newVote(conf config.Config, from, message string) vote {
var ids []string
for _, id := range strings.Split(strings.TrimSpace(message), " ") {
- if !config.isParticipant(id) {
+ if !conf.IsParticipant(id) {
log.Printf("%s is not a participant, excluding from the vote", id)
continue
}
ids = append(ids, id)
}
- return vote{stripPort(from), ids, time.Now().Add(voteExpiry)}
+ return vote{utils.StripPort(from), ids, time.Now().Add(voteExpiry)}
}
func (v vote) expired() bool {
diff --git a/internal/vote_test.go b/internal/vote_test.go
index 9ebb57e..77e54c8 100644
--- a/internal/vote_test.go
+++ b/internal/vote_test.go
@@ -3,11 +3,13 @@ package internal
import (
"testing"
"time"
+
+ "codeberg.org/snonux/gorum/internal/config"
)
func TestVote(t *testing.T) {
- config := config{Participants: []string{"foo:1234", "bay:4321"}}
- v := newVote(config, "earth:334234", " foo bar baz bay\n")
+ conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}}
+ v := newVote(conf, "earth:334234", " foo bar baz bay\n")
if v.from != "earth" {
t.Errorf("Expected vote to come from earth but came from %s", v.from)
@@ -27,8 +29,8 @@ func TestVote(t *testing.T) {
}
func TestVoteExpiry(t *testing.T) {
- config := config{Participants: []string{"foo:1234", "bay:4321"}}
- v := newVote(config, "earth:334234", " foo bar baz bay\n")
+ conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}}
+ v := newVote(conf, "earth:334234", " foo bar baz bay\n")
// Set expiry 1h into the future
v.expiresAt = time.Now().Add(1 * time.Hour)