mirror of
https://github.com/jimeh/ozu.io.git
synced 2026-02-19 08:06:39 +00:00
Get basic HTTP server working
This commit is contained in:
12
main.go
12
main.go
@@ -1,12 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/jimeh/ozu.io/shortner"
|
||||
"github.com/jimeh/ozu.io/storage/goleveldbstore"
|
||||
"github.com/jimeh/ozu.io/web"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -14,8 +15,15 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer store.Close()
|
||||
|
||||
shortner := shortner.New(store)
|
||||
router := web.NewRouter(shortner)
|
||||
fmt.Println(router)
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "8080"
|
||||
}
|
||||
|
||||
log.Fatal(fasthttp.ListenAndServe(":"+port, router.HandleRequest))
|
||||
}
|
||||
|
||||
15
web/responses.go
Normal file
15
web/responses.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package web
|
||||
|
||||
//go:generate easyjson -all responses.go
|
||||
|
||||
// ShortenedResponse contains shortened URL info.
|
||||
type ShortenedResponse struct {
|
||||
UID string `json:"uid"`
|
||||
ShortURL string `json:"short_url"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// ErrorResponse contains error info.
|
||||
type ErrorResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
132
web/responses_easyjson.go
Normal file
132
web/responses_easyjson.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// AUTOGENERATED FILE: easyjson marshaller/unmarshallers.
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
jwriter "github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
var _ = json.RawMessage{} // suppress unused package warning
|
||||
|
||||
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(in *jlexer.Lexer, out *ErrorResponse) {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "error":
|
||||
out.Error = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(out *jwriter.Writer, in ErrorResponse) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
if !first {
|
||||
out.RawByte(',')
|
||||
}
|
||||
first = false
|
||||
out.RawString("\"error\":")
|
||||
out.String(string(in.Error))
|
||||
out.RawByte('}')
|
||||
}
|
||||
func (v ErrorResponse) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
func (v ErrorResponse) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ErrorResponse(w, v)
|
||||
}
|
||||
func (v *ErrorResponse) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
func (v *ErrorResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ErrorResponse(l, v)
|
||||
}
|
||||
func easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(in *jlexer.Lexer, out *ShortenedResponse) {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
return
|
||||
}
|
||||
in.Delim('{')
|
||||
for !in.IsDelim('}') {
|
||||
key := in.UnsafeString()
|
||||
in.WantColon()
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
in.WantComma()
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "uid":
|
||||
out.UID = string(in.String())
|
||||
case "short_url":
|
||||
out.ShortURL = string(in.String())
|
||||
case "url":
|
||||
out.URL = string(in.String())
|
||||
default:
|
||||
in.SkipRecursive()
|
||||
}
|
||||
in.WantComma()
|
||||
}
|
||||
in.Delim('}')
|
||||
}
|
||||
func easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(out *jwriter.Writer, in ShortenedResponse) {
|
||||
out.RawByte('{')
|
||||
first := true
|
||||
_ = first
|
||||
if !first {
|
||||
out.RawByte(',')
|
||||
}
|
||||
first = false
|
||||
out.RawString("\"uid\":")
|
||||
out.String(string(in.UID))
|
||||
if !first {
|
||||
out.RawByte(',')
|
||||
}
|
||||
first = false
|
||||
out.RawString("\"short_url\":")
|
||||
out.String(string(in.ShortURL))
|
||||
if !first {
|
||||
out.RawByte(',')
|
||||
}
|
||||
first = false
|
||||
out.RawString("\"url\":")
|
||||
out.String(string(in.URL))
|
||||
out.RawByte('}')
|
||||
}
|
||||
func (v ShortenedResponse) MarshalJSON() ([]byte, error) {
|
||||
w := jwriter.Writer{}
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(&w, v)
|
||||
return w.Buffer.BuildBytes(), w.Error
|
||||
}
|
||||
func (v ShortenedResponse) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
easyjson_559270ae_encode_github_com_jimeh_ozu_io_web_ShortenedResponse(w, v)
|
||||
}
|
||||
func (v *ShortenedResponse) UnmarshalJSON(data []byte) error {
|
||||
r := jlexer.Lexer{Data: data}
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(&r, v)
|
||||
return r.Error()
|
||||
}
|
||||
func (v *ShortenedResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||
easyjson_559270ae_decode_github_com_jimeh_ozu_io_web_ShortenedResponse(l, v)
|
||||
}
|
||||
@@ -1,12 +1,103 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/buaazp/fasthttprouter"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/jimeh/ozu.io/shortner"
|
||||
"github.com/qiangxue/fasthttp-routing"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func NewRouter(shortner *shortner.Shortner) *fasthttprouter.Router {
|
||||
router := fasthttprouter.New()
|
||||
// NewRouter creates a new fasthttprouter.Router with all handlers registered.
|
||||
func NewRouter(shortner *shortner.Shortner) *routing.Router {
|
||||
router := routing.New()
|
||||
handlers := Handlers{shortner}
|
||||
|
||||
router.Get("/", handlers.Index)
|
||||
router.Get("/api/shorten", handlers.Shorten)
|
||||
router.Get("/api/lookup", handlers.Lookup)
|
||||
router.Get("/<uid>", handlers.LookupAndRedirect)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// Handlers handle HTTP requests.
|
||||
type Handlers struct {
|
||||
s *shortner.Shortner
|
||||
}
|
||||
|
||||
// Index handles requests for root.
|
||||
func (h *Handlers) Index(c *routing.Context) error {
|
||||
c.WriteString("Welcome to ozu.io, a shitty URL shortner.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shorten shortens given URL.
|
||||
func (h *Handlers) Shorten(c *routing.Context) error {
|
||||
c.SetContentType("application/json")
|
||||
|
||||
uid, url, err := h.s.Shorten(c.FormValue("url"))
|
||||
if err != nil {
|
||||
c.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
response, _ := json.Marshal(ErrorResponse{err.Error()})
|
||||
c.Write(response)
|
||||
return nil
|
||||
}
|
||||
|
||||
h.respondWithShortened(c, uid, url)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lookup shortened UID.
|
||||
func (h *Handlers) Lookup(c *routing.Context) error {
|
||||
c.SetContentType("application/json")
|
||||
|
||||
uid := c.FormValue("uid")
|
||||
url, err := h.s.Lookup(uid)
|
||||
if err != nil {
|
||||
c.SetStatusCode(fasthttp.StatusNotFound)
|
||||
respBytes, _ := json.Marshal(ErrorResponse{err.Error()})
|
||||
c.Write(respBytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
h.respondWithShortened(c, uid, url)
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupAndRedirect looks up given UID and redirects to it's URL.
|
||||
func (h *Handlers) LookupAndRedirect(c *routing.Context) error {
|
||||
uid := c.Param("uid")
|
||||
url, err := h.s.Lookup([]byte(uid))
|
||||
if err != nil {
|
||||
c.SetStatusCode(fasthttp.StatusNotFound)
|
||||
fmt.Fprint(c, "404 Not Found")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Redirect(string(url), fasthttp.StatusMovedPermanently)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handlers) respondWithShortened(c *routing.Context, uid []byte, url []byte) {
|
||||
c.SetStatusCode(fasthttp.StatusOK)
|
||||
response := ShortenedResponse{
|
||||
UID: string(uid),
|
||||
ShortURL: h.makeShortURL(c, uid),
|
||||
URL: string(url),
|
||||
}
|
||||
respBytes, _ := json.Marshal(response)
|
||||
c.Write(respBytes)
|
||||
}
|
||||
|
||||
func (h *Handlers) makeShortURL(c *routing.Context, uid []byte) string {
|
||||
shortURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: string(c.Host()),
|
||||
Path: "/" + string(uid),
|
||||
}
|
||||
|
||||
return shortURL.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user