Compare commits
2 commits
ba7938dcf4
...
7749b7c159
Author | SHA1 | Date | |
---|---|---|---|
7749b7c159 | |||
c03f949344 |
8 changed files with 92 additions and 19 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
/config.toml
|
/config.toml
|
||||||
|
/compose.yml
|
||||||
/highscore-server
|
/highscore-server
|
||||||
/db
|
/db
|
||||||
|
|
|
@ -2,10 +2,12 @@ FROM thevlang/vlang:alpine AS build
|
||||||
|
|
||||||
WORKDIR /tmp/app
|
WORKDIR /tmp/app
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN v -prod .
|
RUN v -prod -o highscore-server .
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
|
RUN apk --no-cache add sqlite-dev
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=build /tmp/app/highscore-server .
|
COPY --from=build /tmp/app/highscore-server .
|
||||||
COPY --from=build /tmp/app/config.example.toml ./config.toml
|
COPY --from=build /tmp/app/config.example.toml ./config.toml
|
||||||
|
|
15
compose.example.yml
Normal file
15
compose.example.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
services:
|
||||||
|
highscore-server:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: git.snrd.eu/sunred/highscore-server:latest
|
||||||
|
container_name: highscore-server
|
||||||
|
network_mode: bridge
|
||||||
|
volumes:
|
||||||
|
- ./config.toml:/app/config.toml:ro
|
||||||
|
- ./db:/app/db:rw
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080/tcp"
|
||||||
|
- "[::1]:8080:8080/tcp"
|
||||||
|
restart: unless-stopped
|
17
docker.bake.hcl
Normal file
17
docker.bake.hcl
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
variable "REG" {
|
||||||
|
default = "git.snrd.eu"
|
||||||
|
}
|
||||||
|
variable "REPO" {
|
||||||
|
default = "sunred/higscore-server"
|
||||||
|
}
|
||||||
|
variable "TAG" {
|
||||||
|
default = "latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
group "default" {
|
||||||
|
targets = ["production"]
|
||||||
|
}
|
||||||
|
target "production" {
|
||||||
|
output = ["type=docker"]
|
||||||
|
tags = ["${REG}/${REPO}:latest", "${REG}/${REPO}:${TAG}"]
|
||||||
|
}
|
|
@ -15,6 +15,10 @@ struct Config {
|
||||||
db_path string
|
db_path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (config Config) copy() Config {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
fn load_config() Config {
|
fn load_config() Config {
|
||||||
config := toml.parse_file(path) or { panic(err) }
|
config := toml.parse_file(path) or { panic(err) }
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub mut:
|
||||||
time i64
|
time i64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut app App) create_tables() bool {
|
fn (mut app App) create_tables() int {
|
||||||
return app.db.exec_none(
|
return app.db.exec_none(
|
||||||
"CREATE TABLE IF NOT EXISTS ScoreRes (
|
"CREATE TABLE IF NOT EXISTS ScoreRes (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
@ -16,7 +16,7 @@ fn (mut app App) create_tables() bool {
|
||||||
score INTEGER NOT NULL,
|
score INTEGER NOT NULL,
|
||||||
time SQLITE_INT64_TYPE NOT NULL
|
time SQLITE_INT64_TYPE NOT NULL
|
||||||
)"
|
)"
|
||||||
) == 0
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut app App) insert_score(score ScoreRes) {
|
fn (mut app App) insert_score(score ScoreRes) {
|
||||||
|
|
46
src/main.v
46
src/main.v
|
@ -2,36 +2,64 @@ module main
|
||||||
|
|
||||||
import vweb
|
import vweb
|
||||||
import sqlite
|
import sqlite
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
vweb.Context
|
vweb.Context
|
||||||
pub mut:
|
pub mut:
|
||||||
db sqlite.DB
|
db sqlite.DB
|
||||||
config Config
|
config shared Config
|
||||||
is_admin bool
|
is_admin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut app := &App{}
|
mut app := &App{}
|
||||||
|
mut app_config := Config{}
|
||||||
|
|
||||||
app.config = load_config()
|
lock app.config {
|
||||||
|
app.config = load_config()
|
||||||
|
app_config = app.config.copy()
|
||||||
|
}
|
||||||
|
|
||||||
app.db = sqlite.connect(app.config.db_path) or {
|
if !os.exists(app_config.db_path) {
|
||||||
println('Database Error!')
|
println("Creating database file at " + app_config.db_path)
|
||||||
|
mut file := os.create(app_config.db_path) or { panic(err) }
|
||||||
|
file.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
app.db = sqlite.connect(app_config.db_path) or {
|
||||||
|
println('Database error!')
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.create_tables()
|
sql_code := app.create_tables()
|
||||||
|
|
||||||
|
if sqlite.is_error(sql_code) {
|
||||||
|
println('Could not create tables!')
|
||||||
|
panic('Error code ' + sql_code.str())
|
||||||
|
}
|
||||||
|
|
||||||
mut host := '::'
|
mut host := '::'
|
||||||
|
if app_config.host != "" {
|
||||||
if app.config.host != "" {
|
host = app_config.host
|
||||||
host = app.config.host
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle graceful shutdown for Docker
|
||||||
|
os.signal_opt(os.Signal.int, app.shutdown) or { panic(err) }
|
||||||
|
os.signal_opt(os.Signal.term, app.shutdown) or { panic(err) }
|
||||||
|
|
||||||
vweb.run_at(app, vweb.RunParams{
|
vweb.run_at(app, vweb.RunParams{
|
||||||
host: host
|
host: host
|
||||||
port: app.config.port
|
port: app_config.port
|
||||||
family: .ip6
|
family: .ip6
|
||||||
}) or { panic(err) }
|
}) or { panic(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut app App) shutdown(sig os.Signal) {
|
||||||
|
app.db.close() or { panic(err) }
|
||||||
|
println("Shut down database gracefully")
|
||||||
|
println("Exiting...")
|
||||||
|
time.sleep(1e+9) // Sleep one second
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
|
20
src/web.v
20
src/web.v
|
@ -4,7 +4,7 @@ import vweb
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
struct Status {
|
struct ResultStatus {
|
||||||
status int
|
status int
|
||||||
message string
|
message string
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,10 @@ struct ErrorStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut app App) index() vweb.Result {
|
pub fn (mut app App) index() vweb.Result {
|
||||||
if app.config.redirect {
|
rlock app.config {
|
||||||
app.redirect(app.config.redirect_url)
|
if app.config.redirect {
|
||||||
|
app.redirect(app.config.redirect_url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return app.text("Hello :)")
|
return app.text("Hello :)")
|
||||||
|
@ -69,7 +71,7 @@ pub fn (mut app App) score_submit() vweb.Result {
|
||||||
app.insert_score(ScoreRes{player:body.player, score:body.score, time:time.now().unix_time()})
|
app.insert_score(ScoreRes{player:body.player, score:body.score, time:time.now().unix_time()})
|
||||||
|
|
||||||
return app.json(
|
return app.json(
|
||||||
Status {
|
ResultStatus {
|
||||||
200,
|
200,
|
||||||
"Success"
|
"Success"
|
||||||
}
|
}
|
||||||
|
@ -77,10 +79,14 @@ pub fn (mut app App) score_submit() vweb.Result {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut app App) auth() bool {
|
fn (mut app App) auth() bool {
|
||||||
app.config = load_config()
|
|
||||||
|
|
||||||
auth_header := app.get_header('Authorization')
|
auth_header := app.get_header('Authorization')
|
||||||
token := auth_header.after('Bearer ')
|
token := auth_header.after('Bearer ')
|
||||||
|
|
||||||
return token == app.config.token
|
mut config_token := ""
|
||||||
|
|
||||||
|
rlock app.config {
|
||||||
|
config_token = app.config.token
|
||||||
|
}
|
||||||
|
|
||||||
|
return config_token.len != 0 && token == config_token
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue