Development #287

Merged
bones7242 merged 58 commits from development into master 2017-12-11 20:53:02 +01:00
17 changed files with 374 additions and 388 deletions
Showing only changes of commit cda9efa800 - Show all commits

View file

@ -1,105 +1,8 @@
const lbryApi = require('../helpers/lbryApi.js');
const db = require('../models'); const db = require('../models');
const logger = require('winston'); const logger = require('winston');
const { serveFile, showFile, showFileLite } = require('../helpers/serveHelpers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const SERVE = 'SERVE';
const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE';
const DEFAULT_THUMBNAIL = 'https://spee.ch/assets/img/video_thumb_default.png'; const DEFAULT_THUMBNAIL = 'https://spee.ch/assets/img/video_thumb_default.png';
const NO_CHANNEL = 'NO_CHANNEL'; const NO_CHANNEL = 'NO_CHANNEL';
const NO_CLAIM = 'NO_CLAIM';
function checkForLocalAssetByClaimId (claimId, name) {
logger.debug(`checkForLocalAssetsByClaimId(${claimId}, ${name}`);
return new Promise((resolve, reject) => {
db.File
.findOne({where: { name, claimId }})
.then(result => {
if (result) {
resolve(result.dataValues);
} else {
resolve(null);
}
})
.catch(error => {
reject(error);
});
});
}
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,
outpoint,
height,
address,
fileName: '',
filePath: '',
fileType: '',
nsfw,
};
}
function getAssetByLongClaimId (fullClaimId, name) {
logger.debug('...getting asset by claim Id...');
return new Promise((resolve, reject) => {
// 1. check locally for claim
checkForLocalAssetByClaimId(fullClaimId, name)
.then(dataValues => {
// if a result was found, return early with the result
if (dataValues) {
logger.debug('found a local file for this name and claimId');
resolve(dataValues);
return;
}
logger.debug('no local file found for this name and claimId');
// 2. if no local claim, resolve and get the claim
db.Claim
.resolveClaim(name, fullClaimId)
.then(resolveResult => {
// if no result, return early (claim doesn't exist or isn't free)
if (!resolveResult) {
resolve(NO_CLAIM);
return;
}
logger.debug('resolve result >> ', resolveResult.dataValues);
let fileRecord = {};
// get the claim
lbryApi.getClaim(`${name}#${fullClaimId}`)
.then(getResult => {
logger.debug('getResult >>', getResult);
fileRecord = createFileRecord(resolveResult);
fileRecord = addGetResultsToFileRecord(fileRecord, getResult);
// insert a record in the File table & Update Claim table
return db.File.create(fileRecord);
})
.then(() => {
logger.debug('File record successfully updated');
resolve(fileRecord);
})
.catch(error => {
reject(error);
});
})
.catch(error => {
reject(error);
});
})
.catch(error => {
reject(error);
});
});
}
function chooseThumbnail (claimInfo, defaultThumbnail) { function chooseThumbnail (claimInfo, defaultThumbnail) {
if (!claimInfo.thumbnail || claimInfo.thumbnail.trim() === '') { if (!claimInfo.thumbnail || claimInfo.thumbnail.trim() === '') {
@ -109,42 +12,38 @@ function chooseThumbnail (claimInfo, defaultThumbnail) {
} }
module.exports = { module.exports = {
getAssetByClaim (claimName, claimId) { getClaimId (channelName, channelId, name, claimId) {
logger.debug(`getAssetByClaim(${claimName}, ${claimId})`); if (channelName) {
return module.exports.getClaimIdByChannel(channelName, channelId, name);
} else {
return module.exports.getClaimIdByClaim(name, claimId);
}
},
getClaimIdByClaim (claimName, claimId) {
logger.debug(`getClaimIdByClaim(${claimName}, ${claimId})`);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
db.Claim.getLongClaimId(claimName, claimId) // 1. get the long claim id db.Claim.getLongClaimId(claimName, claimId) // get the long claim id
.then(result => { // 2. get the asset using the long claim id .then(result => {
logger.debug('long claim id ===', result); resolve(result); // resolves with NO_CLAIM or valid claim id
if (result === NO_CLAIM) {
logger.debug('resolving NO_CLAIM');
resolve(NO_CLAIM);
return;
}
resolve(getAssetByLongClaimId(result, claimName));
}) })
.catch(error => { .catch(error => {
reject(error); reject(error);
}); });
}); });
}, },
getAssetByChannel (channelName, channelId, claimName) { getClaimIdByChannel (channelName, channelId, claimName) {
logger.debug('getting asset by channel'); logger.debug(`getClaimIdByChannel(${channelName}, ${channelId}, ${claimName})`);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
db.Certificate.getLongChannelId(channelName, channelId) // 1. get the long channel id db.Certificate.getLongChannelId(channelName, channelId) // 1. get the long channel id
.then(result => { // 2. get the long claim Id .then(result => {
if (result === NO_CHANNEL) { if (result === NO_CHANNEL) {
resolve(NO_CHANNEL); resolve(result); // resolves NO_CHANNEL
return; return;
} }
return db.Claim.getClaimIdByLongChannelId(result, claimName); return db.Claim.getClaimIdByLongChannelId(result, claimName); // 2. get the long claim id
}) })
.then(result => { // 3. get the asset using the long claim id .then(result => {
logger.debug('asset claim id =', result); resolve(result); // resolves with NO_CLAIM or valid claim id
if (result === NO_CHANNEL || result === NO_CLAIM) {
resolve(result);
return;
}
resolve(getAssetByLongClaimId(result, claimName));
}) })
.catch(error => { .catch(error => {
reject(error); reject(error);
@ -172,7 +71,7 @@ module.exports = {
}) })
.then(result => { // 4. add extra data not available from Claim table .then(result => { // 4. add extra data not available from Claim table
if (result === NO_CHANNEL) { if (result === NO_CHANNEL) {
resolve(NO_CHANNEL); resolve(result);
return; return;
} }
if (result) { if (result) {
@ -197,57 +96,23 @@ module.exports = {
}); });
}); });
}, },
serveOrShowAsset (fileInfo, extension, method, headers, originalUrl, ip, res) { getLocalFileRecord (claimId, name) {
// add file extension to the file info return db.File.findOne({where: {claimId, name}})
if (extension === 'gifv') { .then(file => {
fileInfo['fileExt'] = 'gifv'; if (!file) {
} else { return null;
fileInfo['fileExt'] = fileInfo.fileName.substring(fileInfo.fileName.lastIndexOf('.') + 1); }
} return file.dataValues;
// add a record to the stats table });
postToStats(method, originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success'); },
// serve or show getClaimRecord (claimId, name) {
switch (method) { return db.Claim.findOne({where: {claimId, name}})
case SERVE: .then(claim => {
serveFile(fileInfo, res); if (!claim) {
sendGoogleAnalytics(method, headers, ip, originalUrl); throw new Error('no record found in Claim table');
return fileInfo; }
case SHOWLITE: claim.dataValues.thumbnail = chooseThumbnail(claim.dataValues.thumbnail, DEFAULT_THUMBNAIL);
return db.Claim.resolveClaim(fileInfo.name, fileInfo.claimId) return claim.dataValues;
.then(claimRecord => { });
fileInfo['title'] = claimRecord.title;
fileInfo['description'] = claimRecord.description;
showFileLite(fileInfo, res);
return fileInfo;
})
.catch(error => {
logger.error('throwing serverOrShowAsset SHOWLITE error...');
throw error;
});
case SHOW:
return db.Claim
.getShortClaimIdFromLongClaimId(fileInfo.claimId, fileInfo.name)
.then(shortId => {
fileInfo['shortId'] = shortId;
return db.Claim.resolveClaim(fileInfo.name, fileInfo.claimId);
})
.then(resolveResult => {
logger.debug('resolve result >>', resolveResult.dataValues);
fileInfo['thumbnail'] = chooseThumbnail(resolveResult, DEFAULT_THUMBNAIL);
fileInfo['title'] = resolveResult.title;
fileInfo['description'] = resolveResult.description;
if (resolveResult.certificateId) { fileInfo['certificateId'] = resolveResult.certificateId };
if (resolveResult.channelName) { fileInfo['channelName'] = resolveResult.channelName };
showFile(fileInfo, res);
return fileInfo;
})
.catch(error => {
logger.error('throwing serverOrShowAsset SHOW error...');
throw error;
});
default:
logger.error('I did not recognize that method');
break;
}
}, },
}; };

View file

@ -13,10 +13,10 @@ module.exports = {
return new Handlebars.SafeString(gaCode); return new Handlebars.SafeString(gaCode);
}, },
addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) { addOpenGraph (title, mimeType, showUrl, source, description, thumbnail) {
if (title === null || title.trim() === '') { if (!title || title.trim() === '') {
title = 'Spee.ch'; title = 'Spee.ch';
} }
if (description === null || description.trim() === '') { if (!description || description.trim() === '') {
description = 'Open-source, decentralized image and video sharing.'; description = 'Open-source, decentralized image and video sharing.';
} }
const ogTitle = `<meta property="og:title" content="${title}" >`; const ogTitle = `<meta property="og:title" content="${title}" >`;

View file

@ -1,6 +1,10 @@
const logger = require('winston'); const logger = require('winston');
const SERVE = 'SERVE';
const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE';
// const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) { function createOpenGraphInfo ({ claimId, name, fileExt }) {
return { return {
embedUrl : `https://spee.ch/embed/${claimId}/${name}`, embedUrl : `https://spee.ch/embed/${claimId}/${name}`,
showUrl : `https://spee.ch/${claimId}/${name}`, showUrl : `https://spee.ch/${claimId}/${name}`,
@ -10,36 +14,50 @@ function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) {
} }
module.exports = { module.exports = {
serveFile ({ fileName, fileType, filePath }, res) { serveOrShowAsset (method, fileInfo, claimInfo, shortId, res) {
logger.verbose(`serving file ${fileName}`); // add file extension to the file info
// set default options claimInfo['fileExt'] = fileInfo.fileName.substring(fileInfo.fileName.lastIndexOf('.') + 1);
let options = { // serve or show
headers: { switch (method) {
'X-Content-Type-Options': 'nosniff', case SERVE:
'Content-Type' : fileType, module.exports.serveFile(fileInfo, claimInfo, shortId, res);
}, return fileInfo;
}; case SHOWLITE:
// adjust default options as needed module.exports.showFileLite(fileInfo, claimInfo, shortId, res);
switch (fileType) { return fileInfo;
case 'image/jpeg': case SHOW:
case 'image/gif': module.exports.showFile(fileInfo, claimInfo, shortId, res);
case 'image/png': return fileInfo;
case 'video/mp4':
break;
default: default:
logger.warn('sending file with unknown type as .jpeg'); logger.error('I did not recognize that method');
options['headers']['Content-Type'] = 'image/jpeg';
break; break;
} }
},
serveFile ({ filePath }, { claimId, name, contentType }, shortId, res) {
logger.verbose(`serving ${name}#${claimId}`);
// set response options
const headerContentType = contentType || 'image/jpeg';
const options = {
headers: {
'X-Content-Type-Options': 'nosniff',
'Content-Type' : headerContentType,
},
};
// send the file // send the file
res.status(200).sendFile(filePath, options); if (filePath) {
res.status(200).sendFile(filePath, options);
} else {
// 'get' the file
// send the file
res.status(307).redirect(`/api/get/${name}/${claimId}`);
}
}, },
showFile (fileInfo, res) { showFile (fileInfo, claimInfo, shortId, res) {
const openGraphInfo = createOpenGraphInfo(fileInfo); const openGraphInfo = createOpenGraphInfo(claimInfo);
res.status(200).render('show', { layout: 'show', fileInfo, openGraphInfo }); res.status(200).render('show', { layout: 'show', claimInfo, shortId, openGraphInfo });
}, },
showFileLite (fileInfo, res) { showFileLite (fileInfo, claimInfo, shortId, res) {
const openGraphInfo = createOpenGraphInfo(fileInfo); const openGraphInfo = createOpenGraphInfo(claimInfo);
res.status(200).render('showLite', { layout: 'showlite', fileInfo, openGraphInfo }); res.status(200).render('showLite', { layout: 'showlite', claimInfo, shortId, openGraphInfo });
}, },
}; };

View file

@ -171,10 +171,32 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
}); });
}; };
Certificate.validateLongChannelId = function (name, claimId) {
return new Promise((resolve, reject) => {
this.findOne({
where: {name, claimId},
})
.then(result => {
switch (result.length) {
case 0:
return resolve(NO_CHANNEL);
case 1:
return resolve(result[0]);
default:
logger.warn(`more than one entry matches that name (${name}) and certificate Id (${claimId})`);
return resolve(result[0]);
}
})
.catch(error => {
reject(error);
});
});
};
Certificate.getLongChannelId = function (channelName, channelId) { Certificate.getLongChannelId = function (channelName, channelId) {
logger.debug(`getLongChannelId(${channelName}, ${channelId})`); logger.debug(`getLongChannelId(${channelName}, ${channelId})`);
if (channelId && (channelId.length === 40)) { // if a full channel id is provided if (channelId && (channelId.length === 40)) { // if a full channel id is provided
return new Promise((resolve, reject) => resolve(channelId)); return this.validateLongChannelId(channelName, channelId);
} else if (channelId && channelId.length < 40) { // if a short channel id is provided } else if (channelId && channelId.length < 40) { // if a short channel id is provided
return this.getLongChannelIdFromShortChannelId(channelName, channelId); return this.getLongChannelIdFromShortChannelId(channelName, channelId);
} else { } else {

View file

@ -274,10 +274,34 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => {
}); });
}; };
Claim.validateLongClaimId = function (name, claimId) {
return new Promise((resolve, reject) => {
this.findOne({
where: {name, claimId},
})
.then(result => {
// logger.debug('validateLongClaimId result:', result.dataValues);
logger.debug('validateLongClaimId result.length:', result.dataValues.length);
switch (result.dataValues.length) {
case 0:
return resolve(NO_CLAIM);
case 1:
return resolve(claimId);
default:
logger.warn(`more than one entry matches that name (${name}) and claimID (${claimId})`);
return resolve(claimId);
}
})
.catch(error => {
reject(error);
});
});
};
Claim.getLongClaimId = function (claimName, claimId) { Claim.getLongClaimId = function (claimName, claimId) {
logger.debug(`getLongClaimId(${claimName}, ${claimId})`); logger.debug(`getLongClaimId(${claimName}, ${claimId})`);
if (claimId && (claimId.length === 40)) { // if a full claim id is provided if (claimId && (claimId.length === 40)) { // if a full claim id is provided
return new Promise((resolve, reject) => resolve(claimId)); return this.validateLongClaimId(claimName, claimId);
} else if (claimId && claimId.length < 40) { } else if (claimId && claimId.length < 40) {
return this.getLongClaimIdFromShortClaimId(claimName, claimId); // if a short claim id is provided return this.getLongClaimIdFromShortClaimId(claimName, claimId); // if a short claim id is provided
} else { } else {

View file

@ -10,6 +10,77 @@ const errorHandlers = require('../helpers/errorHandlers.js');
const { postToStats } = require('../controllers/statsController.js'); const { postToStats } = require('../controllers/statsController.js');
const { authenticateOrSkip } = require('../auth/authentication.js'); const { authenticateOrSkip } = require('../auth/authentication.js');
function addGetResultsToFileRecord (fileInfo, getResult) {
fileInfo.fileName = getResult.file_name;
fileInfo.filePath = getResult.download_path;
return fileInfo;
}
function createFileRecord ({ name, claimId, outpoint, height, address, nsfw, contentType }) {
return {
name,
claimId,
outpoint,
height,
address,
fileName: '',
filePath: '',
fileType: contentType,
nsfw,
};
}
// function getAssetByLongClaimId (fullClaimId, name) {
// logger.debug('...getting asset by claim Id...');
// return new Promise((resolve, reject) => {
// // 1. check locally for claim
// checkForLocalAssetByClaimId(fullClaimId, name)
// .then(dataValues => {
// // if a result was found, return early with the result
// if (dataValues) {
// logger.debug('found a local file for this name and claimId');
// resolve(dataValues);
// return;
// }
// logger.debug('no local file found for this name and claimId');
// // 2. if no local claim, resolve and get the claim
// db.Claim
// .resolveClaim(name, fullClaimId)
// .then(resolveResult => {
// // if no result, return early (claim doesn't exist or isn't free)
// if (!resolveResult) {
// resolve(NO_CLAIM);
// return;
// }
// logger.debug('resolve result >> ', resolveResult.dataValues);
// let fileRecord = {};
// // get the claim
// lbryApi.getClaim(`${name}#${fullClaimId}`)
// .then(getResult => {
// logger.debug('getResult >>', getResult);
// fileRecord = createFileRecord(resolveResult);
// fileRecord = addGetResultsToFileRecord(fileRecord, getResult);
// // insert a record in the File table & Update Claim table
// return db.File.create(fileRecord);
// })
// .then(() => {
// logger.debug('File record successfully updated');
// resolve(fileRecord);
// })
// .catch(error => {
// reject(error);
// });
// })
// .catch(error => {
// reject(error);
// });
// })
// .catch(error => {
// reject(error);
// });
// });
// }
module.exports = (app) => { module.exports = (app) => {
// route to run a claim_list request on the daemon // route to run a claim_list request on the daemon
app.get('/api/claim_list/:name', ({ ip, originalUrl, params }, res) => { app.get('/api/claim_list/:name', ({ ip, originalUrl, params }, res) => {
@ -27,9 +98,26 @@ module.exports = (app) => {
if (!params.name || !params.claimId) { if (!params.name || !params.claimId) {
res.status(400).json({success: false, message: 'provide a claimId and/or a name'}); res.status(400).json({success: false, message: 'provide a claimId and/or a name'});
} }
getClaim(`${params.name}#${params.claimId}`) let fileRecord;
.then(result => { // 1. resolve the claim
res.status(200).json({status: 'success', message: result}); db.Claim.resolveClaim(params.name, params.claimId)
.then(resolveResult => {
if (!resolveResult) {
throw new Error('No matching uri found in Claim table');
}
fileRecord = createFileRecord(resolveResult);
// 2. get the claim
return getClaim(`${params.name}#${params.claimId}`);
})
.then(getResult => {
res.status(200).json({status: 'success', message: getResult});
logger.debug('response was sent to the client');
fileRecord = addGetResultsToFileRecord(fileRecord, getResult);
// 3. insert a record for the claim into the File table
return db.File.create(fileRecord);
})
.then(() => {
logger.debug('File record successfully created');
}) })
.catch(error => { .catch(error => {
errorHandlers.handleApiError('get', originalUrl, ip, error, res); errorHandlers.handleApiError('get', originalUrl, ip, error, res);

View file

@ -1,12 +1,14 @@
const logger = require('winston'); const logger = require('winston');
const { getAssetByClaim, getChannelContents, getAssetByChannel, serveOrShowAsset } = require('../controllers/serveController.js'); const { getClaimId, getChannelContents, getLocalFileRecord, getClaimRecord } = require('../controllers/serveController.js');
const { serveOrShowAsset } = require('../helpers/serveHelpers.js');
const { handleRequestError } = require('../helpers/errorHandlers.js'); const { handleRequestError } = require('../helpers/errorHandlers.js');
const db = require('../models');
const SERVE = 'SERVE'; const SERVE = 'SERVE';
const SHOW = 'SHOW'; const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE'; const SHOWLITE = 'SHOWLITE';
const CHANNEL = 'CHANNEL'; // const CHANNEL = 'CHANNEL';
const CLAIM = 'CLAIM'; // const CLAIM = 'CLAIM';
const CLAIM_ID_CHAR = ':'; const CLAIM_ID_CHAR = ':';
const CHANNEL_CHAR = '@'; const CHANNEL_CHAR = '@';
const CLAIMS_PER_PAGE = 10; const CLAIMS_PER_PAGE = 10;
@ -25,17 +27,6 @@ function isValidShortIdOrClaimId (input) {
return (isValidClaimId(input) || isValidShortId(input)); return (isValidClaimId(input) || isValidShortId(input));
} }
function getAsset (claimType, channelName, channelId, name, claimId) {
switch (claimType) {
case CHANNEL:
return getAssetByChannel(channelName, channelId, name);
case CLAIM:
return getAssetByClaim(name, claimId);
default:
return new Error('that claim type was not found');
}
}
function getPage (query) { function getPage (query) {
if (query.p) { if (query.p) {
return parseInt(query.p); return parseInt(query.p);
@ -86,7 +77,6 @@ module.exports = (app) => {
app.get('/:identifier/:name', ({ headers, ip, originalUrl, params }, res) => { app.get('/:identifier/:name', ({ headers, ip, originalUrl, params }, res) => {
let identifier = params.identifier; let identifier = params.identifier;
let name = params.name; let name = params.name;
let claimOrChannel;
let channelName = null; let channelName = null;
let claimId = null; let claimId = null;
let channelId = null; let channelId = null;
@ -123,7 +113,6 @@ module.exports = (app) => {
// parse identifier for whether it is a channel, short url, or claim_id // parse identifier for whether it is a channel, short url, or claim_id
if (identifier.charAt(0) === '@') { if (identifier.charAt(0) === '@') {
channelName = identifier; channelName = identifier;
claimOrChannel = CHANNEL;
const channelIdIndex = channelName.indexOf(CLAIM_ID_CHAR); const channelIdIndex = channelName.indexOf(CLAIM_ID_CHAR);
if (channelIdIndex !== -1) { if (channelIdIndex !== -1) {
channelId = channelName.substring(channelIdIndex + 1); channelId = channelName.substring(channelIdIndex + 1);
@ -133,13 +122,11 @@ module.exports = (app) => {
} else { } else {
claimId = identifier; claimId = identifier;
logger.debug('claim id =', claimId); logger.debug('claim id =', claimId);
claimOrChannel = CLAIM;
} }
// 1. retrieve the asset and information // get the claim id
getAsset(claimOrChannel, channelName, channelId, name, claimId) getClaimId(channelName, channelId, name, claimId)
// 2. serve or show
.then(result => { .then(result => {
logger.debug('getAsset result:', result); logger.debug('getClaimId result:', result);
if (result === NO_CLAIM) { if (result === NO_CLAIM) {
res.status(200).render('noClaim'); res.status(200).render('noClaim');
return; return;
@ -147,7 +134,15 @@ module.exports = (app) => {
res.status(200).render('noChannel'); res.status(200).render('noChannel');
return; return;
} }
return serveOrShowAsset(result, fileExtension, method, headers, originalUrl, ip, res); // check for local file info and resolve the claim
return Promise.all([getLocalFileRecord(result, name), getClaimRecord(result, name), db.Claim.getShortClaimIdFromLongClaimId(result, name)]);
})
.then(([fileInfo, claimInfo, shortClaimId]) => {
logger.debug(`file record:`, fileInfo);
logger.debug('claim record:', claimInfo);
logger.debug('short url:', shortClaimId);
// serve or show
return serveOrShowAsset(method, fileInfo, claimInfo, shortClaimId, res);
}) })
// 3. update the file // 3. update the file
.then(fileInfoForUpdate => { .then(fileInfoForUpdate => {
@ -229,24 +224,34 @@ module.exports = (app) => {
} }
logger.debug('claim name = ', name); logger.debug('claim name = ', name);
logger.debug('method =', method); logger.debug('method =', method);
// 1. retrieve the asset and information // get the claim id
getAsset(CLAIM, null, null, name, null) getClaimId(null, null, name, null)
// 2. respond to the request .then(result => {
.then(result => { logger.debug('getClaimId result:', result);
logger.debug('getAsset result', result); if (result === NO_CLAIM) {
if (result === NO_CLAIM) { res.status(200).render('noClaim');
res.status(200).render('noClaim'); return;
} else { } else if (result === NO_CHANNEL) {
return serveOrShowAsset(result, fileExtension, method, headers, originalUrl, ip, res); res.status(200).render('noChannel');
} return;
}) }
// 3. update the database // check for local file info and resolve the claim
.then(fileInfoForUpdate => { return Promise.all([getLocalFileRecord(result, name), getClaimRecord(result, name), db.Claim.getShortClaimIdFromLongClaimId(result, name)]);
// if needed, this is where we would update the file })
}) .then(([fileInfo, claimInfo, shortClaimId]) => {
.catch(error => { logger.debug(`fileInfo:`, fileInfo);
handleRequestError('serve', originalUrl, ip, error, res); logger.debug('claimInfo:', claimInfo);
}); logger.debug('shortClaimId:', shortClaimId);
// serve or show
return serveOrShowAsset(method, fileInfo, claimInfo, shortClaimId, res);
})
// 3. update the file
.then(fileInfoForUpdate => {
// if needed, this is where we would update the file
})
.catch(error => {
handleRequestError('serve', originalUrl, ip, error, res);
});
} }
}); });
}; };

View file

@ -9,9 +9,9 @@
<link rel="stylesheet" href="/assets/css/general.css" type="text/css"> <link rel="stylesheet" href="/assets/css/general.css" type="text/css">
<link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css"> <link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css">
<meta property="fb:app_id" content="1371961932852223"> <meta property="fb:app_id" content="1371961932852223">
{{#unless fileInfo.nsfw}} {{#unless claimInfo.nsfw}}
{{{addTwitterCard fileInfo.fileType openGraphInfo.source openGraphInfo.embedUrl openGraphInfo.directFileUrl}}} {{{addTwitterCard claimInfo.contentType openGraphInfo.source openGraphInfo.embedUrl openGraphInfo.directFileUrl}}}
{{{addOpenGraph fileInfo.title fileInfo.fileType openGraphInfo.showUrl openGraphInfo.source fileInfo.description fileInfo.thumbnail}}} {{{addOpenGraph claimInfo.title claimInfo.contentType openGraphInfo.showUrl openGraphInfo.source claimInfo.description claimInfo.thumbnail}}}
{{/unless}} {{/unless}}
<!--google font--> <!--google font-->
<link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet">

View file

@ -9,10 +9,10 @@
<link rel="stylesheet" href="/assets/css/general.css" type="text/css"> <link rel="stylesheet" href="/assets/css/general.css" type="text/css">
<link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css"> <link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css">
<meta property="fb:app_id" content="1371961932852223"> <meta property="fb:app_id" content="1371961932852223">
{{#unless fileInfo.nsfw}} {{#unless claimInfo.nsfw}}
{{{addTwitterCard fileInfo.fileType openGraphInfo.source openGraphInfo.embedUrl openGraphInfo.directFileUrl}}} {{{addTwitterCard claimInfo.contentType openGraphInfo.source openGraphInfo.embedUrl openGraphInfo.directFileUrl}}}
{{{addOpenGraph fileInfo.title fileInfo.fileType openGraphInfo.showUrl openGraphInfo.source fileInfo.description fileInfo.thumbnail}}} {{{addOpenGraph claimInfo.title claimInfo.contentType openGraphInfo.showUrl openGraphInfo.source claimInfo.description claimInfo.thumbnail}}}
{{/unless}} {{/unless}}
<!-- google analytics --> <!-- google analytics -->
{{ googleAnalytics }} {{ googleAnalytics }}
</head> </head>

View file

@ -1,29 +1,84 @@
{{#ifConditional fileInfo.fileType '===' 'video/mp4'}} {{#ifConditional claimInfo.contentType '===' 'video/mp4'}}
{{#ifConditional fileInfo.fileExt '===' 'gifv'}} {{#ifConditional claimInfo.fileExt '===' 'gifv'}}
<video class="gifv-show" autoplay loop muted> <video class="gifv-show" autoplay loop muted>
<source src="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"> <source src="/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}">
{{!--fallback--}} {{!--fallback--}}
Your browser does not support the <code>video</code> element. Your browser does not support the <code>video</code> element.
</video> </video>
{{else}} {{else}}
<video id="video-player" class="video-show video" controls poster="{{claimInfo.thumbnail}}">
<video id="video-player" class="video-show video" controls poster="{{fileInfo.thumbnail}}"> <source src="/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}">
<source src="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"> {{!--fallback--}}
{{!--fallback--}} Your browser does not support the <code>video</code> element.
Your browser does not support the <code>video</code> element. </video>
</video> <script type="text/javascript">
<script type="text/javascript"> document.addEventListener('DOMContentLoaded', resizeVideoPlayer)
document.addEventListener('DOMContentLoaded', resizeVideoPlayer) window.addEventListener("resize", resizeVideoPlayer);
window.addEventListener("resize", resizeVideoPlayer); function resizeVideoPlayer() {
function resizeVideoPlayer() { const div = document.getElementById('video-player');
const div = document.getElementById('video-player'); const width = div.offsetWidth;
const width = div.offsetWidth; div.height = (width * 9 / 16);
div.height = (width * 9 / 16); }
}
</script> </script>
{{/ifConditional}} {{/ifConditional}}
{{else}} {{else}}
<a href="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"> <a href="/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}">
<img class="image-show" src="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}" /> <img class="image-show" src="/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}" />
</a> </a>
{{/ifConditional}} {{/ifConditional}}
<div id="asset-holder">
<div id="search-message" hidden="true">
<p>We're currently combing the blockchain for your asset!</p>
</div>
<div id="failure-message" hidden="true">
<p>Hmmm, looks like no peers have your content. How anti-social!</p>
</div>
<div id="asset" hidden="true">
</div>
</div>
<script type="text/javascript">
const getAssetFunctions = {
showAsset: function () {
const searchMessage = document.getElementById('search-message');
const asset = document.getElementById('asset');
searchMessage.hidden = true;
asset.hidden = false;
},
showFailureMessage: function (msg) {
console.log(msg);
const searchMessage = document.getElementById('search-message');
const failureMessage = document.getElementById('failure-message');
searchMessage.hidden = true;
failureMessage.hidden = false;
},
displayAsset: function(contentType, source) {
},
getAsset: function(claimName, claimId) {
console.log(`getting ${claimName}#${claimId}}`)
var uri = `/api/get/${claimName}/${claimId}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log('get returned successfully', xhr.response);
this.showAsset();
} else {
console.log('get failed:', xhr.response);
}
} else {
console.log('xhr.readyState', xhr.readyState);
this.showFailureMessage(xhr.readyState.message);
}
};
// Initiate a multipart/form-data upload
xhr.send();
},
}
</script>

View file

@ -1,28 +1,28 @@
{{#if fileInfo.channelName}} {{#if claimInfo.channelName}}
<div class="row row--padded row--wide row--no-top"> <div class="row row--padded row--wide row--no-top">
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<span class="text">Channel:</span> <span class="text">Channel:</span>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
<span class="text"><a href="/{{fileInfo.channelName}}:{{fileInfo.certificateId}}">{{fileInfo.channelName}}</a></span> <span class="text"><a href="/{{claimInfo.channelName}}:{{claimInfo.certificateId}}">{{claimInfo.channelName}}</a></span>
</div> </div>
</div> </div>
{{/if}} {{/if}}
{{#if fileInfo.description}} {{#if claimInfo.description}}
<div class="row row--padded row--wide row--no-top"> <div class="row row--padded row--wide row--no-top">
<span class="text">{{fileInfo.description}}</span> <span class="text">{{claimInfo.description}}</span>
</div> </div>
{{/if}} {{/if}}
<div class="row row--wide"> <div class="row row--wide">
<div id="show-short-link"> <div id="show-short-link">
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<a class="link--primary" href="/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"><span class="text">Link:</span></a> <a class="link--primary" href="/{{shortId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}"><span class="text">Link:</span></a>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
<div class="row row--short row--wide"> <div class="row row--short row--wide">
<div class="column column--7"> <div class="column column--7">
<div class="input-error" id="input-error-copy-short-link" hidden="true"></div> <div class="input-error" id="input-error-copy-short-link" hidden="true"></div>
<input type="text" id="short-link" class="input-disabled input-text--full-width" readonly spellcheck="false" value="https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}" onclick="select()"/> <input type="text" id="short-link" class="input-disabled input-text--full-width" readonly spellcheck="false" value="https://spee.ch/{{shortId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}" onclick="select()"/>
</div><div class="column column--1"></div><div class="column column--2"> </div><div class="column column--1"></div><div class="column column--2">
<button class="button--primary" data-elementtocopy="short-link" onclick="copyToClipboard(event)">copy</button> <button class="button--primary" data-elementtocopy="short-link" onclick="copyToClipboard(event)">copy</button>
</div> </div>
@ -36,10 +36,10 @@
<div class="row row--short row--wide"> <div class="row row--short row--wide">
<div class="column column--7"> <div class="column column--7">
<div class="input-error" id="input-error-copy-embed-text" hidden="true"></div> <div class="input-error" id="input-error-copy-embed-text" hidden="true"></div>
{{#ifConditional fileInfo.fileType '===' 'video/mp4'}} {{#ifConditional claimInfo.contentType '===' 'video/mp4'}}
<input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;video width="100%" controls poster="{{fileInfo.thumbnail}}" src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>&lt;/video>'/> <input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;video width="100%" controls poster="{{claimInfo.thumbnail}}" src="https://spee.ch/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}"/>&lt;/video>'/>
{{else}} {{else}}
<input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;img src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>'/> <input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;img src="https://spee.ch/{{claimInfo.claimId}}/{{claimInfo.name}}.{{claimInfo.fileExt}}"/>'/>
{{/ifConditional}} {{/ifConditional}}
</div><div class="column column--1"></div><div class="column column--2"> </div><div class="column column--1"></div><div class="column column--2">
<button class="button--primary" data-elementtocopy="embed-text" onclick="copyToClipboard(event)">copy</button> <button class="button--primary" data-elementtocopy="embed-text" onclick="copyToClipboard(event)">copy</button>
@ -55,10 +55,10 @@
<span class="text">Share:</span> <span class="text">Share:</span>
</div><div class="column column--7 column--med-10"> </div><div class="column column--7 column--med-10">
<div class="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap"> <div class="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap">
<a class="link--primary" target="_blank" href="https://twitter.com/intent/tweet?text=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}">twitter</a> <a class="link--primary" target="_blank" href="https://twitter.com/intent/tweet?text=https://spee.ch/{{shortId}}/{{claimInfo.name}}">twitter</a>
<a class="link--primary" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}">facebook</a> <a class="link--primary" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https://spee.ch/{{shortId}}/{{claimInfo.name}}">facebook</a>
<a class="link--primary" target="_blank" href="http://tumblr.com/widgets/share/tool?canonicalUrl=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}">tumblr</a> <a class="link--primary" target="_blank" href="http://tumblr.com/widgets/share/tool?canonicalUrl=https://spee.ch/{{shortId}}/{{claimInfo.name}}">tumblr</a>
<a class="link--primary" target="_blank" href="https://www.reddit.com/submit?url=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}&title={{fileInfo.name}}">reddit</a> <a class="link--primary" target="_blank" href="https://www.reddit.com/submit?url=https://spee.ch/{{shortId}}/{{claimInfo.name}}&title={{claimInfo.name}}">reddit</a>
</div> </div>
</div> </div>
</div> </div>
@ -73,29 +73,29 @@
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<span class="text">Name:</span> <span class="text">Name:</span>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
{{fileInfo.name}} {{claimInfo.name}}
</div> </div>
</div> </div>
<div id="show-claim-id"> <div id="show-claim-id">
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<span class="text">Claim Id:</span> <span class="text">Claim Id:</span>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
{{fileInfo.claimId}} {{claimInfo.claimId}}
</div> </div>
</div> </div>
<div id="show-claim-id"> <div id="show-claim-id">
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<span class="text">File Name:</span> <span class="text">File Name:</span>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
{{fileInfo.fileName}} {{claimInfo.fileName}}
</div> </div>
</div> </div>
<div id="show-claim-id"> <div id="show-claim-id">
<div class="column column--2 column--med-10"> <div class="column column--2 column--med-10">
<span class="text">File Type:</span> <span class="text">File Type:</span>
</div><div class="column column--8 column--med-10"> </div><div class="column column--8 column--med-10">
{{#if fileInfo.fileType}} {{#if claimInfo.contentType}}
{{fileInfo.fileType}} {{claimInfo.contentType}}
{{else}} {{else}}
unknown unknown
{{/if}} {{/if}}

View file

@ -1,91 +0,0 @@
<div id="asset-holder">
<div id="peer-info">
<p id="peer-search-placeholder">Searching for peers for this asset...</p>
<p id="peer-search-success" hidden="true">Number of peers with content:<span id="peer-number">?</span></p>
<p id="peer-search-failure" hidden="true">Unfortunately, no peers could be located with that asset</p>
</div>
<div id="asset">
<div id="video-display" hidden="true">
</div>
<div id="gifv-display" hidden="true">
</div>
<div id="gif-display" hidden="true">
</div>
<div id="static-image-display" hidden="true">
</div>
</div>
</div>
<script type="text/javascript">
const getAssetFunctions = {
showPeerListSuccess: function (numberOfPeers) {
const peerSearchPlaceholder = document.getElementById('peer-search-placeholder');
const peerSearchSuccess = document.getElementById('peer-search-success');
const peerSearchNumber = document.getElementById('peer-search-number');
peerSearchPlaceholder.hidden = true;
peerSearchSuccess.hidden = false;
peerSearchNumber.innerText = numberOfPeers;
},
showPeerListFailure: function () {
const peerSearchPlaceholder = document.getElementById('peer-search-placeholder');
const peerSearchFailure = document.getElementById('peer-search-failure');
peerSearchPlaceholder.hidden = true;
peerSearchFailure.hidden = false;
},
showAsset: function (claimName, claimId) {
},
showFailureMessage: function (msg) {
console.log(msg);
},
getAsset: function(claimName, claimId) {
console.log(`getting ${claimName}#${claimId}}`)
var uri = `/api/get/${claimName}/${claimId}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log('get returned successfully')
this.showAsset(claimName, claimId);
} else {
console.log('get failed:', xhr.response);
}
} else {
console.log('xhr.readyState', xhr.readyState);
this.showFailureMessage(xhr.readyState.message);
}
};
// Initiate a multipart/form-data upload
xhr.send();
},
getPeerList: function(claimName, claimId) {
var uri = `/api/peer_list/${claimName}/${claimId}`;
var xhr = new XMLHttpRequest();
xhr.open("GET", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log('peer list retrieved:', JSON.parse(xhr.response).message);
this.showPeerListSuccess(JSON.parse(xhr.response).message);
this.getAsset(claimName, claimId);
} else {
console.log(xhr.response);
console.log('unfortunately no peers could be found');
this.showPeerListFailure(JSON.parse(xhr.response).message);
}
} else {
console.log('xhr.readyState', xhr.readyState);
}
};
// Initiate a multipart/form-data upload
xhr.send();
}
}
getAssetFunctions.getPeerList({{fileInfo.claimName}}, {{fileInfo.claimId}})
</script>

View file

@ -1,12 +1,12 @@
<div class="row row--tall row--padded"> <div class="row row--tall row--padded">
<div class="column column--10"> <div class="column column--10">
<!-- title --> <!-- title -->
<span class="text--large">{{fileInfo.title}}</span> <span class="text--large">{{claimInfo.title}}</span>
</div> </div>
<div class="column column--5 column--sml-10 align-content-top"> <div class="column column--5 column--sml-10 align-content-top">
<!-- asset --> <!-- asset -->
<div class="row row--padded"> <div class="row row--padded">
{{> getAsset}} {{> asset}}
</div> </div>
</div><div class="column column--5 column--sml-10 align-content-top"> </div><div class="column column--5 column--sml-10 align-content-top">
<!-- details --> <!-- details -->

View file

@ -1,7 +1,7 @@
<div class="row row--tall row--padded"> <div class="row row--tall row--padded">
<div class="column column--10"> <div class="column column--10">
<!-- title --> <!-- title -->
<span class="text--large">{{fileInfo.title}}</span> <span class="text--large">{{claimInfo.title}}</span>
</div> </div>
<div class="column column--5 column--sml-10 align-content-top"> <div class="column column--5 column--sml-10 align-content-top">
<!-- asset --> <!-- asset -->

View file

@ -1,2 +0,0 @@
{{> getAsset }}
<a class="link--primary fine-print" href="/{{fileInfo.claimId}}/{{fileInfo.name}}">hosted via spee&lt;h</a>

View file

@ -0,0 +1,2 @@
{{> asset }}
<a class="link--primary fine-print" href="/{{claimInfo.claimId}}/{{claimInfo.name}}">hosted via spee&lt;h</a>

View file

@ -1,2 +1,2 @@
{{> asset }} {{> asset }}
<a class="link--primary fine-print" href="/{{fileInfo.claimId}}/{{fileInfo.name}}">hosted via spee&lt;h</a> <a class="link--primary fine-print" href="/{{claimInfo.claimId}}/{{claimInfo.name}}">hosted via spee&lt;h</a>