rearranged serve route functions into serve controller

This commit is contained in:
bill bittner 2017-08-23 16:01:28 -07:00
parent e5a0dc8eb6
commit c4a4f93a32
3 changed files with 164 additions and 226 deletions

View file

@ -1,7 +1,11 @@
const lbryApi = require('../helpers/lbryApi.js'); const lbryApi = require('../helpers/lbryApi.js');
const db = require('../models'); const db = require('../models');
const logger = require('winston'); const logger = require('winston');
const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable, getClaimIdByChannel } = require('../helpers/serveHelpers.js'); const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable, serveFile, showFile, showFileLite, getShortClaimIdFromLongClaimId, getClaimIdByLongChannelId, getAllChannelClaims, getLongChannelId, getShortChannelIdFromLongChannelId } = require('../helpers/serveHelpers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const SERVE = 'SERVE';
const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE';
function checkForLocalAssetByClaimId (claimId, name) { function checkForLocalAssetByClaimId (claimId, name) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -90,19 +94,6 @@ function getAssetByClaimId (fullClaimId, name) {
} }
module.exports = { module.exports = {
getAssetByChannel (channelName, channelId, claimName) {
logger.debug('channelId =', channelId);
return new Promise((resolve, reject) => {
getClaimIdByChannel(channelName, channelId, claimName)
.then(claimId => {
logger.debug('claim id = ', claimId);
resolve(getAssetByClaimId(claimId, claimName));
})
.catch(error => {
reject(error);
});
});
},
getAssetByShortId: function (shortId, name) { getAssetByShortId: function (shortId, name) {
logger.debug('...getting asset by short id...'); logger.debug('...getting asset by short id...');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -143,10 +134,97 @@ module.exports = {
}); });
}); });
}, },
getChannelByName (name) { getAssetByChannel (channelName, channelId, claimName) {
logger.debug('...getting channel by channel name...'); logger.debug('channelId =', channelId);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
reject(new Error('This feature is not yet supported')); // 1. get the long channel id
getLongChannelId(channelName, channelId)
// 2. get the claim Id
.then(longChannelId => {
return getClaimIdByLongChannelId(longChannelId, claimName);
})
// 3. get the asset by this claim id and name
.then(claimId => {
logger.debug('asset claim id = ', claimId);
resolve(getAssetByClaimId(claimId, claimName));
})
.catch(error => {
reject(error);
});
}); });
}, },
getChannelContents (channelName, channelId) {
return new Promise((resolve, reject) => {
let longChannelId;
let shortChannelId;
// 1. get the long channel Id
getLongChannelId(channelName, channelId)
// 2. get all claims for that channel
.then(result => {
longChannelId = result;
return getShortChannelIdFromLongChannelId(channelName, longChannelId);
})
// 3. get all Claim records for this channel
.then(result => {
shortChannelId = result;
return getAllChannelClaims(longChannelId);
})
// 4. add extra data not available from Claim table
.then(allChannelClaims => {
if (allChannelClaims) {
allChannelClaims.forEach(element => {
element['channelName'] = channelName;
element['longChannelId'] = longChannelId;
element['shortChannelId'] = shortChannelId;
element['fileExtension'] = element.contentType.substring(element.contentType.lastIndexOf('/') + 1);
});
}
return resolve(allChannelClaims);
})
.catch(error => {
reject(error);
});
});
},
serveOrShowAsset (fileInfo, extension, method, headers, originalUrl, ip, res) {
// add file extension to the file info
if (extension === '.gifv') {
fileInfo['fileExt'] = '.gifv';
} else {
fileInfo['fileExt'] = fileInfo.fileName.substring(fileInfo.fileName.lastIndexOf('.'));
}
// serve or show
switch (method) {
case SERVE:
serveFile(fileInfo, res);
sendGoogleAnalytics(method, headers, ip, originalUrl);
postToStats('serve', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
case SHOWLITE:
showFileLite(fileInfo, res);
postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
case SHOW:
return getShortClaimIdFromLongClaimId(fileInfo.claimId, fileInfo.name)
.then(shortId => {
fileInfo['shortId'] = shortId;
return resolveAgainstClaimTable(fileInfo.name, fileInfo.claimId);
})
.then(resolveResult => {
logger.debug('resolve result', resolveResult);
fileInfo['title'] = resolveResult.title;
fileInfo['description'] = resolveResult.description;
showFile(fileInfo, res);
postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
})
.catch(error => {
console.log('thowing error...');
throw error;
});
default:
logger.error('I did not recognize that method');
break;
}
},
}; };

