Skip to content

Instantly share code, notes, and snippets.

@olivernadj
Created April 21, 2019 06:57
Show Gist options
  • Save olivernadj/59e6b397033b2acf639e97d5b826007c to your computer and use it in GitHub Desktop.
Save olivernadj/59e6b397033b2acf639e97d5b826007c to your computer and use it in GitHub Desktop.
URL Shortener - Goland assignment
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