cleaned up errors and updated build scripts

This commit is contained in:
bill bittner 2018-07-31 16:43:08 -07:00
parent dc558e9b9c
commit 60ffe5de95
28 changed files with 139 additions and 127 deletions

View file

@ -1,6 +1,5 @@
node_modules/
exports/
index.js
test/
server/render/build
client/build client/build
node_modules/
public/bundle
server/render/build
test/

2
.gitignore vendored
View file

@ -16,4 +16,6 @@ config/siteConfig.json
public/bundle/bundle.js public/bundle/bundle.js
public/bundle/bundle.js.map public/bundle/bundle.js.map
public/bundle/Lekton-*
public/bundle/style.css

View file

@ -2,15 +2,30 @@
This repo packages the spee.ch server for use with spee.ch implementations. This repo packages the spee.ch server for use with spee.ch implementations.
### Quick start ### Quick start
To get started running your own version of spee.ch, visit [lbryio/www.spee.ch](https://github.com/lbryio/www.spee.ch)
### Install Install dependencies
``` ```
npm install spee.ch --save npm install
```
create config file
```
npm run configure
```
build from source code
```
npm run transpile
```
create client bundle with webpack
```
npm run bundle
```
start the sever
```
npm run start
``` ```
### Dependenceis ### System dependencies
Make sure the following are installed Spee.ch relies on the following programs being installed on your server:
* [imagemagick](https://www.imagemagick.org/script/download.php) * [imagemagick](https://www.imagemagick.org/script/download.php)
* [ffmpeg](https://www.ffmpeg.org/download.html) * [ffmpeg](https://www.ffmpeg.org/download.html)
@ -19,6 +34,7 @@ Make sure the following are installed
* `index.js` is the entry point for the server. It creates the [express app](https://expressjs.com/), requires the routes, syncs the database, and starts the server listening on the `PORT` designated in the config file. * `index.js` is the entry point for the server. It creates the [express app](https://expressjs.com/), requires the routes, syncs the database, and starts the server listening on the `PORT` designated in the config file.
* the `server/routes` folder contains all of the routes for the express app * the `server/routes` folder contains all of the routes for the express app
* the `server/models` folder contains all of the models which the app uses to interact with the `mysql` database. Note: this app uses the [sequelize](http://docs.sequelizejs.com/) ORM. * the `server/models` folder contains all of the models which the app uses to interact with the `mysql` database. Note: this app uses the [sequelize](http://docs.sequelizejs.com/) ORM.
* the `client/` folder contains all of the client code
## Tests ## Tests
* This package uses `mocha` with `chai` for testing. * This package uses `mocha` with `chai` for testing.

View file

@ -166,7 +166,7 @@ inquirer
}) })
.then(() => { .then(() => {
console.log('\nYou\'re all done!'); console.log('\nYou\'re all done!');
console.log('Next step: run "npm run start:dev" to start your server!'); console.log('Next step: run "npm run build" to build your server, then "npm run start" to start your server!');
console.log('If you want to change any settings, you can edit the files in the "/config" folder.'); console.log('If you want to change any settings, you can edit the files in the "/config" folder.');
process.exit(0); process.exit(0);
}) })

View file

@ -4,4 +4,4 @@ import { onHandleShowPageUri } from './show';
export default { export default {
onHandleShowPageUri, onHandleShowPageUri,
} };

View file

@ -4,16 +4,16 @@ import {
updateChannelAvailability, updateChannelAvailability,
updateChannelCreateName, updateChannelCreateName,
updateChannelCreatePassword, updateChannelCreatePassword,
createChannel createChannel,
} from '../../actions/channelCreate'; } from '../../actions/channelCreate';
const mapStateToProps = ({channelCreate: {name, password, error, status }}) => { const mapStateToProps = ({channelCreate: { name, password, error, status }}) => {
return { return {
name, name,
password, password,
error, error,
status, status,
} };
}; };
const mapDispatchToProps = { const mapDispatchToProps = {

View file

@ -4,4 +4,4 @@ import { handleShowPageUri } from './show_uri';
export default { export default {
rootSaga, rootSaga,
handleShowPageUri, handleShowPageUri,
} };

View file

@ -4,24 +4,26 @@
"description": "an npm package that exports a customizeable spee.ch server", "description": "an npm package that exports a customizeable spee.ch server",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"bundle": "webpack --config webpack.config.js",
"bundle:dev": "webpack --config webpack.config.js --watch",
"configure": "node cli/configure.js",
"fix": "eslint . --fix",
"lint": "eslint .",
"precommit": "eslint .",
"start": "npm run server",
"start:dev": "builder concurrent transpile:dev bundle:dev bundle:dev",
"server": "node server.js",
"server:dev": "nodemon server.js",
"test": "mocha --recursive", "test": "mocha --recursive",
"test:no-lbc": "npm test -- --grep @usesLbc --invert", "test:no-lbc": "npm test -- --grep @usesLbc --invert",
"lint": "eslint .", "transpile": "builder concurrent transpile:server transpile:client transpile:client_custom",
"fix": "eslint . --fix", "transpile:dev": "builder concurrent transpile:server:dev transpile:client:dev transpile:client_custom:dev",
"precommit": "eslint .",
"build": "builder concurrent transpile:server transpile:client transpile:client_custom webpack",
"build:dev": "builder concurrent transpile:server:dev transpile:client:dev transpile:client_custom:dev webpack:dev",
"start": "node server.js",
"start:dev": "builder concurrent build:dev server:dev",
"server:dev": "nodemon server.js",
"transpile:server": "babel server/render/src -d server/render/build", "transpile:server": "babel server/render/src -d server/render/build",
"transpile:server:dev": "babel server/render/src -w -d server/render/build", "transpile:server:dev": "babel server/render/src -w -d server/render/build",
"transpile:client": "babel client/src -d client/build", "transpile:client": "babel client/src -d client/build",
"transpile:client:dev": "babel client/src -w -d client/build", "transpile:client:dev": "babel client/src -w -d client/build",
"transpile:client_custom": "babel client_custom/src -d client_custom/build", "transpile:client_custom": "babel client_custom/src -d client_custom/build",
"transpile:client_custom:dev": "babel client_custom/src -w -d client_custom/build", "transpile:client_custom:dev": "babel client_custom/src -w -d client_custom/build"
"webpack": "webpack --config webpack.config.js",
"webpack:dev": "webpack --config webpack.config.js --watch"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -21,9 +21,9 @@ try {
} }
try { try {
const SpeechServer = require('./server'); const Server = require('./server/index.js');
const server = new SpeechServer(); const speech = new Server();
server.start(); speech.start();
} catch (error) { } catch (error) {
console.log('server startup error:', error); console.log('server startup error:', error);
process.exit(1); process.exit(1);

View file

@ -9,7 +9,7 @@ const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
*/ */
function addAtSymbolIfNecessary (name) { function addAtSymbolIfNecessary (name) {
if (name.substring(0,1) !== '@') { if (name.substring(0, 1) !== '@') {
return `@${name}`; return `@${name}`;
} }
return name; return name;
@ -22,12 +22,12 @@ const channelAvailability = ({ ip, originalUrl, params: { name } }, res) => {
.then(isAvailable => { .then(isAvailable => {
let responseObject = { let responseObject = {
success: true, success: true,
data: isAvailable, data : isAvailable,
}; };
if (isAvailable) { if (isAvailable) {
responseObject['message'] = `${name} is available` responseObject['message'] = `${name} is available`;
} else { } else {
responseObject['message'] = `${name} is already in use` responseObject['message'] = `${name} is already in use`;
} }
res.status(200).json(responseObject); res.status(200).json(responseObject);
sendGATimingEvent('end-to-end', 'channel name availability', name, gaStartTime, Date.now()); sendGATimingEvent('end-to-end', 'channel name availability', name, gaStartTime, Date.now());

View file

@ -1,6 +1,5 @@
const { handleErrorResponse } = require('../../../utils/errorHandlers.js'); const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
const getChannelClaims = require('./getChannelClaims.js'); const getChannelClaims = require('./getChannelClaims.js');
const logger = require('winston');
const NO_CHANNEL = 'NO_CHANNEL'; const NO_CHANNEL = 'NO_CHANNEL';

View file

@ -18,7 +18,7 @@ const channelData = ({ ip, originalUrl, body, params }, res) => {
.then(data => { .then(data => {
res.status(200).json({ res.status(200).json({
success: true, success: true,
data data,
}); });
}) })
.catch(error => { .catch(error => {

View file

@ -14,12 +14,12 @@ const claimAvailability = ({ ip, originalUrl, params: { name } }, res) => {
.then(isAvailable => { .then(isAvailable => {
let responseObject = { let responseObject = {
success: true, success: true,
data: isAvailable, data : isAvailable,
}; };
if (isAvailable) { if (isAvailable) {
responseObject['message'] = `That claim name is available` responseObject['message'] = `That claim name is available`;
} else { } else {
responseObject['message'] = `That url is already in use` responseObject['message'] = `That url is already in use`;
} }
res.status(200).json(responseObject); res.status(200).json(responseObject);
sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now()); sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now());

View file

@ -16,12 +16,12 @@ const claimData = ({ ip, originalUrl, body, params }, res) => {
if (!claimInfo) { if (!claimInfo) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: 'No claim could be found' message: 'No claim could be found',
}); });
} }
res.status(200).json({ res.status(200).json({
success: true, success: true,
data: claimInfo data : claimInfo,
}); });
}) })
.catch(error => { .catch(error => {

View file

@ -28,8 +28,8 @@ const claimGet = ({ ip, originalUrl, params }, res) => {
}) })
.then(() => { .then(() => {
const fileData = createFileRecordDataAfterGet(resolveResult, getResult); const fileData = createFileRecordDataAfterGet(resolveResult, getResult);
const upsertCriteria = { name, claimId}; const upsertCriteria = { name, claimId };
return db.upsert(db.File, fileData, upsertCriteria, 'File') return db.upsert(db.File, fileData, upsertCriteria, 'File');
}) })
.then(() => { .then(() => {
const { message, completed } = getResult; const { message, completed } = getResult;

View file

@ -35,7 +35,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
if (disabled) { if (disabled) {
return res.status(503).json({ return res.status(503).json({
success: false, success: false,
message: disabledMessage message: disabledMessage,
}); });
} }
// define variables // define variables
@ -58,14 +58,15 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
checkClaimAvailability(name), checkClaimAvailability(name),
createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId), createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId),
createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw), createThumbnailPublishParams(thumbnailFilePath, name, license, nsfw),
]) ]);
}) })
.then(([ claimAvailable, publishParams, thumbnailPublishParams ]) => { .then(([ claimAvailable, publishParams, thumbnailPublishParams ]) => {
if (!claimAvailable) { if (!claimAvailable) {
throw { const error = {
name: CLAIM_TAKEN, name : CLAIM_TAKEN,
message: 'That claim name is already taken' message: 'That claim name is already taken',
}; };
throw error;
} }
// publish the thumbnail, if one exists // publish the thumbnail, if one exists
if (thumbnailPublishParams) { if (thumbnailPublishParams) {
@ -91,7 +92,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
sendGATimingEvent('end-to-end', 'publish', fileType, gaStartTime, Date.now()); sendGATimingEvent('end-to-end', 'publish', fileType, gaStartTime, Date.now());
}) })
.catch(error => { .catch(error => {
if (error.name = CLAIM_TAKEN) { if (error.name === CLAIM_TAKEN) {
res.status(400).json({ res.status(400).json({
success: false, success: false,
message: error.message, message: error.message,

View file

@ -5,7 +5,7 @@ const { publishing: {
thumbnailChannelId, thumbnailChannelId,
additionalClaimAddresses, additionalClaimAddresses,
disabled, disabled,
disabledMessage disabledMessage,
} } = require('@config/siteConfig'); } } = require('@config/siteConfig');
/* /*
@ -22,7 +22,7 @@ const publishingConfig = (req, res) => {
thumbnailChannelId, thumbnailChannelId,
additionalClaimAddresses, additionalClaimAddresses,
disabled, disabled,
disabledMessage disabledMessage,
}); });
}; };

View file

@ -6,7 +6,6 @@ const getOEmbedDataForAsset = require('./getOEmbedDataForAsset');
const parseSpeechUrl = require('./parseSpeechUrl'); const parseSpeechUrl = require('./parseSpeechUrl');
const getOEmbedData = (req, res) => { const getOEmbedData = (req, res) => {
const { query: { url, format } } = req; const { query: { url, format } } = req;
logger.debug('req url', url); logger.debug('req url', url);
logger.debug('req format', format); logger.debug('req format', format);
@ -20,7 +19,7 @@ const getOEmbedData = (req, res) => {
({ claimName } = lbryUri.parseClaim(paramTwo)); ({ claimName } = lbryUri.parseClaim(paramTwo));
} else { } else {
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(paramOne)); ({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(paramOne));
if (!isChannel ) { if (!isChannel) {
({ claimName } = lbryUri.parseClaim(paramOne)); ({ claimName } = lbryUri.parseClaim(paramOne));
} }
} }
@ -28,11 +27,11 @@ const getOEmbedData = (req, res) => {
if (isChannel && !paramTwo) { if (isChannel && !paramTwo) {
getOEmbedDataForChannel(channelName, channelClaimId) getOEmbedDataForChannel(channelName, channelClaimId)
.then(data => { .then(data => {
if (format === 'xml'){ if (format === 'xml') {
return res.status(503).json({ return res.status(503).json({
success: false, success: false,
message: 'xml format is not implemented yet', message: 'xml format is not implemented yet',
}) });
} else { } else {
return res.status(200).json(data); return res.status(200).json(data);
} }
@ -42,16 +41,15 @@ const getOEmbedData = (req, res) => {
success: false, success: false,
message: error, message: error,
}); });
}) });
} else { } else {
getOEmbedDataForAsset(channelName, channelClaimId, claimName, claimId) getOEmbedDataForAsset(channelName, channelClaimId, claimName, claimId)
.then(data => { .then(data => {
if (format === 'xml'){ if (format === 'xml') {
return res.status(503).json({ return res.status(503).json({
success: false, success: false,
message: 'xml format is not implemented yet', message: 'xml format is not implemented yet',
}) });
} else { } else {
return res.status(200).json(data); return res.status(200).json(data);
} }
@ -61,7 +59,7 @@ const getOEmbedData = (req, res) => {
success: false, success: false,
message: error, message: error,
}); });
}) });
} }
}; };

View file

@ -9,7 +9,7 @@ const db = require('../../../models');
const getTorList = (req, res) => { const getTorList = (req, res) => {
db.Tor.refreshTable() db.Tor.refreshTable()
.then( result => { .then(result => {
logger.debug('number of records', result.length); logger.debug('number of records', result.length);
res.status(200).json(result); res.status(200).json(result);
}) })
@ -18,7 +18,7 @@ const getTorList = (req, res) => {
res.status(500).json({ res.status(500).json({
success: false, success: false,
error, error,
}) });
}); });
}; };

View file

@ -40,11 +40,9 @@ const serveByClaim = (req, res) => {
getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res); getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
sendGAServeEvent(headers, ip, originalUrl); sendGAServeEvent(headers, ip, originalUrl);
} catch (error) { } catch (error) {
return res.status(400).json({success: false, message: error.message}); return res.status(400).json({success: false, message: error.message});
} }
}; };
module.exports = serveByClaim; module.exports = serveByClaim;

View file

@ -41,11 +41,9 @@ const serverByIdentifierAndClaim = (req, res) => {
getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res); getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
sendGAServeEvent(headers, ip, originalUrl); sendGAServeEvent(headers, ip, originalUrl);
} catch (error) { } catch (error) {
return res.status(400).json({success: false, message: error.message}); return res.status(400).json({success: false, message: error.message});
} }
}; };
module.exports = serverByIdentifierAndClaim; module.exports = serverByIdentifierAndClaim;

View file

@ -2,7 +2,7 @@ const logout = (req, res) => {
req.logout(); req.logout();
const responseObject = { const responseObject = {
success: true, success: true,
message: 'you successfully logged out' message: 'you successfully logged out',
}; };
res.status(200).json(responseObject); res.status(200).json(responseObject);
}; };

View file

@ -1,7 +1,7 @@
const user = (req, res) => { const user = (req, res) => {
const responseObject = { const responseObject = {
success: true, success: true,
data: req.user, data : req.user,
}; };
res.status(200).json(responseObject); res.status(200).json(responseObject);
}; };

View file

@ -73,8 +73,8 @@ function Server () {
// initialize passport // initialize passport
app.use(cookieSession({ app.use(cookieSession({
name : 'session', name: 'session',
keys : [sessionKey], keys: [sessionKey],
})); }));
app.use(speechPassport.initialize()); app.use(speechPassport.initialize());
app.use(speechPassport.session()); app.use(speechPassport.session());
@ -82,11 +82,11 @@ function Server () {
// configure handlebars & register it with express app // configure handlebars & register it with express app
const viewsPath = Path.resolve(process.cwd(), 'node_modules/spee.ch/server/views'); const viewsPath = Path.resolve(process.cwd(), 'node_modules/spee.ch/server/views');
app.engine('handlebars', expressHandlebars({ app.engine('handlebars', expressHandlebars({
async: false, async : false,
dataType: 'text', dataType : 'text',
defaultLayout: 'embed', defaultLayout: 'embed',
partialsDir: Path.join(viewsPath, '/partials'), partialsDir : Path.join(viewsPath, '/partials'),
layoutsDir: Path.join(viewsPath, '/layouts') layoutsDir : Path.join(viewsPath, '/layouts'),
})); }));
app.set('views', viewsPath); app.set('views', viewsPath);
app.set('view engine', 'handlebars'); app.set('view engine', 'handlebars');
@ -110,7 +110,7 @@ function Server () {
this.server.listen(PORT, () => { this.server.listen(PORT, () => {
logger.info(`Server is listening on PORT ${PORT}`); logger.info(`Server is listening on PORT ${PORT}`);
resolve(); resolve();
}) });
}); });
}; };
this.syncDatabase = () => { this.syncDatabase = () => {
@ -118,7 +118,7 @@ function Server () {
return createDatabaseIfNotExists() return createDatabaseIfNotExists()
.then(() => { .then(() => {
db.sequelize.sync(); db.sequelize.sync();
}) });
}; };
this.performChecks = () => { this.performChecks = () => {
if (!performChecks) { if (!performChecks) {
@ -130,7 +130,7 @@ function Server () {
]) ])
.then(([walletBalance]) => { .then(([walletBalance]) => {
logger.info('Starting LBC balance:', walletBalance); logger.info('Starting LBC balance:', walletBalance);
}) });
}; };
this.performUpdates = () => { this.performUpdates = () => {
if (!performUpdates) { if (!performUpdates) {
@ -144,7 +144,7 @@ function Server () {
.then(([updatedBlockedList, updatedTorList]) => { .then(([updatedBlockedList, updatedTorList]) => {
logger.info('Blocked list updated, length:', updatedBlockedList.length); logger.info('Blocked list updated, length:', updatedBlockedList.length);
logger.info('Tor list updated, length:', updatedTorList.length); logger.info('Tor list updated, length:', updatedTorList.length);
}) });
}; };
this.start = () => { this.start = () => {
this.initialize(); this.initialize();
@ -158,14 +158,14 @@ function Server () {
return Promise.all([ return Promise.all([
this.performChecks(), this.performChecks(),
this.performUpdates(), this.performUpdates(),
]) ]);
}) })
.then(() => { .then(() => {
logger.info('Spee.ch startup is complete'); logger.info('Spee.ch startup is complete');
}) })
.catch(error => { .catch(error => {
if (error.code === 'ECONNREFUSED') { if (error.code === 'ECONNREFUSED') {
return logger.error('Connection refused. The daemon may not be running.') return logger.error('Connection refused. The daemon may not be running.');
} else if (error.code === 'EADDRINUSE') { } else if (error.code === 'EADDRINUSE') {
return logger.error('Server could not start listening. The port is already in use.'); return logger.error('Server could not start listening. The port is already in use.');
} else if (error.message) { } else if (error.message) {

View file

@ -19,9 +19,9 @@ const sequelize = new Sequelize(database, username, password, {
host : 'localhost', host : 'localhost',
dialect : 'mysql', dialect : 'mysql',
dialectOptions: { dialectOptions: {
decimalNumbers: true decimalNumbers: true,
}, },
logging : false, logging: false,
pool : { pool : {
max : 5, max : 5,
min : 0, min : 0,

View file

@ -21,7 +21,6 @@ const getTorList = require('../../controllers/api/tor');
const getBlockedList = require('../../controllers/api/blocked'); const getBlockedList = require('../../controllers/api/blocked');
const getOEmbedData = require('../../controllers/api/oEmbed'); const getOEmbedData = require('../../controllers/api/oEmbed');
module.exports = (app) => { module.exports = (app) => {
// channel routes // channel routes
app.get('/api/channel/availability/:name', torCheckMiddleware, channelAvailability); app.get('/api/channel/availability/:name', torCheckMiddleware, channelAvailability);
@ -48,5 +47,5 @@ module.exports = (app) => {
// blocked // blocked
app.get('/api/blocked', torCheckMiddleware, getBlockedList); app.get('/api/blocked', torCheckMiddleware, getBlockedList);
// open embed // open embed
app.get('/api/oembed', torCheckMiddleware, getOEmbedData) app.get('/api/oembed', torCheckMiddleware, getOEmbedData);
}; };