mirror of
https://github.com/4rkal/shortr.git
synced 2024-12-05 00:51:07 +02:00
Compare commits
9 Commits
d1f48ae00e
...
d7f09c07dd
Author | SHA1 | Date | |
---|---|---|---|
|
d7f09c07dd | ||
|
6dbe9aa2ce | ||
21518a691f | |||
|
620306b6ae | ||
b12d275fbf | |||
04dc9ae612 | |||
|
c1fc3dd16e | ||
|
77e78d0373 | ||
|
64dcf4614e |
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
||||
/tmp
|
||||
*.log
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM golang:1.23-alpine AS builder
|
||||
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0 \
|
||||
GOOS=linux \
|
||||
GOARCH=amd64
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go build -o /shortr ./cmd/main.go
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=builder /shortr /shortr
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/shortr"]
|
27
README.md
27
README.md
@ -1,3 +1,28 @@
|
||||
# shortr
|
||||
|
||||
A blazingly fast url shortener, written in go
|
||||
***Blazingly fast*** url shortener, written in go
|
||||
|
||||
## Instaallation
|
||||
The first step is cloning this repo:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/4rkal/shortr && cd shortr
|
||||
```
|
||||
|
||||
Edit the `docker-compose.yml` and set a base url:
|
||||
|
||||
command: ["/shortr", "--url", "YOUR_URL"]
|
||||
|
||||
Change the `YOUR_URL`, to the url where your app served from (eg app.4rkal.com)
|
||||
|
||||
Now you can run the application via docker.
|
||||
|
||||
### Using docker
|
||||
Assuming that you have docker compose installed simply run
|
||||
|
||||
```
|
||||
docker compose up
|
||||
```
|
||||
|
||||
Now the application should be available by vissiting `localhost:8080`
|
||||
|
||||
|
39
cmd/main.go
39
cmd/main.go
@ -1,10 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/4rkal/shortr/models"
|
||||
@ -26,6 +29,14 @@ type StatsFormData struct {
|
||||
|
||||
var linkMap = map[string]*models.Link{}
|
||||
|
||||
var baseurl *string
|
||||
|
||||
func init() {
|
||||
baseurl = flag.String("url", "127.0.0.1:8080", "The url (domain) that the server is running on")
|
||||
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
e := echo.New()
|
||||
|
||||
@ -50,6 +61,10 @@ func RedirectHandler(c echo.Context) error {
|
||||
return c.String(http.StatusNotFound, "Link not found")
|
||||
}
|
||||
|
||||
if !strings.Contains(link.Url, "://") {
|
||||
link.Url = "http://" + link.Url
|
||||
}
|
||||
|
||||
link.Clicks = link.Clicks + 1
|
||||
|
||||
return c.Redirect(http.StatusMovedPermanently, link.Url)
|
||||
@ -80,7 +95,7 @@ func SubmitHandler(c echo.Context) error {
|
||||
|
||||
linkMap[id] = &models.Link{Id: id, Url: data.Url}
|
||||
|
||||
return views.Submission(id).Render(c.Request().Context(), c.Response())
|
||||
return views.Submission(id, *baseurl).Render(c.Request().Context(), c.Response())
|
||||
}
|
||||
|
||||
func StatsHandler(c echo.Context) error {
|
||||
@ -102,8 +117,26 @@ func StatsSubmissionHandler(c echo.Context) error {
|
||||
}
|
||||
|
||||
func isURL(s string) bool {
|
||||
_, err := url.ParseRequestURI(s)
|
||||
return err == nil
|
||||
if !strings.Contains(s, "://") {
|
||||
s = "http://" + s
|
||||
}
|
||||
|
||||
parsedUrl, err := url.ParseRequestURI(s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if parsedUrl.Host == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
domainRegex := `^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$`
|
||||
matched, err := regexp.MatchString(domainRegex, parsedUrl.Host)
|
||||
if err != nil || !matched {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func generateRandomString(length int) string {
|
||||
|
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
shortr:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
restart: unless-stopped
|
||||
command: ["/shortr", "--url", "app.4rkal.com"]
|
@ -7,7 +7,7 @@ templ Index(){
|
||||
<h1>Blazingly fast URL shortener</h1>
|
||||
<p>Shorten URLs and track clicks</p>
|
||||
<form action="/submit" method="post">
|
||||
<input type="url" id="url" name="url" placeholder="Enter URL here...">
|
||||
<input type="text" id="url" name="url" placeholder="Enter URL here...">
|
||||
<button type="submit">Shorten URL</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -41,7 +41,7 @@ func Index() templ.Component {
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"card\"><h1>Blazingly fast URL shortener</h1><p>Shorten URLs and track clicks</p><form action=\"/submit\" method=\"post\"><input type=\"url\" id=\"url\" name=\"url\" placeholder=\"Enter URL here...\"> <button type=\"submit\">Shorten URL</button></form></div>")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"card\"><h1>Blazingly fast URL shortener</h1><p>Shorten URLs and track clicks</p><form action=\"/submit\" method=\"post\"><input type=\"text\" id=\"url\" name=\"url\" placeholder=\"Enter URL here...\"> <button type=\"submit\">Shorten URL</button></form></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package views
|
||||
|
||||
templ Submission(url string){
|
||||
templ Submission(url, baseurl string){
|
||||
|
||||
@Base() {
|
||||
<h1>Your url is: {url}</h1>
|
||||
<h1>Your url is: <code>{baseurl + "/" + url}</code></h1>
|
||||
|
||||
<form action="/stats" method="post">
|
||||
<input type="hidden" id="id" name="id" value={url}>
|
||||
|
@ -8,7 +8,7 @@ package views
|
||||
import "github.com/a-h/templ"
|
||||
import templruntime "github.com/a-h/templ/runtime"
|
||||
|
||||
func Submission(url string) templ.Component {
|
||||
func Submission(url, baseurl string) templ.Component {
|
||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||
@ -41,20 +41,20 @@ func Submission(url string) templ.Component {
|
||||
}()
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h1>Your url is: ")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h1>Your url is: <code>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(url)
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(baseurl + "/" + url)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/submit.templ`, Line: 6, Col: 25}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/submit.templ`, Line: 6, Col: 47}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><form action=\"/stats\" method=\"post\"><input type=\"hidden\" id=\"id\" name=\"id\" value=\"")
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></h1><form action=\"/stats\" method=\"post\"><input type=\"hidden\" id=\"id\" name=\"id\" value=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user