diff --git a/src/github.com/turt2live/matrix-media-repo/client/r0/download.go b/src/github.com/turt2live/matrix-media-repo/client/r0/download.go index e42f2bd6a063d9e6e558dfbfdc5c15eb568b76fc..3627022fb6bc3584f9969d6552cea836dc739de5 100644 --- a/src/github.com/turt2live/matrix-media-repo/client/r0/download.go +++ b/src/github.com/turt2live/matrix-media-repo/client/r0/download.go @@ -1,9 +1,11 @@ package r0 import ( + "database/sql" "net/http" "github.com/gorilla/mux" + "github.com/turt2live/matrix-media-repo/client" "github.com/turt2live/matrix-media-repo/config" "github.com/turt2live/matrix-media-repo/storage" ) @@ -17,10 +19,10 @@ import ( // Body: <byte[]> type DownloadMediaResponse struct { - Server string - MediaID string + ContentType string Filename string - Host string + SizeBytes int64 + Location string } func DownloadMedia(w http.ResponseWriter, r *http.Request, db storage.Database, c config.MediaRepoConfig) interface{} { @@ -30,9 +32,23 @@ func DownloadMedia(w http.ResponseWriter, r *http.Request, db storage.Database, mediaId := params["mediaId"] filename := params["filename"] + media, err := db.GetMedia(r.Context(), server, mediaId) + if err != nil { + if err == sql.ErrNoRows { + // TODO: Try remote fetch + return client.NotFoundError() + } + return client.InternalServerError(err.Error()) + } + if filename == "" { - filename = "testasdasdasd.jpg" + filename = media.UploadName } - return &DownloadMediaResponse{server, mediaId, filename, r.Host} + return &DownloadMediaResponse{ + ContentType: media.ContentType, + Filename: filename, + SizeBytes: media.SizeBytes, + Location: media.Location, + } } diff --git a/src/github.com/turt2live/matrix-media-repo/client/responses.go b/src/github.com/turt2live/matrix-media-repo/client/responses.go index 1101041074b838643dfac43660d0898e5e8b5f63..31c7f9d24131316d3490692f1675a7bbb5b8fcd8 100644 --- a/src/github.com/turt2live/matrix-media-repo/client/responses.go +++ b/src/github.com/turt2live/matrix-media-repo/client/responses.go @@ -7,4 +7,8 @@ type ErrorResponse struct { func InternalServerError(message string) *ErrorResponse { return &ErrorResponse{"M_UNKNOWN", message} +} + +func NotFoundError() *ErrorResponse { + return &ErrorResponse{"M_NOT_FOUND", "Not found"} } \ No newline at end of file diff --git a/src/github.com/turt2live/matrix-media-repo/media_repo.go b/src/github.com/turt2live/matrix-media-repo/media_repo.go index f7e45cd7f060694a078542c3a075db8a722603aa..647d647ae01d6202bb83d29d87d8a7dc8e4f2500 100644 --- a/src/github.com/turt2live/matrix-media-repo/media_repo.go +++ b/src/github.com/turt2live/matrix-media-repo/media_repo.go @@ -4,6 +4,7 @@ import ( json "encoding/json" "io" "net/http" + "os" "github.com/gorilla/mux" "github.com/turt2live/matrix-media-repo/client" @@ -12,6 +13,8 @@ import ( "github.com/turt2live/matrix-media-repo/storage" ) +const UnkErrJson = `{"code":"M_UNKNOWN","message":"Unexpected error processing response"}` + type Handler struct { h func(http.ResponseWriter, *http.Request, storage.Database, config.MediaRepoConfig) interface{} opts HandlerOpts @@ -44,17 +47,15 @@ func main() { thumbnailHandler := Handler{r0.ThumbnailMedia, hOpts} rtr.Handle("/_matrix/client/r0/media/upload", uploadHandler).Methods("POST") - rtr.Handle("/_matrix/client/r0/media/download/{server:[a-zA-Z0-9.]+}/{mediaId:[a-zA-Z0-9]+}", downloadHandler).Methods("GET") - rtr.Handle("/_matrix/client/r0/media/download/{server:[a-zA-Z0-9.]+}/{mediaId:[a-zA-Z0-9]+}/{filename:[a-zA-Z0-9._-]+}", downloadHandler).Methods("GET") - rtr.Handle("/_matrix/client/r0/media/thumbnail/{server:[a-zA-Z0-9.]+}/{mediaId:[a-zA-Z0-9]+}", thumbnailHandler).Methods("GET") + rtr.Handle("/_matrix/client/r0/media/download/{server:[a-zA-Z0-9.:-_]+}/{mediaId:[a-zA-Z0-9]+}", downloadHandler).Methods("GET") + rtr.Handle("/_matrix/client/r0/media/download/{server:[a-zA-Z0-9.:-_]+}/{mediaId:[a-zA-Z0-9]+}/{filename:[a-zA-Z0-9._-]+}", downloadHandler).Methods("GET") + rtr.Handle("/_matrix/client/r0/media/thumbnail/{server:[a-zA-Z0-9.:-_]+}/{mediaId:[a-zA-Z0-9]+}", thumbnailHandler).Methods("GET") http.Handle("/", rtr) http.ListenAndServe(":8000", nil) } func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - res := h.h(w, r, h.opts.db, h.opts.config) if res == nil { res = &EmptyResponse{} @@ -62,7 +63,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { b, err := json.Marshal(res) if err != nil { - http.Error(w, `{"code":"M_UNKNOWN","message":"Unexpected error processing response"}`, http.StatusInternalServerError) + w.Header().Set("Content-Type", "application/json") + http.Error(w, UnkErrJson, http.StatusInternalServerError) return } jsonStr := string(b) @@ -70,13 +72,32 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch result := res.(type) { case *client.ErrorResponse: switch result.Code { + case "M_NOT_FOUND": + w.Header().Set("Content-Type", "application/json") + http.Error(w, jsonStr, http.StatusNotFound) + break //case "M_UNKNOWN": default: + w.Header().Set("Content-Type", "application/json") http.Error(w, jsonStr, http.StatusInternalServerError) break } break + case *r0.DownloadMediaResponse: + w.Header().Set("Content-Type", result.ContentType) + w.Header().Set("Content-Disposition", "inline; filename=\"" + result.Filename +"\"") + f, err := os.Open(result.Location) + if err != nil { + w.Header().Set("Content-Type", "application/json") + http.Error(w, UnkErrJson, http.StatusInternalServerError) + break + } + defer f.Close() + io.Copy(w, f) + break default: + w.Header().Set("Content-Type", "application/json") io.WriteString(w, jsonStr) + break } } \ No newline at end of file diff --git a/src/github.com/turt2live/matrix-media-repo/storage/storage.go b/src/github.com/turt2live/matrix-media-repo/storage/storage.go index 421ff55b305f2b1f9100a109ddb40d195d4f1dd4..640ada52564b311d2475a6767863a261ad31e38a 100644 --- a/src/github.com/turt2live/matrix-media-repo/storage/storage.go +++ b/src/github.com/turt2live/matrix-media-repo/storage/storage.go @@ -99,4 +99,20 @@ func (d *Database) GetSizeOfFolderBytes(ctx context.Context, folderPath string) r := &folderSize{} err := d.statements.selectSizeOfFolder.QueryRowContext(ctx, folderPath).Scan(&r.Size) return r.Size, err +} + +func (d *Database) GetMedia(ctx context.Context, origin string, mediaId string) (types.Media, error) { + m := &types.Media{} + err := d.statements.selectMedia.QueryRowContext(ctx, origin, mediaId).Scan( + &m.Origin, + &m.MediaId, + &m.UploadName, + &m.ContentType, + &m.UserId, + &m.Sha256Hash, + &m.SizeBytes, + &m.Location, + &m.CreationTs, + ) + return *m, err } \ No newline at end of file