View file

@ -10,16 +10,6 @@ function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) {
}; };
} }
function getLongChannelId (channelName, channelId) {
if (channelId && (channelId.length === 40)) { // full channel id
return new Promise((resolve, reject) => resolve(channelId));
} else if (channelId && channelId.length < 40) { // short channel id
return getLongChannelIdFromShortChannelId(channelName, channelId);
} else {
return getLongChannelIdFromChannelName(channelName);
}
};
function getLongChannelIdFromShortChannelId (channelName, channelId) { function getLongChannelIdFromShortChannelId (channelName, channelId) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logger.debug(`finding long channel id for ${channelName}:${channelId}`); logger.debug(`finding long channel id for ${channelName}:${channelId}`);
@ -61,125 +51,28 @@ function getLongChannelIdFromChannelName (channelName) {
}); });
} }
function getClaimIdByLongChannelId (channelId, claimName) { function sortResult (result, longId) {
return new Promise((resolve, reject) => { let claimIndex;
logger.debug(`finding claim id for claim "${claimName}" from channel "${channelId}"`); let shortId = longId.substring(0, 1); // default sort id is the first letter
db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${claimName}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) let shortIdLength = 0;
.then(result => { // find the index of this certificate
switch (result.length) { claimIndex = result.findIndex(element => {
case 0: return element.claimId === longId;
return reject(new Error('There is no such claim for that channel'));
default:
return resolve(result[0].claimId);
}
})
.catch(error => {
reject(error);
});
}); });
} if (claimIndex < 0) { throw new Error('claimid not found in possible sorted list') }
// get an array of all certificates with lower height
function getAllChannelClaims (channelId) { let possibleMatches = result.slice(0, claimIndex);
return new Promise((resolve, reject) => { // remove certificates with the same prefixes until none are left.
logger.debug(`finding all claims in channel "${channelId}"`); while (possibleMatches.length > 0) {
db.sequelize.query(`SELECT * FROM Claim WHERE certificateId = '${channelId}' ORDeR BY height DESC;`, { type: db.sequelize.QueryTypes.SELECT }) shortIdLength += 1;
.then(result => { shortId = longId.substring(0, shortIdLength);
switch (result.length) { possibleMatches = possibleMatches.filter(element => {
case 0: return (element.claimId.substring(0, shortIdLength) === shortId);
return resolve(null);
default:
return resolve(result);
}
})
.catch(error => {
reject(error);
}); });
});
}
function determineShortClaimId (claimId, height, claimList) {
logger.debug('determining short url based on claim id and claim list');
logger.debug('claimlist starting length:', claimList.length);
// remove this claim from the claim list, if it exists
claimList = claimList.filter(claim => {
return claim.claimId !== claimId;
});
logger.debug('claim list length without this claim:', claimList.length);
// If there are no other claims, return the first letter of the claim id...
if (claimList.length === 0) {
return claimId.substring(0, 1);
// ...otherwise determine the proper short id.
} else {
const claimListCopy = claimList;
let i = 0;
// find the longest shared prefix (there is a better way to do this that filters, checks next filter, then filters (i.e. combine this step and next))
while (claimList.length !== 0) {
i++;
claimList = claimList.filter(claim => {
const otherClaimIdSegmentToCompare = claim.claimId.substring(0, i);
const thisClaimIdSegmentToCompare = claimId.substring(0, i);
logger.debug('compare:', otherClaimIdSegmentToCompare, '===', thisClaimIdSegmentToCompare, '?');
return (otherClaimIdSegmentToCompare === thisClaimIdSegmentToCompare);
});
}
// use that longest shared prefix to get only those competing claims
const lastMatchIndex = i - 1;
const lastMatch = claimId.substring(0, lastMatchIndex);
logger.debug('last match index:', lastMatchIndex, 'last match:', lastMatch);
if (lastMatchIndex === 0) { // if no other claims share a prefix, return with first letter.
return claimId.substring(0, 1);
}
const allMatchingClaimsAtLastMatch = claimListCopy.filter(claim => {
return (claim.claimId.substring(0, lastMatchIndex) === lastMatch);
});
// for those that share the longest shared prefix: see which came first in time. whichever is earliest, the others take the extra character
const sortedMatchingClaims = allMatchingClaimsAtLastMatch.sort((a, b) => {
return (a.height < b.height);
});
// compare to the earliest one, if it is earlier, this claim takes the extra character
if (sortedMatchingClaims[0].height < height) {
return claimId.substring(0, lastMatchIndex + 1);
}
return claimId.substring(0, lastMatchIndex);
} }
} // return the short Id
logger.debug('short channel id ===', shortId);
function getShortChannelId (channelName, longChannelId) { return shortId;
return new Promise((resolve, reject) => {
logger.debug('finding short channel id');
db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' ORDER BY height;`, { type: db.sequelize.QueryTypes.SELECT })
.then(result => {
switch (result.length) {
case 0:
return reject(new Error('That is an invalid channel name'));
default:
let certificateIndex;
let shortId = longChannelId.substring(0, 1); // default sort id is the first letter
let shortIdLength = 0;
// find the index of this certificate
certificateIndex = result.findIndex(element => {
return element.claimId === longChannelId;
});
if (certificateIndex < 0) { throw new Error('claimid not found in possible sorted list') }
// get an array of all certificates with lower height
let possibleMatches = result.slice(0, certificateIndex);
// remove certificates with the same prefixes until none are left.
while (possibleMatches.length > 0) {
shortIdLength += 1;
shortId = longChannelId.substring(0, shortIdLength);
possibleMatches = possibleMatches.filter(element => {
return (element.claimId.substring(0, shortIdLength) === shortId);
});
}
// return the short Id
logger.debug('short channel id ===', shortId);
return resolve(shortId);
}
})
.catch(error => {
reject(error);
});
});
} }
module.exports = { module.exports = {
@ -233,18 +126,16 @@ module.exports = {
}); });
}); });
}, },
getShortIdFromClaimId (claimId, height, name) { getShortClaimIdFromLongClaimId (claimId, claimName) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logger.debug('finding short claim id from full claim id'); logger.debug('finding short channel id');
db.sequelize.query(`SELECT claimId, height FROM Claim WHERE name = '${name}' ORDER BY claimId;`, { type: db.sequelize.QueryTypes.SELECT }) db.sequelize.query(`SELECT claimId, height FROM Claim WHERE name = '${claimName}' ORDER BY height;`, { type: db.sequelize.QueryTypes.SELECT })
.then(result => { .then(result => {
switch (result.length) { switch (result.length) {
case 0: case 0:
return reject(new Error('That is an invalid claim name')); return reject(new Error('That is an invalid claim name'));
default: // note results must be sorted default:
const shortId = determineShortClaimId(claimId, height, result); return resolve(sortResult(result, claimId));
logger.debug('short claim id ===', shortId);
return resolve(shortId);
} }
}) })
.catch(error => { .catch(error => {
@ -302,47 +193,60 @@ module.exports = {
}); });
}); });
}, },
getClaimIdByChannel (channelName, channelId, claimName) { getClaimIdByLongChannelId (channelId, claimName) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 1. get the long channel id logger.debug(`finding claim id for claim "${claimName}" from channel "${channelId}"`);
getLongChannelId(channelName, channelId) db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${claimName}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT })
// 2. get the claim Id .then(result => {
.then(longChannelId => { switch (result.length) {
return getClaimIdByLongChannelId(longChannelId, claimName); case 0:
}) return reject(new Error('There is no such claim for that channel'));
.then(claimId => { default:
return resolve(claimId); return resolve(result[0].claimId);
}
}) })
.catch(error => { .catch(error => {
reject(error); reject(error);
}); });
}); });
}, },
getChannelContents (channelName, channelId) { getAllChannelClaims (channelId) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let longChannelId; logger.debug(`finding all claims in channel "${channelId}"`);
let shortChannelId; db.sequelize.query(`SELECT * FROM Claim WHERE certificateId = '${channelId}' ORDeR BY height DESC;`, { type: db.sequelize.QueryTypes.SELECT })
// 1. get the long channel Id
getLongChannelId(channelName, channelId)
// 2. get all claims for that channel
.then(result => { .then(result => {
longChannelId = result; switch (result.length) {
return getShortChannelId(channelName, longChannelId); case 0:
}) return resolve(null);
.then(result => { default:
shortChannelId = result; return resolve(result);
return getAllChannelClaims(longChannelId); }
}) })
.then(allChannelClaims => { .catch(error => {
if (allChannelClaims) { reject(error);
allChannelClaims.forEach(element => { });
element['channelName'] = channelName; });
element['longChannelId'] = longChannelId; },
element['shortChannelId'] = shortChannelId; getLongChannelId (channelName, channelId) {
element['fileExtension'] = element.contentType.substring(element.contentType.lastIndexOf('/') + 1); if (channelId && (channelId.length === 40)) { // full channel id
}); return new Promise((resolve, reject) => resolve(channelId));
} else if (channelId && channelId.length < 40) { // short channel id
return getLongChannelIdFromShortChannelId(channelName, channelId);
} else {
return getLongChannelIdFromChannelName(channelName);
}
},
getShortChannelIdFromLongChannelId (channelName, longChannelId) {
return new Promise((resolve, reject) => {
logger.debug('finding short channel id');
db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' ORDER BY height;`, { type: db.sequelize.QueryTypes.SELECT })
.then(result => {
switch (result.length) {
case 0:
return reject(new Error('That is an invalid channel name'));
default:
return resolve(sortResult(result, longChannelId));
} }
return resolve(allChannelClaims);
}) })
.catch(error => { .catch(error => {
reject(error); reject(error);

View file

@ -1,8 +1,6 @@
const logger = require('winston'); const logger = require('winston');
const { serveFile, showFile, showFileLite, getShortIdFromClaimId, resolveAgainstClaimTable, getChannelContents } = require('../helpers/serveHelpers.js'); const { getAssetByShortId, getAssetByClaimId, getAssetByName, getChannelContents, getAssetByChannel, serveOrShowAsset } = require('../controllers/serveController.js');
const { getAssetByChannel, getAssetByShortId, getAssetByClaimId, getAssetByName } = require('../controllers/serveController.js');
const { handleRequestError } = require('../helpers/errorHandlers.js'); const { handleRequestError } = require('../helpers/errorHandlers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const SERVE = 'SERVE'; const SERVE = 'SERVE';
const SHOW = 'SHOW'; const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE'; const SHOWLITE = 'SHOWLITE';
@ -27,48 +25,6 @@ function getAsset (claimType, channelName, channelId, shortId, fullClaimId, name
} }
} }
function serveOrShowAsset (fileInfo, extension, method, headers, originalUrl, ip, res) {
// add file extension to the file info
if (extension === '.gifv') {
fileInfo['fileExt'] = '.gifv';
} else {
fileInfo['fileExt'] = fileInfo.fileName.substring(fileInfo.fileName.lastIndexOf('.'));
}
// serve or show
switch (method) {
case SERVE:
serveFile(fileInfo, res);
sendGoogleAnalytics(method, headers, ip, originalUrl);
postToStats('serve', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
case SHOWLITE:
showFileLite(fileInfo, res);
postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
case SHOW:
return getShortIdFromClaimId(fileInfo.claimId, fileInfo.height, fileInfo.name)
.then(shortId => {
fileInfo['shortId'] = shortId;
return resolveAgainstClaimTable(fileInfo.name, fileInfo.claimId);
})
.then(resolveResult => {
logger.debug('resolve result', resolveResult);
fileInfo['title'] = resolveResult.title;
fileInfo['description'] = resolveResult.description;
showFile(fileInfo, res);
postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
return fileInfo;
})
.catch(error => {
console.log('thowing error...');
throw error;
});
default:
logger.error('I did not recognize that method');
break;
}
}
function isValidClaimId (claimId) { function isValidClaimId (claimId) {
return ((claimId.length === 40) && !/[^A-Za-z0-9]/g.test(claimId)); return ((claimId.length === 40) && !/[^A-Za-z0-9]/g.test(claimId));
} }