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.
bog/server/bog.go

164 lines
3.6 KiB
Go

package server
import (
"caj-larsson/bog/util"
"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"
"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)
}