// // tank // // Import and Playlist Daemon for autoradio project // // // Copyright (C) 2017 Christian Pointner <equinox@helsinki.at> // // This file is part of tank. // // tank is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // tank is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with tank. If not, see <http://www.gnu.org/licenses/>. // package v1 import ( "encoding/json" "fmt" "net/http" "github.com/gorilla/mux" "gitlab.servus.at/autoradio/tank/importer" "gitlab.servus.at/autoradio/tank/store" ) var ( apiListing = APIListing{make(map[string]*APIEndpoint)} ) // common func sendWebResponse(w http.ResponseWriter, status int, respdata interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(respdata) // TODO: Error Handling? } func notFound(w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotFound, ErrorResponse{"not found"}) } func methodNotAllowed(w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusMethodNotAllowed, ErrorResponse{fmt.Sprintf("method %s is not allowed here", r.Method)}) } func listEndpoints(w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusOK, apiListing) } // Groups func listGroups(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"listing groups not yet implemented"}) } // Imports func listImportsOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"listing imports of group not yet implemented"}) } func createImportForGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"creating imports in group not yet implemented"}) } func readImportOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"reading imports of group not yet implemented"}) } func uploadFileToImportOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"uploading files to imports of group not yet implemented"}) } func deleteImportOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"deleting imports from group not yet implemented"}) } // Files func listFilesOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"listing files of group not yet implemented"}) } func readFileOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"reading file of group not yet implemented"}) } func updateFileOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"updateing file of group not yet implemented"}) } func deleteFileOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"deleting file from group not yet implemented"}) } // Playlists func listPlaylistsOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"listing playlists of group not yet implemented"}) } func createPlaylistForGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"creating playlists in group not yet implemented"}) } func readPlaylistOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"reading playlist of group not yet implemented"}) } func updatePlaylistOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"updateing playlist of group not yet implemented"}) } func deletePlaylistOfGroup(st *store.Store, im *importer.SessionStore, w http.ResponseWriter, r *http.Request) { sendWebResponse(w, http.StatusNotImplemented, ErrorResponse{"deleting playlist from group not yet implemented"}) } type apiHandlerFunc func(*store.Store, *importer.SessionStore, http.ResponseWriter, *http.Request) type apiHandler struct { store *store.Store importer *importer.SessionStore H apiHandlerFunc } func (self apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { self.H(self.store, self.importer, w, r) } func InstallHandler(r *mux.Router, st *store.Store, im *importer.SessionStore) { r.NotFoundHandler = http.HandlerFunc(notFound) r.MethodNotAllowedHandler = http.HandlerFunc(methodNotAllowed) // Groups r.Handle("/groups", apiHandler{st, im, listGroups}).Methods("GET") r.HandleFunc("/groups", methodNotAllowed) // Imports r.Handle("/groups/{group-id}/imports", apiHandler{st, im, listImportsOfGroup}).Methods("GET") r.Handle("/groups/{group-id}/imports", apiHandler{st, im, createImportForGroup}).Methods("POST") r.HandleFunc("/groups/{group-id}/imports", methodNotAllowed) r.Handle("/groups/{group-id}/imports/{import-id}", apiHandler{st, im, readImportOfGroup}).Methods("GET") r.Handle("/groups/{group-id}/imports/{import-id}", apiHandler{st, im, uploadFileToImportOfGroup}).Methods("PUT") r.Handle("/groups/{group-id}/imports/{import-id}", apiHandler{st, im, deleteImportOfGroup}).Methods("DELETE") r.HandleFunc("/groups/{group-id}/imports/{import-id}", methodNotAllowed) // Files r.Handle("/groups/{group-id}/files", apiHandler{st, im, listFilesOfGroup}).Methods("GET") r.HandleFunc("/groups/{group-id}/files", methodNotAllowed) r.Handle("/groups/{group-id}/files/{file-id}", apiHandler{st, im, readFileOfGroup}).Methods("GET") r.Handle("/groups/{group-id}/files/{file-id}", apiHandler{st, im, updateFileOfGroup}).Methods("PUT") r.Handle("/groups/{group-id}/files/{file-id}", apiHandler{st, im, deleteFileOfGroup}).Methods("DELETE") r.HandleFunc("/groups/{group-id}/files/{file-id}", methodNotAllowed) // Playlists r.Handle("/groups/{group-id}/playlists", apiHandler{st, im, listPlaylistsOfGroup}).Methods("GET") r.Handle("/groups/{group-id}/playlists", apiHandler{st, im, createPlaylistForGroup}).Methods("POST") r.HandleFunc("/groups/{group-id}/playlists", methodNotAllowed) r.Handle("/groups/{group-id}/playlists/{playlist-id}", apiHandler{st, im, readPlaylistOfGroup}).Methods("GET") r.Handle("/groups/{group-id}/playlists/{playlist-id}", apiHandler{st, im, updatePlaylistOfGroup}).Methods("PUT") r.Handle("/groups/{group-id}/playlists/{playlist-id}", apiHandler{st, im, deletePlaylistOfGroup}).Methods("DELETE") r.HandleFunc("/groups/{group-id}/playlists/{playlist-id}", methodNotAllowed) // Index r.HandleFunc("/", listEndpoints).Methods("GET") r.HandleFunc("/", methodNotAllowed) r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { p, err := route.GetPathTemplate() if err != nil { return nil } m, err := route.GetMethods() if err != nil || len(m) == 0 { return err } if e, exists := apiListing.Endpoints[p]; exists { e.Methods = append(e.Methods, m...) } else { apiListing.Endpoints[p] = &APIEndpoint{m} } return nil }) }