diff --git a/assets/js/apitool-methods-ws.js b/assets/js/apitool-methods-ws.js index 82e64ee767..4b5be0440a 100644 --- a/assets/js/apitool-methods-ws.js +++ b/assets/js/apitool-methods-ws.js @@ -1,4 +1,4 @@ -Request("ACCOUNT METHODS"); +Request("Account Methods"); Request('account_channels', { description: "Returns information about an account's payment channels.", @@ -22,3 +22,396 @@ Request('account_currencies', { "ledger_index": "validated" } }) + +Request('account_info', { + description: "Retrieves information about an account, its activity, and its XRP balance.", + link: "account_info.html", + body: { + "id": 2, + "command": "account_info", + "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "strict": true, + "ledger_index": "current", + "queue": true + } +}) + +Request('account_objects', { + description: "Returns the raw ledger format for all objects owned by an account.", + link: "account_objects.html", + body: { + "id": 1, + "command": "account_objects", + "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "ledger_index": "validated", + "type": "state", + "limit": 10 + } +}) + +Request('account_offers', { + description: "Retrieves a list of offers made by a given account that are outstanding as of a particular ledger version.", + link: "account_offers.html", + body: { + "id": 2, + "command": "account_offers", + "account": "rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM" + } +}) + +Request('account_tx', { + description: "Retrieves a list of transactions that affected the specified account.", + link: "account_tx.html", + body: { + "id": 2, + "command": "account_tx", + "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "ledger_index_min": -1, + "ledger_index_max": -1, + "binary": false, + "limit": 2, + "forward": false + } +}) + +Request('gateway_balances', { + description: "Calculates the total balances issued by a given account, optionally excluding amounts held by operational addresses.", + link: "gateway_balances.html", + body: { + "id": "example_gateway_balances_1", + "command": "gateway_balances", + "account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q", + "strict": true, + "hotwallet": ["rKm4uWpg9tfwbVSeATv4KxDe6mpE9yPkgJ","ra7JkEzrgeKHdzKgo4EUUVBnxggY4z37kt"], + "ledger_index": "validated" + } +}) + +Request('noripple_check', { + description: "Compares an account's DefaultRipple and NoRipple flags to the recommended settings.", + link: "noripple_check.html", + body: { + "id": 0, + "command": "noripple_check", + "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "role": "gateway", + "ledger_index": "current", + "limit": 2, + "transactions": true + } +}) + +Request("Ledger Methods") + +Request('ledger', { + description: "Retrieves information about the public ledger.", + link: "ledger.html", + body: { + "id": 14, + "command": "ledger", + "ledger_index": "validated", + "full": false, + "accounts": false, + "transactions": false, + "expand": false, + "owner_funds": false + } +}) + +Request('ledger_closed', { + description: "Returns the unique identifiers of the most recently closed ledger. (This ledger is not necessarily validated and immutable yet.)", + link: "ledger_closed.html", + body: { + "id": 2, + "command": "ledger_closed" + } +}) + +Request('ledger_current', { + description: "Returns the unique identifiers of the current in-progress ledger.", + link: "ledger_closed.html", + body: { + "id": 2, + "command": "ledger_current" + } +}) + +Request('ledger_data', { + description: "Retrieves contents of the specified ledger.", + link: "ledger_data.html", + body: { + "id": 2, + "ledger_hash": "842B57C1CC0613299A686D3E9F310EC0422C84D3911E5056389AA7E5808A93C8", + "command": "ledger_data", + "limit": 5, + "binary": true + } +}) + +Request('ledger_entry', { + description: "Returns a single ledger object in its raw format.", + link: "ledger_entry.html", + body: { + "id": 3, + "command": "ledger_entry", + "type": "account_root", + "account_root": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "ledger_index": "validated" + } +}) + +Request("Transaction Methods") + +// TODO: maybe special case sign/sign_for so you can use those if you're +// connected to a local server? + +Request('submit', { + description: "Submits a transaction to the network to be confirmed and included in future ledgers.", + link: "submit.html", + body: { + "id": 3, + "command": "submit", + "tx_blob": "1200002280000000240000001E61D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA968400000000000000B732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7447304502210095D23D8AF107DF50651F266259CC7139D0CD0C64ABBA3A958156352A0D95A21E02207FCF9B77D7510380E49FF250C21B57169E14E9B4ACFD314CEDC79DDD0A38B8A681144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754" + } +}) + +Request('submit_multisigned', { + description: "Submits a multi-signed transaction to the network to be confirmed and included in future ledgers.", + link: "submit_multisigned.html", + body: { + "id": "submit_multisigned_example", + "command": "submit_multisigned", + "tx_json": { + "Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC", + "Fee": "30000", + "Flags": 262144, + "LimitAmount": { + "currency": "USD", + "issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "value": "100" + }, + "Sequence": 2, + "Signers": [{ + "Signer": { + "Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", + "SigningPubKey": "02B3EC4E5DD96029A647CFA20DA07FE1F85296505552CCAC114087E66B46BD77DF", + "TxnSignature": "30450221009C195DBBF7967E223D8626CA19CF02073667F2B22E206727BFE848FF42BEAC8A022048C323B0BED19A988BDBEFA974B6DE8AA9DCAE250AA82BBD1221787032A864E5" + } + }, { + "Signer": { + "Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v", + "SigningPubKey": "028FFB276505F9AC3F57E8D5242B386A597EF6C40A7999F37F1948636FD484E25B", + "TxnSignature": "30440220680BBD745004E9CFB6B13A137F505FB92298AD309071D16C7B982825188FD1AE022004200B1F7E4A6A84BB0E4FC09E1E3BA2B66EBD32F0E6D121A34BA3B04AD99BC1" + } + }], + "SigningPubKey": "", + "TransactionType": "TrustSet", + "hash": "BD636194C48FD7A100DE4C972336534C8E710FD008C0F3CF7BC5BF34DAF3C3E6" + } + } +}) + +Request('transaction_entry', { + description: "Retrieves information on a single transaction from a specific ledger version.", + link: "transaction_entry.html", + body: { + "id": 4, + "command": "transaction_entry", + "tx_hash": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7", + "ledger_index": 348734 + } +}) + +Request('tx', { + description: "Retrieves information on a single transaction.", + link: "tx.html", + body: { + "id": 1, + "command": "tx", + "transaction": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7", + "binary": false + } +}) + +Request('tx_history', { + description: "Retrieves some of the most recent transactions made. (DEPRECATED)", + link: "tx_history.html", + body: { + "id": 5, + "command": "tx_history", + "start": 0 + } +}) + +Request("Path and Order Book Methods") + +Request('book_offers', { + description: "Retrieves a list of offers, also known as the order book, between two currencies.", + link: "book_offers.html", + body: { + "id": 4, + "command": "book_offers", + "taker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "taker_gets": { + "currency": "XRP" + }, + "taker_pays": { + "currency": "USD", + "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B" + }, + "limit": 10 + } +}) + +Request('deposit_authorized', { + description: "Checks whether one account is authorized to send payments directly to another.", + link: "deposit_authorized.html", + body: { + "id": 1, + "command": "deposit_authorized", + "source_account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", + "destination_account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", + "ledger_index": "validated" + } +}) + +Request('path_find', { + description: "Searches for a path along which a payment can possibly be made, and periodically sends updates when the path changes over time.", + link: "path_find.html", + body: { + "id": 8, + "command": "path_find", + "subcommand": "create", + "source_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "destination_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "destination_amount": { + "value": "0.001", + "currency": "USD", + "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B" + } + } +}) + +Request('ripple_path_find', { + description: "Searches one time for a payment path.", + link: "ripple_path_find.html", + body: { + "id": 8, + "command": "ripple_path_find", + "source_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "source_currencies": [ + { + "currency": "XRP" + }, + { + "currency": "USD" + } + ], + "destination_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "destination_amount": { + "value": "0.001", + "currency": "USD", + "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B" + } + } +}) + +Request("Payment Channel Methods") + +Request('channel_authorize', { + description: "Creates a signature that can be used to redeem a specific amount of XRP from a payment channel.", + link: "channel_authorize.html", + body: { + "id": "channel_authorize_example_id1", + "command": "channel_authorize", + "channel_id": "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", + "secret": "s████████████████████████████", + "amount": "1000000" + } +}) + +Request('channel_verify', { + description: "Checks the validity of a signature that can be used to redeem a specific amount of XRP from a payment channel.", + link: "channel_verify.html", + body: { + "id": 1, + "command": "channel_verify", + "channel_id": "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", + "signature": "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064", + "public_key": "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3", + "amount": "1000000" + } +}) + +Request("Subscription Methods") + +Request('subscribe', { + description: "Requests periodic notifications from the server when certain events happen.", + link: "subscribe.html", + body: { + "id": "Example watch one account and all new ledgers", + "command": "subscribe", + "streams": ["ledger"], + "accounts": ["rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"] + } +}) + +Request('unsubscribe', { + description: "Tells the server to stop sending messages for a particular subscription or set of subscriptions.", + link: "unsubscribe.html", + body: { + "id": "Example stop watching one account and new ledgers", + "command": "unsubscribe", + "streams": ["ledger"], + "accounts": ["rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"] + } +}) + +Request("Server Info Methods") + +Request('fee', { + description: "Reports the current state of the open-ledger requirements for the transaction cost.", + link: "fee.html", + body: { + "id": "fee_websocket_example", + "command": "fee" + } +}) + +Request('server_info', { + description: "Reports a human-readable version of various information about the rippled server being queried.", + link: "server_info.html", + body: { + "id": 1, + "command": "server_info" + } +}) + +Request('server_state', { + description: "Reports a machine-readable version of various information about the rippled server being queried.", + link: "server_state.html", + body: { + "id": 1, + "command": "server_state" + } +}) + +Request("Utility Methods") + +Request('ping', { + description: "Checks that the connection is working.", + link: "ping.html", + body: { + "id": 1, + "command": "ping" + } +}) + +Request('random', { + description: "Provides a random number, which may be a useful source of entropy for clients.", + link: "random.html", + body: { + "id": 1, + "command": "random" + } +}) diff --git a/assets/js/apitool-websocket2.js b/assets/js/apitool-websocket2.js index 40c5bcb030..d4bfb34d41 100644 --- a/assets/js/apitool-websocket2.js +++ b/assets/js/apitool-websocket2.js @@ -5,11 +5,9 @@ const request_button = $('.send-request') const conn_btn = $(".connection") const stream_pause = $(".stream-pause") const stream_unpause = $(".stream-unpause") - -const GET = "GET" -const POST = "POST" -const PUT = "PUT" -const DELETE = "DELETE" +const trash_button = $(".wipe-responses") +const permalink_button = $(".permalink") +const curl_button = $(".curl") let STREAM_PAUSED = false @@ -59,17 +57,17 @@ function generate_table_of_contents() { } function make_commands_clickable() { - commandlist.children("li").click(function() { - var cmd = slugify($(this).text().trim()); + commandlist.children("li").click(function() { + var cmd = slugify($(this).text().trim()); - if (!requests[cmd]) return; + if (!requests[cmd]) return; - select_request(cmd, true); - window.location.hash = cmd; + select_request(cmd); + window.location.hash = cmd; - $(this).siblings().removeClass('selected'); - $(this).addClass('selected'); - }); + $(this).siblings().removeClass('selected'); + $(this).addClass('selected'); + }); } const cm_request = CodeMirror(request_body.get(0), { @@ -81,16 +79,17 @@ const cm_request = CodeMirror(request_body.get(0), { }) function select_request(request) { + let el if (request === undefined) { - var el = commandlist.children("li:not(.separator)").eq(0) - request = slugify(el.text()) + el = commandlist.children("li:not(.separator)").eq(0) + const request = slugify(el.text()) } else { - var el = commandlist.find("li a[href='#"+request+"']").parent() + el = commandlist.find("li a[href='#"+request+"']").parent() } $(el).siblings().removeClass('selected'); $(el).addClass('selected'); - command = requests[request]; + const command = requests[request]; if (command.description) { $(".api-method-description-wrapper .blurb").html(command.description) @@ -117,7 +116,7 @@ function select_request(request) { }; function send_request() { - if (typeof socket === "undefined" || socket.readyState !== 1) { + if (typeof socket === "undefined" || socket.readyState !== WebSocket.OPEN) { alert("Can't send request: Must be connected first!") return } @@ -136,6 +135,9 @@ function send_request() { let socket; function connect_socket() { + if (typeof socket !== "undefined" && socket.readyState < 2) { + socket.close() + } $(".connect-loader").show() const selected_server_el = $("input[name='wstool-1-connection']:checked") const conn_url = selected_server_el.val() @@ -149,9 +151,8 @@ function connect_socket() { $(".connect-loader").hide() }) socket.addEventListener('close', (event) => { - const new_conn_url = $("input[name='wstool-1-connection']:checked").val() + const new_conn_url = get_current_server() if (event.wasClean && event.originalTarget.url == new_conn_url) { - console.log("socket clean:", event, "vs", new_conn_url) conn_btn.text(selected_server_el.data("shortname") + " (Not Connected)") conn_btn.removeClass("btn-success") conn_btn.removeClass("btn-danger") @@ -162,7 +163,7 @@ function connect_socket() { } }) socket.addEventListener('error', (event) => { - const new_conn_url = $("input[name='wstool-1-connection']:checked").val() + const new_conn_url = get_current_server() if (event.originalTarget.url == new_conn_url) { console.error("socket error:", event) conn_btn.text(selected_server_el.data("shortname") + " (Failed to Connect)") @@ -216,35 +217,105 @@ function connect_socket() { }) } -handle_select_server = function(event) { +const handle_select_server = function(event) { if (typeof socket !== "undefined") { socket.close(1000) } connect_socket() response_wrapper.empty() } +function get_compressed_body() { + let compressed_body; + try { + const body_json = JSON.parse(cm_request.getValue()) + compressed_body = JSON.stringify(body_json, null, null) + } catch(e) { + // Probably invalid JSON. We'll make a permalink anyway, but we can't + // compress all the whitespace because we don't know what's escaped. We can + // assume that newlines are irrelevant because the rippled APIs don't accept + // newlines in strings anywhere + compressed_body = cm_request.getValue().replace("\n","").trim() + } + return compressed_body +} +function get_current_server() { + return $("input[name='wstool-1-connection']:checked").val() +} + +const update_permalink = function(event) { + const start_href = window.location.origin + window.location.pathname + const encoded_body = encodeURIComponent(get_compressed_body()) + const encoded_server = encodeURIComponent(get_current_server()) + + let permalink = start_href + "?server=" + encoded_server + "&req=" + encoded_body + // Future Feature: set the hash if the command matches a known method + $("#permalink-box-1").text(permalink) +} + +const update_curl = function(event) { + let body + try { + // change WS to JSON-RPC syntax + params = JSON.parse(cm_request.getValue()) + delete params.id + const method = params.command + delete params.command + const body_json = {"method":method, "params":[params]} + body = JSON.stringify(body_json, null, null) + } catch(e) { + alert("Can't provide curl format of invalid JSON syntax") + return + } + + const server = $("input[name='wstool-1-connection']:checked").data("jsonrpcurl") + + const curl_syntax = "curl -H 'Content-Type: application/json' -d '"+body+"' "+server + $("#curl-box-1").text(curl_syntax) +} + +function load_from_permalink(params) { + const server = params.get("server") + if (server) { + const server_checkbox = $("input[value='"+server+"']") + if (server_checkbox.length === 1) { + server_checkbox.prop("checked", true) + // relies on connect_socket() being run shortly thereafter + } + } + + let req_body = params.get("req") + if (req_body) { + try { + req_body_json = JSON.parse(req_body) + req_body = JSON.stringify(req_body_json, null, 2) + } catch(e) { + console.warn("Loaded request body is invalid JSON:", e) + } + cm_request.setValue(req_body) + } +} $(document).ready(function() { //wait for the Requests to be populated by another file - generate_table_of_contents(); - make_commands_clickable(); + generate_table_of_contents() + make_commands_clickable() + + const search_params = new URLSearchParams(window.location.search) if (window.location.hash) { var cmd = window.location.hash.slice(1).toLowerCase(); select_request(cmd); + } else if (search_params.has("server") || search_params.has("req")) { + load_from_permalink(search_params) } else { select_request(); } - // TODO: permalink stuff here? - // if (urlParams["base_url"]) { - // //TODO: change_base_url(urlParams["base_url"]); - // } - connect_socket() - request_button.click(send_request); + request_button.click(send_request) + $("input[name='wstool-1-connection']").click(handle_select_server) stream_pause.click((event) => { STREAM_PAUSED = true @@ -257,17 +328,10 @@ $(document).ready(function() { stream_unpause.hide() }) + trash_button.click((event) => { + response_wrapper.empty() + }) + permalink_button.click(update_permalink) + curl_button.click(update_curl) + }); - -var urlParams; -(window.onpopstate = function () { - var match, - pl = /\+/g, // Regex for replacing addition symbol with a space - search = /([^&=]+)=?([^&]*)/g, - decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, - query = window.location.search.substring(1); - - urlParams = {}; - while (match = search.exec(query)) - urlParams[decode(match[1])] = decode(match[2]); -})(); diff --git a/tool/template-websocket-api-tool.html b/tool/template-websocket-api-tool.html index 7f1dba4ce5..848c03c16b 100644 --- a/tool/template-websocket-api-tool.html +++ b/tool/template-websocket-api-tool.html @@ -61,6 +61,9 @@ + @@ -87,25 +90,25 @@