diff --git a/lbryum b/lbryum index 07882aa76..65703001c 160000 --- a/lbryum +++ b/lbryum @@ -1 +1 @@ -Subproject commit 07882aa766acf296a494bd641d88397a27bea83a +Subproject commit 65703001c7f199492c0aa5ef4dc976c8fde0fad5 diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 6a03869e7..05a416b4c 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -8,9 +8,8 @@ Web UI version numbers should always match the corresponding version of LBRY App ## [Unreleased] ### Added - * - * - * + * You can now make API calls directly on the lbry module, e.g. lbry.peer_list() + * New-style API calls return promises instead of using callbacks ### Changed * diff --git a/ui/js/jsonrpc.js b/ui/js/jsonrpc.js new file mode 100644 index 000000000..5fa869a03 --- /dev/null +++ b/ui/js/jsonrpc.js @@ -0,0 +1,69 @@ +const jsonrpc = {}; + +jsonrpc.call = function (connectionString, method, params, callback, errorCallback, connectFailedCallback, timeout) { + var xhr = new XMLHttpRequest; + if (typeof connectFailedCallback !== 'undefined') { + if (timeout) { + xhr.timeout = timeout; + } + + xhr.addEventListener('error', function (e) { + connectFailedCallback(e); + }); + xhr.addEventListener('timeout', function() { + connectFailedCallback(new Error('XMLHttpRequest connection timed out')); + }) + } + xhr.addEventListener('load', function() { + var response = JSON.parse(xhr.responseText); + + if (response.error) { + if (errorCallback) { + errorCallback(response.error); + } else { + var errorEvent = new CustomEvent('unhandledError', { + detail: { + connectionString: connectionString, + method: method, + params: params, + code: response.error.code, + message: response.error.message, + data: response.error.data + } + }); + document.dispatchEvent(errorEvent) + } + } else if (callback) { + callback(response.result); + } + }); + + if (connectFailedCallback) { + xhr.addEventListener('error', function (event) { + connectFailedCallback(event); + }); + } else { + xhr.addEventListener('error', function (event) { + var errorEvent = new CustomEvent('unhandledError', { + detail: { + connectionString: connectionString, + method: method, + params: params, + code: xhr.status, + message: 'Connection to API server failed' + } + }); + document.dispatchEvent(errorEvent); + }); + } + + xhr.open('POST', connectionString, true); + xhr.send(JSON.stringify({ + 'jsonrpc': '2.0', + 'method': method, + 'params': params, + 'id': 0 + })); +}; + +export default jsonrpc; diff --git a/ui/js/lbry.js b/ui/js/lbry.js index b2729cf6a..7ac4105f3 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -1,9 +1,10 @@ import lighthouse from './lighthouse.js'; +import jsonrpc from './jsonrpc.js'; const {remote} = require('electron'); const menu = remote.require('./menu/main-menu'); -var lbry = { +let lbry = { isConnected: false, rootPath: '.', daemonConnectionString: 'http://localhost:5279/lbryapi', @@ -22,74 +23,8 @@ var lbry = { } }; -lbry.jsonrpc_call = function (connectionString, method, params, callback, errorCallback, connectFailedCallback, timeout) { - var xhr = new XMLHttpRequest; - if (typeof connectFailedCallback !== 'undefined') { - if (timeout) { - xhr.timeout = timeout; - } - - xhr.addEventListener('error', function (e) { - connectFailedCallback(e); - }); - xhr.addEventListener('timeout', function() { - connectFailedCallback(new Error('XMLHttpRequest connection timed out')); - }) - } - xhr.addEventListener('load', function() { - var response = JSON.parse(xhr.responseText); - - if (response.error) { - if (errorCallback) { - errorCallback(response.error); - } else { - var errorEvent = new CustomEvent('unhandledError', { - detail: { - connectionString: connectionString, - method: method, - params: params, - code: response.error.code, - message: response.error.message, - data: response.error.data - } - }); - document.dispatchEvent(errorEvent) - } - } else if (callback) { - callback(response.result); - } - }); - - if (connectFailedCallback) { - xhr.addEventListener('error', function (event) { - connectFailedCallback(event); - }); - } else { - xhr.addEventListener('error', function (event) { - var errorEvent = new CustomEvent('unhandledError', { - detail: { - connectionString: connectionString, - method: method, - params: params, - code: xhr.status, - message: 'Connection to API server failed' - } - }); - document.dispatchEvent(errorEvent); - }); - } - - xhr.open('POST', connectionString, true); - xhr.send(JSON.stringify({ - 'jsonrpc': '2.0', - 'method': method, - 'params': params, - 'id': 0 - })); -} - lbry.call = function (method, params, callback, errorCallback, connectFailedCallback) { - lbry.jsonrpc_call(lbry.daemonConnectionString, method, [params], callback, errorCallback, connectFailedCallback); + jsonrpc.call(lbry.daemonConnectionString, method, [params], callback, errorCallback, connectFailedCallback); } @@ -244,12 +179,10 @@ lbry.getCostInfoForName = function(name, callback, errorCallback) { }, errorCallback); } - lighthouse.getSizeForName(name, (size) => { + lighthouse.get_size_for_name(name).then((size) => { getCostWithData(name, size, callback, errorCallback); }, () => { getCostNoData(name, callback, errorCallback); - }, () => { - getCostNoData(name, callback, errorCallback); }); } @@ -329,7 +262,7 @@ lbry.getFileInfoWhenListed = function(name, callback, timeoutCallback, tryNum=0) // Calls callback with file info when it appears in the lbrynet file manager. // If timeoutCallback is provided, it will be called if the file fails to appear. - lbry.getFileStatus(name, (fileInfo) => { + lbry.file_list({name: name}).then(([fileInfo]) => { if (fileInfo) { callback(fileInfo); } else { @@ -560,4 +493,18 @@ lbry.showMenuIfNeeded = function() { sessionStorage.setItem('menuShown', chosenMenu); }; +lbry = new Proxy(lbry, { + get: function(target, name) { + if (name in target) { + return target[name]; + } + + return function(params={}) { + return new Promise((resolve, reject) => { + jsonrpc.call(lbry.connectionString, name, [params], resolve, reject, reject); + }); + }; + } +}); + export default lbry; diff --git a/ui/js/lighthouse.js b/ui/js/lighthouse.js index 6d349a3a8..a8b60f0fa 100644 --- a/ui/js/lighthouse.js +++ b/ui/js/lighthouse.js @@ -1,67 +1,64 @@ import lbry from './lbry.js'; +import jsonrpc from './jsonrpc.js'; -var lighthouse = { - _query_timeout: 5000, - _max_query_tries: 5, +const queryTimeout = 5000; +const maxQueryTries = 5; +const defaultServers = [ + 'http://lighthouse4.lbry.io:50005', + 'http://lighthouse5.lbry.io:50005', + 'http://lighthouse6.lbry.io:50005', +]; +const path = '/'; - servers: [ - 'http://lighthouse4.lbry.io:50005', - 'http://lighthouse5.lbry.io:50005', - 'http://lighthouse6.lbry.io:50005', - ], - path: '/', +let server = null; +let connectTryNum = 0; - call: function(method, params, callback, errorCallback, connectFailedCallback, timeout) { - const handleConnectFailed = function(tryNum=0) { - if (tryNum > lighthouse._max_query_tries) { - if (connectFailedCallback) { - connectFailedCallback(); - } else { - throw new Error(`Could not connect to Lighthouse server. Last server attempted: ${lighthouse.server}`); - } - } else { - lbry.call(method, params, callback, errorCallback, () => { handleConnectFailed(tryNum + 1) }, timeout); - } - } +function getServers() { + return lbry.getClientSetting('useCustomLighthouseServers') + ? lbry.getClientSetting('customLighthouseServers') + : defaultServers; +} - // Set the Lighthouse server if it hasn't been set yet, or if the current server is not in - // the current set of servers (most likely because of a settings change). - if (typeof lighthouse.server === 'undefined' || lighthouse.getServers().indexOf(lighthouse.server) == -1) { - lighthouse.chooseNewServer(); - } - - lbry.jsonrpc_call(this.server + this.path, method, params, callback, errorCallback, - () => { handleConnectFailed() }, timeout || lighthouse.query_timeout); - }, - - getServers: function() { - return lbry.getClientSetting('useCustomLighthouseServers') - ? lbry.getClientSetting('customLighthouseServers') - : lighthouse.servers; - }, - - chooseNewServer: function() { - // Randomly choose a new Lighthouse server and switch to it. If a server is already set, this - // will choose a different one (used for switching servers after a failed query). - const servers = lighthouse.getServers(); - let newServerChoices; - if (!lighthouse.server) { - newServerChoices = servers; +function call(method, params, callback, errorCallback) { + if (connectTryNum > maxQueryTries) { + if (connectFailedCallback) { + connectFailedCallback(); } else { - newServerChoices = lighthouse.getServers().slice(); - newServerChoices.splice(newServerChoices.indexOf(lighthouse.server), 1); + throw new Error(`Could not connect to Lighthouse server. Last server attempted: ${server}`); } - lighthouse.server = newServerChoices[Math.round(Math.random() * (newServerChoices.length - 1))]; - }, - - search: function(query, callback, errorCallback, connectFailedCallback, timeout) { - lighthouse.call('search', [query], callback, errorCallback, connectFailedCallback, timeout); - }, - - getSizeForName: function(name, callback, errorCallback, connectFailedCallback, timeout) { - lighthouse.call('get_size_for_name', [name], callback, errorCallback, connectFailedCallback, timeout); } -}; + /** + * Set the Lighthouse server if it hasn't been set yet, if the current server is not in current + * set of servers (most likely because of a settings change), or we're re-trying after a failed + * query. + */ + if (!server || !getServers().includes(server) || connectTryNum > 0) { + // If there's a current server, filter it out so we get a new one + const newServerChoices = server ? getServers().filter((s) => s != server) : getServers(); + server = newServerChoices[Math.round(Math.random() * (newServerChoices.length - 1))]; + } + + jsonrpc.call(server + path, method, params, (response) => { + connectTryNum = 0; + callback(response); + }, (error) => { + connectTryNum = 0; + errorCallback(error); + }, () => { + connectTryNum++; + call(method, params, callback, errorCallback); + }); +} + +const lighthouse = new Proxy({}, { + get: function(target, name) { + return function(...params) { + return new Promise((resolve, reject) => { + call(name, params, resolve, reject); + }); + }; + }, +}); export default lighthouse; diff --git a/ui/js/main.js b/ui/js/main.js index 6c8eb3634..eb5863fb1 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -9,9 +9,7 @@ lbry.showMenuIfNeeded(); var init = function() { window.lbry = lbry; - if (lbry.getClientSetting('debug')) { - window.lighthouse = lighthouse; - } + window.lighthouse = lighthouse; var canvas = document.getElementById('canvas'); if (window.sessionStorage.getItem('loaded') == 'y') { diff --git a/ui/js/page/discover.js b/ui/js/page/discover.js index e7a722c47..c01cbe75b 100644 --- a/ui/js/page/discover.js +++ b/ui/js/page/discover.js @@ -125,7 +125,7 @@ var DiscoverPage = React.createClass({ query: query, }); - lighthouse.search(query, this.searchCallback); + lighthouse.search(query).then(this.searchCallback); }, componentWillMount: function() {