You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
3.6 KiB
Go
164 lines
3.6 KiB
Go
package server
|
|
|
|
import (
|
|
"caj-larsson/bog/dataswamp"
|
|
"caj-larsson/bog/dataswamp/namespace"
|
|
"caj-larsson/bog/dataswamp/swampfile"
|
|
fs_swampfile "caj-larsson/bog/infrastructure/fs/swampfile"
|
|
sql_namespace "caj-larsson/bog/infrastructure/sqlite/namespace"
|
|
"caj-larsson/bog/infrastructure/system_time"
|
|
"caj-larsson/bog/util"
|
|
"net/http"
|
|
"strconv"
|
|
"text/template"
|
|
"time"
|
|
)
|
|
|
|
type Router interface {
|
|
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
|
ServeHTTP(http.ResponseWriter, *http.Request)
|
|
}
|
|
|
|
type Bog struct {
|
|
router Router
|
|
adminRouter Router
|
|
file_service dataswamp.SwampFileService
|
|
address string
|
|
adminAddress string
|
|
logger util.Logger
|
|
}
|
|
|
|
func buildFileDataRepository(config FileConfig) swampfile.Repository {
|
|
r, err := fs_swampfile.NewRepository(config.Path)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func buildNamespaceRepository(config DatabaseConfig) namespace.Repository {
|
|
if config.Backend != "sqlite" {
|
|
panic("Can only handle sqlite")
|
|
}
|
|
return sql_namespace.NewRepository(config.Connection)
|
|
}
|
|
|
|
func (b *Bog) fileHandler(w http.ResponseWriter, r *http.Request) {
|
|
ref := swampfile.FileReference{r.URL.Path, r.Header["User-Agent"][0]}
|
|
|
|
if r.URL.Path == "/" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
switch r.Method {
|
|
case "GET":
|
|
swamp_file, err := b.file_service.OpenOutFile(ref)
|
|
|
|
if err == swampfile.ErrNotExists {
|
|
templ, err := template.ParseFiles("server/views/upload.html")
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
w.WriteHeader(404)
|
|
err = templ.Execute(w, nil)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
b.logger.Info("Serving file '%s' of size %d from '%s'", ref.Path, swamp_file.Size(), ref.UserAgent)
|
|
w.Header().Set("Content-Disposition", "attachment")
|
|
http.ServeContent(w, r, swamp_file.Path(), swamp_file.Modified(), swamp_file)
|
|
case "POST":
|
|
fallthrough
|
|
case "PUT":
|
|
size_str := r.Header["Content-Length"][0]
|
|
|
|
size, err := strconv.ParseInt(size_str, 10, 64)
|
|
if err != nil {
|
|
w.WriteHeader(422)
|
|
return
|
|
}
|
|
|
|
b.logger.Info("Recieving file '%s' of size %d from '%s'", ref.Path, size, ref.UserAgent)
|
|
err = b.file_service.SaveFile(ref, r.Body, size)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *Bog) dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
|
templ, err := template.ParseFiles("server/views/dashboard.html")
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
stats := b.file_service.NamespaceStats()
|
|
err = templ.Execute(w, stats)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (b *Bog) routes() {
|
|
b.router.HandleFunc("/", b.fileHandler)
|
|
b.adminRouter.HandleFunc("/", b.dashboardHandler)
|
|
}
|
|
|
|
func (b *Bog) cleanNamespaces() {
|
|
for true {
|
|
b.file_service.CleanUpExpiredFiles()
|
|
time.Sleep(time.Minute * 10)
|
|
}
|
|
}
|
|
|
|
func New(config *Configuration) *Bog {
|
|
b := new(Bog)
|
|
b.address = config.Server.bindAddress()
|
|
b.adminAddress = config.Admin.bindAddress()
|
|
|
|
fsSwampRepo := buildFileDataRepository(config.File)
|
|
nsRepo := buildNamespaceRepository(config.Database)
|
|
|
|
logger := ServerLogger{Debug}
|
|
ns_svc := namespace.NewNamespaceService(
|
|
nsRepo,
|
|
logger,
|
|
system_time.Clock{},
|
|
config.Quota.ParsedDuration(),
|
|
config.Quota.ParsedSizeBytes(),
|
|
)
|
|
|
|
b.file_service = *dataswamp.NewSwampFileService(
|
|
*ns_svc,
|
|
fsSwampRepo,
|
|
logger,
|
|
)
|
|
b.logger = logger
|
|
b.router = new(http.ServeMux)
|
|
b.adminRouter = new(http.ServeMux)
|
|
b.routes()
|
|
return b
|
|
}
|
|
|
|
func (b *Bog) Run() {
|
|
b.logger.Info("Starting bog on address: %s", b.address)
|
|
go b.cleanNamespaces()
|
|
go func() { http.ListenAndServe(b.adminAddress, b.adminRouter) }()
|
|
http.ListenAndServe(b.address, b.router)
|
|
}
|