diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | LICENCE | 19 | ||||
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | cache.go | 60 | ||||
-rw-r--r-- | db.go | 55 | ||||
-rw-r--r-- | files.go | 23 | ||||
-rw-r--r-- | handlers.go | 91 | ||||
-rw-r--r-- | logger.go | 23 | ||||
-rw-r--r-- | main.go | 13 | ||||
-rw-r--r-- | router.go | 24 | ||||
-rw-r--r-- | routes.go | 39 |
12 files changed, 355 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a7359c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +audiocache @@ -0,0 +1,19 @@ +Copyright (c) 2015 Audiocache + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. @@ -0,0 +1,5 @@ +The Audiocache Golang server software + +1. go get github.com/Audiocache/audiocache-server +2. go build +3. ./audiocache @@ -0,0 +1,2 @@ +* Remove things that should be configy to a config file +* Remove mp3 assumption diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..6eed536 --- /dev/null +++ b/cache.go @@ -0,0 +1,60 @@ +package main + +import ( + "time" +) + +var FileRoot string = "http://localhost:8080/files/" + +type APICache struct { + Id uint64 `json:"id"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Created time.Time `json:"created"` + URI string `json:"uri"` +} + +type APICaches []APICache + +type DBCache struct { + Id uint64 + Latitude float64 + Longitude float64 + Created time.Time + Path string +} + +type DBCaches []DBCache + +type PostCache struct { + Latitude float64 + Longitude float64 + Data string +} + +func PathToURI(path string) string { + return FileRoot + path +} + +func DBToAPI(db DBCache) APICache { + var api APICache + + api.Id = db.Id + api.Latitude = db.Latitude + api.Longitude = db.Longitude + api.Created = db.Created + api.URI = PathToURI(db.Path) + + return api +} + +func PostToDB(post PostCache, filename string) DBCache { + var db DBCache + + db.Latitude = post.Latitude + db.Longitude = post.Longitude + db.Created = time.Now() + db.Path = filename + + return db +} @@ -0,0 +1,55 @@ +package main + +import ( + "github.com/jmoiron/sqlx" + _ "github.com/lib/pq" +) + +func getCaches() (DBCaches, error) { + var caches DBCaches + + db, err := sqlx.Connect("postgres", "user=audiocache password=audiocache dbname=audiocache sslmode=disable") + if err != nil { + return caches, err + } + + err = db.Select(&caches, "SELECT * FROM caches ORDER BY id ASC") + if err != nil { + return caches, err + } + + err = db.Close() + return caches, err +} + +func getCache(id uint64) (DBCache, error) { + var cache DBCache + + db, err := sqlx.Connect("postgres", "user=audiocache password=audiocache dbname=audiocache sslmode=disable") + if err != nil { + return cache, err + } + + err = db.Get(&cache, "SELECT * FROM caches WHERE id=$1", id) + if err != nil { + return cache, err + } + + err = db.Close() + return cache, err +} + +func postCache(dbcache DBCache) error { + db, err := sqlx.Connect("postgres", "user=audiocache password=audiocache dbname=audiocache sslmode=disable") + if err != nil { + return err + } + + _, err = db.NamedExec("INSERT INTO caches (latitude, longitude, created, path) VALUES (:latitude, :longitude, :created, :path)", dbcache) + if err != nil { + return err + } + + err = db.Close() + return err +} diff --git a/files.go b/files.go new file mode 100644 index 0000000..f1a3d6c --- /dev/null +++ b/files.go @@ -0,0 +1,23 @@ +package main + +import ( + "encoding/base64" + "io/ioutil" +) + +func writeFile(postcache PostCache, filename string) error { + data := postcache.Data + var binary []byte + + n, err := base64.StdEncoding.Decode(binary, []byte(data)) + if n == 0 || err != nil { + return err + } + + err = ioutil.WriteFile("files/"+filename, binary, 0644) + if err != nil { + return err + } + + return nil +} diff --git a/handlers.go b/handlers.go new file mode 100644 index 0000000..c0ec657 --- /dev/null +++ b/handlers.go @@ -0,0 +1,91 @@ +package main + +import ( + "code.google.com/p/go-uuid/uuid" + "encoding/json" + "fmt" + "github.com/gorilla/mux" + "io" + "io/ioutil" + "net/http" + "strconv" +) + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Welcome!") +} + +func CacheIndex(w http.ResponseWriter, r *http.Request) { + dbcaches, err := getCaches() + if err != nil { + panic(err) + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + + var apicaches APICaches + for db := range dbcaches { + apicaches = append(apicaches, DBToAPI(dbcaches[db])) + } + + if err := json.NewEncoder(w).Encode(apicaches); err != nil { + panic(err) + } +} + +func CacheShow(w http.ResponseWriter, r *http.Request) { + cacheId, err := strconv.ParseUint(mux.Vars(r)["cacheId"], 10, 64) + if err != nil { + panic(err) + } + + cache, err := getCache(cacheId) + if err != nil { + panic(err) + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + + if err := json.NewEncoder(w).Encode(DBToAPI(cache)); err != nil { + panic(err) + } +} + +func CacheCreate(w http.ResponseWriter, r *http.Request) { + var postcache PostCache + + body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576)) + if err != nil { + panic(err) + } + if err := r.Body.Close(); err != nil { + panic(err) + } + if err := json.Unmarshal(body, &postcache); err != nil { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(422) // unprocessable entity + if err := json.NewEncoder(w).Encode(err); err != nil { + panic(err) + } + } + + filename := uuid.New() + ".mp3" + dbcache := PostToDB(postcache, filename) + + err = postCache(dbcache) + if err != nil { + panic(err) + } + + err = writeFile(postcache, filename) + if err != nil { + panic(err) + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusCreated) + + fmt.Fprintln(w, "OK") +} diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..3f002e3 --- /dev/null +++ b/logger.go @@ -0,0 +1,23 @@ +package main + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s\t%s\t%s\t%s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} @@ -0,0 +1,13 @@ +package main + +import ( + "log" + "net/http" +) + +func main() { + + router := NewRouter() + + log.Fatal(http.ListenAndServe(":8080", router)) +} diff --git a/router.go b/router.go new file mode 100644 index 0000000..32caba3 --- /dev/null +++ b/router.go @@ -0,0 +1,24 @@ +package main + +import ( + "net/http" + + "github.com/gorilla/mux" +) + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + + } + return router +} diff --git a/routes.go b/routes.go new file mode 100644 index 0000000..830b0d0 --- /dev/null +++ b/routes.go @@ -0,0 +1,39 @@ +package main + +import "net/http" + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +var routes = Routes{ + Route{ + "Index", + "GET", + "/", + Index, + }, + Route{ + "CacheIndex", + "GET", + "/caches", + CacheIndex, + }, + Route{ + "CacheShow", + "GET", + "/caches/{cacheId}", + CacheShow, + }, + Route{ + "CacheCreate", + "POST", + "/caches", + CacheCreate, + }, +} |