diff options
| author | Paul Buetow <paul@buetow.org> | 2023-05-21 23:49:03 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2023-05-21 23:49:03 +0300 |
| commit | e958dc957a2339228bfe74865b4e1728484f4fd0 (patch) | |
| tree | 186bdf561be5a122e122f94106fd2d82aece1fe3 | |
| parent | 6cd559398b5b1183c19ac0ab2b5840b02132489c (diff) | |
refactor config to separate package
| -rw-r--r-- | internal/client.go | 10 | ||||
| -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.go | 12 | ||||
| -rw-r--r-- | internal/quorum_test.go | 44 | ||||
| -rw-r--r-- | internal/run.go | 7 | ||||
| -rw-r--r-- | internal/server.go | 8 | ||||
| -rw-r--r-- | internal/tcpserver.go | 18 | ||||
| -rw-r--r-- | internal/utils/string.go | 10 | ||||
| -rw-r--r-- | internal/utils/string_test.go | 11 | ||||
| -rw-r--r-- | internal/vote.go | 9 | ||||
| -rw-r--r-- | internal/vote_test.go | 10 |
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) |
