Skip to content

Commit

Permalink
Add go variant
Browse files Browse the repository at this point in the history
  • Loading branch information
Mattzi committed Jan 20, 2025
0 parents commit 9ceb396
Show file tree
Hide file tree
Showing 9 changed files with 597 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/release-pleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: releaser-pleaser

on:
push:
branches: [main]
pull_request_target:
types:
- edited
- labeled
- unlabeled

jobs:
releaser-pleaser:
runs-on: ubuntu-latest
steps:
- name: releaser-pleaser
uses: apricote/releaser-pleaser@b61723279775f6ff425884ce78baf158e1aa2357 # v0.5.0
with:
token: ${{ secrets.RELEASER_PLEASER_TOKEN }}
53 changes: 53 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: goreleaser

on:
push:
tags:
- "v*"

jobs:
goreleaser:
runs-on: ubuntu-latest
permissions:
# Required for Artifacts and Releases
contents: write
# Required to push docker images to ghcr.io
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.22

- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Run GoReleaser
id: goreleaser
uses: goreleaser/goreleaser-action@v6
if: startsWith(github.ref, 'refs/tags/')
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CGO_ENABLED: 0

- name: Sentry release
uses: getsentry/action-release@v1
if: startsWith(github.ref, 'refs/tags/')
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ips-hosting-eu
SENTRY_PROJECT: ts-bot-go
with:
version: ts-bot-go@${{ fromJSON(steps.goreleaser.outputs.metadata).version }}
22 changes: 22 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Test

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5
with:
go-version: 1.22

- name: Test
run: go test ./...
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/einfach-gaming/egmrp-daemon

go 1.22.5

require github.com/rs/zerolog v1.33.0

require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
golang.org/x/sys v0.12.0 // indirect
)
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
168 changes: 168 additions & 0 deletions handle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package main

import (
"encoding/json"
"fmt"

"github.com/rs/zerolog/log"
)

// Message is the inbound/outbound JSON structure.
type Message struct {
Context string `json:"context"`
Data interface{} `json:"data"`
Sender *float64 `json:"sender,omitempty"`
Target interface{} `json:"target"`
}

// handleLine is called for each newline-delimited JSON message from a client.
func handleLine(client *AuthenticatedClient, line string) error {
var msg Message
if err := json.Unmarshal([]byte(line), &msg); err != nil {
return fmt.Errorf("json decode: %w", err)
}

switch t := msg.Target.(type) {
case string:
switch t {
case "i":
return identifyServer(client, &msg)
case "b":
if !client.initialized {
return fmt.Errorf("sender not initialized, cannot broadcast to all")
}
broadcastAll(client, &msg)
case "g":
if !client.initialized {
return fmt.Errorf("sender not initialized, cannot broadcast to group")
}
broadcastGroup(client, &msg)
default:
log.Error().Str("target", t).Msg("Unknown target string")
}

case float64:
if !client.initialized {
return fmt.Errorf("sender not initialized, cannot direct-send")
}
receiverID := int(t)
receiver := getClientByID(receiverID)
if receiver == nil {
log.Error().Int("receiverID", receiverID).Msg("Unknown receiver")
return nil
}
sendMessageToClient(receiver, &msg)

default:
log.Error().Msgf("Unknown target type: %T", t)
}

return nil
}

func identifyServer(client *AuthenticatedClient, msg *Message) error {
dataBytes, err := json.Marshal(msg.Data)
if err != nil {
return fmt.Errorf("failed to marshal identify data: %w", err)
}

var info ServerInfo
if err := json.Unmarshal(dataBytes, &info); err != nil {
return fmt.Errorf("failed to unmarshal identify data: %w", err)
}

client.serverInfo = &info
client.initialized = true

log.Info().
Str("name", info.Name).
Str("group", info.Group).
Bool("hidden", info.Hidden).
Msgf("%s has joined group %s", info.Name, info.Group)

identifyConfirmation := Message{
Context: "Identify",
Data: client.serverID,
Target: "i",
}
sendMessageToClient(client, &identifyConfirmation)

currentServerMsg := Message{
Context: "Connect",
Target: "i",
}
clientsMu.RLock()
for _, existing := range clients {
if existing.initialized &&
existing.serverInfo != nil &&
existing.serverInfo.Group == info.Group &&
existing.serverID != client.serverID &&
!existing.hidden {
msgData := map[string]interface{}{
"id": existing.serverID,
"ip": existing.serverInfo.IP,
"name": existing.serverInfo.Name,
"port": existing.serverInfo.Port,
}
currentServerMsg.Data = msgData
sendMessageToClient(client, &currentServerMsg)
}
}
clientsMu.RUnlock()

if !client.hidden {
welcomeMsg := Message{
Context: "Connect",
Data: map[string]interface{}{
"id": client.serverID,
"ip": info.IP,
"name": info.Name,
"port": info.Port,
},
Target: "i",
}
broadcastGroup(client, &welcomeMsg)
}

return nil
}

func broadcastAll(sender *AuthenticatedClient, msg *Message) {
clientsMu.RLock()
defer clientsMu.RUnlock()

for _, c := range clients {
if c.initialized && c.serverID != sender.serverID {
sendMessageToClient(c, msg)
}
}
}

func broadcastGroup(sender *AuthenticatedClient, msg *Message) {
if sender.serverInfo == nil {
return
}
group := sender.serverInfo.Group

clientsMu.RLock()
defer clientsMu.RUnlock()
for _, c := range clients {
if c.initialized && c.serverInfo != nil &&
c.serverInfo.Group == group &&
c.serverID != sender.serverID {
sendMessageToClient(c, msg)
}
}
}

func sendMessageToClient(receiver *AuthenticatedClient, msg *Message) {
data, err := json.Marshal(msg)
if err != nil {
log.Error().Err(err).Msg("Failed to marshal message")
return
}
_, err = receiver.conn.Write(append(data, '\n'))
if err != nil {
log.Error().Err(err).Msg("Failed to write message to client")
}
}
53 changes: 53 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

func addClient(c *AuthenticatedClient) {
clientsMu.Lock()
defer clientsMu.Unlock()
clients = append(clients, c)
}

func removeClient(c *AuthenticatedClient) {
clientsMu.Lock()
defer clientsMu.Unlock()

for i, cc := range clients {
if cc == c {
clients = append(clients[:i], clients[i+1:]...)
break
}
}
}

func getClientByID(id int) *AuthenticatedClient {
clientsMu.RLock()
defer clientsMu.RUnlock()

for _, c := range clients {
if c.serverID == id {
return c
}
}
return nil
}

func findSpareServerID() int {
clientsMu.RLock()
defer clientsMu.RUnlock()

id := 1
for {
if !containsID(id) {
return id
}
id++
}
}

func containsID(id int) bool {
for _, c := range clients {
if c.serverID == id {
return true
}
}
return false
}
Loading

0 comments on commit 9ceb396

Please sign in to comment.