serving static stuff

This commit is contained in:
billettc 2020-11-10 08:48:24 -05:00
parent 86727110c5
commit 5f67ae0ec1
13 changed files with 954 additions and 11 deletions

View File

@ -5,6 +5,8 @@ import (
"net"
"net/http"
"github.com/dfuse-io/solana-go/api/graphql/static"
"github.com/gorilla/handlers"
"github.com/dfuse-io/derr"
@ -55,8 +57,8 @@ func StartHTTPServer(listenAddr string, schema *graphql.Schema) error {
w.Write([]byte("ok"))
})
//staticRouter := router.PathPrefix("/").Subrouter()
//static.RegisterStaticRoutes(staticRouter)
staticRouter := router.PathPrefix("/").Subrouter()
static.RegisterStaticRoutes(staticRouter)
restRouter := router.PathPrefix("/").Subrouter()
restRouter.Use(apollo.NewMiddleware(schema).Handler)

View File

@ -0,0 +1,10 @@
This package uses https://github.com/GeertJohan/go.rice to embed the
static files within the Go binary.
Install with:
go get github.com/GeertJohan/go.rice/rice
Generate the new `rice-box.go`:
go generate

View File

@ -0,0 +1,104 @@
{
"eos": [
{
"label": "EOS - Search Stream (Forward)",
"query": "subscription ($query: String!, $cursor: String, $limit: Int64) {\n searchTransactionsForward(query: $query, limit: $limit, cursor: $cursor) {\n undo\n cursor\n trace {\n \tblock {\n \tnum\n id\n confirmed\n timestamp\n previous\n }\n id\n matchingActions {\n \taccount\n name\n json\n seq\n receiver\n }\n }\n }\n}\n",
"variables": {
"mainnet": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"cursor\": \"\",\n \"limit\": 10\n}",
"jungle": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"cursor\": \"\",\n \"limit\": 10\n}",
"kylin": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"cursor\": \"\",\n \"limit\": 10\n}",
"local": "{\n \"query\": \"action:onblock\",\n \"cursor\": \"\",\n \"limit\": 10\n}"
}
},
{
"label": "EOS - Search Query (Forward)",
"query": "query ($query: String!, $cursor: String, $limit: Int64, $low: Int64, $high: Int64) {\n searchTransactionsForward(query: $query, lowBlockNum: $low, highBlockNum: $high, limit: $limit, cursor: $cursor) {\n results {\n undo\n cursor\n trace {\n block {\n num\n id\n confirmed\n timestamp\n previous\n }\n id\n matchingActions {\n account\n name\n json\n seq\n receiver\n }\n }\n }\n }\n}\n",
"variables": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"low\": -500,\n \"high\": -1,\n \"cursor\": \"\",\n \"limit\": 10\n}"
},
{
"label": "EOS - Search Stream (Backward)",
"query": "subscription ($query: String!, $cursor: String, $limit: Int64, $low: Int64) {\n searchTransactionsBackward(query: $query, lowBlockNum: $low, limit: $limit, cursor: $cursor) {\n cursor\n trace {\n \tblock {\n \tnum\n id\n confirmed\n timestamp\n previous\n }\n id\n matchingActions {\n \taccount\n name\n json\n seq\n receiver\n }\n }\n }\n}\n",
"variables": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"cursor\": \"\",\n \"low\": 1,\n \"limit\": 10\n}"
},
{
"label": "EOS - Search Query (Backward)",
"query": "query ($query: String!, $cursor: String, $limit: Int64, $low: Int64, $high: Int64) {\n searchTransactionsBackward(query: $query, lowBlockNum: $low, highBlockNum: $high, limit: $limit, cursor: $cursor) {\n results {\n cursor\n trace {\n block {\n num\n id\n confirmed\n timestamp\n previous\n }\n id\n matchingActions {\n account\n name\n json\n seq\n receiver\n }\n }\n }\n }\n}\n",
"variables": "{\n \"query\": \"receiver:eosio.token action:transfer -data.quantity:'0.0001 EOS'\",\n \"low\": -500,\n \"high\": -1,\n \"cursor\": \"\",\n \"limit\": 10\n}"
},
{
"label": "EOS - Time Ranges",
"query": "query ($start: Time!, $end: Time!) {\n low: blockIDByTime(time: $start) {\n num\n id\n }\n high: blockIDByTime(time: $end) {\n num\n id\n }\n}\n",
"variables": "{\"start\": \"2019-11-14T12:00:00.000Z\", \"end\": \"2019-11-14T17:00:00.000Z\"}\n\n"
},
{
"label": "EOS - (Alpha) Get Block By Id",
"query": "query ($blockId: String!) {\n block(id: $blockId) {\n id\n num\n dposLIBNum\n executedTransactionCount\n irreversible\n header {\n id\n num\n timestamp\n producer\n previous\n }\n transactionTraces(first: 5) {\n pageInfo {\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n status\n topLevelActions {\n account\n name\n receiver\n json\n }\n }\n }\n }\n }\n}\n",
"variables": {
"mainnet": "{\"blockId\": \"063a7e525142f64d7465bbebc690afbb228bff7d7e0ffda31d9a06106fbc1982\"}\n",
"jungle": "{\"blockId\": \"047c7822f396e64b9cbb28cc2b199b8e5a4c33c894b8742eab646e670486bb0d\"}\n",
"kylin": "{\"blockId\": \"05609e94b57cdea5ce4ff8afa89070d37a85923855f0d41efdbd956dbaddb5f7\"}\n"
}
},
{
"label": "EOS - (Alpha) Get Block By Num",
"query": "query ($blockNum: Uint32) {\n block(num: $blockNum) {\n id\n num\n dposLIBNum\n executedTransactionCount\n irreversible\n header {\n id\n num\n timestamp\n producer\n previous\n }\n transactionTraces(first: 5) {\n pageInfo {\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n status\n topLevelActions {\n account\n name\n receiver\n json\n }\n }\n }\n }\n }\n}\n",
"variables": {
"mainnet": "{\"blockNum\": 104782163}\n",
"jungle": "{\"blockNum\": 75430834}\n",
"kylin": "{\"blockNum\": 90340699}\n"
}
},
{
"label": "EOS - (Alpha) Get Tokens",
"query": "query {\n tokens {\n blockRef {\n id\n number\n }\n pageInfo {\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n symbol\n contract\n holders\n totalSupply\n \n }\n }\n }\n}",
"variables": ""
},
{
"label": "EOS - (Alpha) Get Token Balances",
"query": "query($contract: String!,$symbol:String!,$limit:\tUint32, $opts: [ACCOUNT_BALANCE_OPTION!]) {\n tokenBalances(contract: $contract, symbol: $symbol,limit: $limit, options: $opts) {\n blockRef {\n id\n number\n }\n pageInfo {\n startCursor\n endCursor\n }\n edges {\n node {\n account\n contract\n symbol\n precision\n amount\n balance\n }\n }\n }\n}",
"variables": "{\n \"contract\": \"eosio.token\",\n \"symbol\": \"EOS\",\n \"opts\": [\"EOS_INCLUDE_STAKED\"],\n \"limit\": 10\n}"
},
{
"label": "EOS - (Alpha) Get Account Balances",
"query": "query($account: String!,$limit:\tUint32, $opts: [ACCOUNT_BALANCE_OPTION!]) {\n accountBalances(account: $account,limit: $limit, options: $opts) {\n blockRef {\n id\n number\n }\n pageInfo {\n startCursor\n endCursor\n }\n edges {\n node {\n account\n contract\n symbol\n precision\n amount\n balance\n }\n }\n }\n}",
"variables": "{\n \"account\": \"eosio.token\",\n \"opts\": [\"EOS_INCLUDE_STAKED\"],\n \"limit\": 0\n}"
}
],
"eth": [
{
"label": "ETH - Stream Search",
"query": "subscription ($query: String!, $sort: SORT, $low: Int64, $high: Int64, $limit: Int64) {\n searchTransactions(indexName: CALLS, query: $query, sort: $sort, lowBlockNum: $low, highBlockNum: $high, limit: $limit) {\n undo\n cursor\n block {\n hash\n number\n }\n node {\n hash\n from\n to\n value(encoding: ETHER)\n gasLimit\n gasPrice(encoding: ETHER)\n matchingCalls {\n from\n to\n value\n inputData\n returnData\n balanceChanges {\n address\n newValue(encoding: ETHER)\n reason\n }\n logs {\n address\n topics\n data\n }\n storageChanges {\n key\n oldValue\n newValue\n }\n }\n }\n }\n}\n",
"variables": "{\"query\": \"-value:0\",\"sort\":\"ASC\",\"low\":-1,\"limit\":10}\n"
},
{
"label": "ETH - Get Transaction",
"query": "query ($hash: String!) {\n transaction(hash: $hash) {\n hash\n from\n to\n value(encoding: ETHER)\n gasLimit\n gasPrice(encoding: ETHER)\n flatCalls {\n from\n to\n value\n inputData\n returnData\n balanceChanges {\n address\n newValue(encoding: ETHER)\n reason\n }\n logs {\n address\n topics\n data\n }\n storageChanges {\n key\n oldValue\n newValue\n }\n }\n }\n}\n",
"variables": {
"mainnet": "{\"hash\": \"df98f1f0c3e962ac829a165e0f54e35a25148d1b1322808b258e49ab66dce697\"}\n",
"ropsten": "{\"hash\": \"9c3a9d3a4634c4953b8b3b02ac22777d82d6132019c8a3ad5c5f03e7da7f8be5\"}\n"
}
},
{
"label":"ETH - Stream Blocks",
"query": "subscription {\n blocks {\n undo\n node {\n hash\n number\n transactionTraces {\n edges {\n node {\n from\n to\n flatCalls {\n callType\n depth\n }\n }\n }\n }\n }\n }\n}\n"
},
{
"label":"ETH - (Alpha) Execute",
"query": "query ($from: String!, $to: String!, $value: String, $input: String!, $gasLimit: Uint64!, $gasPrice: String!, $blockRef: BlockRef) {\n _alphaExecute(from: $from, to: $to, input: $input, gasLimit: $gasLimit, gasPrice: $gasPrice, value: $value, atBlock: $blockRef) {\n hash\n from\n to\n value(encoding: ETHER)\n gasLimit\n gasPrice(encoding: ETHER)\n flatCalls {\n from\n to\n value\n inputData\n returnData\n balanceChanges {\n address\n newValue(encoding: ETHER)\n reason\n }\n logs {\n address\n topics\n data\n }\n storageChanges {\n key\n oldValue\n newValue\n }\n }\n }\n}\n",
"alpha": true,
"variables": {
"mainnet": "{\n \"from\": \"965e553fa090e747ff6b85150ca4d8378b3c1711\",\n \"to\": \"d7b9a9b2f665849c4071ad5af77d8c76aa30fb32\",\n \"input\": \"\",\n \"value\": \"b1904d40e790c1\",\n \"gasLimit\": \"21000\",\n \"gasPrice\": \"0x8f0d1800\",\n \"blockRef\": {\n \"number\": 945754\n }\n}\n",
"ropsten": "{\n \"from\": \"d820c9EAC4E44bDc645C81a8E554A65068E20BE8\",\n \"to\": \"1056A76b5ffF557d0C70Cef64D45BDB172dBcAea\",\n \"input\": \"a6f2ae3a\",\n \"value\": \"4139c1192c560000\",\n \"gasLimit\": \"237644\",\n \"gasPrice\": \"77359400\",\n \"blockRef\": {\n \"number\": 7267470\n }\n}\n"
}
},
{
"label":"ETH - (Alpha) Replay",
"query": "query ($hash: String!, $blockRef: BlockRef) {\n _alphaReplay(hash: $hash, atBlock: $blockRef) {\n hash\n from\n to\n value(encoding: ETHER)\n gasLimit\n gasPrice(encoding: ETHER)\n block {\n number\n }\n flatCalls {\n from\n to\n value\n inputData\n returnData\n balanceChanges {\n address\n newValue(encoding: ETHER)\n reason\n }\n logs {\n address\n topics\n data\n }\n storageChanges {\n key\n oldValue\n newValue\n }\n }\n }\n}\n ",
"alpha": true,
"variables": {
"mainnet": "{\n \"hash\": \"5913720c8414ccb9d97dd1aae426146ae9fdf8794dfb9f0321f6b2a0a34eea1a\",\n \"blockRef\": {\n \"number\": 75042\n }\n}\n",
"ropsten": "{\n \"hash\": \"9c3a9d3a4634c4953b8b3b02ac22777d82d6132019c8a3ad5c5f03e7da7f8be5\",\n \"blockRef\": {\n \"number\": 7267470\n }\n}\n"
}
}
]
}

