Skip to content

Commit

Permalink
Intercept Xonotic stdout for SDK Integration
Browse files Browse the repository at this point in the history
Change the Xonotic example to have wrapper
around the server execution, and use the
content of stdout to determine what to do
with the SDK for GameServer lifecycle management.
  • Loading branch information
markmandel authored and enocom committed May 24, 2018
1 parent 4858e9e commit f25a3c7
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 25 deletions.
7 changes: 3 additions & 4 deletions examples/xonotic/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ RUN curl -o xonotic.zip http://dl.xonotic.org/xonotic-0.8.2.zip && \
#

RUN mkdir -p ./.xonotic/data && mv /home/xonotic/Xonotic/server/server_linux.sh /home/xonotic/Xonotic/
COPY ./bin/sdk .
COPY run.sh .
COPY ./bin/wrapper .
COPY server.cfg ./.xonotic/data
RUN chown -R xonotic:xonotic . && chmod +x run.sh && chmod +x sdk
RUN chown -R xonotic:xonotic . && chmod +x wrapper

USER xonotic
ENTRYPOINT /home/xonotic/run.sh
ENTRYPOINT /home/xonotic/wrapper -i /home/xonotic/Xonotic/server_linux.sh
4 changes: 2 additions & 2 deletions examples/xonotic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ REPOSITORY = gcr.io/agones-images
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
agones_path := $(realpath $(project_path)/../..)
image_tag = $(REPOSITORY)/xonotic-example:0.1
image_tag = $(REPOSITORY)/xonotic-example:0.2

# _____ _
# |_ _|_ _ _ __ __ _ ___| |_ ___
Expand All @@ -44,7 +44,7 @@ build: build-go-binary
# build the go binary with Docker, so you don't have to install anything
build-go-binary: MOUNTPATH="/go/src/agones.dev/agones"
build-go-binary:
docker run --rm -v $(agones_path):$(MOUNTPATH) golang:1.9.4 go build -o $(MOUNTPATH)/examples/xonotic/bin/sdk agones.dev/agones/examples/xonotic
docker run --rm -v $(agones_path):$(MOUNTPATH) golang:1.10.2 go build -o $(MOUNTPATH)/examples/xonotic/bin/wrapper agones.dev/agones/examples/xonotic



Expand Down
6 changes: 5 additions & 1 deletion examples/xonotic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Example using a [Xonotic](http://www.xonotic.org) dedicated game server.

*Note:* This example doesn't directly integrate the SDK (yet), but calls it via a separate binary.
This example wraps the Xonotic server with a [Go](https://golang.org) binary, and introspects
stdout to provide the event hooks for the SDK integration.

It is not a direct integration, but is an approach for to integrate with existing
dedicated game servers.

You will need to download the Xonotic client separately to play.
2 changes: 1 addition & 1 deletion examples/xonotic/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ spec:
spec:
containers:
- name: xonotic
image: gcr.io/agones-images/xonotic-example:0.1
image: gcr.io/agones-images/xonotic-example:0.2
2 changes: 1 addition & 1 deletion examples/xonotic/fleetallocation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ metadata:
# will need to be created with `kubectl create`
generateName: xonotic-
spec:
fleetName: xonotic
fleetName: xonotic
4 changes: 2 additions & 2 deletions examples/xonotic/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ spec:
spec:
containers:
- name: xonotic
image: gcr.io/agones-images/xonotic-example:0.1
# imagePullPolicy: Always # add for development
image: gcr.io/agones-images/xonotic-example:0.2
# imagePullPolicy: Always # add for development
86 changes: 78 additions & 8 deletions examples/xonotic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,95 @@
package main

import (
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"time"

"agones.dev/agones/sdks/go"
)

// main cheats a little, and just declares the game server as ready
// as soon as it fires up
const (
begin = "BEGIN"
configLoaded = "CONFIGLOADED"
listening = "LISTENING"
)

type interceptor struct {
forward io.Writer
intercept func(p []byte)
}

// Write will intercept the incoming stream, and forward
// the contents to its `forward` Writer.
func (i *interceptor) Write(p []byte) (n int, err error) {
if i.intercept != nil {
i.intercept(p)
}

return i.forward.Write(p)
}

// main intercepts the stdout of the Xonotic gameserver and uses it
// to determine if the game server is ready or not.
func main() {
input := flag.String("i", "", "path to server_linux.sh")
flag.Parse()

fmt.Println(">>> Connecting to Agones with the SDK")
s, err := sdk.NewSDK()
if err != nil {
log.Fatalf("Could not connect to sdk: %v", err)
log.Fatalf(">>> Could not connect to sdk: %v", err)
}
err = s.Ready()

fmt.Println(">>> Starting health checking")
go doHealth(s)

fmt.Println(">>> Starting wrapper for Xonotic!")
fmt.Printf(">>> Path to Xonotic server script: %s \n", *input)

// state tracks the state
state := begin

cmd := exec.Command(*input) // #nosec
cmd.Stderr = &interceptor{forward: os.Stderr}
cmd.Stdout = &interceptor{
forward: os.Stdout,
intercept: func(p []byte) {
if state == listening {
return
}

str := strings.TrimSpace(string(p))
// since the game server starts, then loads the server.cfg
// and then restarts itself, we need to wait for this line
// before we look for "Server listening on address", since
// it is output twice.
if state == begin && str == "execing server.cfg" {
fmt.Printf(">>> Moving to configLoaded: %s", str)
state = configLoaded
return
}
if state == configLoaded && strings.Contains(str, "Server listening on address") {
state = listening
fmt.Printf(">>> Moving to listening: %s", str)
err = s.Ready()
if err != nil {
log.Fatalf("Could not send ready message")
}
}
}}

err = cmd.Start()
if err != nil {
log.Fatalf("Could not send ready message")
log.Fatalf(">>> Error Starting Cmd %v", err)
}

doHealth(s)
err = cmd.Wait()
log.Fatal(">>> Xonotic shutdown unexpectantly", err)
}

// doHealth sends the regular Health Pings
Expand All @@ -42,7 +112,7 @@ func doHealth(sdk *sdk.SDK) {
for {
err := sdk.Health()
if err != nil {
log.Fatalf("Could not send health ping, %v", err)
log.Fatalf("[wrapper] Could not send health ping, %v", err)
}
<-tick
}
Expand Down
6 changes: 0 additions & 6 deletions examples/xonotic/run.sh

This file was deleted.

0 comments on commit f25a3c7

Please sign in to comment.