Skip to content

Commit

Permalink
Add initial support for running in a container.
Browse files Browse the repository at this point in the history
This commit is focused on building and running the
container in a local docker environment. Parameters
were added to the go program to allow us to adjust
the number of registration retries and the time between
each retry, looking forward to the need to wait for a
delay in our container's external network connectivity.

An example env file, example-container.env, has been provided
to show how to pass parameters to our container. Commentary in
example-container.env describes how to build a local Docker
container and then run it using the env file.

Documentation for each important environment variable can be found
in the container's startup script, container-startup.sh.
  • Loading branch information
curfman committed Feb 10, 2016
1 parent 3566e68 commit 5c92525
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 19 deletions.
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# Build from the go source directory:
# docker build -t goroom:1.5 .

FROM golang:1.5

# We need gorilla, so go get it.
RUN cd $GOPATH && go get github.com/gorilla/websocket

# Copy our go source files and build/install the
# code. If successful, the executable file,
# $GOPATH/bin/gameon-room-go, will be built.
RUN mkdir -p $GOPATH/src/gameon-room-go
COPY ./*.go $GOPATH/src/gameon-room-go/
COPY ./container-startup.sh /usr/bin/container-startup.sh
RUN cd $GOPATH/src/gameon-room-go && go install

# Our room should always listen on port 3000 (-lp)
# although the mapped host callback port (-cp) may
# be different.
EXPOSE 3000
WORKDIR $GOPATH/gameon-room-go/src

# The real work of running the game is done in the startup script
# which reads environment variables to drive its choices for startup.
ENTRYPOINT ["/bin/bash", "/usr/bin/container-startup.sh"]
74 changes: 74 additions & 0 deletions container-startup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash
# This is the startup script for the golang GameOn! room.
#
# The following environment variables are required:
# CONTAINER_IP - The public IP address to which your container is bound.
# (This is needed for the websocket callback.)
# GAMEON_ID - The ID given in Game On!
# GAMEON_SECRET - The shared secret given in Game On!
# ROOM_NAME - Your name for the room.
#
# The following environment variables are optional:
# GAMEON_ADDR - The game server address, defaults to game-on.org.
# GAMEON_PORT - Our external port, defaults to 3000.
# (This is needed for the websocket callback.)
# GAMEON_DEBUG - Any non-empty value turns on debug output
# GAMEON_TIMESHIFT - Use this to adjust our timestamps to match the
# GameOn! server in cases where the time is skewed
# relative to our room and the server. This is
# expressed in milliseconds. The default is 0.
#
# The following two variables allow for a delay in network connectivity.
#
# GAMEON_REG_RETRIES - Number of initial registration attempts.
# Defaults to 5
# GAMEON_REG_SECONDS_BETWEEN - Number of seconds between registration
# attempts. Defaults to 30

export ROOM_BINARY=$GOPATH/bin/gameon-room-go
# Print an error message ($1) and exit.
function fatal
{
echo "FAIL: FATAL ERROR, $1"
exit 1
}

# $1 is var name
# $2 is var content
function assert_var_set
{
if [ -z "$2" ] ; then
fatal "$1 was not set."
fi
}

# Make sure the required env vars are defined with non-empty values
assert_var_set CONTAINER_IP $CONTAINER_IP
assert_var_set GAMEON_ID $GAMEON_ID
assert_var_set GAMEON_SECRET $GAMEON_SECRET
assert_var_set ROOM_NAME $ROOM_NAME

# Make sure any optional env vars are given default values if they are not defined
export GAMEON_ADDR=${GAMEON_ADDR-game-on.org}
export GAMEON_PORT=${GAMEON_PORT-3000}
export GAMEON_REG_RETRIES=${GAMEON_REG_RETRIES-10}
export GAMEON_REG_SECONDS_BETWEEN=${GAMEON_REG_SECONDS_BETWEEN-15}
export GAMEON_TIMESHIFT=${GAMEON_TIMESHIFT-0}
if [ -z "$GAMEON_DEBUG" ] ; then
DEBUG_FLAG=""
else
DEBUG_FLAG="-d"
fi

$ROOM_BINARY \
-c $CONTAINER_IP \
-g $GAMEON_ADDR \
-cp 3000 \
-lp $GAMEON_PORT \
-r $ROOM_NAME \
-id "$GAMEON_ID" \
-secret "$GAMEON_SECRET" \
-retries $GAMEON_REG_RETRIES \
-between $GAMEON_REG_SECONDS_BETWEEN \
-ts $GAMEON_TIMESHIFT \
$DEBUG_FLAG
20 changes: 20 additions & 0 deletions example-container.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This is an example environment variable file for use with
# the gameon-room-go container. The current values are just
# for illustration and most certainly will not work for you
# until you change the values to match your needs.
#
# Build the container locally:
# docker build -t go-room:1.0 .
# Run the container locally using this file:
# docker run -it --env-file=example-container.env go-room:1.0
#
CONTAINER_IP=127.0.0.1
GAMEON_ID=MyFakeId
GAMEON_SECRET=MyFakeSecret
ROOM_NAME=MyRoom
GAMEON_PORT=3000
GAMEON_ADDR=127.0.0.1
GAMEON_DEBUG=true
GAMEON_REG_RETRIES=2
GAMEON_REG_SECONDS_BETWEEN=5
GAMEON_TIMESHIFT=0
18 changes: 11 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ type RoomConfig struct {
// if you logged in using your Google ID:
// 'google:132043241444397884152'
id string
// This is the secret key that was obtained during your GameOn!
// This is the shared secret that was obtained during your GameOn!
// browser login. If you logged in using your Google ID it might
// look like this: 'LNIkaoiu62addlGp/rCZc7g,n3s9jUtOpXErr062kos='
key string
localServer bool
timeShift int
secret string
localServer bool
timeShift int
retries int
secondsBetween int
}

var config RoomConfig
Expand Down Expand Up @@ -85,10 +87,12 @@ func processCommandline() (err error) {
flag.StringVar(&config.west, "west", "An old swinging door leads west.", "Describes our western door")
flag.StringVar(&config.up, "up", "There is a rickety set of steps leading up.", "GameOn! often ignores this door")
flag.StringVar(&config.down, "down", "Heat eminates from an opening in the floor.", "GameOn! often ignores this door")
flag.StringVar(&config.id, "id", "", "The id associated with our key.")
flag.StringVar(&config.key, "key", localSecret, "Our secret key.")
flag.StringVar(&config.id, "id", "", "The id associated with our shared secret.")
flag.StringVar(&config.secret, "secret", localSecret, "Our shared secret.")
flag.BoolVar(&config.localServer, "local", false, "We are using a local server. Local servers expect http://; remote servers expect https://")
flag.IntVar(&config.timeShift, "ts", 0, "The number of milleseconds to add or subtract from our timestamp so that we can better match the server clock")
flag.IntVar(&config.retries, "retries", 5, "The number of initial registration attempts.")
flag.IntVar(&config.secondsBetween, "between", 5, "The number of seconds between registration attempts.")

flag.Parse()
if config.gameonAddr == "" {
Expand Down Expand Up @@ -127,7 +131,7 @@ func printConfig(c *RoomConfig) {
fmt.Printf("timeShift=%d\n", config.timeShift)
if config.debug {
fmt.Printf("id=%s\n", config.id)
fmt.Printf("key=%s\n", config.key)
fmt.Printf("secret=%s\n", config.secret)
}
}

Expand Down
19 changes: 7 additions & 12 deletions register.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ import (
"time"
)

const (
regRetries = 1
regMSBetween = 10000
)

// A RoomExit describes an exit out of a GameOn! room.
// Here is an example of a corresponding JSON fragment:
// {
Expand Down Expand Up @@ -91,18 +86,18 @@ type RoomRegistrationResp struct {
// Registers our room with the GameOn! server, with retries on failure.
func registerWithRetries() (e error) {
locus := "REG_W_RETRIES"
checkpoint(locus, fmt.Sprintf("retries=%d msBetween=%d", regRetries, regMSBetween))
for i := 0; i < regRetries; i++ {
checkpoint(locus, fmt.Sprintf("retries=%d secondsBetween=%d", config.retries, config.secondsBetween))
for i := 0; i < config.retries; i++ {
checkpoint(locus, fmt.Sprintf("Begin attempt %d of %d",
i+1, regRetries))
i+1, config.retries))
e = register()
if e == nil {
checkpoint(locus, "Registration was successful.")
return
}
checkpoint(locus, fmt.Sprintf("sleeping %d ms.", regMSBetween))
if i+1 < regRetries {
time.Sleep(regMSBetween * time.Millisecond)
checkpoint(locus, fmt.Sprintf("sleeping %d seconds.", config.secondsBetween))
if i+1 < config.retries {
time.Sleep(time.Duration(config.secondsBetween) * time.Second)
}
}
checkpoint(locus, "Registration failed.")
Expand Down Expand Up @@ -210,7 +205,7 @@ func registerOurRoom(client *http.Client) (err error) {
ts := makeTimestamp()
bodyHash := hash(registration)
tokens := []string{config.id, ts, bodyHash}
sig := buildHmac(tokens, config.key)
sig := buildHmac(tokens, config.secret)
var u string
if config.localServer {
u = fmt.Sprintf("http://%s/map/v1/sites", config.gameonAddr)
Expand Down

0 comments on commit 5c92525

Please sign in to comment.