sliding-sync/v3.go

125 lines
3.1 KiB
Go
Raw Normal View History

2021-05-14 16:49:33 +01:00
package syncv3
import (
2021-09-20 17:21:02 +01:00
"encoding/json"
"fmt"
2021-05-14 16:49:33 +01:00
"net/http"
"os"
2022-08-16 14:23:05 +01:00
"strings"
2021-05-14 16:49:33 +01:00
"time"
"github.com/gorilla/mux"
2022-08-16 14:23:05 +01:00
"github.com/matrix-org/sync-v3/internal"
2021-05-14 16:49:33 +01:00
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
)
var logger = zerolog.New(os.Stdout).With().Timestamp().Logger().Output(zerolog.ConsoleWriter{
Out: os.Stderr,
TimeFormat: "15:04:05",
})
2022-08-16 14:23:05 +01:00
var Version string
2021-07-21 12:12:57 +01:00
type server struct {
chain []func(next http.Handler) http.Handler
final http.Handler
}
func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h := s.final
for i := range s.chain {
h = s.chain[len(s.chain)-1-i](h)
}
h.ServeHTTP(w, req)
}
func allowCORS(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
2021-11-24 16:27:33 +00:00
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
if req.Method == "OPTIONS" {
w.WriteHeader(200)
return
}
next.ServeHTTP(w, req)
}
}
2021-05-14 16:49:33 +01:00
// RunSyncV3Server is the main entry point to the server
func RunSyncV3Server(h http.Handler, bindAddr, destV2Server string) {
2021-05-14 16:49:33 +01:00
// HTTP path routing
r := mux.NewRouter()
2021-11-24 16:27:33 +00:00
r.Handle("/_matrix/client/v3/sync", allowCORS(h))
2021-12-22 18:20:02 +00:00
r.Handle("/_matrix/client/unstable/org.matrix.msc3575/sync", allowCORS(h))
serverJSON, _ := json.Marshal(struct {
2022-08-16 14:23:05 +01:00
Server string `json:"server"`
Version string `json:"version"`
}{
Server: destV2Server,
Version: Version,
})
r.Handle("/client/server.json", allowCORS(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(200)
rw.Write(serverJSON)
})))
r.PathPrefix("/client/").HandlerFunc(
allowCORS(
http.StripPrefix("/client/", http.FileServer(http.Dir("./client"))),
),
)
2021-07-21 12:12:57 +01:00
srv := &server{
chain: []func(next http.Handler) http.Handler{
hlog.NewHandler(logger),
2022-08-16 14:23:05 +01:00
func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r = r.WithContext(internal.RequestContext(r.Context()))
next.ServeHTTP(w, r)
})
},
2021-07-21 12:12:57 +01:00
hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
if r.Method == "OPTIONS" {
return
}
2022-08-16 14:23:05 +01:00
entry := internal.DecorateLogger(r.Context(), hlog.FromRequest(r).Info())
if !strings.HasSuffix(r.URL.Path, "/sync") {
entry.Str("path", r.URL.Path)
}
entry.Int("status", status).
2021-07-21 12:12:57 +01:00
Int("size", size).
Dur("duration", duration).
Msg("")
}),
},
final: r,
}
2021-05-14 16:49:33 +01:00
// Block forever
logger.Info().Msgf("listening on %s", bindAddr)
2021-07-21 12:12:57 +01:00
if err := http.ListenAndServe(bindAddr, srv); err != nil {
logger.Fatal().Err(err).Msg("failed to listen and serve")
2021-05-14 16:49:33 +01:00
}
}
2021-09-20 17:21:02 +01:00
type HandlerError struct {
StatusCode int
Err error
}
func (e *HandlerError) Error() string {
return fmt.Sprintf("HTTP %d : %s", e.StatusCode, e.Err.Error())
}
type jsonError struct {
Err string `json:"error"`
}
func (e HandlerError) JSON() []byte {
je := jsonError{e.Error()}
b, _ := json.Marshal(je)
return b
}