implement like all the boilerplate
This commit is contained in:
parent
c61f730395
commit
82cf7c8145
44
.air.toml
Normal file
44
.air.toml
Normal file
@ -0,0 +1,44 @@
|
||||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "./tmp/main"
|
||||
cmd = "go build -o ./tmp/main ."
|
||||
delay = 0
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
db.sqlite
|
||||
obs-replay-server
|
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "main.go"
|
||||
}
|
||||
]
|
||||
}
|
11
db/query.sql
Normal file
11
db/query.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- name: UserByName :one
|
||||
SELECT * FROM users WHERE name = ? LIMIT 1;
|
||||
|
||||
-- name: ReplaysForUser :many
|
||||
SELECT * FROM replays JOIN users ON replays.owner = users.id WHERE users.name = ?;
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (name) VALUES (?) RETURNING *;
|
||||
|
||||
-- name: AddReplay :one
|
||||
INSERT INTO replays (file_path, owner) VALUES (?, ?) RETURNING *;
|
12
db/schema.sql
Normal file
12
db/schema.sql
Normal file
@ -0,0 +1,12 @@
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name text NOT NULL,
|
||||
CONSTRAINT username_unique UNIQUE (name)
|
||||
);
|
||||
|
||||
CREATE TABLE replays (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
file_path text NOT NULL,
|
||||
owner INTEGER NOT NULL,
|
||||
FOREIGN KEY (owner) REFERENCES users (id)
|
||||
);
|
9
go.mod
9
go.mod
@ -4,15 +4,19 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/andreykaipov/goobs v0.12.0
|
||||
github.com/labstack/echo v3.3.10+incompatible
|
||||
github.com/charmbracelet/log v0.2.2
|
||||
github.com/labstack/echo/v4 v4.10.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.7.1 // indirect
|
||||
github.com/charmbracelet/log v0.2.2 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||
@ -21,6 +25,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.1 // indirect
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
|
14
go.sum
14
go.sum
@ -13,12 +13,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
@ -30,13 +30,13 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
|
||||
@ -50,7 +50,7 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
@ -64,12 +64,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -1,17 +1,63 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/radiden/obs-replay-server/services"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
var sv *services.Services
|
||||
|
||||
func InitHandlers(svs *services.Services) {
|
||||
sv = svs
|
||||
}
|
||||
|
||||
func IndexHandler(c echo.Context) error {
|
||||
t, err := template.ParseFiles("views/base.html", "views/public/index.html")
|
||||
if err != nil {
|
||||
log.Error("failed to parse template", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return t.Execute(c.Response().Writer, nil)
|
||||
}
|
||||
|
||||
func AuthHandler(c echo.Context) error {
|
||||
userName := c.FormValue("username")
|
||||
c.SetCookie(&http.Cookie{
|
||||
Name: "sdvxreplay_session",
|
||||
Value: userName,
|
||||
})
|
||||
|
||||
_, err := sv.DB.Queries.UserByName(c.Request().Context(), userName)
|
||||
if err == sql.ErrNoRows {
|
||||
_, err := sv.DB.Queries.CreateUser(c.Request().Context(), userName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t, err := template.ParseFiles("views/base.html", "views/public/login_success.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.Execute(c.Response().Writer, nil)
|
||||
}
|
||||
|
||||
func PanelHandler(c echo.Context) error {
|
||||
_, err := c.Cookie("sdvxreplay_session")
|
||||
if err != nil {
|
||||
return c.Redirect(http.StatusBadRequest, "/")
|
||||
}
|
||||
t, err := template.ParseFiles("views/base.html", "views/public/panel.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.Execute(c.Response().Writer, nil)
|
||||
|
68
main.go
68
main.go
@ -1,42 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/andreykaipov/goobs"
|
||||
"github.com/andreykaipov/goobs/api/events"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/radiden/obs-replay-server/handlers"
|
||||
"github.com/radiden/obs-replay-server/services"
|
||||
|
||||
_ "embed"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// init obs connection
|
||||
client, err := goobs.New("localhost:4455", goobs.WithPassword("ThpNdGXBwneYn9X7"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Disconnect()
|
||||
//go:embed db/schema.sql
|
||||
var initialSchema string
|
||||
|
||||
isRecording, err := client.Outputs.GetReplayBufferStatus()
|
||||
var sv *services.Services
|
||||
|
||||
func main() {
|
||||
sv = services.InitServices(initialSchema)
|
||||
handlers.InitHandlers(sv)
|
||||
|
||||
isRecording, err := sv.OBS.Outputs.GetReplayBufferStatus()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatal("couldn't get replay buffer status", "error", err)
|
||||
}
|
||||
if !isRecording.OutputActive {
|
||||
client.Outputs.StartReplayBuffer()
|
||||
sv.OBS.Outputs.StartReplayBuffer()
|
||||
}
|
||||
|
||||
// init echo
|
||||
// start echo
|
||||
e := echo.New()
|
||||
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
|
||||
LogStatus: true,
|
||||
LogURI: true,
|
||||
LogError: true,
|
||||
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
|
||||
if err == nil {
|
||||
log.Info("[request]", "uri", v.URI, "status", v.Status)
|
||||
} else {
|
||||
log.Error("[request]", "uri", v.URI, "status", v.Status, "err", v.Error)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}))
|
||||
e.Static("/assets", "assets")
|
||||
e.GET("/", handlers.IndexHandler)
|
||||
e.POST("/auth", handlers.AuthHandler)
|
||||
e.GET("/panel", handlers.PanelHandler)
|
||||
e.Logger.Fatal(e.Start(":1323"))
|
||||
}
|
||||
|
||||
func getSavedPath(client *goobs.Client) string {
|
||||
for {
|
||||
msg := <-client.IncomingEvents
|
||||
switch m := msg.(type) {
|
||||
case *events.ReplayBufferSaved:
|
||||
return m.SavedReplayPath
|
||||
}
|
||||
}
|
||||
}
|
||||
// func getSavedPath(client *goobs.Client) string {
|
||||
// for {
|
||||
// msg := <-client.IncomingEvents
|
||||
// switch m := msg.(type) {
|
||||
// case *events.ReplayBufferSaved:
|
||||
// return m.SavedReplayPath
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
31
models/db.go
Normal file
31
models/db.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.18.0
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
18
models/models.go
Normal file
18
models/models.go
Normal file
@ -0,0 +1,18 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.18.0
|
||||
|
||||
package models
|
||||
|
||||
import ()
|
||||
|
||||
type Replay struct {
|
||||
ID int64
|
||||
FilePath string
|
||||
Owner int64
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
Name string
|
||||
}
|
89
models/query.sql.go
Normal file
89
models/query.sql.go
Normal file
@ -0,0 +1,89 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.18.0
|
||||
// source: query.sql
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const addReplay = `-- name: AddReplay :one
|
||||
INSERT INTO replays (file_path, owner) VALUES (?, ?) RETURNING id, file_path, owner
|
||||
`
|
||||
|
||||
type AddReplayParams struct {
|
||||
FilePath string
|
||||
Owner int64
|
||||
}
|
||||
|
||||
func (q *Queries) AddReplay(ctx context.Context, arg AddReplayParams) (Replay, error) {
|
||||
row := q.db.QueryRowContext(ctx, addReplay, arg.FilePath, arg.Owner)
|
||||
var i Replay
|
||||
err := row.Scan(&i.ID, &i.FilePath, &i.Owner)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (name) VALUES (?) RETURNING id, name
|
||||
`
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, name string) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, createUser, name)
|
||||
var i User
|
||||
err := row.Scan(&i.ID, &i.Name)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const replaysForUser = `-- name: ReplaysForUser :many
|
||||
SELECT replays.id, file_path, owner, users.id, name FROM replays JOIN users ON replays.owner = users.id WHERE users.name = ?
|
||||
`
|
||||
|
||||
type ReplaysForUserRow struct {
|
||||
ID int64
|
||||
FilePath string
|
||||
Owner int64
|
||||
ID_2 int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func (q *Queries) ReplaysForUser(ctx context.Context, name string) ([]ReplaysForUserRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, replaysForUser, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ReplaysForUserRow
|
||||
for rows.Next() {
|
||||
var i ReplaysForUserRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.FilePath,
|
||||
&i.Owner,
|
||||
&i.ID_2,
|
||||
&i.Name,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const userByName = `-- name: UserByName :one
|
||||
SELECT id, name FROM users WHERE name = ? LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) UserByName(ctx context.Context, name string) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, userByName, name)
|
||||
var i User
|
||||
err := row.Scan(&i.ID, &i.Name)
|
||||
return i, err
|
||||
}
|
58
services/services.go
Normal file
58
services/services.go
Normal file
@ -0,0 +1,58 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
|
||||
"github.com/andreykaipov/goobs"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/radiden/obs-replay-server/models"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
Client *sql.DB
|
||||
Queries *models.Queries
|
||||
}
|
||||
|
||||
type Services struct {
|
||||
OBS *goobs.Client
|
||||
DB *Database
|
||||
}
|
||||
|
||||
func InitServices(initialSchema string) *Services {
|
||||
db, err := initDB(initialSchema)
|
||||
if err != nil {
|
||||
log.Fatal("couldn't initialize db", "error", err)
|
||||
}
|
||||
|
||||
obs, err := initOBS()
|
||||
if err != nil {
|
||||
log.Fatal("couldn't connect to obs", "error", err)
|
||||
}
|
||||
return &Services{
|
||||
DB: db,
|
||||
OBS: obs,
|
||||
}
|
||||
}
|
||||
|
||||
func initDB(initialSchema string) (*Database, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
db, err := sql.Open("sqlite3", "file:db.sqlite")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db.ExecContext(ctx, initialSchema)
|
||||
|
||||
return &Database{
|
||||
Client: db,
|
||||
Queries: models.New(db),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initOBS() (*goobs.Client, error) {
|
||||
obs, err := goobs.New("localhost:4455", goobs.WithPassword("ThpNdGXBwneYn9X7"))
|
||||
return obs, err
|
||||
}
|
9
sqlc.yaml
Normal file
9
sqlc.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
version: 2
|
||||
sql:
|
||||
- engine: "sqlite"
|
||||
schema: "db/schema.sql"
|
||||
queries: "db/query.sql"
|
||||
gen:
|
||||
go:
|
||||
package: "models"
|
||||
out: "models"
|
@ -6,6 +6,7 @@
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<title>{{ template "title" . }}</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kimeiga/bahunya/dist/bahunya.min.css">
|
||||
</head>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
{{define "content"}}
|
||||
<h1>SDVX Replay Server</h1>
|
||||
<h2>Wpisz swój nick aby kontynuować</h2>
|
||||
<form action="">
|
||||
<form action="/auth" method="POST">
|
||||
<input type="text" name="username" placeholder="Nick">
|
||||
<input type="submit" value="Kontynuuj">
|
||||
</form>
|
||||
|
9
views/public/login_success.html
Normal file
9
views/public/login_success.html
Normal file
@ -0,0 +1,9 @@
|
||||
{{define "title"}}Pomyślnie zalogowano{{end}}
|
||||
{{define "content"}}
|
||||
<script>
|
||||
setInterval(window.location = "/panel", 1000)
|
||||
</script>
|
||||
<h1>
|
||||
Pomyślnie zalogowano! Wkrótce nastąpi przekierowanie...
|
||||
</h1>
|
||||
{{end}}
|
9
views/public/panel.html
Normal file
9
views/public/panel.html
Normal file
@ -0,0 +1,9 @@
|
||||
{{define "title"}}SDVX Replay - panel{{end}}
|
||||
{{define "content"}}
|
||||
<form action="/save" method="GET">
|
||||
<button style="font-size: 24pt; padding: .5em; background-color: #599e34; color: #0e1117;" type="submit">Zapisz
|
||||
powtórkę</button>
|
||||
</form>
|
||||
|
||||
<h1>Moje powtórki</h1>
|
||||
{{end}}
|
Loading…
Reference in New Issue
Block a user