aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Lasseter <Nathan Lasseter nathan@bytemark.co.uk>2015-09-22 17:22:43 +0100
committerNathan Lasseter <Nathan Lasseter nathan@bytemark.co.uk>2015-09-22 17:22:43 +0100
commita50da4215c88efcdcab1da2835459b64a5b341b4 (patch)
treed99f45ab6416906ac0954e0d3b8f90b860264cbd
Initial Commit
-rw-r--r--.gitignore1
-rw-r--r--LICENCE19
-rw-r--r--README5
-rw-r--r--TODO2
-rw-r--r--cache.go60
-rw-r--r--db.go55
-rw-r--r--files.go23
-rw-r--r--handlers.go91
-rw-r--r--logger.go23
-rw-r--r--main.go13
-rw-r--r--router.go24
-rw-r--r--routes.go39
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
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..6a1adda
--- /dev/null
+++ b/LICENCE
@@ -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.
diff --git a/README b/README
new file mode 100644
index 0000000..51ff7f6
--- /dev/null
+++ b/README
@@ -0,0 +1,5 @@
+The Audiocache Golang server software
+
+1. go get github.com/Audiocache/audiocache-server
+2. go build
+3. ./audiocache
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..523ead7
--- /dev/null
+++ b/TODO
@@ -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
+}
diff --git a/db.go b/db.go
new file mode 100644
index 0000000..a2c1d1e
--- /dev/null
+++ b/db.go
@@ -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),
+ )
+ })
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..3fcb722
--- /dev/null
+++ b/main.go
@@ -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,
+ },
+}