package shortener import ( "log" "net/http" "git.xdrm.io/example/aicra/service/auth" "git.xdrm.io/example/aicra/storage" "git.xdrm.io/go/aicra" "git.xdrm.io/go/aicra/api" ) // Service manages the url shortener type Service struct { storage *storage.Client authService *auth.Service } // New returns a bare service func New(storage *storage.Client, auth *auth.Service) *Service { log.Printf("[service.shortener] created") return &Service{ storage: storage, authService: auth, } } // Wire to the aicra server func (svc *Service) Wire(server *aicra.Server) { log.Printf("[service.shortener] wired") server.HandleFunc("GET", "/", svc.redirect) server.HandleFunc("POST", "/", svc.authService.CheckToken(svc.register)) server.HandleFunc("PUT", "/", svc.authService.CheckToken(svc.update)) server.HandleFunc("DELETE", "/", svc.authService.CheckToken(svc.delete)) } // redirect from a tiny url to the long url func (svc *Service) redirect(req api.Request, res *api.Response) { // 1. extract input tinyURL, err := req.Param.GetString("url") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("url") res.Err.Put(err.Error()) return } // 2. check in db if exists longURL := svc.storage.Get(storage.DATA, tinyURL) if longURL == nil { res.Err = api.ErrorNoMatchFound() return } // 3. redirect res.Status = http.StatusPermanentRedirect res.Headers.Set("Location", string(longURL)) res.Err = api.ErrorSuccess() } // register registers a new tiny url to a long one func (svc *Service) register(req api.Request, res *api.Response) { // 1. extract arguments longURL, err := req.Param.GetString("target") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("target") res.Err.Put(err.Error()) return } tinyURL, err := req.Param.GetString("url") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("url") res.Err.Put(err.Error()) return } // 2. fail if already used if svc.storage.Get(storage.DATA, tinyURL) != nil { res.Err = api.ErrorAlreadyExists() res.Err.Put("url") return } // 3. store association if !svc.storage.Set(storage.DATA, tinyURL, longURL) { res.Err = api.ErrorFailure() return } res.Err = api.ErrorSuccess() } // update updates an existing tiny url to a new long one func (svc *Service) update(req api.Request, res *api.Response) { // 1. extract arguments longURL, err := req.Param.GetString("target") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("target") res.Err.Put(err.Error()) return } tinyURL, err := req.Param.GetString("url") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("url") res.Err.Put(err.Error()) return } // 2. fail if not already existing if svc.storage.Get(storage.DATA, tinyURL) == nil { res.Err = api.ErrorNoMatchFound() return } // 3. update association if !svc.storage.Set(storage.DATA, tinyURL, longURL) { res.Err = api.ErrorFailure() return } res.Err = api.ErrorSuccess() } // delete removes a new tiny url func (svc *Service) delete(req api.Request, res *api.Response) { // 1. extract arguments tinyURL, err := req.Param.GetString("url") if err != nil { res.Err = api.ErrorInvalidParam() res.Err.Put("url") res.Err.Put(err.Error()) return } // 2. fail if not already existing if svc.storage.Get(storage.DATA, tinyURL) == nil { res.Err = api.ErrorNoMatchFound() return } // 3. update association if !svc.storage.Del(storage.DATA, tinyURL) { res.Err = api.ErrorFailure() return } res.Err = api.ErrorSuccess() }