From a43836d6396ccbe5092c010fb38fe71d0432c19d Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 21 Aug 2017 13:27:13 -0700 Subject: [PATCH 01/23] added Certificate model --- models/certificate.js | 91 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 models/certificate.js diff --git a/models/certificate.js b/models/certificate.js new file mode 100644 index 00000000..702e8783 --- /dev/null +++ b/models/certificate.js @@ -0,0 +1,91 @@ +module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, ARRAY, DECIMAL, DOUBLE }) => { + const Certificate = sequelize.define( + 'Certificate', + { + address: { + type : STRING, + default: null, + }, + amount: { + type : STRING, + default: null, + }, + claimId: { + type : STRING, + default: null, + }, + claimSequence: { + type : INTEGER, + default: null, + }, + decodedClaim: { + type : BOOLEAN, + default: null, + }, + depth: { + type : INTEGER, + default: null, + }, + effectiveAmount: { + type : STRING, + default: null, + }, + hasSignature: { + type : BOOLEAN, + default: null, + }, + height: { + type : STRING, + default: null, + }, + hex: { + type : TEXT('long'), + default: null, + }, + name: { + type : STRING, + default: null, + }, + nout: { + type : INTEGER, + default: null, + }, + txid: { + type : STRING, + default: null, + }, + validAtHeight: { + type : STRING, + default: null, + }, + outpoint: { + type : STRING, + default: null, + }, + valueVersion: { + type : STRING, + default: null, + }, + claimType: { + type : STRING, + default: null, + }, + certificateVersion: { + type : STRING, + default: null, + }, + keyType: { + type : STRING, + default: null, + }, + publicKey: { + type : TEXT('long'), + default: null, + }, + }, + { + freezeTableName: true, + } + ); + return Certificate; +}; -- 2.45.3 From 28ab926ef9238762451345b827ba36e32560e2f8 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 21 Aug 2017 18:03:57 -0700 Subject: [PATCH 02/23] added support for channel with full id --- controllers/serveController.js | 25 ++++++++++++++++--------- helpers/serveHelpers.js | 18 ++++++++++++++++++ routes/serve-routes.js | 33 ++++++++++++++++++++------------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/controllers/serveController.js b/controllers/serveController.js index fe1ed0a6..88a7fb78 100644 --- a/controllers/serveController.js +++ b/controllers/serveController.js @@ -1,7 +1,7 @@ const lbryApi = require('../helpers/lbryApi.js'); const db = require('../models'); const logger = require('winston'); -const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable } = require('../helpers/serveHelpers.js'); +const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable, getClaimIdByChannelId } = require('../helpers/serveHelpers.js'); function checkForLocalAssetByClaimId (claimId, name) { return new Promise((resolve, reject) => { @@ -82,14 +82,21 @@ function getAssetByClaimId (fullClaimId, name) { } module.exports = { - getAssetByChannel (channelName, name) { - logger.debug('...getting asset by channel...'); - return new Promise((resolve, reject) => { - // temporarily throw error - reject(new Error('channel names are not currently supported')); - // get the claim id - // get the asset by claim Id - }); + getAssetByChannel (channelName, channelId, name) { + if (channelId) { + return new Promise((resolve, reject) => { + getClaimIdByChannelId(channelId, name) + .then(claimId => { + logger.debug('claim id = ', claimId); + resolve(getAssetByClaimId(claimId, name)); + }) + .catch(error => { + reject(error); + }); + }); + } else { + return new Error('this is not supported yet'); + } }, getAssetByShortId: function (shortId, name) { logger.debug('...getting asset by short id...'); diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index 188cf915..356b314c 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -127,6 +127,24 @@ module.exports = { }); }); }, + getClaimIdByChannelId (channelId, name) { + return new Promise((resolve, reject) => { + logger.debug('finding claim id from channel id'); + db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${name}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + switch (result.length) { + case 0: + return reject(new Error('That is an invalid Channel Id')); + default: // note results must be sorted + logger.debug('found result', result); + return resolve(result[0].claimId); + } + }) + .catch(error => { + reject(error); + }); + }); + }, getAllFreeClaims (name) { return new Promise((resolve, reject) => { db.sequelize.query(`SELECT * FROM Claim WHERE name = '${name}' ORDER BY amount DESC, height ASC`, { type: db.sequelize.QueryTypes.SELECT }) diff --git a/routes/serve-routes.js b/routes/serve-routes.js index cfbab943..94a3509e 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -7,19 +7,20 @@ const SERVE = 'SERVE'; const SHOW = 'SHOW'; const SHOWLITE = 'SHOWLITE'; const CHANNEL = 'CHANNEL'; -const SHORTURL = 'SHORTURL'; -const CLAIMID = 'CLAIMID'; -const NAME = 'NAME'; +const CLAIM_ID_SHORT = 'CLAIM_ID_SHORT'; +const CLAIM_ID_LONG = 'CLAIM_ID_LONG'; +const CLAIM_NAME = 'CLAIM_NAME'; +const CHANNELID_INDICATOR = ':'; -function getAsset (claimType, channelName, shortId, fullClaimId, name) { +function getAsset (claimType, channelName, channelId, shortId, fullClaimId, name) { switch (claimType) { case CHANNEL: - return getAssetByChannel(channelName, name); - case SHORTURL: + return getAssetByChannel(channelName, channelId, name); + case CLAIM_ID_SHORT: return getAssetByShortId(shortId, name); - case CLAIMID: + case CLAIM_ID_LONG: return getAssetByClaimId(fullClaimId, name); - case NAME: + case CLAIM_NAME: return getAssetByName(name); default: return new Error('that claim type was not found'); @@ -89,6 +90,7 @@ module.exports = (app) => { let channelName = null; let shortId = null; let fullClaimId = null; + let channelId = null; let method; let extension; // parse the name @@ -121,24 +123,29 @@ module.exports = (app) => { logger.debug('method =', method); // parse identifier for whether it is a channel, short url, or claim_id if (identifier.charAt(0) === '@') { - channelName = identifier.substring(1); + channelName = identifier; logger.debug('channel name =', channelName); claimType = CHANNEL; + const channelIdIndex = channelName.indexOf(CHANNELID_INDICATOR); + if (channelIdIndex !== -1) { + channelId = channelName.substring(channelIdIndex + 1); + channelName = channelName.substring(0, channelIdIndex); + } } else if (identifier.length === 40) { fullClaimId = identifier; logger.debug('full claim id =', fullClaimId); - claimType = CLAIMID; + claimType = CLAIM_ID_LONG; } else if (identifier.length < 40) { shortId = identifier; logger.debug('short claim id =', shortId); - claimType = SHORTURL; + claimType = CLAIM_ID_SHORT; } else { logger.error('The URL provided could not be parsed'); res.send('that url is invalid'); return; }; // 1. retrieve the asset and information - getAsset(claimType, channelName, shortId, fullClaimId, name) + getAsset(claimType, channelName, channelId, shortId, fullClaimId, name) // 2. serve or show .then(fileInfo => { logger.debug('fileInfo', fileInfo); @@ -179,7 +186,7 @@ module.exports = (app) => { logger.debug('claim name = ', name); logger.debug('method =', method); // 1. retrieve the asset and information - getAsset(NAME, null, null, null, name) + getAsset(CLAIM_NAME, null, null, null, name) // 2. serve or show .then(fileInfo => { if (!fileInfo) { -- 2.45.3 From ccc54b8197c1bc4e7f4a8faa49b431f4c43594f3 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 22 Aug 2017 07:20:44 -0700 Subject: [PATCH 03/23] fixed /:name missing arg error --- routes/serve-routes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/serve-routes.js b/routes/serve-routes.js index 94a3509e..7a851103 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -186,7 +186,7 @@ module.exports = (app) => { logger.debug('claim name = ', name); logger.debug('method =', method); // 1. retrieve the asset and information - getAsset(CLAIM_NAME, null, null, null, name) + getAsset(CLAIM_NAME, null, null, null, null, name) // 2. serve or show .then(fileInfo => { if (!fileInfo) { -- 2.45.3 From 5078d4e906f1363eb68216f0687d6da0e6a27ebc Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 22 Aug 2017 15:50:20 -0700 Subject: [PATCH 04/23] added support for partial channel names --- controllers/serveController.js | 33 ++++---- helpers/serveHelpers.js | 133 ++++++++++++++++++++++++++++----- routes/serve-routes.js | 2 +- 3 files changed, 132 insertions(+), 36 deletions(-) diff --git a/controllers/serveController.js b/controllers/serveController.js index 88a7fb78..3f6d010c 100644 --- a/controllers/serveController.js +++ b/controllers/serveController.js @@ -1,7 +1,7 @@ const lbryApi = require('../helpers/lbryApi.js'); const db = require('../models'); const logger = require('winston'); -const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable, getClaimIdByChannelId } = require('../helpers/serveHelpers.js'); +const { getTopFreeClaim, getFullClaimIdFromShortId, resolveAgainstClaimTable, getClaimIdByChannel } = require('../helpers/serveHelpers.js'); function checkForLocalAssetByClaimId (claimId, name) { return new Promise((resolve, reject) => { @@ -82,21 +82,18 @@ function getAssetByClaimId (fullClaimId, name) { } module.exports = { - getAssetByChannel (channelName, channelId, name) { - if (channelId) { - return new Promise((resolve, reject) => { - getClaimIdByChannelId(channelId, name) - .then(claimId => { - logger.debug('claim id = ', claimId); - resolve(getAssetByClaimId(claimId, name)); - }) - .catch(error => { - reject(error); - }); + getAssetByChannel (channelName, channelId, claimName) { + logger.debug('channelId =', channelId); + return new Promise((resolve, reject) => { + getClaimIdByChannel(channelName, channelId) + .then(claimId => { + logger.debug('claim id = ', claimId); + resolve(getAssetByClaimId(claimId, claimName)); + }) + .catch(error => { + reject(error); }); - } else { - return new Error('this is not supported yet'); - } + }); }, getAssetByShortId: function (shortId, name) { logger.debug('...getting asset by short id...'); @@ -138,4 +135,10 @@ module.exports = { }); }); }, + getChannelByName (name) { + logger.debug('...getting channel by channel name...'); + return new Promise((resolve, reject) => { + reject(new Error('This feature is not yet supported')); + }); + }, }; diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index 356b314c..914d27f6 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -1,6 +1,101 @@ const logger = require('winston'); const db = require('../models'); +// function determineShortChannelId (name, longChannelId) { +// return new Promise((resolve, reject) => { +// logger.debug('finding short channel id'); +// db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${name}' 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 claim id ===', shortId); +// return resolve(shortId); +// } +// }) +// .catch(error => { +// reject(error); +// }); +// }); +// } + +function getLongChannelId (channelName, channelId) { + if (channelId && (channelId.length === 40)) { // full channel id + return channelId; + } else if (channelId && channelId.length < 40) { // short channel id + return getLongChannelIdFromShortChannelId(channelName, channelId); + } else { + return getChannelIdFromChannelName(channelName); + } +}; + +function getClaimIdByLongChannelId (channelId, name) { + return new Promise((resolve, reject) => { + logger.debug('finding claim id from channel id and claim name'); + db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${name}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + switch (result.length) { + case 0: + return reject(new Error('There is no such claim for that channel')); + default: + return resolve(result[0].claimId); + } + }) + .catch(error => { + reject(error); + }); + }); +} + +function getLongChannelIdFromShortChannelId (channelName, channelId) { + return new Promise((resolve, reject) => { + logger.debug(`finding long channel id for ${channelName}:${channelId}`); + // get the long channel Id + db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' AND claimId LIKE '${channelId}%' ORDER BY height ASC LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + logger.debug('result >>', result); + switch (result.length) { + case 0: + throw new Error('That is an invalid Short Channel Id'); + default: // note results must be sorted + return (result[0].claimId); + } + }) + // return the long channel id + .then(longChannelId => { + logger.debug('channelId =', longChannelId); + return resolve(longChannelId); + }) + .catch(error => { + reject(error); + }); + }); +} + +function getChannelIdFromChannelName (channelName, claimName) { + // select the top top channel id +} + function determineShortClaimId (claimId, height, claimList) { logger.debug('determining short url based on claim id and claim list'); logger.debug('claimlist starting length:', claimList.length); @@ -98,7 +193,7 @@ module.exports = { .then(result => { switch (result.length) { case 0: - return reject(new Error('That is an invalid Short Id')); + return reject(new Error('That is an invalid Short Claim Id')); default: // note results must be sorted return resolve(result[0].claimId); } @@ -115,7 +210,7 @@ module.exports = { .then(result => { switch (result.length) { case 0: - return reject(new Error('That is an invalid Claim Id')); + return reject(new Error('That is an invalid claim name')); default: // note results must be sorted const shortId = determineShortClaimId(claimId, height, result); logger.debug('short claim id ===', shortId); @@ -127,24 +222,6 @@ module.exports = { }); }); }, - getClaimIdByChannelId (channelId, name) { - return new Promise((resolve, reject) => { - logger.debug('finding claim id from channel id'); - db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${name}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) - .then(result => { - switch (result.length) { - case 0: - return reject(new Error('That is an invalid Channel Id')); - default: // note results must be sorted - logger.debug('found result', result); - return resolve(result[0].claimId); - } - }) - .catch(error => { - reject(error); - }); - }); - }, getAllFreeClaims (name) { return new Promise((resolve, reject) => { db.sequelize.query(`SELECT * FROM Claim WHERE name = '${name}' ORDER BY amount DESC, height ASC`, { type: db.sequelize.QueryTypes.SELECT }) @@ -195,4 +272,20 @@ module.exports = { }); }); }, + getClaimIdByChannel (channelName, channelId, claimName) { + return new Promise((resolve, reject) => { + // 1. get the long channel id + getLongChannelId(channelName, channelId) + // 2. get the claim Id + .then(longChannelId => { + return getClaimIdByLongChannelId(longChannelId, claimName); + }) + .then(claimId => { + return resolve(claimId); + }) + .catch(error => { + reject(error); + }); + }); + }, }; diff --git a/routes/serve-routes.js b/routes/serve-routes.js index 7a851103..d21de474 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -124,13 +124,13 @@ module.exports = (app) => { // parse identifier for whether it is a channel, short url, or claim_id if (identifier.charAt(0) === '@') { channelName = identifier; - logger.debug('channel name =', channelName); claimType = CHANNEL; const channelIdIndex = channelName.indexOf(CHANNELID_INDICATOR); if (channelIdIndex !== -1) { channelId = channelName.substring(channelIdIndex + 1); channelName = channelName.substring(0, channelIdIndex); } + logger.debug('channel name =', channelName); } else if (identifier.length === 40) { fullClaimId = identifier; logger.debug('full claim id =', fullClaimId); -- 2.45.3 From 994b3c6ce42cf45871e963433f6682e1d19b0159 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 22 Aug 2017 16:14:42 -0700 Subject: [PATCH 05/23] fixed issue with getClaimIdByLongChannelId --- controllers/serveController.js | 2 +- helpers/serveHelpers.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/serveController.js b/controllers/serveController.js index 3f6d010c..b781a521 100644 --- a/controllers/serveController.js +++ b/controllers/serveController.js @@ -85,7 +85,7 @@ module.exports = { getAssetByChannel (channelName, channelId, claimName) { logger.debug('channelId =', channelId); return new Promise((resolve, reject) => { - getClaimIdByChannel(channelName, channelId) + getClaimIdByChannel(channelName, channelId, claimName) .then(claimId => { logger.debug('claim id = ', claimId); resolve(getAssetByClaimId(claimId, claimName)); diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index 914d27f6..ffd02642 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -49,10 +49,10 @@ function getLongChannelId (channelName, channelId) { } }; -function getClaimIdByLongChannelId (channelId, name) { +function getClaimIdByLongChannelId (channelId, claimName) { return new Promise((resolve, reject) => { - logger.debug('finding claim id from channel id and claim name'); - db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${name}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + logger.debug(`finding claim id for claim "${claimName}" from channel "${channelId}"`); + db.sequelize.query(`SELECT claimId FROM Claim WHERE name = '${claimName}' AND certificateId = '${channelId}' LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) .then(result => { switch (result.length) { case 0: -- 2.45.3 From 00045eb696238d4fac632a40577de4e9a59239cc Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 22 Aug 2017 16:32:27 -0700 Subject: [PATCH 06/23] added support for /@exampleChannel/example.gif without identifier --- helpers/serveHelpers.js | 72 ++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index ffd02642..cc7c43c3 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -45,10 +45,51 @@ function getLongChannelId (channelName, channelId) { } else if (channelId && channelId.length < 40) { // short channel id return getLongChannelIdFromShortChannelId(channelName, channelId); } else { - return getChannelIdFromChannelName(channelName); + return getLongChannelIdFromChannelName(channelName); } }; +function getLongChannelIdFromShortChannelId (channelName, channelId) { + return new Promise((resolve, reject) => { + logger.debug(`finding long channel id for ${channelName}:${channelId}`); + // get the long channel Id + db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' AND claimId LIKE '${channelId}%' ORDER BY height ASC LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + logger.debug('result >>', result); + switch (result.length) { + case 0: + throw new Error('That is an invalid Short Channel Id'); + default: // note results must be sorted + return resolve(result[0].claimId); + } + }) + .catch(error => { + reject(error); + }); + }); +} + +function getLongChannelIdFromChannelName (channelName) { + // select the top top channel id + return new Promise((resolve, reject) => { + logger.debug(`finding long channel id for ${channelName}`); + // get the long channel Id + db.sequelize.query(`SELECT claimId, amount, height FROM Certificate WHERE name = '${channelName}' ORDER BY amount DESC, height ASC LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + logger.debug('result >>', result); + switch (result.length) { + case 0: + throw new Error('That is an invalid Channel Name'); + default: + return resolve(result[0].claimId); + } + }) + .catch(error => { + reject(error); + }); + }); +} + function getClaimIdByLongChannelId (channelId, claimName) { return new Promise((resolve, reject) => { logger.debug(`finding claim id for claim "${claimName}" from channel "${channelId}"`); @@ -67,35 +108,6 @@ function getClaimIdByLongChannelId (channelId, claimName) { }); } -function getLongChannelIdFromShortChannelId (channelName, channelId) { - return new Promise((resolve, reject) => { - logger.debug(`finding long channel id for ${channelName}:${channelId}`); - // get the long channel Id - db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' AND claimId LIKE '${channelId}%' ORDER BY height ASC LIMIT 1;`, { type: db.sequelize.QueryTypes.SELECT }) - .then(result => { - logger.debug('result >>', result); - switch (result.length) { - case 0: - throw new Error('That is an invalid Short Channel Id'); - default: // note results must be sorted - return (result[0].claimId); - } - }) - // return the long channel id - .then(longChannelId => { - logger.debug('channelId =', longChannelId); - return resolve(longChannelId); - }) - .catch(error => { - reject(error); - }); - }); -} - -function getChannelIdFromChannelName (channelName, claimName) { - // select the top top channel id -} - function determineShortClaimId (claimId, height, claimList) { logger.debug('determining short url based on claim id and claim list'); logger.debug('claimlist starting length:', claimList.length); -- 2.45.3 From ed9e7ffefd6b1007b79b20a8e906def6448b0071 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 22 Aug 2017 19:14:31 -0700 Subject: [PATCH 07/23] fix for the full channel id scenario --- helpers/serveHelpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index cc7c43c3..b59fa343 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -41,7 +41,7 @@ const db = require('../models'); function getLongChannelId (channelName, channelId) { if (channelId && (channelId.length === 40)) { // full channel id - return channelId; + return new Promise((resolve, reject) => resolve(channelId)); } else if (channelId && channelId.length < 40) { // short channel id return getLongChannelIdFromShortChannelId(channelName, channelId); } else { -- 2.45.3 From bcf0484b5b66fd292e7bb0f42712ac94d3756933 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 23 Aug 2017 10:21:31 -0700 Subject: [PATCH 08/23] fixed "Cannot read property "stream" of null" on new get requests --- controllers/serveController.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/controllers/serveController.js b/controllers/serveController.js index b781a521..980e6d36 100644 --- a/controllers/serveController.js +++ b/controllers/serveController.js @@ -20,15 +20,24 @@ function checkForLocalAssetByClaimId (claimId, name) { }); } -function formatGetResultsToFileInfo ({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) { +function addGetResultsToFileRecord (fileInfo, getResult) { + fileInfo.fileName = getResult.file_name; + fileInfo.filePath = getResult.download_path; + fileInfo.fileType = getResult.mime_type; + return fileInfo; +} + +function createFileRecord ({ name, claimId, outpoint, height, address, nsfw }) { return { name, - claimId : claim_id, + claimId, outpoint, - fileName: file_name, - filePath: download_path, - fileType: mime_type, - nsfw : metadata.stream.metadata.nsfw, + height, + address, + fileName: '', + filePath: '', + fileType: '', + nsfw, }; } @@ -57,9 +66,8 @@ function getAssetByClaimId (fullClaimId, name) { lbryApi.getClaim(`${name}#${fullClaimId}`) .then(getResult => { logger.debug('getResult >>', getResult); - fileRecord = formatGetResultsToFileInfo(getResult); - fileRecord['address'] = (resolveResult.address || 0); - fileRecord['height'] = resolveResult.height; + fileRecord = createFileRecord(resolveResult); + fileRecord = addGetResultsToFileRecord(fileRecord, getResult); // insert a record in the File table & Update Claim table return db.File.create(fileRecord); }) -- 2.45.3 From 2490d709c9282c0b0cad7fb9ade853e62065c220 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 23 Aug 2017 12:21:15 -0700 Subject: [PATCH 09/23] added basic support for /@channelname --- helpers/serveHelpers.js | 135 +++++++++++++++++++++++++------------ routes/serve-routes.js | 88 ++++++++++++++++-------- views/channel.handlebars | 32 +++++++++ views/noChannel.handlebars | 8 +++ 4 files changed, 190 insertions(+), 73 deletions(-) create mode 100644 views/channel.handlebars create mode 100644 views/noChannel.handlebars diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index b59fa343..1829d11f 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -1,43 +1,14 @@ const logger = require('winston'); const db = require('../models'); -// function determineShortChannelId (name, longChannelId) { -// return new Promise((resolve, reject) => { -// logger.debug('finding short channel id'); -// db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${name}' 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 claim id ===', shortId); -// return resolve(shortId); -// } -// }) -// .catch(error => { -// reject(error); -// }); -// }); -// } +function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) { + return { + embedUrl : `https://spee.ch/embed/${claimId}/${name}`, + showUrl : `https://spee.ch/${claimId}/${name}`, + source : `https://spee.ch/${claimId}/${name}${fileExt}`, + directFileUrl: `https://spee.ch/media/${fileName}`, + }; +} function getLongChannelId (channelName, channelId) { if (channelId && (channelId.length === 40)) { // full channel id @@ -108,6 +79,24 @@ function getClaimIdByLongChannelId (channelId, claimName) { }); } +function getAllChannelClaims (channelId) { + return new Promise((resolve, reject) => { + logger.debug(`finding all claims in channel "${channelId}"`); + db.sequelize.query(`SELECT * FROM Claim WHERE certificateId = '${channelId}' ORDeR BY height DESC;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + switch (result.length) { + case 0: + 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); @@ -155,13 +144,42 @@ function determineShortClaimId (claimId, height, claimList) { } } -function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) { - return { - embedUrl : `https://spee.ch/embed/${claimId}/${name}`, - showUrl : `https://spee.ch/${claimId}/${name}`, - source : `https://spee.ch/${claimId}/${name}${fileExt}`, - directFileUrl: `https://spee.ch/media/${fileName}`, - }; +function getShortChannelId (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: + 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 claim id ===', shortId); + return resolve(shortId); + } + }) + .catch(error => { + reject(error); + }); + }); } module.exports = { @@ -300,4 +318,33 @@ module.exports = { }); }); }, + 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 getShortChannelId(channelName, longChannelId); + }) + .then(result => { + shortChannelId = result; + return getAllChannelClaims(longChannelId); + }) + .then(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); + }); + }); + }, }; diff --git a/routes/serve-routes.js b/routes/serve-routes.js index d21de474..bbde9bac 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -1,5 +1,5 @@ const logger = require('winston'); -const { serveFile, showFile, showFileLite, getShortIdFromClaimId, resolveAgainstClaimTable } = require('../helpers/serveHelpers.js'); +const { serveFile, showFile, showFileLite, getShortIdFromClaimId, resolveAgainstClaimTable, getChannelContents } = require('../helpers/serveHelpers.js'); const { getAssetByChannel, getAssetByShortId, getAssetByClaimId, getAssetByName } = require('../controllers/serveController.js'); const { handleRequestError } = require('../helpers/errorHandlers.js'); const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); @@ -169,38 +169,68 @@ module.exports = (app) => { let name = params.name; let method; let fileExtension; - if (name.indexOf('.') !== -1) { - method = SERVE; - if (headers['accept'] && headers['accept'].split(',').includes('text/html')) { - method = SHOWLITE; + let channelName = null; + let channelId = null; + if (name.charAt(0) === '@') { + channelName = name; + const channelIdIndex = channelName.indexOf(CHANNELID_INDICATOR); + if (channelIdIndex !== -1) { + channelId = channelName.substring(channelIdIndex + 1); + channelName = channelName.substring(0, channelIdIndex); } - fileExtension = name.substring(name.indexOf('.')); - name = name.substring(0, name.indexOf('.')); - logger.debug('file extension =', fileExtension); + logger.debug('channel name =', channelName); + logger.debug('channel Id =', channelId); + // 1. retrieve the channel contents + getChannelContents(channelName, channelId) + // 2. respond to the request + .then(channelContents => { + if (!channelContents) { + res.status(200).render('noChannel'); + } else { + const handlebarsData = { + channelName, + channelContents, + }; + res.status(200).render('channel', handlebarsData); + } + }) + .catch(error => { + handleRequestError('serve', originalUrl, ip, error, res); + }); } else { - method = SHOW; - if (headers['accept'] && !headers['accept'].split(',').includes('text/html')) { + if (name.indexOf('.') !== -1) { method = SERVE; - } - } - logger.debug('claim name = ', name); - logger.debug('method =', method); - // 1. retrieve the asset and information - getAsset(CLAIM_NAME, null, null, null, null, name) - // 2. serve or show - .then(fileInfo => { - if (!fileInfo) { - res.status(200).render('noClaims'); + if (headers['accept'] && headers['accept'].split(',').includes('text/html')) { + method = SHOWLITE; + } + fileExtension = name.substring(name.indexOf('.')); + name = name.substring(0, name.indexOf('.')); + logger.debug('file extension =', fileExtension); } else { - return serveOrShowAsset(fileInfo, null, method, headers, originalUrl, ip, res); + method = SHOW; + if (headers['accept'] && !headers['accept'].split(',').includes('text/html')) { + method = SERVE; + } } - }) - // 3. update the database - .then(fileInfoForUpdate => { - // if needed, this is where we would update the file - }) - .catch(error => { - handleRequestError('serve', originalUrl, ip, error, res); - }); + logger.debug('claim name = ', name); + logger.debug('method =', method); + // 1. retrieve the asset and information + getAsset(CLAIM_NAME, null, null, null, null, name) + // 2. respond to the request + .then(fileInfo => { + if (!fileInfo) { + res.status(200).render('noClaims'); + } else { + return serveOrShowAsset(fileInfo, null, method, headers, originalUrl, ip, res); + } + }) + // 3. update the database + .then(fileInfoForUpdate => { + // if needed, this is where we would update the file + }) + .catch(error => { + handleRequestError('serve', originalUrl, ip, error, res); + }); + } }); }; diff --git a/views/channel.handlebars b/views/channel.handlebars new file mode 100644 index 00000000..44ba3b20 --- /dev/null +++ b/views/channel.handlebars @@ -0,0 +1,32 @@ +
+ {{> topBar}} +
+

{{this.channelName}}

+

Below are all the free claims in this channel.

+ {{#each channelContents}} +
+ {{#ifConditional this.fileType '===' 'video/mp4'}} + + {{else}} + + {{/ifConditional}} + +
+ +
+
+ {{/each}} +
+ {{> footer}} +
\ No newline at end of file diff --git a/views/noChannel.handlebars b/views/noChannel.handlebars new file mode 100644 index 00000000..66405b50 --- /dev/null +++ b/views/noChannel.handlebars @@ -0,0 +1,8 @@ +
+ {{> topBar}} +
+

No Claims

+

There are no free, public assets on this channel.

+

If you think this message is an error, contact us in Slack!

+
+
\ No newline at end of file -- 2.45.3 From 2a74a895c335547808fd4e75d8762675fe5deb6c Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 23 Aug 2017 12:24:51 -0700 Subject: [PATCH 10/23] fixed bug with video/mp4 not showing in channel --- views/channel.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/channel.handlebars b/views/channel.handlebars index 44ba3b20..a4435e41 100644 --- a/views/channel.handlebars +++ b/views/channel.handlebars @@ -5,7 +5,7 @@

Below are all the free claims in this channel.

{{#each channelContents}}
- {{#ifConditional this.fileType '===' 'video/mp4'}} + {{#ifConditional this.contentType '===' 'video/mp4'}}