2020-02-09 14:21:53 +01:00
package routes
import (
"database/sql"
"fmt"
"io"
2020-02-21 12:05:28 +01:00
"log"
2020-02-09 14:21:53 +01:00
"net/http"
"os"
2020-02-23 12:43:45 +01:00
"path"
"strconv"
2020-02-09 14:21:53 +01:00
2020-02-21 16:50:50 +01:00
"github.com/gorilla/mux"
2020-02-09 14:21:53 +01:00
"github.com/viktorstrate/photoview/api/graphql/models"
2020-02-23 12:43:45 +01:00
"github.com/viktorstrate/photoview/api/scanner"
2020-02-09 14:21:53 +01:00
)
2020-02-21 16:50:50 +01:00
func RegisterPhotoRoutes ( db * sql . DB , router * mux . Router ) {
router . HandleFunc ( "/{name}" , func ( w http . ResponseWriter , r * http . Request ) {
2020-07-10 14:26:19 +02:00
media_name := mux . Vars ( r ) [ "name" ]
2020-02-09 14:21:53 +01:00
2020-07-10 14:26:19 +02:00
row := db . QueryRow ( "SELECT media_url.purpose, media_url.content_type, media_url.media_id FROM media_url, media WHERE media_url.media_name = ? AND media_url.media_id = media.media_id" , media_name )
2020-02-09 14:21:53 +01:00
2020-07-10 12:58:11 +02:00
var purpose models . MediaPurpose
2020-02-09 14:21:53 +01:00
var content_type string
2020-07-10 14:26:19 +02:00
var media_id int
2020-02-09 14:21:53 +01:00
2020-07-10 14:26:19 +02:00
if err := row . Scan ( & purpose , & content_type , & media_id ) ; err != nil {
2020-02-09 14:21:53 +01:00
w . WriteHeader ( http . StatusNotFound )
w . Write ( [ ] byte ( "404" ) )
return
}
2020-07-10 14:26:19 +02:00
row = db . QueryRow ( "SELECT * FROM media WHERE media_id = ?" , media_id )
media , err := models . NewMediaFromRow ( row )
2020-02-23 18:00:08 +01:00
if err != nil {
log . Printf ( "WARN: %s" , err )
w . WriteHeader ( http . StatusInternalServerError )
w . Write ( [ ] byte ( "internal server error" ) )
}
2020-07-12 18:52:48 +02:00
if success , response , status , err := authenticateMedia ( media , db , r ) ; ! success {
2020-02-21 12:05:28 +01:00
if err != nil {
2020-07-12 18:52:48 +02:00
log . Printf ( "WARN: error authenticating photo: %s\n" , err )
2020-02-21 12:05:28 +01:00
}
2020-07-12 18:52:48 +02:00
w . WriteHeader ( status )
w . Write ( [ ] byte ( response ) )
return
2020-02-20 17:31:41 +01:00
}
2020-02-23 18:00:08 +01:00
var cachedPath string
var file * os . File = nil
2020-02-09 14:21:53 +01:00
2020-07-11 14:21:10 +02:00
if purpose == models . PhotoThumbnail || purpose == models . PhotoHighRes || purpose == models . VideoThumbnail {
2020-07-10 14:26:19 +02:00
cachedPath = path . Join ( scanner . PhotoCache ( ) , strconv . Itoa ( media . AlbumId ) , strconv . Itoa ( media_id ) , media_name )
2020-07-11 15:57:58 +02:00
} else if purpose == models . MediaOriginal {
2020-07-10 14:26:19 +02:00
cachedPath = media . Path
2020-07-11 15:57:58 +02:00
} else {
log . Printf ( "ERROR: Can not handle media_purpose for photo: %s\n" , purpose )
w . WriteHeader ( http . StatusInternalServerError )
w . Write ( [ ] byte ( "internal server error" ) )
return
2020-02-23 18:00:08 +01:00
}
file , err = os . Open ( cachedPath )
2020-07-11 15:57:58 +02:00
defer file . Close ( )
2020-02-23 18:00:08 +01:00
if err != nil {
if os . IsNotExist ( err ) {
tx , err := db . Begin ( )
if err != nil {
log . Printf ( "ERROR: %s\n" , err )
w . WriteHeader ( http . StatusInternalServerError )
w . Write ( [ ] byte ( "internal server error" ) )
return
}
2020-07-10 14:26:19 +02:00
_ , err = scanner . ProcessMedia ( tx , media )
2020-02-23 18:00:08 +01:00
if err != nil {
log . Printf ( "ERROR: processing image not found in cache: %s\n" , err )
w . WriteHeader ( http . StatusInternalServerError )
w . Write ( [ ] byte ( "internal server error" ) )
tx . Rollback ( )
return
}
file , err = os . Open ( cachedPath )
if err != nil {
log . Printf ( "ERROR: after reprocessing image not found in cache: %s\n" , err )
w . WriteHeader ( http . StatusInternalServerError )
w . Write ( [ ] byte ( "internal server error" ) )
tx . Rollback ( )
return
}
tx . Commit ( )
2020-02-09 14:21:53 +01:00
}
}
2020-02-23 12:43:45 +01:00
w . Header ( ) . Set ( "Content-Type" , content_type )
2020-02-09 14:21:53 +01:00
if stats , err := file . Stat ( ) ; err == nil {
w . Header ( ) . Set ( "Content-Length" , fmt . Sprintf ( "%d" , stats . Size ( ) ) )
}
2020-09-30 14:08:30 +02:00
// Allow caching the resource for 1 day
w . Header ( ) . Set ( "Cache-Control" , "private, max-age=86400, immutable" )
2020-02-09 14:21:53 +01:00
io . Copy ( w , file )
} )
}