mirror of
https://github.com/1f349/jasmine.git
synced 2024-11-21 19:11:34 +00:00
Rewrite to use new internal library
This commit is contained in:
parent
4026a7f237
commit
9b56087ee9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
.idea/
|
.idea/
|
||||||
|
.data/
|
||||||
|
config.json
|
||||||
|
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Jasmine
|
||||||
|
|
||||||
|
A CalDav-based calendar service.
|
||||||
|
|
||||||
|
Built using:
|
||||||
|
- [Tokidoki](https://git.sr.ht/~sircmpwn/tokidoki)
|
||||||
|
- [go-webdav](https://github.com/emersion/go-webdav)
|
62
auth.go
Normal file
62
auth.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package jasmine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextKey int
|
||||||
|
|
||||||
|
var authCtxKey contextKey = 0
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
UserName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContext(ctx context.Context, a *Context) context.Context {
|
||||||
|
return context.WithValue(ctx, authCtxKey, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromContext(ctx context.Context) (*Context, bool) {
|
||||||
|
a, ok := ctx.Value(authCtxKey).(*Context)
|
||||||
|
return a, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProviderMiddleware interface {
|
||||||
|
Middleware(next http.Handler) http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
var authError = errors.New("auth context error")
|
||||||
|
|
||||||
|
type Auth struct{}
|
||||||
|
|
||||||
|
func (u *Auth) Middleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Header.Get("Authorization") == "" {
|
||||||
|
w.Header().Add("WWW-Authenticate", `Basic realm="Please provide a password", charset="UTF-8"`)
|
||||||
|
http.Error(w, "HTTP auth is required", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
username, accessToken, ok := r.BasicAuth()
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Authorization invalid", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: verify accessToken later
|
||||||
|
_ = accessToken
|
||||||
|
|
||||||
|
r = r.WithContext(NewContext(r.Context(), &Context{UserName: username}))
|
||||||
|
r.BasicAuth()
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Auth) CurrentUserPrincipal(ctx context.Context) (string, error) {
|
||||||
|
authCtx, ok := FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return "", authError
|
||||||
|
}
|
||||||
|
return "/" + authCtx.UserName + "/", nil
|
||||||
|
}
|
55
backend.go
55
backend.go
@ -1,55 +0,0 @@
|
|||||||
package jasmine
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/emersion/go-ical"
|
|
||||||
"github.com/emersion/go-webdav/caldav"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Backend struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) CalendarHomeSetPath(ctx context.Context) (string, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) ListCalendars(ctx context.Context) ([]caldav.Calendar, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) GetCalendar(ctx context.Context, path string) (*caldav.Calendar, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) GetCalendarObject(ctx context.Context, path string, req *caldav.CalendarCompRequest) (*caldav.CalendarObject, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) ListCalendarObjects(ctx context.Context, path string, req *caldav.CalendarCompRequest) ([]caldav.CalendarObject, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) QueryCalendarObjects(ctx context.Context, query *caldav.CalendarQuery) ([]caldav.CalendarObject, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) PutCalendarObject(ctx context.Context, path string, calendar *ical.Calendar, opts *caldav.PutCalendarObjectOptions) (loc string, err error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) DeleteCalendarObject(ctx context.Context, path string) error {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Backend) CurrentUserPrincipal(ctx context.Context) (string, error) {
|
|
||||||
//TODO implement me
|
|
||||||
panic("implement me")
|
|
||||||
}
|
|
@ -6,14 +6,17 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"github.com/1f349/jasmine"
|
"github.com/1f349/jasmine"
|
||||||
"github.com/1f349/violet/utils"
|
"github.com/1f349/violet/utils"
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/mrmelon54/exit-reload"
|
"github.com/mrmelon54/exit-reload"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type serveCmd struct{ configPath string }
|
type serveCmd struct {
|
||||||
|
configPath string
|
||||||
|
debugLog bool
|
||||||
|
}
|
||||||
|
|
||||||
func (s *serveCmd) Name() string { return "serve" }
|
func (s *serveCmd) Name() string { return "serve" }
|
||||||
|
|
||||||
@ -21,6 +24,7 @@ func (s *serveCmd) Synopsis() string { return "Serve calendar service" }
|
|||||||
|
|
||||||
func (s *serveCmd) SetFlags(f *flag.FlagSet) {
|
func (s *serveCmd) SetFlags(f *flag.FlagSet) {
|
||||||
f.StringVar(&s.configPath, "conf", "", "/path/to/config.json : path to the config file")
|
f.StringVar(&s.configPath, "conf", "", "/path/to/config.json : path to the config file")
|
||||||
|
f.BoolVar(&s.debugLog, "debug", false, "enable debug logging")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serveCmd) Usage() string {
|
func (s *serveCmd) Usage() string {
|
||||||
@ -30,19 +34,22 @@ func (s *serveCmd) Usage() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...any) subcommands.ExitStatus {
|
func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...any) subcommands.ExitStatus {
|
||||||
log.Println("[Jasmine] Starting...")
|
if s.debugLog {
|
||||||
|
jasmine.Logger.SetLevel(log.DebugLevel)
|
||||||
|
}
|
||||||
|
jasmine.Logger.Info("Starting...")
|
||||||
|
|
||||||
if s.configPath == "" {
|
if s.configPath == "" {
|
||||||
log.Println("[Jasmine] Error: config flag is missing")
|
jasmine.Logger.Error("Config flag is missing")
|
||||||
return subcommands.ExitUsageError
|
return subcommands.ExitUsageError
|
||||||
}
|
}
|
||||||
|
|
||||||
openConf, err := os.Open(s.configPath)
|
openConf, err := os.Open(s.configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Println("[Jasmine] Error: missing config file")
|
jasmine.Logger.Error("Missing config file")
|
||||||
} else {
|
} else {
|
||||||
log.Println("[Jasmine] Error: open config file: ", err)
|
jasmine.Logger.Error("Open config file", "err", err)
|
||||||
}
|
}
|
||||||
return subcommands.ExitFailure
|
return subcommands.ExitFailure
|
||||||
}
|
}
|
||||||
@ -50,13 +57,14 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...any) subcomm
|
|||||||
var config jasmine.Conf
|
var config jasmine.Conf
|
||||||
err = json.NewDecoder(openConf).Decode(&config)
|
err = json.NewDecoder(openConf).Decode(&config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Jasmine] Error: invalid config file: ", err)
|
jasmine.Logger.Error("Invalid config file", "err", err)
|
||||||
return subcommands.ExitFailure
|
return subcommands.ExitFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
configPathAbs, err := filepath.Abs(s.configPath)
|
configPathAbs, err := filepath.Abs(s.configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("[Jasmine] Failed to get absolute config path")
|
jasmine.Logger.Error("Failed to get absolute config path")
|
||||||
|
return subcommands.ExitFailure
|
||||||
}
|
}
|
||||||
wd := filepath.Dir(configPathAbs)
|
wd := filepath.Dir(configPathAbs)
|
||||||
normalLoad(config, wd)
|
normalLoad(config, wd)
|
||||||
@ -65,7 +73,7 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...any) subcomm
|
|||||||
|
|
||||||
func normalLoad(startUp jasmine.Conf, wd string) {
|
func normalLoad(startUp jasmine.Conf, wd string) {
|
||||||
srv := jasmine.NewHttpServer(startUp, wd)
|
srv := jasmine.NewHttpServer(startUp, wd)
|
||||||
log.Printf("[Jasmine] Starting HTTP server on '%s'\n", srv.Addr)
|
jasmine.Logger.Infof("Starting HTTP server on '%s'", srv.Addr)
|
||||||
go utils.RunBackgroundHttp("HTTP", srv)
|
go utils.RunBackgroundHttp("HTTP", srv)
|
||||||
|
|
||||||
exit_reload.ExitReload("Jasmine", func() {}, func() {
|
exit_reload.ExitReload("Jasmine", func() {}, func() {
|
||||||
|
27
go.mod
27
go.mod
@ -3,19 +3,30 @@ module github.com/1f349/jasmine
|
|||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/1f349/mjwt v0.2.5
|
git.sr.ht/~sircmpwn/tokidoki v0.0.0-20240419154046-4ca7d8c4e7ca
|
||||||
github.com/1f349/violet v0.0.13
|
github.com/1f349/violet v0.0.13
|
||||||
github.com/emersion/go-webdav v0.5.0
|
github.com/charmbracelet/log v0.4.0
|
||||||
|
github.com/emersion/go-webdav v0.5.1-0.20240419143909-21f251fa1de2
|
||||||
github.com/google/subcommands v1.2.0
|
github.com/google/subcommands v1.2.0
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.22
|
|
||||||
github.com/mrmelon54/exit-reload v0.0.2
|
github.com/mrmelon54/exit-reload v0.0.2
|
||||||
|
github.com/rs/zerolog v1.32.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
github.com/charmbracelet/lipgloss v0.10.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6 // indirect
|
||||||
|
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/teambition/rrule-go v1.8.2 // indirect
|
github.com/teambition/rrule-go v1.8.2 // indirect
|
||||||
golang.org/x/net v0.19.0 // indirect
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
)
|
)
|
||||||
|
68
go.sum
68
go.sum
@ -1,34 +1,66 @@
|
|||||||
github.com/1f349/mjwt v0.2.5 h1:IxjLaali22ayTzZ628lH7j0JDdYJoj6+CJ/VktCqtXQ=
|
git.sr.ht/~sircmpwn/tokidoki v0.0.0-20240419154046-4ca7d8c4e7ca h1:HBRu4nwicaaZ4oqwTis2qy4Gb/CKLA2OSlibdKpMhb8=
|
||||||
github.com/1f349/mjwt v0.2.5/go.mod h1:KEs6jd9JjWrQW+8feP2pGAU7pdA3aYTqjkT/YQr73PU=
|
git.sr.ht/~sircmpwn/tokidoki v0.0.0-20240419154046-4ca7d8c4e7ca/go.mod h1:/1jsi+vx9b/T8UHrDRJXwoY8td9JUXd9UajtVCpVoeg=
|
||||||
github.com/1f349/violet v0.0.13 h1:lJpTz15Ea83Uc1VAISXTjtKuzr8Pe8NM4cMGp3Aiyhk=
|
github.com/1f349/violet v0.0.13 h1:lJpTz15Ea83Uc1VAISXTjtKuzr8Pe8NM4cMGp3Aiyhk=
|
||||||
github.com/1f349/violet v0.0.13/go.mod h1:Ga5/hWqI+EkR6J1mAMNzs7aJhuGcA89XFqgQaDXC7Jo=
|
github.com/1f349/violet v0.0.13/go.mod h1:Ga5/hWqI+EkR6J1mAMNzs7aJhuGcA89XFqgQaDXC7Jo=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
|
||||||
|
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
|
||||||
|
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||||
|
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f h1:feGUUxxvOtWVOhTko8Cbmp33a+tU0IMZxMEmnkoAISQ=
|
github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6 h1:kHoSgklT8weIDl6R6xFpBJ5IioRdBU1v2X2aCZRVCcM=
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f/go.mod h1:2MKFUgfNMULRxqZkadG1Vh44we3y5gJAtTBlVsx1BKQ=
|
github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6/go.mod h1:BEksegNspIkjCQfmzWgsgbu6KdeJ/4LwUZs7DMBzjzw=
|
||||||
|
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9 h1:ATgqloALX6cHCranzkLb8/zjivwQ9DWWDCQRnxTPfaA=
|
||||||
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
||||||
github.com/emersion/go-webdav v0.5.0 h1:Ak/BQLgAihJt/UxJbCsEXDPxS5Uw4nZzgIMOq3rkKjc=
|
github.com/emersion/go-webdav v0.5.1-0.20240419143909-21f251fa1de2 h1:k/NO/RfeXFuKGcpHDkspYoE8u6tWoHs03tH5DXg22To=
|
||||||
github.com/emersion/go-webdav v0.5.0/go.mod h1:ycyIzTelG5pHln4t+Y32/zBvmrM7+mV7x+V+Gx4ZQno=
|
github.com/emersion/go-webdav v0.5.1-0.20240419143909-21f251fa1de2/go.mod h1:mI8iBx3RAODwX7PJJ7qzsKAKs/vY429YfS2/9wKnDbQ=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mrmelon54/exit-reload v0.0.2 h1:vqgfrMD/bF21HkDsWgg5+NLjFDrD3KGVEN/iTrMn9Ms=
|
github.com/mrmelon54/exit-reload v0.0.2 h1:vqgfrMD/bF21HkDsWgg5+NLjFDrD3KGVEN/iTrMn9Ms=
|
||||||
github.com/mrmelon54/exit-reload v0.0.2/go.mod h1:aE3NhsqGMLUqmv6cJZRouC/8gXkZTvVSabRGOpI+Vjc=
|
github.com/mrmelon54/exit-reload v0.0.2/go.mod h1:aE3NhsqGMLUqmv6cJZRouC/8gXkZTvVSabRGOpI+Vjc=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||||
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
|
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||||
|
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/teambition/rrule-go v1.7.2/go.mod h1:mBJ1Ht5uboJ6jexKdNUJg2NcwP8uUMNvStWXlJD3MvU=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||||
|
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/teambition/rrule-go v1.8.2 h1:lIjpjvWTj9fFUZCmuoVDrKVOtdiyzbzc93qTmRVe/J8=
|
github.com/teambition/rrule-go v1.8.2 h1:lIjpjvWTj9fFUZCmuoVDrKVOtdiyzbzc93qTmRVe/J8=
|
||||||
github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4=
|
github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4=
|
||||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
54
logger.go
Normal file
54
logger.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package jasmine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
log2 "github.com/rs/zerolog/log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Logger = log.NewWithOptions(os.Stderr, log.Options{
|
||||||
|
ReportCaller: true,
|
||||||
|
ReportTimestamp: true,
|
||||||
|
Prefix: "Jasmine",
|
||||||
|
})
|
||||||
|
|
||||||
|
type zeroToCharmLogger struct{}
|
||||||
|
|
||||||
|
func (z *zeroToCharmLogger) Write(p []byte) (n int, err error) {
|
||||||
|
s := string(p)
|
||||||
|
if len(s) <= 3 {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
inLevel := s[:3]
|
||||||
|
var level log.Level
|
||||||
|
switch inLevel {
|
||||||
|
case "TRC", "DBG":
|
||||||
|
level = log.DebugLevel
|
||||||
|
case "INF":
|
||||||
|
level = log.InfoLevel
|
||||||
|
case "WRN":
|
||||||
|
level = log.WarnLevel
|
||||||
|
case "ERR":
|
||||||
|
level = log.ErrorLevel
|
||||||
|
case "FTL", "PNC":
|
||||||
|
level = log.FatalLevel
|
||||||
|
}
|
||||||
|
Logger.Helper()
|
||||||
|
translator := Logger.With()
|
||||||
|
translator.SetCallerFormatter(func(s string, i int, s2 string) string {
|
||||||
|
return "tokidoki internal"
|
||||||
|
})
|
||||||
|
translator.Log(level, strings.TrimSpace(s[4:]))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log2.Logger = log2.Output(zerolog.ConsoleWriter{
|
||||||
|
Out: &zeroToCharmLogger{},
|
||||||
|
FormatTimestamp: func(i interface{}) string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
88
server.go
88
server.go
@ -1,8 +1,11 @@
|
|||||||
package jasmine
|
package jasmine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.sr.ht/~sircmpwn/tokidoki/storage"
|
||||||
|
"github.com/emersion/go-webdav"
|
||||||
"github.com/emersion/go-webdav/caldav"
|
"github.com/emersion/go-webdav/caldav"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,14 +13,76 @@ type Conf struct {
|
|||||||
Listen string `json:"listen"`
|
Listen string `json:"listen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpServer(conf Conf, wd string) *http.Server {
|
type jasmineHandler struct {
|
||||||
h := &caldav.Handler{
|
auth *Auth
|
||||||
Backend: &Backend{},
|
backend caldav.Backend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *jasmineHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
principlePath, err := j.auth.CurrentUserPrincipal(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var homeSets []webdav.BackendSuppliedHomeSet
|
||||||
|
path, err := j.backend.CalendarHomeSetPath(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
homeSets = append(homeSets, caldav.NewCalendarHomeSet(path))
|
||||||
|
|
||||||
|
if req.URL.Path == principlePath {
|
||||||
|
opts := webdav.ServePrincipalOptions{
|
||||||
|
CurrentUserPrincipalPath: principlePath,
|
||||||
|
HomeSets: homeSets,
|
||||||
|
Capabilities: []webdav.Capability{
|
||||||
|
caldav.CapabilityCalendar,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
webdav.ServePrincipal(rw, req, &opts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.URL.Path == "/" {
|
||||||
|
http.Error(rw, "Jasmine API Endpoint", http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
http.NotFound(rw, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHttpServer(conf Conf, wd string) *http.Server {
|
||||||
|
// TODO: database auth
|
||||||
|
principle := &Auth{}
|
||||||
|
|
||||||
|
calStorage, _, err := storage.NewFilesystem(filepath.Join(wd, "storage"), "/calendar/", "/contacts/", principle)
|
||||||
|
if err != nil {
|
||||||
|
Logger.Fatal("Failed to load storage backend", "err", err)
|
||||||
|
}
|
||||||
|
calHandler := &caldav.Handler{Backend: calStorage}
|
||||||
|
|
||||||
|
handler := &jasmineHandler{
|
||||||
|
auth: principle,
|
||||||
|
backend: calStorage,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := http.NewServeMux()
|
||||||
|
r.Handle("/", handler)
|
||||||
|
r.Handle("/.well-known/caldav", calHandler)
|
||||||
|
r.Handle("/{user}/calendar/", calHandler)
|
||||||
|
|
||||||
|
r2 := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
t := time.Now()
|
||||||
|
r.ServeHTTP(rw, req)
|
||||||
|
td := time.Since(t)
|
||||||
|
Logger.Debug("Request", "method", req.Method, "url", req.URL.String(), "remote", req.RemoteAddr, "dur", td.String())
|
||||||
|
})
|
||||||
|
|
||||||
return &http.Server{
|
return &http.Server{
|
||||||
Addr: conf.Listen,
|
Addr: conf.Listen,
|
||||||
Handler: h,
|
Handler: principle.Middleware(r2),
|
||||||
ReadTimeout: time.Minute,
|
ReadTimeout: time.Minute,
|
||||||
ReadHeaderTimeout: time.Minute,
|
ReadHeaderTimeout: time.Minute,
|
||||||
WriteTimeout: time.Minute,
|
WriteTimeout: time.Minute,
|
||||||
@ -25,3 +90,18 @@ func NewHttpServer(conf Conf, wd string) *http.Server {
|
|||||||
MaxHeaderBytes: 2500,
|
MaxHeaderBytes: 2500,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MainHandler(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
rw.Header().Set("Dav", "1, 2, 3, calendar-access, extended-mkcol")
|
||||||
|
if (req.Method == http.MethodHead || req.Method == http.MethodGet || req.Method == http.MethodPost) && req.RequestURI == "/" {
|
||||||
|
if req.Method == http.MethodHead {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(rw, "Jasmine API Endpoint", http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Logger.Info("Request", "method", req.Method, "url", req.URL.String())
|
||||||
|
next.ServeHTTP(rw, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user