From 82ab3b47b196654fde126735e7de5aec03a8e4a2 Mon Sep 17 00:00:00 2001 From: ProfessorDey Date: Thu, 30 May 2019 14:33:53 +0100 Subject: [PATCH 1/5] Added Server Response Error Handling Presently the spee.ch client will error out if it received an unexpected response, resulting in hangs and a very vague JSON parsing error. This failsafe will catch the known issue of server request size limits causing 413 responses if misconfigured, making things easier to diagnose, as well as catching any other unexpected responses cleanly. Further specific behaviours can be added to ensure administrators spend less time debugging simple configuration issues. The 413 error response should be fairly self explanatory, sufficient to not need further documentation, though adding an addendum to the README.md would aid other developers have a smooth experience. --- client/src/channels/publish.js | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/client/src/channels/publish.js b/client/src/channels/publish.js index 0a89feb4..27595986 100644 --- a/client/src/channels/publish.js +++ b/client/src/channels/publish.js @@ -23,14 +23,29 @@ export const makePublishRequestChannel = (fd, isUpdate) => { // set state change handler xhr.onreadystatechange = () => { if (xhr.readyState === 4) { - const response = JSON.parse(xhr.response); - if ((xhr.status === 200) && response.success) { - emitter({success: response}); - emitter(END); - } else { - emitter({error: new Error(response.message)}); - emitter(END); - } + switch (xhr.status) { + case 413: + emitter({error: new Error("Unfortunately it appears this web server " + + "has been misconfigured, please inform the service administrators " + + "that they must set their nginx/apache request size maximums higher " + + "than their file size limits.")}); + emitter(END); + break; + case 200: + var response = JSON.parse(xhr.response); + if (response.success) { + emitter({success: response}); + emitter(END); + } else { + emitter({error: new Error(response.message)}); + emitter(END); + } + break; + default: + emitter({error: new Error("Received an unexpected response from " + + "server: " + xhr.status)}); + emitter(END); + } } }; // open and send From dee61b5b6f98f4c02764d756b15a7184ff8152b6 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 30 May 2019 14:57:47 -0400 Subject: [PATCH 2/5] fix: abandoning claims Confirmed working locally. File/claims table has outpoint. Claim was abandoned by the sdk. --- client/src/api/assetApi.js | 26 +++++++++---------- client/src/sagas/abandon.js | 14 +++++----- server/controllers/api/claim/abandon/index.js | 20 +++++++------- server/lbrynet/index.js | 9 ++++--- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/client/src/api/assetApi.js b/client/src/api/assetApi.js index 0750b572..2c8779b1 100644 --- a/client/src/api/assetApi.js +++ b/client/src/api/assetApi.js @@ -1,6 +1,6 @@ import Request from '../utils/request'; -export function getLongClaimId (host, name, modifier) { +export function getLongClaimId(host, name, modifier) { let body = {}; // create request params if (modifier) { @@ -13,40 +13,40 @@ export function getLongClaimId (host, name, modifier) { } body['claimName'] = name; const params = { - method : 'POST', + method: 'POST', headers: { 'Content-Type': 'application/json' }, - body : JSON.stringify(body), + body: JSON.stringify(body), }; // create url const url = `${host}/api/claim/long-id`; // return the request promise return Request(url, params); -}; +} -export function getShortId (host, name, claimId) { +export function getShortId(host, name, claimId) { const url = `${host}/api/claim/short-id/${claimId}/${name}`; return Request(url); -}; +} -export function getClaimData (host, name, claimId) { +export function getClaimData(host, name, claimId) { const url = `${host}/api/claim/data/${name}/${claimId}`; return Request(url); -}; +} -export function checkClaimAvailability (claim) { +export function checkClaimAvailability(claim) { const url = `/api/claim/availability/${claim}`; return Request(url); } -export function getClaimViews (claimId) { +export function getClaimViews(claimId) { const url = `/api/claim/views/${claimId}`; return Request(url); } -export function doAbandonClaim (claimId) { +export function doAbandonClaim(outpoint) { const params = { - method : 'POST', - body : JSON.stringify({claimId}), + method: 'POST', + body: JSON.stringify({ outpoint }), headers: new Headers({ 'Content-Type': 'application/json', }), diff --git a/client/src/sagas/abandon.js b/client/src/sagas/abandon.js index db290274..51f73d15 100644 --- a/client/src/sagas/abandon.js +++ b/client/src/sagas/abandon.js @@ -5,17 +5,19 @@ import { updatePublishStatus, clearFile } from '../actions/publish'; import { removeAsset } from '../actions/show'; import { doAbandonClaim } from '../api/assetApi'; -function * abandonClaim (action) { +function* abandonClaim(action) { const { claimData, history } = action.data; - const { claimId } = claimData; + const { outpoint } = claimData; - const confirm = window.confirm('Are you sure you want to abandon this claim? This action cannot be undone.'); + const confirm = window.confirm( + 'Are you sure you want to abandon this claim? This action cannot be undone.' + ); if (!confirm) return; yield put(updatePublishStatus(publishStates.ABANDONING, 'Your claim is being abandoned...')); try { - yield call(doAbandonClaim, claimId); + yield call(doAbandonClaim, outpoint); } catch (error) { return console.log('abandon error:', error.message); } @@ -25,6 +27,6 @@ function * abandonClaim (action) { return history.push('/'); } -export function * watchAbandonClaim () { +export function* watchAbandonClaim() { yield takeLatest(actions.ABANDON_CLAIM, abandonClaim); -}; +} diff --git a/server/controllers/api/claim/abandon/index.js b/server/controllers/api/claim/abandon/index.js index 08a6505f..f808cd2e 100644 --- a/server/controllers/api/claim/abandon/index.js +++ b/server/controllers/api/claim/abandon/index.js @@ -9,28 +9,28 @@ const authenticateUser = require('../publish/authentication.js'); */ const claimAbandon = async (req, res) => { - const {claimId} = req.body; - const {user} = req; + const { outpoint } = req.body; + const { user } = req; try { const [channel, claim] = await Promise.all([ authenticateUser(user.channelName, null, null, user), - db.Claim.findOne({where: {claimId}}), + db.Claim.findOne({ where: { outpoint } }), ]); if (!claim) throw new Error('That channel does not exist'); - if (!channel.channelName) throw new Error('You don\'t own this channel'); + if (!channel.channelName) throw new Error("You don't own this channel"); - await abandonClaim({claimId}); - const file = await db.File.findOne({where: {claimId}}); + await abandonClaim({ outpoint }); + const file = await db.File.findOne({ where: { outpoint } }); await Promise.all([ deleteFile(file.filePath), - db.File.destroy({where: {claimId}}), - db.Claim.destroy({where: {claimId}}), + db.File.destroy({ where: { outpoint } }), + db.Claim.destroy({ where: { outpoint } }), ]); - logger.debug(`Claim abandoned: ${claimId}`); + logger.debug(`Claim abandoned: ${outpoint}`); res.status(200).json({ success: true, - message: `Claim with id ${claimId} abandonded`, + message: `Claim with outpoint ${outpoint} abandonded`, }); } catch (error) { logger.error('abandon claim error:', error); diff --git a/server/lbrynet/index.js b/server/lbrynet/index.js index 1beea877..60626792 100644 --- a/server/lbrynet/index.js +++ b/server/lbrynet/index.js @@ -73,13 +73,14 @@ module.exports = { }); }); }, - async abandonClaim({ claimId }) { - logger.debug(`lbryApi >> Abandon claim "${claimId}"`); + async abandonClaim({ outpoint }) { + logger.debug(`lbryApi >> Abandon claim "${outpoint}"`); const gaStartTime = Date.now(); + const [txid, nout] = outpoint.split(':'); try { const abandon = await axios.post(lbrynetUri, { - method: 'claim_abandon', - params: { claim_id: claimId }, + method: 'stream_abandon', + params: { txid: txid, nout: Number(nout) }, }); sendGATimingEvent('lbrynet', 'abandonClaim', 'ABANDON_CLAIM', gaStartTime, Date.now()); return abandon.data; From 8a6cd2db13dc2cce141ec83e857e79631070bbe4 Mon Sep 17 00:00:00 2001 From: ProfessorDey Date: Fri, 31 May 2019 00:15:27 +0100 Subject: [PATCH 3/5] Tab Removal & Check Abstraction Per Jessop's request: https://github.com/lbryio/spee.ch/pull/1011#pullrequestreview-243975520 Corrected tabs and added the clarified abstraction to the request state check. --- client/src/channels/publish.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/src/channels/publish.js b/client/src/channels/publish.js index 27595986..87f69f67 100644 --- a/client/src/channels/publish.js +++ b/client/src/channels/publish.js @@ -22,16 +22,16 @@ export const makePublishRequestChannel = (fd, isUpdate) => { xhr.upload.addEventListener('load', onLoad); // set state change handler xhr.onreadystatechange = () => { - if (xhr.readyState === 4) { - switch (xhr.status) { - case 413: - emitter({error: new Error("Unfortunately it appears this web server " + - "has been misconfigured, please inform the service administrators " + - "that they must set their nginx/apache request size maximums higher " + - "than their file size limits.")}); - emitter(END); - break; - case 200: + if (xhr.readyState === XMLHttpRequest.DONE) { + switch (xhr.status) { + case 413: + emitter({error: new Error("Unfortunately it appears this web server " + + "has been misconfigured, please inform the service administrators " + + "that they must set their nginx/apache request size maximums higher " + + "than their file size limits.")}); + emitter(END); + break; + case 200: var response = JSON.parse(xhr.response); if (response.success) { emitter({success: response}); @@ -40,12 +40,12 @@ export const makePublishRequestChannel = (fd, isUpdate) => { emitter({error: new Error(response.message)}); emitter(END); } - break; - default: - emitter({error: new Error("Received an unexpected response from " + + break; + default: + emitter({error: new Error("Received an unexpected response from " + "server: " + xhr.status)}); - emitter(END); - } + emitter(END); + } } }; // open and send From 6992b870333167bf67ffcd73960a62ea57b255ce Mon Sep 17 00:00:00 2001 From: Jessop Breth Date: Wed, 5 Jun 2019 10:08:13 -0400 Subject: [PATCH 4/5] stops logging metrics to localdb --- server/index.js | 7 ++----- server/middleware/httpContextMiddleware.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 server/middleware/httpContextMiddleware.js diff --git a/server/index.js b/server/index.js index e3806779..87455cea 100644 --- a/server/index.js +++ b/server/index.js @@ -20,10 +20,7 @@ const { setupBlockList } = require('./utils/blockList'); const speechPassport = require('./speechPassport'); const processTrending = require('./utils/processTrending'); -const { - logMetricsMiddleware, - setRouteDataInContextMiddleware, -} = require('./middleware/logMetricsMiddleware'); +const { setRouteDataInContextMiddleware } = require('./middleware/httpContextMiddleware'); const { details: { port: PORT, blockListEndpoint }, @@ -145,7 +142,7 @@ function Server() { app[routeMethod]( routePath, - logMetricsMiddleware, + // logMetricsMiddleware, setRouteDataInContextMiddleware(routePath, routeData), ...controllers ); diff --git a/server/middleware/httpContextMiddleware.js b/server/middleware/httpContextMiddleware.js new file mode 100644 index 00000000..b41c602f --- /dev/null +++ b/server/middleware/httpContextMiddleware.js @@ -0,0 +1,13 @@ +const httpContext = require('express-http-context'); + +function setRouteDataInContextMiddleware(routePath, routeData) { + return function(req, res, next) { + httpContext.set('routePath', routePath); + httpContext.set('routeData', routeData); + next(); + }; +} + +module.exports = { + setRouteDataInContextMiddleware, +}; From 39095c16a9cfcefd4b049980c86d98208af68c58 Mon Sep 17 00:00:00 2001 From: jessop Date: Fri, 21 Jun 2019 14:40:07 -0400 Subject: [PATCH 5/5] changes max publishes to 20 --- server/middleware/autoblockPublishMiddleware.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/middleware/autoblockPublishMiddleware.js b/server/middleware/autoblockPublishMiddleware.js index 426323a1..5238280b 100644 --- a/server/middleware/autoblockPublishMiddleware.js +++ b/server/middleware/autoblockPublishMiddleware.js @@ -7,7 +7,7 @@ const { const ipBanFile = './site/config/ipBan.txt'; const forbiddenMessage = '

Forbidden

If you are seeing this by mistake, please contact us using https://chat.lbry.com/'; - +const maxPublishesInTenMinutes = 20; let ipCounts = {}; let blockedAddresses = []; @@ -44,7 +44,7 @@ const autoblockPublishMiddleware = (req, res, next) => { } }, 600000 /* 10 minute retainer */); - if (count === 10) { + if (count === maxPublishesInTenMinutes) { logger.error(`Banning IP: ${ip}`); blockedAddresses.push(ip); res.status(403).send(forbiddenMessage);