containerized the base application and connected it to the database. Example env file and build script included. To run, copy the env file to .env and enter a password.
This commit is contained in:
parent
27e964549f
commit
f0d486fd6c
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,3 +21,4 @@
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
.env
|
||||
|
34
Dockerfile
Normal file
34
Dockerfile
Normal file
@ -0,0 +1,34 @@
|
||||
FROM golang:1.22-alpine AS build
|
||||
|
||||
# Set destination for COPY of gui files
|
||||
WORKDIR /src
|
||||
|
||||
# Download Go modules
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy the source code. Note the slash at the end, as explained in
|
||||
# https://docs.docker.com/reference/dockerfile/#copy
|
||||
# COPY *.go ./
|
||||
|
||||
# RUN CGO_ENABLED=0 GOOS=linux go build -o /adonis
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o adonis .
|
||||
|
||||
FROM alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /src/adonis .
|
||||
COPY --from=build /src/static ./static
|
||||
|
||||
# Build
|
||||
# Optional:
|
||||
# To bind to a TCP port, runtime parameters must be supplied to the docker command.
|
||||
# But we can document in the Dockerfile what ports
|
||||
# the application is going to listen on by default.
|
||||
# https://docs.docker.com/reference/dockerfile/#expose
|
||||
EXPOSE 80
|
||||
|
||||
# Run
|
||||
ENTRYPOINT ["/app/adonis"]
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Keegan Deppe
|
||||
Copyright (c) 2025 Keegan Deppe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
4
build.sh
Executable file
4
build.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
# ensures correct tag is applied
|
||||
docker build . -t adonis
|
@ -1,13 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.keegandeppe.com/kdeppe/adonis/internal/crypto"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("adonis")
|
||||
crypto.test()
|
||||
os.Exit(0)
|
||||
}
|
27
docker-compose.yml
Normal file
27
docker-compose.yml
Normal file
@ -0,0 +1,27 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
environment:
|
||||
# REQUIRED
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- db
|
||||
adonis:
|
||||
image: adonis:latest
|
||||
ports:
|
||||
- "42069:80"
|
||||
env_file: ".env"
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- db
|
||||
|
||||
networks:
|
||||
db:
|
||||
|
||||
volumes:
|
||||
db_data:
|
6
env
Normal file
6
env
Normal file
@ -0,0 +1,6 @@
|
||||
GO_VERSION="1.22.1"
|
||||
|
||||
POSTGRES_USER="adonis"
|
||||
POSTGRES_PASSWORD=""
|
||||
POSTGRES_DB="adonis"
|
||||
POSTGRES_HOSTNAME="postgres"
|
17
go.mod
17
go.mod
@ -1,3 +1,16 @@
|
||||
module git.keegandeppe.com/kdeppe/adonis-backend
|
||||
module git.keegandeppe.com/kdeppe/adonis
|
||||
|
||||
go 1.22.1
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/jackc/pgx/v5 v5.7.2
|
||||
golang.org/x/crypto v0.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
)
|
||||
|
28
go.sum
Normal file
28
go.sum
Normal file
@ -0,0 +1,28 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
|
||||
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
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/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=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -1,11 +1,23 @@
|
||||
package crypto
|
||||
|
||||
import "crypto/bcrypt"
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func Test() {
|
||||
|
||||
hash("test")
|
||||
hash("test")
|
||||
hash("test1")
|
||||
}
|
||||
|
||||
func hash(pwd string) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
|
||||
|
||||
func test() {
|
||||
hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(hash))
|
||||
|
||||
fmt.Printf("Password hash: %x\n", hash)
|
||||
}
|
||||
|
44
internal/db/db.go
Normal file
44
internal/db/db.go
Normal file
@ -0,0 +1,44 @@
|
||||
// package db serves as a database wrapper for adonis
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
conn *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewDatabase(username, password, hostname, database string) *Database {
|
||||
|
||||
// pool ensures thread safety
|
||||
url := url(username, password, hostname, database)
|
||||
dbpool, err := pgxpool.New(context.Background(), url)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to create connection pool: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
var greeting string
|
||||
err = dbpool.QueryRow(context.Background(), "select 'Hello, world!'").Scan(&greeting)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(greeting)
|
||||
|
||||
return &Database{conn: dbpool}
|
||||
}
|
||||
|
||||
// this function assumes default port because i cant be bothered
|
||||
func url(username, password, hostname, database string) string {
|
||||
// generate url based on passed params
|
||||
// safe to disable SSL as comms occur over docker network
|
||||
return fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable",
|
||||
username, password, hostname, database)
|
||||
}
|
56
main.go
Normal file
56
main.go
Normal file
@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
db "git.keegandeppe.com/kdeppe/adonis/internal/db"
|
||||
)
|
||||
|
||||
type Todo struct {
|
||||
Title string
|
||||
Done bool
|
||||
}
|
||||
|
||||
type TodoPageData struct {
|
||||
PageTitle string
|
||||
Todos []Todo
|
||||
}
|
||||
|
||||
func main() {
|
||||
base := template.Must(template.ParseFiles("static/index.html"))
|
||||
tmpl := template.Must(template.ParseFiles("static/layout.html"))
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
base.Execute(w, nil)
|
||||
})
|
||||
http.HandleFunc("/htmx.min.js", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "static/js/htmx.min.js")
|
||||
})
|
||||
|
||||
http.HandleFunc("/gettasks", func(w http.ResponseWriter, r *http.Request) {
|
||||
data := TodoPageData{
|
||||
PageTitle: "My TODO list",
|
||||
Todos: []Todo{
|
||||
{Title: "test", Done: false},
|
||||
},
|
||||
}
|
||||
tmpl.Execute(w, data)
|
||||
})
|
||||
|
||||
// setup database connection based on env vars
|
||||
username := os.Getenv("POSTGRES_USER")
|
||||
password := os.Getenv("POSTGRES_PASSWORD")
|
||||
database := os.Getenv("POSTGRES_DB")
|
||||
hostname := os.Getenv("POSTGRES_HOSTNAME")
|
||||
|
||||
db.NewDatabase(username, password, hostname, database)
|
||||
|
||||
// attach webserver
|
||||
log.Fatal(http.ListenAndServe(":80", nil))
|
||||
|
||||
// crypto.Test()
|
||||
// os.Exit(0)
|
||||
|
||||
}
|
4
static/index.html
Normal file
4
static/index.html
Normal file
@ -0,0 +1,4 @@
|
||||
<script src="htmx.min.js"></script>
|
||||
|
||||
<button hx-get="/gettasks" hx-target="#todo">Get Todos</button>
|
||||
<div id="todo"></div>
|
1
static/js/htmx.min.js
vendored
Normal file
1
static/js/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
static/layout.html
Normal file
15
static/layout.html
Normal file
@ -0,0 +1,15 @@
|
||||
<h1>{{.PageTitle}}</h1>
|
||||
<ul>
|
||||
{{range .Todos}}
|
||||
{{if .Done}}
|
||||
<li class="done">{{.Title}}</li>
|
||||
{{else}}
|
||||
<li class="notdone">{{.Title}}</li>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
.done {color: green}
|
||||
.notdone {color: red}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user