mirror of
https://github.com/restic/rest-server.git
synced 2026-09-29 07:21:26 -07:00
server strucutre draft
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
var root string
|
||||||
|
|
||||||
|
func Init(path string) {
|
||||||
|
root = path
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConfigPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Config))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DataPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SnapshotPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Snapshot))
|
||||||
|
}
|
||||||
|
|
||||||
|
func IndexPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Index))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LockPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Lock))
|
||||||
|
}
|
||||||
|
|
||||||
|
func KeyPath(repository string) string {
|
||||||
|
return filepath.Join(root, repository, string(backend.Key))
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/bchapuis/restic-server/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
repo, err := ExtractRepository(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid repository", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := config.ConfigPath(repo)
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
http.Error(w, "404 repository not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
repo, err := ExtractRepository(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid repository", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := config.ConfigPath(repo)
|
||||||
|
if _, err := os.Stat(file); err == nil {
|
||||||
|
bytes, _ := ioutil.ReadFile(file)
|
||||||
|
w.Write(bytes)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
http.Error(w, "404 repository not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
repo, err := ExtractRepository(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid repository", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := config.ConfigPath(repo)
|
||||||
|
if _, err := os.Stat(file); err == nil {
|
||||||
|
http.Error(w, "409 repository already initialized", 409)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
bytes, _ := ioutil.ReadAll(r.Body)
|
||||||
|
ioutil.WriteFile(file, bytes, 0600)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/bchapuis/restic-server/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
repo, err := ExtractRepository(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid repository", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := ExtractID(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid ID", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := filepath.Join(config.DataPath(repo), id)
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
http.Error(w, "404 repository not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
repo, err := ExtractRepository(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid repository", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := ExtractID(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "403 invalid ID", 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file := filepath.Join(config.DataPath(repo), id)
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
http.Error(w, "404 repository not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "index")
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "key")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "key")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "key")
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadLock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostLock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteLock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "lock")
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RequestLogger(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%v %v", r.Method, r.URL.String())
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HeadSnapshot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "data")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSnapshot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "snapshot")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostSnapshot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "snapshot")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSnapshot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintln(w, "snapshot")
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExtractUser(r *http.Request) (string, string, error) {
|
||||||
|
return "username", "password", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtractRepository(r *http.Request) (string, error) {
|
||||||
|
return "repository", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtractID(r *http.Request) (backend.ID, error) {
|
||||||
|
path := strings.Split(r.URL.String(), "/")
|
||||||
|
if len(path) != 3 {
|
||||||
|
return backend.ID{}, errors.New("invalid request path")
|
||||||
|
}
|
||||||
|
return backend.ParseID(path[2])
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bchapuis/restic-server/config"
|
||||||
|
"github.com/bchapuis/restic-server/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
method string
|
||||||
|
pattern string
|
||||||
|
handler http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
filters []http.Handler
|
||||||
|
routes []Route
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRouter() Router {
|
||||||
|
filters := []http.Handler{}
|
||||||
|
routes := []Route{}
|
||||||
|
return Router{filters, routes}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router *Router) Filter(handler http.Handler) {
|
||||||
|
router.filters = append(router.filters, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router *Router) FilterFunc(handlerFunc http.HandlerFunc) {
|
||||||
|
router.Filter(handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router *Router) Handle(method string, pattern string, handler http.Handler) {
|
||||||
|
router.routes = append(router.routes, Route{method, pattern, handler})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router *Router) HandleFunc(method string, pattern string, handlerFunc http.HandlerFunc) {
|
||||||
|
router.Handle(method, pattern, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (router Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
for i := 0; i < len(router.filters); i++ {
|
||||||
|
filter := router.filters[i]
|
||||||
|
filter.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(router.routes); i++ {
|
||||||
|
route := router.routes[i]
|
||||||
|
if route.method == r.Method && strings.HasPrefix(r.URL.String(), route.pattern) {
|
||||||
|
route.handler.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
path, _ := ioutil.TempDir("", "restic-repository-")
|
||||||
|
|
||||||
|
config.Init(path)
|
||||||
|
|
||||||
|
router := NewRouter()
|
||||||
|
|
||||||
|
router.FilterFunc(handlers.RequestLogger)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/config", handlers.HeadConfig)
|
||||||
|
router.HandleFunc("GET", "/config", handlers.GetConfig)
|
||||||
|
router.HandleFunc("POST", "/config", handlers.PostConfig)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/data", handlers.HeadData)
|
||||||
|
router.HandleFunc("GET", "/data", handlers.GetData)
|
||||||
|
router.HandleFunc("POST", "/data", handlers.PostData)
|
||||||
|
router.HandleFunc("DELETE", "/data", handlers.DeleteData)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/snapshot", handlers.HeadSnapshot)
|
||||||
|
router.HandleFunc("GET", "/snapshot", handlers.GetSnapshot)
|
||||||
|
router.HandleFunc("POST", "/snapshot", handlers.PostSnapshot)
|
||||||
|
router.HandleFunc("DELETE", "/snapshot", handlers.DeleteSnapshot)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/index", handlers.HeadIndex)
|
||||||
|
router.HandleFunc("GET", "/index", handlers.GetIndex)
|
||||||
|
router.HandleFunc("POST", "/index", handlers.PostIndex)
|
||||||
|
router.HandleFunc("DELETE", "/index", handlers.DeleteIndex)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/lock", handlers.HeadLock)
|
||||||
|
router.HandleFunc("GET", "/lock", handlers.GetLock)
|
||||||
|
router.HandleFunc("POST", "/lock", handlers.PostLock)
|
||||||
|
router.HandleFunc("DELETE", "/lock", handlers.DeleteLock)
|
||||||
|
|
||||||
|
router.HandleFunc("HEAD", "/key", handlers.HeadKey)
|
||||||
|
router.HandleFunc("GET", "/key", handlers.GetKey)
|
||||||
|
router.HandleFunc("POST", "/key", handlers.PostKey)
|
||||||
|
router.HandleFunc("DELETE", "/key", handlers.DeleteKey)
|
||||||
|
|
||||||
|
http.ListenAndServe(":8000", router)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user