View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--
Copyright 2019 dfuse Platform Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphiql@0.16.0/graphiql.css"/>
<link rel="stylesheet" href="graphiql_dfuse_override.css"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato&display=swap">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
<script src="//unpkg.com/graphiql@0.16.0/graphiql.js"></script>
<script src="//unpkg.com/subscriptions-transport-ws@0.8.3/browser/client.js"></script>
<script src="//unpkg.com/graphiql-subscriptions-fetcher@0.0.2/browser/client.js"></script>
<script src="helper.js"></script>
<script src="https://unpkg.com/@dfuse/client@0.3.9/dist/dfuse-client.umd.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
<div id="graphiql" style="height: 100vh;">Loading...</div>
<script>
window.DfuseClientConfig = --== json . ==--;
</script>
<script>
const url = new URL(window.location.href)
const urlPathSegments = url.toString().split("/");
const queryParams = url.searchParams
const server = urlPathSegments[2];
const proto = urlPathSegments[0];
const alphaSchema = isAlphaSchemaQueryParamFound(queryParams)
async function initialize() {
loadGraphiql()
}
function loadGraphiql() {
const subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient((proto == 'https:' ? 'wss://' : 'ws://') + server + '/graphql',
{
reconnect: true,
connectionCallback: (error) => {
if (error != null) {
alert(error.message)
}
}
});
let activeQuery = fetchQueryProp(queryParams)
let activeVariables = fetchVariablesProp(queryParams)
const graphqlFetcher = graphQLFetcherFactory(queryParams)
const subscriptionsFetcher = window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphqlFetcher);
ReactDOM.render(
React.createElement(GraphiQL, {
fetcher: subscriptionsFetcher,
query: activeQuery,
variables: activeVariables,
onEditQuery: function(query) {
activeQuery = query || undefined
pushState(url, activeQuery, activeVariables)
},
onEditVariables: function(variables) {
activeVariables = variables || undefined
pushState(url, activeQuery, activeVariables)
},
}),
document.getElementById("graphiql")
);
}
initialize();
</script>
</body>
</html>

