added 404 page and streamlined deployment process
This commit is contained in:
-26
@@ -1,26 +0,0 @@
|
|||||||
# Use a lightweight, official Go image as the base
|
|
||||||
FROM golang:1.21-alpine AS builder
|
|
||||||
|
|
||||||
# Set the working directory inside the image
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy the source code to the working directory
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build the Go application
|
|
||||||
RUN go build -o main .
|
|
||||||
|
|
||||||
# Create a new stage for the production image
|
|
||||||
FROM alpine:latest
|
|
||||||
|
|
||||||
# Copy the built binary from the builder stage
|
|
||||||
COPY --from=builder /app/main /app/
|
|
||||||
|
|
||||||
# Set the working directory
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Expose the port the application will listen on
|
|
||||||
EXPOSE 8888
|
|
||||||
|
|
||||||
# Define the command to run the application
|
|
||||||
CMD ["./main"]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
module joshashton.dev/live
|
|
||||||
|
|
||||||
go 1.23.2
|
|
||||||
|
|
||||||
require github.com/gorilla/mux v1.8.1
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
|
||||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
|
||||||
github.com/spf13/afero v1.11.0 // indirect
|
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
github.com/spf13/viper v1.19.0 // indirect
|
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
|
||||||
golang.org/x/text v0.14.0 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
|
||||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
|
||||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
|
||||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
|
||||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
|
||||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
|
||||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
|
||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
|
||||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
|
||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
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=
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
import Navigation from './components/Navigation';
|
||||||
|
import Splash from './components/Splash';
|
||||||
|
import Footer from './components/Footer';
|
||||||
|
|
||||||
|
export default function Home( {projects} ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Navigation />
|
||||||
|
<Splash primaryText="404" secondaryText="This is not the page you're looking for."/>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
+13
-8
@@ -11,6 +11,7 @@ import Contact from "./Contact";
|
|||||||
import About from "./About";
|
import About from "./About";
|
||||||
import Blog from "./Blog";
|
import Blog from "./Blog";
|
||||||
import Resume from "./Resume";
|
import Resume from "./Resume";
|
||||||
|
import PageNotFound from "./PageNotFound";
|
||||||
|
|
||||||
const root = document.getElementById("root");
|
const root = document.getElementById("root");
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ const projects = [
|
|||||||
backend: "",
|
backend: "",
|
||||||
id: "graph",
|
id: "graph",
|
||||||
name: "Graph",
|
name: "Graph",
|
||||||
description: "Interactive representation of a graph data structure, developed in Java.",
|
description: "Interactive representation of a graph data structure.",
|
||||||
url: "https://github.com/quaxlyqueen/2420-graph-visualizer",
|
url: "https://github.com/quaxlyqueen/2420-graph-visualizer",
|
||||||
img: "/assets/img/graph.png",
|
img: "/assets/img/graph.png",
|
||||||
imgCaption: "A screenshot of my graph data structure visualizer application."
|
imgCaption: "A screenshot of my graph data structure visualizer application."
|
||||||
@@ -53,7 +54,7 @@ const projects = [
|
|||||||
backend: "",
|
backend: "",
|
||||||
id: "dnd",
|
id: "dnd",
|
||||||
name: "D&D",
|
name: "D&D",
|
||||||
description: "A Dungeons and Dragons character builder app, developed in Java.",
|
description: "A Dungeons and Dragons character builder app.",
|
||||||
url: "https://github.com/quaxlyqueen/dnd",
|
url: "https://github.com/quaxlyqueen/dnd",
|
||||||
img: "/assets/img/dnd.png",
|
img: "/assets/img/dnd.png",
|
||||||
imgCaption: "A screenshot of my Dungeons and Dragons character builder application."
|
imgCaption: "A screenshot of my Dungeons and Dragons character builder application."
|
||||||
@@ -63,12 +64,16 @@ const projects = [
|
|||||||
ReactDOM.createRoot(root).render(
|
ReactDOM.createRoot(root).render(
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home projects={projects} />} />
|
<Route exact path="/" element={<Home projects={projects} />} />
|
||||||
<Route path="/projects" element={<Projects projects={projects} />} />
|
<Route exact path="/projects" element={<Projects projects={projects} />} />
|
||||||
<Route path="/contact" element={<Contact />} />
|
<Route exact path="/contact" element={<Contact />} />
|
||||||
<Route path="/about" element={<About />} />
|
<Route exact path="/about" element={<About />} />
|
||||||
<Route path="/blog" element={<Blog />} />
|
<Route exact path="/blog" element={<Blog />} />
|
||||||
<Route path="/resume" element={<Resume />} />
|
<Route exact path="/resume" element={<Resume />} />
|
||||||
|
<Route
|
||||||
|
path="*"
|
||||||
|
element={<PageNotFound />}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
|
|||||||
-114
@@ -1,114 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CONFIG_FILE string
|
|
||||||
var config ConfigStructure
|
|
||||||
|
|
||||||
// Serve a directory to a port.
|
|
||||||
func servePage(router *mux.Router, dest string, path string, port string) {
|
|
||||||
router.PathPrefix(path).Handler(http.FileServer(http.Dir(dest)))
|
|
||||||
|
|
||||||
srv := &http.Server{
|
|
||||||
Addr: "0.0.0.0: " + port,
|
|
||||||
// Good practice to set timeouts to avoid Slowloris attacks.
|
|
||||||
WriteTimeout: time.Second * 15,
|
|
||||||
ReadTimeout: time.Second * 15,
|
|
||||||
IdleTimeout: time.Second * 60,
|
|
||||||
Handler: router, // Pass our instance of gorilla/mux in.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run our server in a goroutine so that it doesn't block.
|
|
||||||
go func() {
|
|
||||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
log.Println("Web server is running on port " + string(port))
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseConfig() {
|
|
||||||
viper.SetConfigType("json")
|
|
||||||
viper.SetConfigFile(CONFIG_FILE)
|
|
||||||
viper.ReadInConfig()
|
|
||||||
|
|
||||||
// TODO: Handle error
|
|
||||||
viper.Unmarshal(&config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCLI() {
|
|
||||||
// Define CLI option, shorthand, default value, and description
|
|
||||||
// TODO: Dynamically obtain default config location from environment variables.
|
|
||||||
pflag.StringP("config", "c", "/home/violet/.config/joshashton.dev/portfolio/live.json", "Configuration file used in initializing my portfolio.")
|
|
||||||
|
|
||||||
pflag.Parse()
|
|
||||||
viper.BindPFlags(pflag.CommandLine)
|
|
||||||
|
|
||||||
// Retrieve CLI argument, either the default value or the user provided value.
|
|
||||||
CONFIG_FILE = viper.GetString("config")
|
|
||||||
}
|
|
||||||
|
|
||||||
func serve() {
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
r := mux.NewRouter()
|
|
||||||
servePage(r, config.WebpageDir, "/", config.WebpagePort)
|
|
||||||
addr := "0.0.0.0:" + config.RouterPort
|
|
||||||
|
|
||||||
srv := &http.Server{
|
|
||||||
Addr: addr,
|
|
||||||
// Good practice to set timeouts to avoid Slowloris attacks.
|
|
||||||
WriteTimeout: time.Second * 15,
|
|
||||||
ReadTimeout: time.Second * 15,
|
|
||||||
IdleTimeout: time.Second * 60,
|
|
||||||
Handler: r, // Pass our instance of gorilla/mux in.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run our server in a goroutine so that it doesn't block.
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
log.Println("Router is running on port ", config.RouterPort)
|
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
|
||||||
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+Shift+C)
|
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
|
|
||||||
// Block until we receive our signal.
|
|
||||||
<-c
|
|
||||||
|
|
||||||
// Create a deadline to wait for.
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(30))
|
|
||||||
defer cancel()
|
|
||||||
// Doesn't block if no connections, but will otherwise wait
|
|
||||||
// until the timeout deadline.
|
|
||||||
srv.Shutdown(ctx)
|
|
||||||
// Optionally, you could run srv.Shutdown in a goroutine and block on
|
|
||||||
// <-ctx.Done() if your application should wait for other services
|
|
||||||
// to finalize based on context cancellation.
|
|
||||||
log.Println("shutting down")
|
|
||||||
wg.Wait()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
parseCLI()
|
|
||||||
parseConfig()
|
|
||||||
serve()
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user