2017-08-02 03:58:13 +02:00
const logger = require ( 'winston' ) ;
2017-12-07 21:23:21 +01:00
const { getClaimId , getChannelViewData , getLocalFileRecord } = require ( '../controllers/serveController.js' ) ;
2017-11-27 23:35:29 +01:00
const serveHelpers = require ( '../helpers/serveHelpers.js' ) ;
2017-08-03 02:13:02 +02:00
const { handleRequestError } = require ( '../helpers/errorHandlers.js' ) ;
2017-12-07 19:13:42 +01:00
const { postToStats } = require ( '../controllers/statsController.js' ) ;
2017-11-21 21:53:43 +01:00
const db = require ( '../models' ) ;
2017-12-07 19:13:42 +01:00
const lbryUri = require ( '../helpers/lbryUri.js' ) ;
2017-09-08 00:31:32 +02:00
const SERVE = 'SERVE' ;
const SHOW = 'SHOW' ;
const SHOWLITE = 'SHOWLITE' ;
2017-10-18 00:09:43 +02:00
const NO _CHANNEL = 'NO_CHANNEL' ;
2017-10-18 00:50:35 +02:00
const NO _CLAIM = 'NO_CLAIM' ;
2017-11-28 00:57:20 +01:00
const NO _FILE = 'NO_FILE' ;
2017-07-25 10:52:31 +02:00
2017-08-04 01:46:44 +02:00
function isValidClaimId ( claimId ) {
2017-08-04 06:59:22 +02:00
return ( ( claimId . length === 40 ) && ! /[^A-Za-z0-9]/g . test ( claimId ) ) ;
2017-08-04 01:46:44 +02:00
}
2017-08-10 19:49:19 +02:00
function isValidShortId ( claimId ) {
2017-11-27 23:35:29 +01:00
return claimId . length === 1 ; // it should really evaluate the short url itself
2017-08-04 01:46:44 +02:00
}
2017-08-10 19:49:19 +02:00
function isValidShortIdOrClaimId ( input ) {
return ( isValidClaimId ( input ) || isValidShortId ( input ) ) ;
2017-08-04 01:46:44 +02:00
}
2017-12-07 21:23:21 +01:00
function sendChannelInfoAndContentToClient ( channelPageData , res ) {
if ( channelPageData === NO _CHANNEL ) {
2017-11-27 22:15:09 +01:00
res . status ( 200 ) . render ( 'noChannel' ) ;
2017-12-07 21:23:21 +01:00
} else {
res . status ( 200 ) . render ( 'channel' , channelPageData ) ;
2017-11-27 22:15:09 +01:00
}
}
2017-12-07 03:36:17 +01:00
function showChannelPageToClient ( channelName , channelClaimId , originalUrl , ip , query , res ) {
2017-11-27 22:15:09 +01:00
// 1. retrieve the channel contents
2017-12-07 21:23:21 +01:00
getChannelViewData ( channelName , channelClaimId , query )
. then ( channelViewData => {
sendChannelInfoAndContentToClient ( channelViewData , res ) ;
2017-11-27 22:15:09 +01:00
} )
. catch ( error => {
2017-12-07 03:49:05 +01:00
handleRequestError ( originalUrl , ip , error , res ) ;
2017-11-27 22:15:09 +01:00
} ) ;
}
2017-12-13 23:55:26 +01:00
function clientAcceptsHtml ( { accept } ) {
return accept && accept . match ( /text\/html/ ) ;
}
function clientWantsAsset ( { accept } ) {
const imageIsWanted = accept && accept . match ( /image\/.*/ ) && ! accept . match ( /text\/html/ ) && ! accept . match ( /text\/\*/ ) ; // checks if an image is accepted, but not a video
const videoIsWanted = false ;
return imageIsWanted || videoIsWanted ;
2017-12-07 00:35:40 +01:00
}
2017-12-07 03:36:17 +01:00
function determineResponseType ( isServeRequest , headers ) {
2017-11-27 22:15:09 +01:00
let responseType ;
2017-12-07 03:36:17 +01:00
if ( isServeRequest ) {
2017-11-27 22:15:09 +01:00
responseType = SERVE ;
2017-12-07 00:35:40 +01:00
if ( clientAcceptsHtml ( headers ) ) { // this is in case a serve request comes from a browser
2017-11-27 22:15:09 +01:00
responseType = SHOWLITE ;
}
} else {
responseType = SHOW ;
2017-12-13 23:55:26 +01:00
if ( clientWantsAsset ( headers ) ) { // this is in case someone embeds a show url
logger . debug ( 'Show request actually want\'s an asset!' ) ;
2017-11-29 23:36:51 +01:00
responseType = SERVE ;
}
2017-11-27 22:15:09 +01:00
}
return responseType ;
}
2017-11-27 23:35:29 +01:00
function showAssetToClient ( claimId , name , res ) {
return Promise
2017-12-06 20:53:31 +01:00
. all ( [ db . Claim . resolveClaim ( name , claimId ) , db . Claim . getShortClaimIdFromLongClaimId ( claimId , name ) ] )
2017-11-27 23:52:46 +01:00
. then ( ( [ claimInfo , shortClaimId ] ) => {
2017-12-13 23:55:26 +01:00
// logger.debug('claimInfo:', claimInfo);
// logger.debug('shortClaimId:', shortClaimId);
2017-11-27 23:52:46 +01:00
return serveHelpers . showFile ( claimInfo , shortClaimId , res ) ;
} )
. catch ( error => {
throw error ;
} ) ;
2017-11-27 23:35:29 +01:00
}
2017-12-07 00:15:21 +01:00
function showLiteAssetToClient ( claimId , name , res ) {
2017-11-27 23:35:29 +01:00
return Promise
2017-12-07 00:15:21 +01:00
. all ( [ db . Claim . resolveClaim ( name , claimId ) , db . Claim . getShortClaimIdFromLongClaimId ( claimId , name ) ] )
2017-11-27 23:52:46 +01:00
. then ( ( [ claimInfo , shortClaimId ] ) => {
2017-12-13 23:55:26 +01:00
// logger.debug('claimInfo:', claimInfo);
// logger.debug('shortClaimId:', shortClaimId);
2017-11-27 23:52:46 +01:00
return serveHelpers . showFileLite ( claimInfo , shortClaimId , res ) ;
} )
. catch ( error => {
throw error ;
} ) ;
2017-11-27 23:35:29 +01:00
}
function serveAssetToClient ( claimId , name , res ) {
return getLocalFileRecord ( claimId , name )
2017-11-27 23:52:46 +01:00
. then ( fileInfo => {
2017-12-13 23:55:26 +01:00
// logger.debug('fileInfo:', fileInfo);
2017-11-28 00:57:20 +01:00
if ( fileInfo === NO _FILE ) {
2017-12-07 19:13:42 +01:00
return res . status ( 307 ) . redirect ( ` /api/claim-get/ ${ name } / ${ claimId } ` ) ;
2017-11-27 23:52:46 +01:00
}
2017-12-07 19:13:42 +01:00
return serveHelpers . serveFile ( fileInfo , claimId , name , res ) ;
2017-11-27 23:52:46 +01:00
} )
. catch ( error => {
throw error ;
} ) ;
2017-11-27 23:35:29 +01:00
}
2017-11-28 03:12:58 +01:00
function showOrServeAsset ( responseType , claimId , claimName , res ) {
switch ( responseType ) {
case SHOW :
return showAssetToClient ( claimId , claimName , res ) ;
case SHOWLITE :
2017-12-07 00:15:21 +01:00
return showLiteAssetToClient ( claimId , claimName , res ) ;
2017-11-28 03:12:58 +01:00
case SERVE :
return serveAssetToClient ( claimId , claimName , res ) ;
default :
break ;
}
}
function flipClaimNameAndIdForBackwardsCompatibility ( identifier , name ) {
2017-11-30 19:02:18 +01:00
// this is a patch for backwards compatability with 'spee.ch/name/claim_id' url format
2017-11-28 03:12:58 +01:00
if ( isValidShortIdOrClaimId ( name ) && ! isValidShortIdOrClaimId ( identifier ) ) {
const tempName = name ;
name = identifier ;
identifier = tempName ;
}
return [ identifier , name ] ;
}
function logRequestData ( responseType , claimName , channelName , claimId ) {
logger . debug ( 'responseType ===' , responseType ) ;
logger . debug ( 'claim name === ' , claimName ) ;
logger . debug ( 'channel name ===' , channelName ) ;
logger . debug ( 'claim id ===' , claimId ) ;
}
2017-06-30 02:10:14 +02:00
module . exports = ( app ) => {
2017-11-30 19:02:18 +01:00
// route to serve a specific asset using the channel or claim id
2017-08-01 02:02:39 +02:00
app . get ( '/:identifier/:name' , ( { headers , ip , originalUrl , params } , res ) => {
2017-12-07 03:36:17 +01:00
let isChannel , channelName , channelClaimId , claimId , claimName , isServeRequest ;
try {
2017-12-07 19:13:42 +01:00
( { isChannel , channelName , channelClaimId , claimId } = lbryUri . parseIdentifier ( params . identifier ) ) ;
( { claimName , isServeRequest } = lbryUri . parseName ( params . name ) ) ;
2017-12-07 03:36:17 +01:00
} catch ( error ) {
2017-12-07 03:49:05 +01:00
return handleRequestError ( originalUrl , ip , error , res ) ;
2017-12-07 03:36:17 +01:00
}
if ( ! isChannel ) {
[ claimId , claimName ] = flipClaimNameAndIdForBackwardsCompatibility ( claimId , claimName ) ;
2017-08-24 02:00:16 +02:00
}
2017-12-07 03:36:17 +01:00
let responseType = determineResponseType ( isServeRequest , headers ) ;
2017-11-30 19:02:18 +01:00
// log the request data for debugging
2017-11-28 03:12:58 +01:00
logRequestData ( responseType , claimName , channelName , claimId ) ;
2017-11-30 19:02:18 +01:00
// get the claim Id and then serve/show the asset
2017-12-06 00:11:16 +01:00
getClaimId ( channelName , channelClaimId , claimName , claimId )
2017-11-28 00:57:20 +01:00
. then ( fullClaimId => {
if ( fullClaimId === NO _CLAIM ) {
2017-11-28 03:12:58 +01:00
return res . status ( 200 ) . render ( 'noClaim' ) ;
2017-11-28 00:57:20 +01:00
} else if ( fullClaimId === NO _CHANNEL ) {
2017-11-28 03:12:58 +01:00
return res . status ( 200 ) . render ( 'noChannel' ) ;
2017-08-02 22:16:39 +02:00
}
2017-11-28 03:12:58 +01:00
showOrServeAsset ( responseType , fullClaimId , claimName , res ) ;
2017-12-07 19:13:42 +01:00
postToStats ( responseType , originalUrl , ip , claimName , fullClaimId , 'success' ) ;
2017-08-02 22:16:39 +02:00
} )
. catch ( error => {
2017-12-07 03:49:05 +01:00
handleRequestError ( originalUrl , ip , error , res ) ;
2017-08-02 22:16:39 +02:00
} ) ;
2017-06-19 18:37:35 +02:00
} ) ;
2017-11-30 19:02:18 +01:00
// route to serve the winning asset at a claim or a channel page
2017-12-07 03:36:17 +01:00
app . get ( '/:identifier' , ( { headers , ip , originalUrl , params , query } , res ) => {
let isChannel , channelName , channelClaimId ;
try {
2017-12-07 19:13:42 +01:00
( { isChannel , channelName , channelClaimId } = lbryUri . parseIdentifier ( params . identifier ) ) ;
2017-12-07 03:36:17 +01:00
} catch ( error ) {
2017-12-07 03:49:05 +01:00
return handleRequestError ( originalUrl , ip , error , res ) ;
2017-12-07 03:36:17 +01:00
}
if ( isChannel ) {
// log the request data for debugging
logRequestData ( null , null , channelName , null ) ;
// handle showing the channel page
showChannelPageToClient ( channelName , channelClaimId , originalUrl , ip , query , res ) ;
2017-08-03 20:14:50 +02:00
} else {
2017-12-07 03:36:17 +01:00
let claimName , isServeRequest ;
try {
2017-12-07 19:13:42 +01:00
( { claimName , isServeRequest } = lbryUri . parseName ( params . identifier ) ) ;
2017-12-07 03:36:17 +01:00
} catch ( error ) {
2017-12-07 03:49:05 +01:00
return handleRequestError ( originalUrl , ip , error , res ) ;
2017-12-07 03:36:17 +01:00
}
let responseType = determineResponseType ( isServeRequest , headers ) ;
2017-11-30 19:02:18 +01:00
// log the request data for debugging
2017-11-28 03:12:58 +01:00
logRequestData ( responseType , claimName , null , null ) ;
2017-11-30 19:02:18 +01:00
// get the claim Id and then serve/show the asset
2017-11-28 00:57:20 +01:00
getClaimId ( null , null , claimName , null )
. then ( fullClaimId => {
if ( fullClaimId === NO _CLAIM ) {
2017-11-28 03:12:58 +01:00
return res . status ( 200 ) . render ( 'noClaim' ) ;
2017-11-21 21:53:43 +01:00
}
2017-11-28 03:12:58 +01:00
showOrServeAsset ( responseType , fullClaimId , claimName , res ) ;
2017-12-07 19:13:42 +01:00
postToStats ( responseType , originalUrl , ip , claimName , fullClaimId , 'success' ) ;
2017-11-21 21:53:43 +01:00
} )
. catch ( error => {
2017-12-07 03:49:05 +01:00
handleRequestError ( originalUrl , ip , error , res ) ;
2017-11-21 21:53:43 +01:00
} ) ;
2017-08-23 21:21:15 +02:00
}
2017-06-19 18:37:35 +02:00
} ) ;
} ;