Several improvements
* Make Dockerfile build and run correctly on alpine, fix missing sqlite * Make config shared to avoid reading from file on each request * Correctly handle Signals to gracefully stop database connection and to speed up shutdown, relevant for docker deployment * Correctly check for sqlite error on table creation
This commit is contained in:
parent
c03f949344
commit
7749b7c159
5 changed files with 59 additions and 19 deletions
|
@ -2,10 +2,12 @@ FROM thevlang/vlang:alpine AS build
|
|||
|
||||
WORKDIR /tmp/app
|
||||
COPY . .
|
||||
RUN v -prod .
|
||||
RUN v -prod -o highscore-server .
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk --no-cache add sqlite-dev
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=build /tmp/app/highscore-server .
|
||||
COPY --from=build /tmp/app/config.example.toml ./config.toml
|
||||
|
|
|
@ -15,6 +15,10 @@ struct Config {
|
|||
db_path string
|
||||
}
|
||||
|
||||
fn (config Config) copy() Config {
|
||||
return config
|
||||
}
|
||||
|
||||
fn load_config() Config {
|
||||
config := toml.parse_file(path) or { panic(err) }
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ pub mut:
|
|||
time i64
|
||||
}
|
||||
|
||||
fn (mut app App) create_tables() bool {
|
||||
fn (mut app App) create_tables() int {
|
||||
return app.db.exec_none(
|
||||
"CREATE TABLE IF NOT EXISTS ScoreRes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
|
@ -16,7 +16,7 @@ fn (mut app App) create_tables() bool {
|
|||
score INTEGER NOT NULL,
|
||||
time SQLITE_INT64_TYPE NOT NULL
|
||||
)"
|
||||
) == 0
|
||||
)
|
||||
}
|
||||
|
||||
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 sqlite
|
||||
import time
|
||||
import os
|
||||
|
||||
struct App {
|
||||
vweb.Context
|
||||
pub mut:
|
||||
db sqlite.DB
|
||||
config Config
|
||||
config shared Config
|
||||
is_admin bool
|
||||
}
|
||||
|
||||
fn main() {
|
||||
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 {
|
||||
println('Database Error!')
|
||||
if !os.exists(app_config.db_path) {
|
||||
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)
|
||||
}
|
||||
|
||||
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 := '::'
|
||||
|
||||
if app.config.host != "" {
|
||||
host = app.config.host
|
||||
if 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{
|
||||
host: host
|
||||
port: app.config.port
|
||||
port: app_config.port
|
||||
family: .ip6
|
||||
}) 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 time
|
||||
|
||||
struct Status {
|
||||
struct ResultStatus {
|
||||
status int
|
||||
message string
|
||||
}
|
||||
|
@ -16,8 +16,10 @@ struct ErrorStatus {
|
|||
}
|
||||
|
||||
pub fn (mut app App) index() vweb.Result {
|
||||
if app.config.redirect {
|
||||
app.redirect(app.config.redirect_url)
|
||||
rlock app.config {
|
||||
if app.config.redirect {
|
||||
app.redirect(app.config.redirect_url)
|
||||
}
|
||||
}
|
||||
|
||||
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()})
|
||||
|
||||
return app.json(
|
||||
Status {
|
||||
ResultStatus {
|
||||
200,
|
||||
"Success"
|
||||
}
|
||||
|
@ -77,10 +79,14 @@ pub fn (mut app App) score_submit() vweb.Result {
|
|||
}
|
||||
|
||||
fn (mut app App) auth() bool {
|
||||
app.config = load_config()
|
||||
|
||||
auth_header := app.get_header('Authorization')
|
||||
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