View File

@ -0,0 +1,228 @@
/**
* Copyright 2019 dfuse Platform Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.graphiql-container .topBar {
background-image: url('https://www.dfuse.io/hubfs/dfuse-graphiQL-logo-white-03-01.svg');
background-size: auto 31px;
background-repeat: no-repeat;
background-position: 10px 12px;
background-position-x: right;
height:44px;
border-bottom: 1px solid #c9cacf;
}
.graphiql-container .docExplorerShow, .graphiql-container .historyShow {
border-bottom: 1px solid #c9cacf!important;
}
.CodeMirror-linenumber {
color:#9a9ba3;
}
.graphiql-container .execute-options > li.selected, .graphiql-container .toolbar-menu-items > li.hover, .graphiql-container .toolbar-menu-items > li:active, .graphiql-container .toolbar-menu-items > li:hover, .graphiql-container .toolbar-select-options > li.hover, .graphiql-container .toolbar-select-options > li:active, .graphiql-container .toolbar-select-options > li:hover, .graphiql-container .history-contents > p:hover, .graphiql-container .history-contents > p:active {
background: #ff4660;
color: #fff;
}
.graphiql-container .topBarWrap {
background-image: linear-gradient(to right, rgb(255, 70, 96) 8%, rgb(65, 17, 160) 93%);
background-repeat: no-repeat;
background-position: 0px 0px;
background-size: cover;
}
.graphiql-container .topBar .title {
display:none;
}
.graphiql-container .execute-button {
background: rgba(255,255,255,.3);
border-radius: 17px;
border: 0px solid rgba(0, 0, 0, 0.25);
-webkit-box-shadow: none !important;
box-shadow: none !important;
cursor: pointer;
fill: #fff;
height: 34px;
margin: 0;
padding: 0;
width: 34px;
font-family: 'Lato', sans sherif;
text-transform: uppercase;
font-size: 13px;
}
.graphiql-container .execute-button svg {
position:relative;
top:1px;
left:1px;
}
.graphiql-container .execute-button-wrap {
margin: 0px 14px 0 7px;
}
.graphiql-container .toolbar-button {
background: rgba(255,255,255,.3);
-webkit-box-shadow: none !important;
box-shadow: none !important;
border-radius: 5px;
color: #fff;
cursor: pointer;
display: inline-block;
margin: 0 5px;
padding: 8px 20px 8px;
text-decoration: none;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Lato', sans sherif;
text-transform: uppercase;
font-size: 13px;
}
.docExplorerShow,
.history-title,
.doc-explorer-title {
font-family: 'Lato', sans sherif;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 1px;
}
.graphiql-container .toolbar-button:hover,
.graphiql-container .execute-button:hover {
background: rgba(255,255,255,.4);
}
.graphiql-container .docExplorerShow, .graphiql-container .historyShow {
background: #fff;
border-bottom: 1px solid #d0d0d0;
border-right: none;
border-top: none;
color: #4111A0;
cursor: pointer;
font-size: 14px;
margin: 0;
outline: 0;
padding: 2px 20px 0 18px;
}
.graphiql-container .docExplorerShow:before {
border-left: 2px solid #4111A0;
border-top: 2px solid #4111A0;
}
.graphiql-container .doc-explorer-title-bar, .graphiql-container .history-title-bar {
height:44px;
place-items: center;
}
.graphiql-container .doc-explorer-contents, .graphiql-container .history-contents {
top: 57px;
}
.graphiql-container, .graphiql-container button, .graphiql-container input {
color: #22244b;
}
.graphiql-container .search-box {
border-bottom: none;
display: block;
font-size: 14px;
margin: 10px 0px 32px 0px;
position: relative;
}
.graphiql-container .search-box:before {
top: 4px;
left: 13px;
}
.graphiql-container .search-box > input {
-webkit-appearance: none;
-moz-appearance: none;
box-shadow: none !important;
outline: none;
background: #f8f8fa;
border: 1px solid #e1e1e4 !important;
padding: 13px 20px 13px 40px;
box-sizing: border-box;
margin: 0px 0px;
width: 100%;
outline: none;
color: #586090 !important;
border-radius: 8px;
}
.CodeMirror-scroll {
background: #f8f8fa;
}
.graphiql-container .variable-editor-title {
background: #e7e7ec;
border-top: 1px solid #dbdbe8;
border-bottom: 1px solid #dbdbe8;
}
.graphiql-container .result-window .CodeMirror-gutters, .CodeMirror-gutters {
background: #f0f0f5;
border-color: #dbdbe8;
}
.cm-keyword {
color: #030b8c;
}
.cm-punctuation {
color: #a2a2a2;
}
.cm-variable {
color: #4bb310;
}
.cm-atom {
color: #b9f;
}
.cm-property {
color: #4f6bc1;
}
.cm-number {
color: #5bcfff;
}
.cm-attribute {
color: #8B2BB9;
}
.cm-def {
color: #e60a0a;
}
.cm-string {
color: #E48F32;
}
.graphiql-container .type-name {
color: #0db4de;
}

View File

@ -0,0 +1,276 @@
/**
* Copyright 2019 dfuse Platform Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function refreshToken(server, token, apiKey, onCompletion, onError) {
if(token === "") {
return getToken(apiKey, onCompletion, onError)
}
const jwt = parseJwt(token);
const exp = jwt["exp"];
const now = Date.now() / 1000;
console.log("exp : " + exp);
console.log("now : " + now);
const remainingTime = exp - now;
console.log("Time remaining in second: " + remainingTime);
if (remainingTime < 60 * 60) {
return getToken(apiKey, onCompletion, onError)
}
onCompletion(token);
}
function getToken(apiKey, onCompletion, onError) {
const url = "https://auth.dfuse.io/v1/auth/issue";
const r = new XMLHttpRequest();
r.open("POST", url, false);
r.setRequestHeader("Content-type", "application/json");
r.onreadystatechange = function() {//Call a function when the state changes.
if(r.readyState === 4) {
if (r.status === 200) {
console.log("Got new token: " + r.response);
const responseToken = JSON.parse(r.response)
onCompletion(responseToken["token"]);
} else {
alert("Error: " + r.status + " - " + r.response);
onError(r.status, r.response);
}
}
};
r.send('{"api_key":"' + apiKey + '"}');
}
function graphQLFetcherFactory(urlQueryParams) {
let graphqlUrl = "/graphql"
if (isAlphaSchemaQueryParamFound(urlQueryParams)) {
console.log("Requesting alpha endpoints")
graphqlUrl += "?alpha-schema=true"
}
return (graphQLParams) => {
return fetch(graphqlUrl, {
method: "post",
// headers: {
// Authorization: "Bearer " + token,
// },
body: JSON.stringify(graphQLParams),
credentials: "include",
}).then(function (response) {
return response.text();
}).then(function (responseBody) {
try {
return JSON.parse(responseBody);
} catch (error) {
return error.message;
}
}).catch(function (error) {
console.log("Error:", error);
alert(error)
});
}
}
function isAlphaSchemaQueryParamFound(urlQueryParams) {
if (urlQueryParams.has("alpha-schema")) {
return urlQueryParams.get("alpha-schema") === "true"
}
if (urlQueryParams.has("alphaSchema")) {
return urlQueryParams.get("alphaSchema") === "true"
}
return false
}
function fetchQueryProp(queryParams) {
if (!queryParams.has("query")) {
return undefined
}
try {
return window.atob(queryParams.get("query"))
} catch (error) {
console.error("query params 'query' is not a valid base64 object")
return undefined
}
}
function fetchVariablesProp(queryParams) {
if (!queryParams.has("variables")) {
return undefined
}
try {
return window.atob(queryParams.get("variables"))
} catch (error) {
console.error("query params 'variables' is not a valid base64 object")
return undefined
}
}
function pushState(url, query, variables) {
const queryParams = []
if (query !== undefined) {
queryParams.push(`query=${window.btoa(query)}`)
}
if (variables !== undefined) {
queryParams.push(`variables=${window.btoa(variables)}`)
}
if (queryParams.length <= 0) {
return
}
window.history.pushState("", "New Query", `${url.pathname}?${queryParams.join("&")}`);
}
async function getConfig() {
if (window.location.hostname === "localhost") {
return await fetchConfig()
}
const parts = window.location.host.split(".");
return { network: parts[0], protocol: parts[1] }
}
function fetchFavorites() {
console.info("Fetching favorites JSON data")
return fetch("/graphiql/favorites.json")
.then((response) => response.json())
.then((body) => {
console.log("Got favorites JSON data")
return body
})
.catch((error) => {
console.log("Fetch favorites JSON data error", error);
return {}
})
}
function fetchConfig() {
console.info("Fetching config JSON data")
return fetch("/graphiql/config.json")
.then((response) => response.json())
.then((body) => {
console.log("Got config JSON data")
return body
})
.catch((error) => {
console.log("Fetch config JSON data error", error);
return {}
})
}
function getFavoriteFromStorage() {
const storageItem = localStorage.getItem("graphiql:favorites");
console.log("Retrieved client favorites from browser storage")
store = { favorites: [] };
if (storageItem !== null) {
store = JSON.parse(storageItem);
}
return store
}
function setFavoriteFromStorage(store) {
console.log("Saving client favorites to browser storage")
localStorage.setItem("graphiql:favorites", toJSON(store));
}
async function reconfigureGraphiQLStorage(protocol, network, alphaSchema) {
const isFirstTime = localStorage.getItem("dfuse:graphiql:is_first_time");
if (isFirstTime == null) {
// Let's open the history pane the first time the user opens this page
localStorage.setItem("graphiql:historyPaneOpen", toJSON(true));
}
const serverFavorites = await setFavorites(protocol, network, alphaSchema)
localStorage.setItem("dfuse:graphiql:is_first_time", toJSON(false))
if (isFirstTime == null && serverFavorites.length > 0) {
localStorage.setItem("graphiql:query", serverFavorites[0].query);
if (serverFavorites[0].variables) {
localStorage.setItem("graphiql:variables", serverFavorites[0].variables);
}
}
}
async function setFavorites(protocol, network, alphaSchema) {
const favoritesByProtocolMap = await fetchFavorites()
console.log(`Looking for favorites for given ${protocol}/${network} values`)
const serverFavorites = favoritesByProtocolMap[protocol]
if (serverFavorites == null) {
console.log("Favorites not found for this protocol/network values.")
return
}
const store = getFavoriteFromStorage()
// Clear all dfuse managed favorites, we will add them back
store["favorites"] = store["favorites"].filter((value) =>
// We keep only favorites that don't have the `procotol`
value.protocol == null
)
console.log("Favorites store prior update")
serverFavorites.reverse().forEach((favorite) => {
if (!alphaSchema && favorite.alpha) {
return
}
favorite.favorite = true
favorite.protocol = protocol
if (favorite.variables && typeof favorite.variables === "object") {
const networkVariables = favorite.variables[network]
if (networkVariables != null) {
favorite.variables = networkVariables
}
}
store["favorites"] = updateFavorite(store["favorites"], favorite);
})
console.log("Favorites store after update")
setFavoriteFromStorage(store)
// We reverse it again because the `reverse` operation is "in-place"
return serverFavorites.reverse()
}
function updateFavorite(favorites, fav) {
const index = favorites.findIndex(f => (f.label === fav.label));
if (index >= 0) {
console.log(`Updating favorite ${fav.label}`)
favorites[index] = fav
} else {
console.log(`Adding favorite ${fav.label}`)
favorites.push(fav)
}
return favorites
}
function toJSON(input) {
return JSON.stringify(input)
}

133
api/graphql/static/http.go Normal file
View File

@ -0,0 +1,133 @@
// Copyright 2019 dfuse Platform Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package static
//go:generate rice embed-go
import (
"bytes"
"encoding/json"
"html/template"
"io"
"net/http"
rice "github.com/GeertJohan/go.rice"
"github.com/gorilla/mux"
"go.uber.org/zap"
)
const IndexFilename = "graphiql.html"
const (
MIME_TYPE_CSS = "text/css"
MIME_TYPE_HTML = "text/html"
MIME_TYPE_JS = "application/javascript"
MIME_TYPE_JSON = "application/json"
)
func RegisterStaticRoutes(router *mux.Router) {
zlog.Info("registering static route")
box := rice.MustFindBox("build")
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/graphiql/", 302)
})
router.HandleFunc("/graphiql", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/graphiql/", 302)
})
serveIndexHTML(router, box, "/graphiql/")
serveFileAsset(router, box, "/graphiql/graphiql_dfuse_override.css", "graphiql_dfuse_override.css", MIME_TYPE_CSS)
serveFileAsset(router, box, "/graphiql/helper.js", "helper.js", MIME_TYPE_JS)
serveFileAsset(router, box, "/graphiql/favorites.json", "favorites.json", MIME_TYPE_JSON)
// Redirects since it was supported at some point, redirects everyone to `GraphiQL` instead
router.HandleFunc("/playground", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/graphiql/", 302)
})
router.HandleFunc("/playground/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/graphiql/", 302)
})
}
func serveInMemoryAsset(router *mux.Router, path string, content string, contentType string) {
router.HandleFunc(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", contentType)
w.Write([]byte(content))
}))
}
func serveIndexHTML(router *mux.Router, box *rice.Box, path string) {
zlog.Info("setting up index http handler")
router.HandleFunc(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
zlog.Info("serving index",
zap.String("path", path),
zap.String("file_to_template", IndexFilename),
)
reader, err := templatedIndex(box)
if err != nil {
zlog.Error("unable to serve graphiql.html", zap.Error(err))
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("unable to read asset"))
return
}
w.Header().Set("Content-Type", MIME_TYPE_HTML)
_, _ = io.Copy(w, reader)
}))
}
func serveFileAsset(router *mux.Router, box *rice.Box, path string, asset string, contentType string, options ...interface{}) {
router.HandleFunc(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reader, err := box.Open(asset)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("unable to read asset"))
return
}
defer reader.Close()
w.Header().Set("Content-Type", contentType)
// We ignore the error since if we are unable to write to HTTP pipe, it's probably broken
io.Copy(w, reader)
}))
}
func templatedIndex(box *rice.Box) (*bytes.Reader, error) {
zlog.Info("rendering templated index")
indexContent, err := box.Bytes(IndexFilename)
if err != nil {
return nil, err
}
tpl, err := template.New(IndexFilename).Funcs(template.FuncMap{
"json": func(v interface{}) (template.JS, error) {
cnt, err := json.Marshal(v)
return template.JS(cnt), err
},
}).Delims("--==", "==--").Parse(string(indexContent))
if err != nil {
return nil, err
}
buf := &bytes.Buffer{}
if err := tpl.Execute(buf, nil); err != nil {
return nil, err
}
return bytes.NewReader(buf.Bytes()), nil
}

View File

@ -0,0 +1,26 @@
// Copyright 2019 dfuse Platform Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package static
import (
"github.com/dfuse-io/logging"
"go.uber.org/zap"
)
var zlog *zap.Logger
func init() {
logging.Register("github.com/dfuse-io/dgraphql/static", &zlog)
}

File diff suppressed because one or more lines are too long

View File

@ -27,7 +27,7 @@ var apiGraphqlCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
SetupLogger(viper.GetBool("global-debug"))
server := graphql.NewServer("/Users/cbillett/devel/dfuse/go/solana-go/api/graphql/schema.graphql", ":9000")
server := graphql.NewServer("/Users/cbillett/devel/dfuse/go/solana-go/api/graphql/schema.graphql", ":8080")
zlog.Info("serving ...")
return server.Launch()

6
go.sum
View File

@ -22,12 +22,14 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -202,6 +204,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@ -257,6 +260,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -359,7 +363,9 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/ybbus/jsonrpc v2.1.2+incompatible h1:V4mkE9qhbDQ92/MLMIhlhMSbz8jNXdagC3xBR5NDwaQ=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long