Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intercept Xonotic stdout for SDK Integration #218

Merged
merged 1 commit into from
May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.