diff --git a/.vscode/launch.json b/.vscode/launch.json index fb58120..bc86fbf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,16 +1,16 @@ -{ - // 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": "${workspaceFolder}/cmd/web" - } - ] +{ + // 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": "${workspaceFolder}/cmd/web" + } + ] } \ No newline at end of file diff --git a/cmd/api/db.go b/cmd/api/db.go index 570fd82..c63ac5a 100644 --- a/cmd/api/db.go +++ b/cmd/api/db.go @@ -1,141 +1,141 @@ -package main - -import ( - "context" - "github.com/jackc/pgx/v5" - "log" -) - -func database_init(conn *pgx.Conn) { - sql := `DROP TABLE IF EXISTS vote; -DROP TABLE IF EXISTS vote_token; -DROP TABLE IF EXISTS option; -DROP TABLE IF EXISTS issue; -DROP TABLE IF EXISTS account;` - - _, err := conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `CREATE TABLE account ( -id BIGINT primary key generated always as identity, -username VARCHAR(50) UNIQUE NOT NULL, -email VARCHAR(255) UNIQUE NOT NULL, -password_hash TEXT NOT NULL, -first_name TEXT not null, -last_name TEXT not null, -created TIMESTAMPTZ DEFAULT now() NOT NULL, -last_login TIMESTAMPTZ -)` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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'); - -INSERT INTO account -(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');` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `CREATE TABLE issue ( -id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -title VARCHAR(255) NOT NULL, -description TEXT, -start_time TIMESTAMPTZ NOT NULL, -end_time TIMESTAMPTZ NOT NULL, -created_at TIMESTAMPTZ NOT NULL DEFAULT now() -)` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `CREATE TABLE option ( -id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE, -label VARCHAR(255) NOT NULL, -created_at TIMESTAMPTZ NOT NULL DEFAULT now() -)` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `CREATE TABLE vote_token ( -id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE, -token UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(), -used BOOLEAN NOT NULL DEFAULT FALSE, -created_at TIMESTAMPTZ NOT NULL DEFAULT now() -)` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - sql = `CREATE TABLE vote ( -id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -token UUID NOT NULL UNIQUE REFERENCES vote_token(token) ON DELETE CASCADE, -option_id BIGINT NOT NULL REFERENCES option(id) ON DELETE CASCADE, -voted_at TIMESTAMPTZ NOT NULL DEFAULT now() -)` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } - - 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_options_issue_id ON option(issue_id);` - - _, err = conn.Exec(context.Background(), sql) - if err != nil { - log.Fatal(err) - } -} +package main + +import ( + "context" + "github.com/jackc/pgx/v5" + "log" +) + +func database_init(conn *pgx.Conn) { + sql := `DROP TABLE IF EXISTS vote; +DROP TABLE IF EXISTS vote_token; +DROP TABLE IF EXISTS option; +DROP TABLE IF EXISTS issue; +DROP TABLE IF EXISTS account;` + + _, err := conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `CREATE TABLE account ( +id BIGINT primary key generated always as identity, +username VARCHAR(50) UNIQUE NOT NULL, +email VARCHAR(255) UNIQUE NOT NULL, +password_hash TEXT NOT NULL, +first_name TEXT not null, +last_name TEXT not null, +created TIMESTAMPTZ DEFAULT now() NOT NULL, +last_login TIMESTAMPTZ +)` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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'); + +INSERT INTO account +(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');` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `CREATE TABLE issue ( +id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, +title VARCHAR(255) NOT NULL, +description TEXT, +start_time TIMESTAMPTZ NOT NULL, +end_time TIMESTAMPTZ NOT NULL, +created_at TIMESTAMPTZ NOT NULL DEFAULT now() +)` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `CREATE TABLE option ( +id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, +issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE, +label VARCHAR(255) NOT NULL, +created_at TIMESTAMPTZ NOT NULL DEFAULT now() +)` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `CREATE TABLE vote_token ( +id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, +issue_id BIGINT NOT NULL REFERENCES issue(id) ON DELETE CASCADE, +token UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(), +used BOOLEAN NOT NULL DEFAULT FALSE, +created_at TIMESTAMPTZ NOT NULL DEFAULT now() +)` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + sql = `CREATE TABLE vote ( +id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, +token UUID NOT NULL UNIQUE REFERENCES vote_token(token) ON DELETE CASCADE, +option_id BIGINT NOT NULL REFERENCES option(id) ON DELETE CASCADE, +voted_at TIMESTAMPTZ NOT NULL DEFAULT now() +)` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } + + 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_options_issue_id ON option(issue_id);` + + _, err = conn.Exec(context.Background(), sql) + if err != nil { + log.Fatal(err) + } +} diff --git a/cmd/api/handlers.go b/cmd/api/handlers.go index 6ef868c..946978d 100644 --- a/cmd/api/handlers.go +++ b/cmd/api/handlers.go @@ -1,92 +1,92 @@ -package main - -import ( - "fmt" - "net/http" - "time" - "log" - "html/template" -) - -func home(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/" { - http.NotFound(w, r) - return - } - - fmt.Println(r.URL.Path) - - ts, err := template.ParseFiles("ui/html/home.page.tmpl", "ui/html/base.layout.tmpl") - if err != nil { - log.Println(err.Error()) - http.Error(w, "Internal Server Error", 500) - return - } - - err = ts.Execute(w, nil) - if err != nil { - log.Println(err.Error()) - http.Error(w, "Internal Server Error", 500) - } - - // data := struct { - // Name string - // }{ - // Name: "Vicente", - // } - // page_template.Execute(w, data) -} - -func ws(w http.ResponseWriter, r *http.Request) { - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - fmt.Println("Upgrade error:", err) - return - } - defer conn.Close() - - done := make(chan struct{}) - - go func() { - ticker := time.NewTicker(1 * time.Second); - - for { - select { - case <-done: - return - case t := <-ticker.C: - msg := map[string]interface{}{ - "type": "server_tick", - "timestamp": t.Format(time.RFC3339), - } - - - if err := conn.WriteJSON(msg); err != nil { - fmt.Println("Write error:", err) - return - } - } - } - }() - - for { - var msg Message - err := conn.ReadJSON(&msg) - if err != nil { - fmt.Println("Read error:", err) - break - } - fmt.Println(msg) - - // Send a response - // response := fmt.Sprintf("Server time: %s", time.Now()) - // if err := conn.WriteMessage(websocket.TextMessage, []byte(response)); err != nil { - // fmt.Println("Write error:", err) - // break - // } - } -} - -func redirectToHTTPS(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "https://localhost:8443" + r.URL.RequestURI(), http.StatusMovedPermanently) -} +package main + +import ( + "fmt" + "net/http" + "time" + "log" + "html/template" +) + +func home(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + + fmt.Println(r.URL.Path) + + ts, err := template.ParseFiles("ui/html/home.page.tmpl", "ui/html/base.layout.tmpl") + if err != nil { + log.Println(err.Error()) + http.Error(w, "Internal Server Error", 500) + return + } + + err = ts.Execute(w, nil) + if err != nil { + log.Println(err.Error()) + http.Error(w, "Internal Server Error", 500) + } + + // data := struct { + // Name string + // }{ + // Name: "Vicente", + // } + // page_template.Execute(w, data) +} + +func ws(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + fmt.Println("Upgrade error:", err) + return + } + defer conn.Close() + + done := make(chan struct{}) + + go func() { + ticker := time.NewTicker(1 * time.Second); + + for { + select { + case <-done: + return + case t := <-ticker.C: + msg := map[string]interface{}{ + "type": "server_tick", + "timestamp": t.Format(time.RFC3339), + } + + + if err := conn.WriteJSON(msg); err != nil { + fmt.Println("Write error:", err) + return + } + } + } + }() + + for { + var msg Message + err := conn.ReadJSON(&msg) + if err != nil { + fmt.Println("Read error:", err) + break + } + fmt.Println(msg) + + // Send a response + // response := fmt.Sprintf("Server time: %s", time.Now()) + // if err := conn.WriteMessage(websocket.TextMessage, []byte(response)); err != nil { + // fmt.Println("Write error:", err) + // break + // } + } +} + +func redirectToHTTPS(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "https://localhost:8443" + r.URL.RequestURI(), http.StatusMovedPermanently) +} diff --git a/cmd/api/main.go b/cmd/api/main.go index 0b519ce..6a8e492 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -1,95 +1,85 @@ -package main - -import ( - "context" - "log" - //"html/template" - "net/http" - "flag" - - "github.com/gorilla/websocket" - - "github.com/jackc/pgx/v5" -) - -import ( - "fmt" - "os" - "time" -) - -const version = "1.0.0" - -type config struct { - port int - env string -} - -type application struct { - config config - logger *log.Logger -} - -type Message struct { - Type string `json:"type"` - Timestamp string `json:"timestamp"` - Random float64 `json:"random"` -} - -//var page_template = template.Must(template.ParseFiles("../../ui/html/index.html")) - -var upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins -} - -func main() { - - - var cfg config - - flag.IntVar(&cfg.port, "port", 4000, "API server port") - flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)") - //addr := flag.String("addr", ":8443", "HTTP network address") - flag.Parse() - - - logger := log.New(os.Stdout, "", log.Ldate | log.Ltime) - - app := &application{ - config: cfg, - logger: logger, - } - - conn, err := pgx.Connect(context.Background(), "postgres://party:iK2SoVbDhdCki5n3LxGyP6zKpLspt4@losandesgames.com:5432/party") - if err != nil { - log.Fatal(err) - } - - defer conn.Close(context.Background()) - - database_init(conn) - - fileServer := http.FileServer(http.Dir("ui/static")) - - mux := http.NewServeMux() - mux.HandleFunc("/", home) - mux.HandleFunc("/ws", ws) - mux.Handle("/static/", http.StripPrefix("/static", fileServer)) - mux.HandleFunc("/v1/healthcheck", app.healthcheckHandler) - - srv := &http.Server{ - Addr: fmt.Sprintf(":%d", cfg.port), - Handler: mux, - IdleTimeout: time.Minute, - 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) - } -} +package main + +import ( + "context" + "log" + //"html/template" + "net/http" + "flag" + + "github.com/gorilla/websocket" + + "github.com/jackc/pgx/v5" +) + +import ( + "fmt" + "os" + "time" +) + +const version = "1.0.0" + +type config struct { + port int + env string +} + +type application struct { + config config + logger *log.Logger +} + +type Message struct { + Type string `json:"type"` + Timestamp string `json:"timestamp"` + Random float64 `json:"random"` +} + +//var page_template = template.Must(template.ParseFiles("../../ui/html/index.html")) + +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins +} + +func main() { + + var cfg config + + flag.IntVar(&cfg.port, "port", 4000, "API server port") + flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)") + //addr := flag.String("addr", ":8443", "HTTP network address") + flag.Parse() + + logger := log.New(os.Stdout, "", log.Ldate | log.Ltime) + + app := &application{ + config: cfg, + logger: logger, + } + + conn, err := pgx.Connect(context.Background(), "postgres://party:iK2SoVbDhdCki5n3LxGyP6zKpLspt4@losandesgames.com:5432/party") + if err != nil { + log.Fatal(err) + } + + defer conn.Close(context.Background()) + + database_init(conn) + + srv := &http.Server{ + Addr: fmt.Sprintf(":%d", cfg.port), + Handler: app.routes(), + IdleTimeout: time.Minute, + 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) + } +} diff --git a/cmd/api/routes.go b/cmd/api/routes.go new file mode 100644 index 0000000..fb7457a --- /dev/null +++ b/cmd/api/routes.go @@ -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 +} diff --git a/go.mod b/go.mod index 1f00497..d13eb6c 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.2 require ( github.com/gorilla/websocket v1.5.3 github.com/jackc/pgx/v5 v5.7.6 + github.com/julienschmidt/httprouter v1.3.0 ) require ( diff --git a/go.sum b/go.sum index ea8a8e3..3a3d815 100644 --- a/go.sum +++ b/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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/ui/html/base.layout.tmpl b/ui/html/base.layout.tmpl index fab842f..668c30f 100644 --- a/ui/html/base.layout.tmpl +++ b/ui/html/base.layout.tmpl @@ -1,38 +1,38 @@ -{{define "base"}} - - -
- -