package main import ( "encoding/json" "errors" "fmt" nurl "net/url" "strings" "time" "github.com/lithammer/shortuuid" "github.com/prologic/bitcask" ) // URL ... type URL struct { ID string URL string Name string CreatedAt time.Time UpdatedAt time.Time } func (env *Env) GenerateID() string { for { id := shortuuid.New() if !env.db.Has([]byte(id)) { return id } } } func (url *URL) save(db *bitcask.Bitcask) (err error) { if url.ID == "" { return errors.New("no URL ID specified") } data, err := json.Marshal(url) if err != nil { return } err = db.Put([]byte(url.ID), data) return } func (env *Env) NewURL(target string) (url *URL, err error) { u, err := parse(target) if err != nil { return } url = &URL{ID: env.GenerateID(), URL: u.String(), CreatedAt: time.Now()} err = url.save(env.db) return } func parse(target string) (u *nurl.URL, err error) { u, err = nurl.Parse(strings.TrimSpace(target)) if err != nil { return nil, fmt.Errorf("URL (%s) no satisfied", target) } if u.Scheme == "" || u.Host == "" { return nil, fmt.Errorf("URL (%s) without scheme or host", target) } return u, nil } // SetName ... func (u *URL) SetName(db *bitcask.Bitcask, name string) error { u.Name = name return db.Put([]byte(u.ID), []byte(u.Name)) } func (u *URL) update(db *bitcask.Bitcask, target string) error { url, err := parse(target) if err != nil { return err } if err := del(db, u.ID); err != nil { return err } u.URL = url.String() u.UpdatedAt = time.Now() return u.save(db) } func del(db *bitcask.Bitcask, id string) error { return db.Delete([]byte(id)) } func get(db *bitcask.Bitcask, id string) (u URL, err error) { val, err := db.Get([]byte(id)) if err != nil { return } err = json.Unmarshal(val, &u) return }