Genvid Project¶
The Genvid Project is a minimalist setup that allows you maximum of flexibility for how to test and deploy your project with Genvid. We will study the HCL format of the file, which we find easier to maintain, but the JSON format is a straight translation of the HCL format [1].
Let’s use the Tutorial project as an example. Here the whole file, but we will explore it section by section [2]:
// *** Preamble *** //
// Version number. Don't change it.
version = "1.3.0"
// The name of the game. Mostly used as a reference.
name = "tutorial"
// *** End of Preamble *** //
// *** Game Configuration *** //
// The game job. The name of the job should match the template name.
job "tutorial" {
// Services that the game depends before starting
depends_on = [
"nats",
"compose",
]
// Add the job to the default start jobs.
// It is true by default.
// autostart = true
}
// The game events map-reduce definition.
event "game" {
path = "{{env `PROJECTDIR` | js}}\\app\\mr.json"
}
// Log for the game
log "game" {
task = "tutorial"
stdout = false
}
// *** End of Game Configuration *** //
// *** Web Server Configuration *** //
// The web server job
job "web" {
}
// Standard output of the web server
log "web" {
stdout = true
task = "web"
}
// Standard error output of the web server.
log "weberr" {
stdout = false
task = "web"
}
// *** End of WebServer Configuration *** //
// *** Key-Value Store Configuration *** //
config {
local {
// Some website configuration, used by the local web job template
website {
root = "{{env `PROJECTDIR` | js}}\\web"
script = "{{env `PROJECTDIR` | js}}\\web\\bin\\www"
}
// The game binary, used by the local game job template
binary {
tutorial {
path = "{{env `PROJECTDIR` | js}}\\app\\x64\\Release\\Tutorial.exe"
}
node {
// Here, we used the C:\Windows\System32\where.exe command here
// to find the path to node.
path = "{{plugin `where.exe` `node` | js}}"
}
}
appdir = "{{env `PROJECTDIR` | js}}\\app"
}
// The web server image, used by the cloud web job.
cloud {
image {
web {
tag = "sampleweb:dev"
}
}
}
}
// *** End of Key-Value Store Configuration *** //
// *** Build Scripts Definitions *** //
// The local build script.
script "build" {
commands = [
// Build the game
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\run.py\" build",
// Build the web site
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\web\\build.py\" build",
]
}
// The cloud build script
script "build_cloud" {
commands = [
// Build the game and archive it for the cloud
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\run.py\" all",
// Build a docker image of the website
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\web\\build-docker.py\" all",
]
}
// *** End of Build Scripts Definitions *** //
// *** Links Configuration *** //
// Links to the web sites
link {
web {
name = "Tutorial Demo"
template = "http://${service `web`}/"
}
admin {
name = "Tutorial Admin"
template = "http://${serviceEx `web` `` true}/admin"
}
}
// ***End of Links Configuration *** //
Preamble¶
The first thing at the top is the preamble:
// Version number. Don't change it.
version = "1.3.0"
// The name of the game. Mostly used as a reference.
name = "tutorial"
We only have two things here: the version
of the configuration
(currently 1.3.0
), and the name
of the project. You must not
change the version, which will be used to help future upgrades. The
name is free form, but you should try to make it match the name of
your main job. The version number represents the first version of the
SDK supporting this format.
Game Configuration¶
The second section contains the configuration for the game job:
// The game job. The name of the job should match the template name.
job "tutorial" {
// Services that the game depends before starting
depends_on = [
"nats",
"compose",
]
// Add the job to the default start jobs.
// It is true by default.
// autostart = true
}
// The game events map-reduce definition.
event "game" {
path = "{{env `PROJECTDIR` | js}}\\app\\mr.json"
}
// Log for the game
log "game" {
task = "tutorial"
stdout = false
}
We have three elements in this section: a job
, an
event
, and a log
. Let’s check them one by one.
The first element is a new job. The name of the job should match the name of the template file as well as the name of the job in the template file. Job configurations have two attributes:
- depends_on: a list of service to wait on before starting the job. The default is none.
- autostart: if the job must be automatically started on a start command without argument.
The next element in the section is the event. Right now, the event can
only point to a file using the path
attribute, containing a
Schema for the Events Channel.
Finally, the log
give the default options to pass to the
show_alloc_log()
command when you run
local.py log game
.
Web Server Configuration¶
The third section is very similar to the previous one, but it is for
the web server. It contains a single job
, with only the default
attribute, and two log
elements: one for the standard output, and
the other for the standard error.
// The web server job
job "web" {
}
// Standard output of the web server
log "web" {
stdout = true
task = "web"
}
// Standard error output of the web server.
log "weberr" {
stdout = false
task = "web"
}
Key-Value Store Configuration¶
The fourth section contains a single element: config
:
config {
local {
// Some website configuration, used by the local web job template
website {
root = "{{env `PROJECTDIR` | js}}\\web"
script = "{{env `PROJECTDIR` | js}}\\web\\bin\\www"
}
// The game binary, used by the local game job template
binary {
tutorial {
path = "{{env `PROJECTDIR` | js}}\\app\\x64\\Release\\Tutorial.exe"
}
node {
// Here, we used the C:\Windows\System32\where.exe command here
// to find the path to node.
path = "{{plugin `where.exe` `node` | js}}"
}
}
appdir = "{{env `PROJECTDIR` | js}}\\app"
}
// The web server image, used by the cloud web job.
cloud {
image {
web {
tag = "sampleweb:dev"
}
}
}
}
The content of this element is added to the key-value store, each object being considered as a folder, and each value converted to string and inserted as a key.
An interesting element in this section is the usage of a
consul-template’s plugin for determining the location of the
node.exe
binary. The plugin simply calls the executable where
(a DOS command) with the argument node
, and returns the output of
the command. You can use your own executables, as long as they are in
your path when the project is loaded. The js method is also quite
useful here to ensure elements like Windows path separators are
correctly quoted in the file.
We also use the consul-template’s env method, for accessing
environment variables. In this case, it uses the PROJECT_DIR
variable which always points to the folder of the project file. The
template system has access to all environment variables of the
scripts, plus some set by the script itself. You can list these
variables by running:
py local.py env
The key-value store is always initialized first with this section,
then with the key-value found under the <project_dir>\config
, and
finally with the ones found under the <rootdir>\config
, the latest
ones overwriting the previous ones.
Build Scripts Definitions¶
This section contains two script
elements. They are used when
you run the local.py run-script <name>
command. Right now, the
two scripts present here are only used for building the binaries, one
for the local deployment (build
), and the other for the cloud
(build_cloud
):
// The local build script.
script "build" {
commands = [
// Build the game
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\run.py\" build",
// Build the web site
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\web\\build.py\" build",
]
}
// The cloud build script
script "build_cloud" {
commands = [
// Build the game and archive it for the cloud
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\run.py\" all",
// Build a docker image of the website
"\"{{env `PYTHON_EXECUTABLE` | js}}\" \"{{env `PROJECTDIR` | js}}\\web\\build-docker.py\" all",
]
}
Right now, script elements have a single attribute, commands
,
which contains a list of commands to be run. The command are
interpreted directly with the local shell, so you could put
environment variables in it directly, or even redirection. In our
case, we opted to let consul-template do the substitution and used
PYTHON_EXECUTABLE
to ensure the Python interpreter is the same one used
for running the local.py
script. We could have simply used the
py
launcher instead.
[1] | JSON is also the format we used when we saved it under
config/_local.json , so don’t hesitate to take a look there
if you want to see the result of a transformation. |
[2] | This division by section is purely to help the presentation. You don’t have to respect this order. |
Links Configuration¶
This section contains multiple link elements. They are used add
uri to the system. By running local.py open
you can see the
list of available links.
// Links to the web sites
link {
web {
name = "Tutorial Demo"
template = "http://${service `web`}/"
}
admin {
name = "Tutorial Admin"
template = "http://${serviceEx `web` `` true}/admin"
}
}
These links are using a template system to produce the final link.
In this case, the template http://${service `web`}/
would be
transform into the website uri.
The available template functions are…
- service service: Give the service address and port
- serviceEx service tag external : Give the service address and port. The tag is an arbitrary value used to find a service. The external is asking for an external address
- key key: Give the value from a consul key value pair.
- key_or_default key default_value: Give the value from a consul key value pair. Get the default value if the key is not available.