no crlf
This commit is contained in:
parent
0069aeaa24
commit
943408255c
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
// Use IntelliSense to learn about possible attributes.
|
||||||
// Hover to view descriptions of existing attributes.
|
// Hover to view descriptions of existing attributes.
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Launch Package",
|
"name": "Launch Package",
|
||||||
"type": "go",
|
"type": "go",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "${workspaceFolder}/cmd/web"
|
"program": "${workspaceFolder}/cmd/web"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
282
cmd/api/db.go
282
cmd/api/db.go
@ -1,141 +1,141 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func database_init(conn *pgx.Conn) {
|
func database_init(conn *pgx.Conn) {
|
||||||
sql := `DROP TABLE IF EXISTS vote;
|
sql := `DROP TABLE IF EXISTS vote;
|
||||||
DROP TABLE IF EXISTS vote_token;
|
DROP TABLE IF EXISTS vote_token;
|
||||||
DROP TABLE IF EXISTS option;
|
DROP TABLE IF EXISTS option;
|
||||||
DROP TABLE IF EXISTS issue;
|
DROP TABLE IF EXISTS issue;
|
||||||
DROP TABLE IF EXISTS account;`
|
DROP TABLE IF EXISTS account;`
|
||||||
|
|
||||||
_, err := conn.Exec(context.Background(), sql)
|
_, err := conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE TABLE account (
|
sql = `CREATE TABLE account (
|
||||||
id BIGINT primary key generated always as identity,
|
id BIGINT primary key generated always as identity,
|
||||||
username VARCHAR(50) UNIQUE NOT NULL,
|
username VARCHAR(50) UNIQUE NOT NULL,
|
||||||
email VARCHAR(255) UNIQUE NOT NULL,
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
password_hash TEXT NOT NULL,
|
password_hash TEXT NOT NULL,
|
||||||
first_name TEXT not null,
|
first_name TEXT not null,
|
||||||
last_name TEXT not null,
|
last_name TEXT not null,
|
||||||
created TIMESTAMPTZ DEFAULT now() NOT NULL,
|
created TIMESTAMPTZ DEFAULT now() NOT NULL,
|
||||||
last_login TIMESTAMPTZ
|
last_login TIMESTAMPTZ
|
||||||
)`
|
)`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `INSERT INTO account
|
sql = `INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('vik', '$argon2id$v=19$m=65536,t=1,p=32$+dQ9uB7kKL7t7G3bI+TOMw$Wvic27W6SYH6Fx2Pp84irhVJ/blVh5qINlkv58bpgEc', 'Vicente', 'Ferrari Smith', 'vikhenzo@gmail.com', '2024-05-24 13:21:48.179');
|
VALUES('vik', '$argon2id$v=19$m=65536,t=1,p=32$+dQ9uB7kKL7t7G3bI+TOMw$Wvic27W6SYH6Fx2Pp84irhVJ/blVh5qINlkv58bpgEc', 'Vicente', 'Ferrari Smith', 'vikhenzo@gmail.com', '2024-05-24 13:21:48.179');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('Al Orjales', '$argon2id$v=19$m=65536,t=1,p=1$rQODKJ0+mUZ6v6ChUAcr4Q$x0cDjym/QB9lFFq/77FPv7R90Ao5gldb9cuNprBpGAs', '', '', '', '2024-09-26 17:43:37.879');
|
VALUES('Al Orjales', '$argon2id$v=19$m=65536,t=1,p=1$rQODKJ0+mUZ6v6ChUAcr4Q$x0cDjym/QB9lFFq/77FPv7R90Ao5gldb9cuNprBpGAs', '', '', '', '2024-09-26 17:43:37.879');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('mkBflwkpe', '$argon2id$v=19$m=65536,t=1,p=1$BWcWdp8bhgS84LWqUCb2IA$DGF/FzQbSNHnfZraE9F2qvfdBGf5XB81+w00QgY/jG0', 'zWkxKTNolTgJwO', 'OahedOBLSo', 'bellrebekaou@gmail.com', '2024-11-25 03:00:18.211');
|
VALUES('mkBflwkpe', '$argon2id$v=19$m=65536,t=1,p=1$BWcWdp8bhgS84LWqUCb2IA$DGF/FzQbSNHnfZraE9F2qvfdBGf5XB81+w00QgY/jG0', 'zWkxKTNolTgJwO', 'OahedOBLSo', 'bellrebekaou@gmail.com', '2024-11-25 03:00:18.211');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('TzBeIMeRjxrfsM', '$argon2id$v=19$m=65536,t=1,p=1$ZIpNaO6RPeGncWe9cw8Iog$di0qjf8G0HlcZE8Hl+krNDlBeMrtfuGMwFWAlAnEMNs', 'ZBbLOWXqQlr', 'pIomimIQ', 'denielkgb21@gmail.com', '2024-11-19 13:20:33.177');
|
VALUES('TzBeIMeRjxrfsM', '$argon2id$v=19$m=65536,t=1,p=1$ZIpNaO6RPeGncWe9cw8Iog$di0qjf8G0HlcZE8Hl+krNDlBeMrtfuGMwFWAlAnEMNs', 'ZBbLOWXqQlr', 'pIomimIQ', 'denielkgb21@gmail.com', '2024-11-19 13:20:33.177');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('TeAOvwIdnfqpxy', '$argon2id$v=19$m=65536,t=1,p=1$GRL555iybL1S8GjPq8jlOg$YnuwBxHAT8/I+cU548CYuhwaJdcEXe+R2PQbYpV7UKQ', 'RzqsaECTYrz', 'zreWiEtZGOeRNI', 'aolelonnum@yahoo.com', '2024-11-26 01:19:37.780');
|
VALUES('TeAOvwIdnfqpxy', '$argon2id$v=19$m=65536,t=1,p=1$GRL555iybL1S8GjPq8jlOg$YnuwBxHAT8/I+cU548CYuhwaJdcEXe+R2PQbYpV7UKQ', 'RzqsaECTYrz', 'zreWiEtZGOeRNI', 'aolelonnum@yahoo.com', '2024-11-26 01:19:37.780');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('XIdQMFvxmT', '$argon2id$v=19$m=65536,t=1,p=1$PIcX7GObR0wlgRTmcMRUug$Kpc7SAv5K1PRxBtqioV4uoCZlkvGebkBmYyXCwoTgmM', 'ayZKALohBYmBx', 'smILWvtOvb', 'heilwoodsf@gmail.com', '2024-11-23 00:41:59.471');
|
VALUES('XIdQMFvxmT', '$argon2id$v=19$m=65536,t=1,p=1$PIcX7GObR0wlgRTmcMRUug$Kpc7SAv5K1PRxBtqioV4uoCZlkvGebkBmYyXCwoTgmM', 'ayZKALohBYmBx', 'smILWvtOvb', 'heilwoodsf@gmail.com', '2024-11-23 00:41:59.471');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('yIQvINFS', '$argon2id$v=19$m=65536,t=1,p=1$SJxMxkotEr+lfGeaCs7vlA$fffslijaMuPy+XPBEdv9iPqLbt66H/qJbGUHGrbpdz0', 'nKXBOwRbtXmMedo', 'KvMechDKtPPMgM', 'cortezzavira@gmail.com', '2024-11-24 06:29:58.378');
|
VALUES('yIQvINFS', '$argon2id$v=19$m=65536,t=1,p=1$SJxMxkotEr+lfGeaCs7vlA$fffslijaMuPy+XPBEdv9iPqLbt66H/qJbGUHGrbpdz0', 'nKXBOwRbtXmMedo', 'KvMechDKtPPMgM', 'cortezzavira@gmail.com', '2024-11-24 06:29:58.378');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('HEjcEByjlPjtaGE', '$argon2id$v=19$m=65536,t=1,p=1$Hu2qnPxi0nz0OHx97h5j5Q$xh7HwKBIi9mp+WWU7rS9MfnDohtJqrv0EUrF2mVpnto', 'yJrQikhSHRYNgdu', 'GttOfPxSPoVWWl', 'jacobsheizitn4963@gmail.com', '2024-11-27 00:07:53.617');
|
VALUES('HEjcEByjlPjtaGE', '$argon2id$v=19$m=65536,t=1,p=1$Hu2qnPxi0nz0OHx97h5j5Q$xh7HwKBIi9mp+WWU7rS9MfnDohtJqrv0EUrF2mVpnto', 'yJrQikhSHRYNgdu', 'GttOfPxSPoVWWl', 'jacobsheizitn4963@gmail.com', '2024-11-27 00:07:53.617');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('DggewDRjXu', '$argon2id$v=19$m=65536,t=1,p=1$MzFSqUr5J5IRC930empHrw$y7kogPP715NOtazsXqjR56LQGF2Eaes9CyAoPjRm3xk', 'uMezBkaQcfBbD', 'YoaQNBvZgHvTaFf', 'kinharrispa@gmail.com', '2024-11-27 21:55:53.037');
|
VALUES('DggewDRjXu', '$argon2id$v=19$m=65536,t=1,p=1$MzFSqUr5J5IRC930empHrw$y7kogPP715NOtazsXqjR56LQGF2Eaes9CyAoPjRm3xk', 'uMezBkaQcfBbD', 'YoaQNBvZgHvTaFf', 'kinharrispa@gmail.com', '2024-11-27 21:55:53.037');
|
||||||
|
|
||||||
INSERT INTO account
|
INSERT INTO account
|
||||||
(username, password_hash, first_name, last_name, email, created)
|
(username, password_hash, first_name, last_name, email, created)
|
||||||
VALUES('yyZGFAsmPEBoSf', '$argon2id$v=19$m=65536,t=1,p=1$vLVm5ol6GQkXPU0BPut92g$Kyvp7/dl3lGUszXRiXfgsgB/IY0EKulZVpVttXQaDDU', 'svVjyPUaAkN', 'mdngeHlf', 'giyahyd4141@gmail.com', '2024-11-28 19:02:32.806');`
|
VALUES('yyZGFAsmPEBoSf', '$argon2id$v=19$m=65536,t=1,p=1$vLVm5ol6GQkXPU0BPut92g$Kyvp7/dl3lGUszXRiXfgsgB/IY0EKulZVpVttXQaDDU', 'svVjyPUaAkN', 'mdngeHlf', 'giyahyd4141@gmail.com', '2024-11-28 19:02:32.806');`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE TABLE issue (
|
sql = `CREATE TABLE issue (
|
||||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
start_time TIMESTAMPTZ NOT NULL,
|
start_time TIMESTAMPTZ NOT NULL,
|
||||||
end_time TIMESTAMPTZ NOT NULL,
|
end_time TIMESTAMPTZ NOT NULL,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
)`
|
)`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE TABLE option (
|
sql = `CREATE TABLE option (
|
||||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE,
|
issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE,
|
||||||
label VARCHAR(255) NOT NULL,
|
label VARCHAR(255) NOT NULL,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
)`
|
)`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE TABLE vote_token (
|
sql = `CREATE TABLE vote_token (
|
||||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE,
|
issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE,
|
||||||
token UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
token UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
||||||
used BOOLEAN NOT NULL DEFAULT FALSE,
|
used BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
)`
|
)`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE TABLE vote (
|
sql = `CREATE TABLE vote (
|
||||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
token UUID NOT NULL UNIQUE REFERENCES vote_token(token) ON DELETE CASCADE,
|
token UUID NOT NULL UNIQUE REFERENCES vote_token(token) ON DELETE CASCADE,
|
||||||
option_id BIGINT NOT NULL REFERENCES option(id) ON DELETE CASCADE,
|
option_id BIGINT NOT NULL REFERENCES option(id) ON DELETE CASCADE,
|
||||||
voted_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
voted_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
)`
|
)`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = `CREATE INDEX idx_votes_option_id ON vote(option_id);
|
sql = `CREATE INDEX idx_votes_option_id ON vote(option_id);
|
||||||
CREATE INDEX idx_vote_tokens_issue_id ON vote_token(issue_id);
|
CREATE INDEX idx_vote_tokens_issue_id ON vote_token(issue_id);
|
||||||
CREATE INDEX idx_options_issue_id ON option(issue_id);`
|
CREATE INDEX idx_options_issue_id ON option(issue_id);`
|
||||||
|
|
||||||
_, err = conn.Exec(context.Background(), sql)
|
_, err = conn.Exec(context.Background(), sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,92 +1,92 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
"log"
|
"log"
|
||||||
"html/template"
|
"html/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
func home(w http.ResponseWriter, r *http.Request) {
|
func home(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path != "/" {
|
if r.URL.Path != "/" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(r.URL.Path)
|
fmt.Println(r.URL.Path)
|
||||||
|
|
||||||
ts, err := template.ParseFiles("ui/html/home.page.tmpl", "ui/html/base.layout.tmpl")
|
ts, err := template.ParseFiles("ui/html/home.page.tmpl", "ui/html/base.layout.tmpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err.Error())
|
log.Println(err.Error())
|
||||||
http.Error(w, "Internal Server Error", 500)
|
http.Error(w, "Internal Server Error", 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ts.Execute(w, nil)
|
err = ts.Execute(w, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err.Error())
|
log.Println(err.Error())
|
||||||
http.Error(w, "Internal Server Error", 500)
|
http.Error(w, "Internal Server Error", 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
// data := struct {
|
// data := struct {
|
||||||
// Name string
|
// Name string
|
||||||
// }{
|
// }{
|
||||||
// Name: "Vicente",
|
// Name: "Vicente",
|
||||||
// }
|
// }
|
||||||
// page_template.Execute(w, data)
|
// page_template.Execute(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ws(w http.ResponseWriter, r *http.Request) {
|
func ws(w http.ResponseWriter, r *http.Request) {
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Upgrade error:", err)
|
fmt.Println("Upgrade error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
ticker := time.NewTicker(1 * time.Second);
|
ticker := time.NewTicker(1 * time.Second);
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
return
|
return
|
||||||
case t := <-ticker.C:
|
case t := <-ticker.C:
|
||||||
msg := map[string]interface{}{
|
msg := map[string]interface{}{
|
||||||
"type": "server_tick",
|
"type": "server_tick",
|
||||||
"timestamp": t.Format(time.RFC3339),
|
"timestamp": t.Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if err := conn.WriteJSON(msg); err != nil {
|
if err := conn.WriteJSON(msg); err != nil {
|
||||||
fmt.Println("Write error:", err)
|
fmt.Println("Write error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var msg Message
|
var msg Message
|
||||||
err := conn.ReadJSON(&msg)
|
err := conn.ReadJSON(&msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Read error:", err)
|
fmt.Println("Read error:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
|
|
||||||
// Send a response
|
// Send a response
|
||||||
// response := fmt.Sprintf("Server time: %s", time.Now())
|
// response := fmt.Sprintf("Server time: %s", time.Now())
|
||||||
// if err := conn.WriteMessage(websocket.TextMessage, []byte(response)); err != nil {
|
// if err := conn.WriteMessage(websocket.TextMessage, []byte(response)); err != nil {
|
||||||
// fmt.Println("Write error:", err)
|
// fmt.Println("Write error:", err)
|
||||||
// break
|
// break
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func redirectToHTTPS(w http.ResponseWriter, r *http.Request) {
|
func redirectToHTTPS(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "https://localhost:8443" + r.URL.RequestURI(), http.StatusMovedPermanently)
|
http.Redirect(w, r, "https://localhost:8443" + r.URL.RequestURI(), http.StatusMovedPermanently)
|
||||||
}
|
}
|
||||||
|
|||||||
180
cmd/api/main.go
180
cmd/api/main.go
@ -1,95 +1,85 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
//"html/template"
|
//"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"flag"
|
"flag"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "1.0.0"
|
const version = "1.0.0"
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
port int
|
port int
|
||||||
env string
|
env string
|
||||||
}
|
}
|
||||||
|
|
||||||
type application struct {
|
type application struct {
|
||||||
config config
|
config config
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Timestamp string `json:"timestamp"`
|
Timestamp string `json:"timestamp"`
|
||||||
Random float64 `json:"random"`
|
Random float64 `json:"random"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//var page_template = template.Must(template.ParseFiles("../../ui/html/index.html"))
|
//var page_template = template.Must(template.ParseFiles("../../ui/html/index.html"))
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins
|
CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
var cfg config
|
||||||
var cfg config
|
|
||||||
|
flag.IntVar(&cfg.port, "port", 4000, "API server port")
|
||||||
flag.IntVar(&cfg.port, "port", 4000, "API server port")
|
flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)")
|
||||||
flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)")
|
//addr := flag.String("addr", ":8443", "HTTP network address")
|
||||||
//addr := flag.String("addr", ":8443", "HTTP network address")
|
flag.Parse()
|
||||||
flag.Parse()
|
|
||||||
|
logger := log.New(os.Stdout, "", log.Ldate | log.Ltime)
|
||||||
|
|
||||||
logger := log.New(os.Stdout, "", log.Ldate | log.Ltime)
|
app := &application{
|
||||||
|
config: cfg,
|
||||||
app := &application{
|
logger: logger,
|
||||||
config: cfg,
|
}
|
||||||
logger: logger,
|
|
||||||
}
|
conn, err := pgx.Connect(context.Background(), "postgres://party:iK2SoVbDhdCki5n3LxGyP6zKpLspt4@losandesgames.com:5432/party")
|
||||||
|
if err != nil {
|
||||||
conn, err := pgx.Connect(context.Background(), "postgres://party:iK2SoVbDhdCki5n3LxGyP6zKpLspt4@losandesgames.com:5432/party")
|
log.Fatal(err)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatal(err)
|
|
||||||
}
|
defer conn.Close(context.Background())
|
||||||
|
|
||||||
defer conn.Close(context.Background())
|
database_init(conn)
|
||||||
|
|
||||||
database_init(conn)
|
srv := &http.Server{
|
||||||
|
Addr: fmt.Sprintf(":%d", cfg.port),
|
||||||
fileServer := http.FileServer(http.Dir("ui/static"))
|
Handler: app.routes(),
|
||||||
|
IdleTimeout: time.Minute,
|
||||||
mux := http.NewServeMux()
|
ReadTimeout: 10 * time.Second,
|
||||||
mux.HandleFunc("/", home)
|
WriteTimeout: 30 * time.Second,
|
||||||
mux.HandleFunc("/ws", ws)
|
}
|
||||||
mux.Handle("/static/", http.StripPrefix("/static", fileServer))
|
|
||||||
mux.HandleFunc("/v1/healthcheck", app.healthcheckHandler)
|
logger.Printf("starting %s server on %s", cfg.env, srv.Addr);
|
||||||
|
|
||||||
srv := &http.Server{
|
// Start HTTPS server (requires cert.pem and key.pem in current dir)
|
||||||
Addr: fmt.Sprintf(":%d", cfg.port),
|
err = srv.ListenAndServe()
|
||||||
Handler: mux,
|
if err != nil {
|
||||||
IdleTimeout: time.Minute,
|
panic(err)
|
||||||
ReadTimeout: 10 * time.Second,
|
}
|
||||||
WriteTimeout: 30 * time.Second,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger.Printf("starting %s server on %s", cfg.env, srv.Addr);
|
|
||||||
|
|
||||||
// Start HTTPS server (requires cert.pem and key.pem in current dir)
|
|
||||||
err = srv.ListenAndServe()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
22
cmd/api/routes.go
Normal file
22
cmd/api/routes.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (app *application) routes() *httprouter.Router {
|
||||||
|
|
||||||
|
router := httprouter.New()
|
||||||
|
|
||||||
|
fileServer := http.FileServer(http.Dir("ui/static"))
|
||||||
|
|
||||||
|
router.HandlerFunc(http.MethodGet, "/", home)
|
||||||
|
router.HandlerFunc(http.MethodGet, "/ws", ws)
|
||||||
|
router.Handler(http.MethodGet, "/static/", http.StripPrefix("/static", fileServer))
|
||||||
|
router.HandlerFunc(http.MethodGet, "/v1/healthcheck", app.healthcheckHandler)
|
||||||
|
// router.HandlerFunc(http.MethodPost, "/v1/movies", app.createMovieHandler)
|
||||||
|
// router.HandlerFunc(http.MethodGet, "/v1/movies/:id", app.showMovieHandler)
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
||||||
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.24.2
|
|||||||
require (
|
require (
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
github.com/jackc/pgx/v5 v5.7.6
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -11,6 +11,8 @@ github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
|||||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|||||||
@ -1,38 +1,38 @@
|
|||||||
{{define "base"}}
|
{{define "base"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>{{template "title" .}}</title>
|
<title>{{template "title" .}}</title>
|
||||||
<script>
|
<script>
|
||||||
const ws = new WebSocket("wss://localhost:8443/ws");
|
const ws = new WebSocket("wss://localhost:8443/ws");
|
||||||
|
|
||||||
ws.onopen = () => console.log("Connected")
|
ws.onopen = () => console.log("Connected")
|
||||||
ws.onmessage = (event) => console.log(event.data)
|
ws.onmessage = (event) => console.log(event.data)
|
||||||
ws.onclose = () => console.log("Closed")
|
ws.onclose = () => console.log("Closed")
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
const message = {
|
const message = {
|
||||||
type: "ping",
|
type: "ping",
|
||||||
timestamp: Date(),
|
timestamp: Date(),
|
||||||
random: Math.random()
|
random: Math.random()
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.send(JSON.stringify(message))
|
ws.send(JSON.stringify(message))
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000)
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Alfa+Slab+One&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Alfa+Slab+One&display=swap');
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="/static/style.css"/>
|
<link rel="stylesheet" href="/static/style.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{template "body" .}}
|
{{template "body" .}}
|
||||||
|
|
||||||
<h1>Hello, {{.Name}}!</h1>
|
<h1>Hello, {{.Name}}!</h1>
|
||||||
<h1>This is THE PARTY.</h1>
|
<h1>This is THE PARTY.</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{{template "base" .}}
|
{{template "base" .}}
|
||||||
|
|
||||||
{{define "title"}}Home{{end}}
|
{{define "title"}}Home{{end}}
|
||||||
|
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<h1>The Party?</h1>
|
<h1>The Party?</h1>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user