Skip to content

Commit

Permalink
Add UI
Browse files Browse the repository at this point in the history
  • Loading branch information
matbur committed Nov 22, 2024
1 parent 1c5011c commit a24c1e5
Show file tree
Hide file tree
Showing 10 changed files with 519 additions and 65 deletions.
52 changes: 52 additions & 0 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
cmd = "make build-local"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = ["templates/templates_templ.go"]
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "templ"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = true

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
silent = false
time = false

[misc]
clean_on_exit = false

[proxy]
app_port = 0
enabled = false
proxy_port = 0

[screen]
clear_on_rebuild = false
keep_scroll = true
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,13 @@ logs:
docker compose logs -f

test:
go test ./...
go test ./...

goimports:
goimports -w -local $(cat go.mod | grep "^module " | cut -d' ' -f 2) .

templ:
templ generate

build-local: templ goimports
go build -o ./tmp/main ./cmd/image-text
7 changes: 3 additions & 4 deletions cmd/image-text/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ func main() {
func mode1(addr string) {
slog.Info("Starting server", "addr", addr)

http.HandleFunc("/favicon.ico", server.HandleFavicon)
http.HandleFunc("/healthz", server.HandleHealthz)
http.HandleFunc("/", server.HandleMain())
if err := http.ListenAndServe(addr, nil); err != nil {
srv := server.NewServer()

if err := http.ListenAndServe(addr, srv); err != nil {
if errors.Is(err, http.ErrServerClosed) {
slog.Info("Server closed")
return
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
module github.com/matbur/image-text

go 1.16
go 1.21

toolchain go1.23.0

require (
github.com/a-h/templ v0.2.793
github.com/go-chi/chi/v5 v5.1.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/kelseyhightower/envconfig v1.3.0
golang.org/x/image v0.0.0-20191214001246-9130b4cfad52
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY=
github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM=
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
golang.org/x/image v0.0.0-20191214001246-9130b4cfad52 h1:2fktqPPvDiVEEVT/vSTeoUPXfmRxRaGy6GU8jypvEn0=
Expand Down
4 changes: 4 additions & 0 deletions image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func New(size, background, foreground, text string) (*Image, error) {

rgba := image.NewRGBA(image.Rect(0, 0, width, height))

if text == "" {
text = size
}

return &Image{
Width: width,
Height: height,
Expand Down
46 changes: 0 additions & 46 deletions server/interceptors.go

This file was deleted.

118 changes: 105 additions & 13 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,116 @@
package server

import (
"bytes"
"encoding/base64"
"encoding/json"
"io"
"log/slog"
"net/http"
"net/url"
"time"

"github.com/a-h/templ"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"

"github.com/matbur/image-text/image"
"github.com/matbur/image-text/resources"
"github.com/matbur/image-text/templates"
)

func HandleMain() http.HandlerFunc {
return chain(
dumpReq,
checkMethod(http.MethodGet),
)(handle)
func NewServer() chi.Router {
r := chi.NewRouter()

r.Use(middleware.Logger)
r.Use(middleware.Recoverer)

r.Get("/", handleMain)
r.Post("/post", handlePost)
r.Get("/favicon.ico", handleFavicon)
r.Get("/docs", handleDocs)
r.Get("/*", handle)

return r
}

func handleMain(w http.ResponseWriter, r *http.Request) {
params := templates.IndexPageParams{
Text: r.URL.Query().Get("text"),
BgColor: r.URL.Query().Get("bg_color"),
FgColor: r.URL.Query().Get("fg_color"),
Size: r.URL.Query().Get("size"),
}

img, err := image.New(params.Size, params.BgColor, params.FgColor, params.Text)
if err != nil {
slog.Error("Failed to create image", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

buf := bytes.Buffer{}
if err := img.Draw(&buf); err != nil {
slog.Error("Failed to draw image", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

params.Image = "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())

templ.Handler(templates.IndexPage(params)).ServeHTTP(w, r)
}

func handlePost(w http.ResponseWriter, r *http.Request) {
bb, err := io.ReadAll(r.Body)
if err != nil {
slog.Error("Failed to read body", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

if err := r.Body.Close(); err != nil {
slog.Error("Failed to close body", "err", err)
}

var params templates.IndexPageParams
if err := json.Unmarshal(bb, &params); err != nil {
slog.Error("Failed to unmarshal body", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

slog.Debug("Request to post", "path", r.URL.Path, "body", string(bb))

q := url.Values{}
q.Set("text", params.Text)
q.Set("bg_color", params.BgColor)
q.Set("fg_color", params.FgColor)
q.Set("size", params.Size)

u := url.URL{
Path: "/",
RawQuery: q.Encode(),
}

img, err := image.New(params.Size, params.BgColor, params.FgColor, params.Text)
if err != nil {
slog.Error("Failed to create image", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

buf := bytes.Buffer{}
if err := img.Draw(&buf); err != nil {
slog.Error("Failed to draw image", "err", err)
writeJSON(w, "Internal Server Error", http.StatusInternalServerError)
return
}

params.Image = "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())

w.Header().Set("HX-Push-Url", u.String())
templ.Handler(templates.IndexPage(params)).ServeHTTP(w, r)
}

func handle(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -55,7 +151,7 @@ func handle(w http.ResponseWriter, r *http.Request) {
).Info("Response")
}

func HandleFavicon(w http.ResponseWriter, r *http.Request) {
func handleFavicon(w http.ResponseWriter, r *http.Request) {
bb, err := resources.Static.ReadFile("favicon.png")
if err != nil {
slog.Error("Failed to load favicon", "err", err)
Expand All @@ -64,6 +160,7 @@ func HandleFavicon(w http.ResponseWriter, r *http.Request) {
}
if _, err := w.Write(bb); err != nil {
slog.Error("Failed to write favicon", "err", err)
return
}
}

Expand All @@ -75,8 +172,8 @@ var docs = struct {
}{
Path: "HOST/size/background/foreground?text=rendered+text",
Examples: map[string]string{
"with_names": "http://localhost:8021/hd720/steel_blue/yellow?text=rendered+text",
"with_codes": "http://localhost:8021/320x200/000/FFFF00",
"with_names": "/hd720/steel_blue/yellow?text=rendered+text",
"with_codes": "/320x200/000/FFFF00",
},
Colors: image.Colors,
Sizes: image.Sizes,
Expand All @@ -94,8 +191,3 @@ func handleDocs(w http.ResponseWriter, r *http.Request) {
slog.Error("Failed to write docs", "err", err)
}
}

func HandleHealthz(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
w.WriteHeader(http.StatusOK)
}
Loading

0 comments on commit a24c1e5

Please sign in to comment.