Created
April 21, 2019 06:57
-
-
Save olivernadj/59e6b397033b2acf639e97d5b826007c to your computer and use it in GitHub Desktop.
URL Shortener - Goland assignment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"gopkg.in/yaml.v2" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"os" | |
"strconv" | |
) | |
type Redirect struct { | |
Slug string `yaml:"slug"` | |
Link string `yaml:"link"` | |
} | |
type Config struct { | |
Redirects [] Redirect `yaml:"redirects"` | |
} | |
func main() { | |
slug := flag.String("a", "", "The short link. Must be unique.") | |
link := flag.String("u", "", "The URI of the deep link.") | |
list := flag.Bool("l", false, "List redirections.") | |
help := flag.Bool("h", false, "Print usage info.") | |
run := flag.Bool("r", false, "Start HTTP server.") | |
port := flag.Int64("p", 8080, "The port to listen on for HTTP requests.") | |
flag.Usage = func() { | |
fmt.Fprintf(os.Stderr, "Usage: %s Options are:\n ", os.Args) | |
flag.PrintDefaults() | |
} | |
flag.Parse() | |
if *help == true { | |
flag.Usage() | |
} | |
if *slug != "" && *link != "" { | |
addConfig(*slug, *link) | |
} | |
if *list { | |
c, err := loadConfig() | |
check(err) | |
for i, r := range (*c).Redirects { | |
fmt.Println(i, r.Slug, r.Link) | |
} | |
} | |
if *run { | |
runServer(*port) | |
} | |
} | |
func check(err error) { | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "Error: %v\n", err) | |
os.Exit(1) | |
} | |
} | |
func runServer(port int64) { | |
log.Printf("Server started on %v port", strconv.FormatInt(port, 10)) | |
c, err := loadConfig() | |
check(err) | |
h := func (w http.ResponseWriter, r *http.Request) { | |
slug := r.URL.Path[1:] | |
i := find((*c).Redirects, slug) | |
if i < len((*c).Redirects) { | |
http.Redirect(w, r, (*c).Redirects[i].Link, 307) | |
} else { | |
fmt.Fprintf(w, "No redirection found for '%s'!", r.URL.Path[1:]) | |
} | |
} | |
http.HandleFunc("/", h) | |
log.Fatal(http.ListenAndServe(":" + strconv.FormatInt(port, 10), nil)) | |
} | |
func find(rs []Redirect, s string) int { | |
for i, r := range rs { | |
if r.Slug == s { | |
return i | |
} | |
} | |
return len(rs) | |
} | |
func addConfig(slug string, link string) { | |
c, err := loadConfig() | |
check(err) | |
i := find((*c).Redirects, slug) | |
if i < len((*c).Redirects) { | |
(*c).Redirects[i] = Redirect { | |
slug, | |
link, | |
} | |
} else { | |
(*c).Redirects = append((*c).Redirects, Redirect{ | |
slug, | |
link, | |
}) | |
} | |
err = c.saveConfig() | |
check(err) | |
} | |
func loadConfig() (*Config, error) { | |
c :=Config{} | |
cYaml, err := ioutil.ReadFile("config.yaml") | |
if err != nil { | |
return &c, err | |
} | |
err = yaml.Unmarshal(cYaml, &c) | |
return &c, err | |
} | |
func (c *Config) saveConfig() error { | |
cYaml, err := yaml.Marshal(c) | |
if err != nil { | |
return err | |
} | |
err = ioutil.WriteFile("config.yaml", cYaml, 0664) | |
return err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment