main.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/binary"
  6. "encoding/json"
  7. "flag"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "log"
  12. "math/rand"
  13. "net/http"
  14. "os"
  15. "path/filepath"
  16. "strings"
  17. "time"
  18. "github.com/syndtr/goleveldb/leveldb"
  19. )
  20. const (
  21. dbFilename = "keys.db"
  22. )
  23. type Route struct {
  24. Url string
  25. Time time.Time
  26. }
  27. func (r *Route) Write(w io.Writer) error {
  28. if err := binary.Write(w, binary.LittleEndian, r.Time.UnixNano()); err != nil {
  29. return err
  30. }
  31. if _, err := w.Write([]byte(r.Url)); err != nil {
  32. return err
  33. }
  34. return nil
  35. }
  36. func (o *Route) Read(r io.Reader) error {
  37. var t int64
  38. if err := binary.Read(r, binary.LittleEndian, &t); err != nil {
  39. return err
  40. }
  41. b, err := ioutil.ReadAll(r)
  42. if err != nil {
  43. return err
  44. }
  45. o.Url = string(b)
  46. o.Time = time.Unix(0, t)
  47. return nil
  48. }
  49. type Context struct {
  50. path string
  51. }
  52. func (c *Context) Init() error {
  53. if _, err := os.Stat(c.path); err != nil {
  54. if err := os.MkdirAll(c.path, os.ModePerm); err != nil {
  55. return err
  56. }
  57. }
  58. db, err := openDb(c.path)
  59. if err != nil {
  60. return err
  61. }
  62. return db.Close()
  63. }
  64. func openDb(path string) (*leveldb.DB, error) {
  65. return leveldb.OpenFile(filepath.Join(path, dbFilename), nil)
  66. }
  67. func (c *Context) Get(key string) (*Route, error) {
  68. db, err := openDb(c.path)
  69. if err != nil {
  70. return nil, err
  71. }
  72. defer db.Close()
  73. val, err := db.Get([]byte(key), nil)
  74. if err != nil {
  75. return nil, err
  76. }
  77. r := &Route{}
  78. if err := r.Read(bytes.NewBuffer(val)); err != nil {
  79. return nil, err
  80. }
  81. return r, nil
  82. }
  83. func (c *Context) Put(key string, r *Route) error {
  84. db, err := openDb(c.path)
  85. if err != nil {
  86. return err
  87. }
  88. defer db.Close()
  89. var buf bytes.Buffer
  90. if err := r.Write(&buf); err != nil {
  91. return err
  92. }
  93. return db.Put([]byte(key), buf.Bytes(), nil)
  94. }
  95. func MakeName() string {
  96. var buf bytes.Buffer
  97. binary.Write(&buf, binary.LittleEndian, rand.Int63())
  98. return base64.URLEncoding.EncodeToString(buf.Bytes())
  99. }
  100. func ParseName(base, path string) string {
  101. t := path[len(base):]
  102. ix := strings.Index(t, "/")
  103. if ix == -1 {
  104. return t
  105. } else {
  106. return t[:ix]
  107. }
  108. }
  109. func WriteJson(w http.ResponseWriter, data interface{}, status int) {
  110. w.Header().Set("Content-Type", "application/json;charset=utf-8")
  111. if err := json.NewEncoder(w).Encode(data); err != nil {
  112. log.Panic(err)
  113. }
  114. }
  115. func WriteJsonError(w http.ResponseWriter, error string, status int) {
  116. WriteJson(w, map[string]interface{}{
  117. "error": error,
  118. }, status)
  119. }
  120. func WriteJsonRoute(w http.ResponseWriter, name string, rt *Route) {
  121. res := struct {
  122. Name string `json:"name"`
  123. URL string `json:"url"`
  124. Time time.Time `json:"time"`
  125. }{
  126. name,
  127. rt.Url,
  128. rt.Time,
  129. }
  130. WriteJson(w, &res, http.StatusOK)
  131. }
  132. func ServeAsset(w http.ResponseWriter, r *http.Request, name string) {
  133. n, err := AssetInfo(name)
  134. if err != nil {
  135. http.NotFound(w, r)
  136. return
  137. }
  138. a, err := Asset(name)
  139. if err != nil {
  140. http.NotFound(w, r)
  141. return
  142. }
  143. http.ServeContent(w, r, n.Name(), n.ModTime(), bytes.NewReader(a))
  144. }
  145. type DefaultHandler struct {
  146. ctx *Context
  147. }
  148. func (h *DefaultHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  149. p := ParseName("/", r.URL.Path)
  150. if p == "" {
  151. http.Redirect(w, r,
  152. fmt.Sprintf("/edit/%s", MakeName()),
  153. http.StatusTemporaryRedirect)
  154. return
  155. }
  156. rt, err := h.ctx.Get(p)
  157. if err == leveldb.ErrNotFound {
  158. http.Redirect(w, r,
  159. fmt.Sprintf("/edit/%s", p),
  160. http.StatusTemporaryRedirect)
  161. return
  162. } else if err != nil {
  163. log.Panic(err)
  164. }
  165. http.Redirect(w, r,
  166. rt.Url,
  167. http.StatusTemporaryRedirect)
  168. }
  169. type EditHandler struct {
  170. ctx *Context
  171. }
  172. func (h *EditHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  173. p := ParseName("/edit/", r.URL.Path)
  174. if p == "" {
  175. http.Redirect(w, r,
  176. fmt.Sprintf("/edit/%s", MakeName()),
  177. http.StatusTemporaryRedirect)
  178. return
  179. }
  180. ServeAsset(w, r, "index.html")
  181. }
  182. type ApiHandler struct {
  183. ctx *Context
  184. }
  185. func (h *ApiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  186. p := ParseName("/api/url/", r.URL.Path)
  187. if p == "" {
  188. WriteJsonError(w,
  189. http.StatusText(http.StatusNotFound),
  190. http.StatusNotFound)
  191. return
  192. }
  193. if r.Method == "POST" {
  194. var req struct {
  195. URL string `json:"url"`
  196. }
  197. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  198. WriteJsonError(w, "invalid json", http.StatusBadRequest)
  199. return
  200. }
  201. if req.URL == "" {
  202. WriteJsonError(w, "url required", http.StatusBadRequest)
  203. return
  204. }
  205. rt := Route{
  206. Url: req.URL,
  207. Time: time.Now(),
  208. }
  209. if err := h.ctx.Put(p, &rt); err != nil {
  210. log.Panic(err)
  211. }
  212. WriteJsonRoute(w, p, &rt)
  213. } else if r.Method == "GET" {
  214. rt, err := h.ctx.Get(p)
  215. if err == leveldb.ErrNotFound {
  216. WriteJsonError(w, "no such route", http.StatusNotFound)
  217. return
  218. } else if err != nil {
  219. log.Panic(err)
  220. }
  221. WriteJsonRoute(w, p, rt)
  222. } else {
  223. WriteJsonError(w,
  224. http.StatusText(http.StatusMethodNotAllowed),
  225. http.StatusMethodNotAllowed)
  226. }
  227. }
  228. func main() {
  229. flagData := flag.String("data", "data", "data")
  230. flagAddr := flag.String("addr", ":8067", "addr")
  231. flag.Parse()
  232. ctx := &Context{
  233. path: *flagData,
  234. }
  235. if err := ctx.Init(); err != nil {
  236. log.Panic(err)
  237. }
  238. mux := http.NewServeMux()
  239. mux.Handle("/", &DefaultHandler{ctx})
  240. mux.Handle("/edit/", &EditHandler{ctx})
  241. mux.Handle("/api/url/", &ApiHandler{ctx})
  242. mux.HandleFunc("/s/", func(w http.ResponseWriter, r *http.Request) {
  243. ServeAsset(w, r, r.URL.Path[len("/s/"):])
  244. })
  245. log.Panic(http.ListenAndServe(*flagAddr, mux))
  246. }