Last active
October 5, 2018 16:35
-
-
Save atomize/fa844855cb0767ae2f8a938f02df97da to your computer and use it in GitHub Desktop.
WIP CryptoCompare API+WebSockets example ES6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let imageUrls; | |
let globalmenu = {}; | |
const appInfo = { | |
aggSubs: [], | |
allSubs: [], | |
actualSubs: new Set(), | |
pair: ["???", "???"] | |
}; | |
const params = { | |
credentials: "omit", | |
headers: {}, | |
referrer: "https://cryptoqween.github.io/streamer/trade/", | |
referrerPolicy: "no-referrer-when-downgrade", | |
body: null, | |
method: "GET", | |
mode: "cors" | |
}; | |
function showImage(list) { | |
let fragment = document.createDocumentFragment(); | |
list.forEach(function(element) { | |
var imgElem = document.createElement("img"); | |
fragment.appendChild(imgElem); | |
imgElem.classList = "coinlogo"; | |
imgElem.src = element; | |
}); | |
container.appendChild(fragment); | |
} | |
const toggleSetVal = async (set, val) => { | |
if (set !== undefined) { | |
set.has(val) ? set.delete(val) : set.add(val); | |
} | |
}; | |
function promiseMap(xs, f) { | |
const reducer = (ysAcc$, x) => | |
ysAcc$.then(ysAcc => | |
f(x).then(y => { | |
ysAcc[x] = y; | |
return ysAcc; | |
}) | |
); | |
return xs.reduce(reducer, Promise.resolve({})); | |
} | |
function RateLimit(fn, delay, context) { | |
var queue = [], | |
timer = null; | |
function processQueue() { | |
var item = queue.shift(); | |
if (item) fn.apply(item.context, item.arguments); | |
if (queue.length === 0) clearInterval(timer), (timer = null); | |
} | |
return function limited() { | |
queue.push({ | |
context: context || this, | |
arguments: [].slice.call(arguments) | |
}); | |
if (!timer) { | |
processQueue(); // start immediately on the first invocation | |
timer = setInterval(processQueue, delay); | |
} | |
}; | |
} | |
function bigImg() { | |
var container = document.getElementById("container"); | |
container.innerHTML = ""; | |
chunkArray(unique(Array.from(imageUrls.values())), 30).then(arr => { | |
var bar = RateLimit(showImage, 500); | |
arr.map(x => bar(x)); | |
}); | |
//showImage(Array.from(imageUrls.values())) | |
} | |
const union = (setA, setB) => { | |
var _union = new Set(setA); | |
for (var elem of setB) { | |
_union.add(elem); | |
} | |
return _union; | |
}; | |
const unique = arr => [...new Set(arr)]; | |
const uniqueFilter = (arr, zeroTwoOrFive) => { | |
return unique(arr.filter(bases => bases.split("~")[0] === zeroTwoOrFive)); | |
}; | |
const reducer = (a, c) => | |
Array.isArray(c) || (typeof c === "object" && c !== null) | |
? [...a, ...c] | |
: [...a, c]; | |
const subReducer = res => { | |
let vals = Object.values(res); | |
vals[0] !== "Error" | |
? (vals = vals | |
.flat() | |
.map(y => { | |
return Object.values(y).reduce(reducer); | |
}) | |
.reduce(reducer)) | |
: (vals = []); | |
console.log("vals reduce: ", vals); | |
return vals; | |
}; | |
const chunkArray = async (myArray, chunk_size) => { | |
let results = []; | |
while (myArray.length) { | |
results.push(myArray.splice(0, chunk_size)); | |
} | |
return results; | |
}; | |
const cccCoins = () => | |
fetch("https://min-api.cryptocompare.com/data/all/coinlist", params).then( | |
res => res.json() | |
); | |
const cccSubs = (...parameters) => { | |
let fsym = parameters[0]; | |
let dataUrl = "https://min-api.cryptocompare.com/data/subs?fsym=" + fsym; | |
return fetch(dataUrl, params) | |
.then(res => res.json()) | |
.then(res => { | |
return parameters.includes(1) ? res : subReducer(res); | |
}); | |
}; | |
const cccaggOrCustom = () => { | |
if (appInfo.aggSubs !== undefined) { | |
if ( | |
appInfo.aggSubs.size < appInfo.allSubs.size && | |
appInfo.aggSubs.size !== 0 | |
) { | |
updateOutput(2); | |
} else { | |
updateOutput(5); | |
} | |
} | |
}; | |
const fsym = coin => | |
cccSubs(coin).then(res => { | |
if (res.length !== 0) { | |
let menus = unique(makeMenus(res)); | |
globalmenu = menus; | |
appInfo.aggSubs = new Set(globalmenu[4]); | |
appInfo.allSubs = new Set(globalmenu[4]); | |
appInfo.pair = [coin, "???"]; | |
fillMenu(menus[1], "tsym"); | |
updateOutput(5); | |
} else { | |
init(true); | |
} | |
}); | |
const tsym = coin => { | |
filteredExs = unique( | |
globalmenu[2] | |
.filter(x => x.match(coin)) | |
.filter(x => x.includes("2~")) | |
.map(exchanges => exchanges.split("~")[1]) | |
).sort(); | |
appInfo.aggSubs = new Set(filteredExs); | |
appInfo.allSubs = new Set(filteredExs); | |
appInfo.pair[1] = coin; | |
updateOutput(5); | |
}; | |
const fillMenu = (list, selector) => { | |
let subsSelect = document.getElementById(selector); | |
subsSelect.innerHTML = ""; | |
let fragment = document.createDocumentFragment(); | |
list.sort(); | |
list.unshift("Select..."); | |
list.forEach(function(element) { | |
let opt = document.createElement("option"); | |
opt.value = element; | |
opt.innerHTML = element; | |
fragment.appendChild(opt); | |
}); | |
subsSelect.appendChild(fragment); | |
}; | |
const makeMenus = res => { | |
let exs5 = uniqueFilter(res, "5"); | |
let exs2 = uniqueFilter(res, "2") | |
.map(exchanges => exchanges.split("~")[1]) | |
.sort(); | |
let exs0 = uniqueFilter(res, "0").map(exchanges => exchanges.split("~")[1]); | |
let menus = [ | |
res[0].split("~")[2], | |
unique(res.map(bases => bases.split("~")[3])), | |
res, | |
exs5, | |
exs2, | |
exs0 | |
]; | |
return menus; | |
}; | |
const isChecked = lineEl => { | |
return appInfo.aggSubs.has(lineEl) ? "checked" : ""; | |
}; | |
const markupList = (lineEls, typeOf, delimiter = "") => { | |
let exchangemarkup = `<ul> | |
${lineEls | |
.map( | |
lineEl => | |
`<li class='exchange-item'> | |
<input type = "checkbox" | |
class="exchange-checkbox" | |
name = "${lineEl}" | |
value ="${lineEl}" | |
${isChecked(lineEl)}> | |
${lineEl} | |
</li>` | |
) | |
.join(delimiter)} | |
</ul>`; | |
let subscriptionmarkup = `<ul> | |
${lineEls | |
.map( | |
lineEl => | |
`<li class='subItem'> | |
${typeOf}~${lineEl}~${appInfo.pair[0]}~${appInfo.pair[1]}</li>` | |
) | |
.join(delimiter)} | |
</ul>`; | |
return typeOf === "exchange" ? exchangemarkup : subscriptionmarkup; | |
}; | |
const updateOutput = (twoOrFive = 0) => { | |
if (twoOrFive === 5) { | |
document.getElementById("wsoutput2").innerHTML = `<ul><li>5~CCCAGG~${ | |
appInfo.pair[0] | |
}~${appInfo.pair[1]}</li></ul>`; | |
} else { | |
document.getElementById("wsoutput2").innerHTML = markupList( | |
Array.from(appInfo.aggSubs).filter(x => x !== "Select..."), | |
twoOrFive | |
); | |
} | |
document.getElementById("exchanges").innerHTML = markupList( | |
Array.from(appInfo.allSubs).filter(x => x !== ("Select..." || "CCCAGG")), | |
"exchange" | |
); | |
}; | |
const init = input => { | |
cccCoins().then(coins => { | |
["fsym", "tsym"].map(selectors => { | |
fillMenu(Object.keys(coins.Data), selectors); | |
}); | |
imageUrls = new Map( | |
Object.entries(coins.Data).reduce((a, c, i) => { | |
a[i] = [c[0], `https://www.cryptocompare.com/${c[1].ImageUrl}`]; | |
return a; | |
}, []) | |
); | |
}); | |
if (input) { | |
updateOutput(5); | |
} | |
}; | |
const createSubscriptionStrings = () => { | |
appInfo.actualSubs = new Set(); | |
appInfo.actualSubs = union(appInfo.actualSubs, appInfo.aggSubs); | |
appInfo.actualSubs = Array.from(appInfo.actualSubs).reduce((a, c) => { | |
a.push(`2~${c}~${appInfo.pair[0]}~${appInfo.pair[1]}`); | |
return a; | |
}, []); | |
return appInfo.actualSubs.length === appInfo.allSubs.size | |
? (appInfo.actualSubs = [`5~CCCAGG~${appInfo.pair[0]}~${appInfo.pair[1]}`]) | |
: appInfo.actualSubs; | |
}; | |
document.addEventListener("change", function() { | |
if (event.target instanceof HTMLSelectElement) { | |
if (event.target.id === "fsym") { | |
fsym(event.target.value); | |
} | |
if (event.target.id === "tsym") { | |
tsym(event.target.value); | |
} | |
} | |
}); | |
document.addEventListener("mouseup", function() { | |
event.target instanceof HTMLInputElement && | |
event.target.getAttribute("type") == "checkbox" | |
? toggleSetVal(appInfo.aggSubs, event.target.value).then(cccaggOrCustom()) | |
: console.log("other mouse up, not a checkbox!"); | |
if (event.target.classList.contains("exchange-item")) { | |
console.log(event.target.querySelector(".exchange-checkbox").checked); | |
} | |
if (event.target.classList.contains("subscribe")) { | |
if (appInfo.actualSubs.length > 0) { | |
removeSubs(appInfo.actualSubs); | |
} | |
createSubscriptionStrings(); | |
addSubs(appInfo.actualSubs); | |
} | |
}); | |
var socket = io.connect("https://streamer.cryptocompare.com/"); | |
const addSubs = subsArr => { | |
socket.emit("SubAdd", { | |
subs: subsArr | |
}); | |
}; | |
const removeSubs = subsArr => { | |
socket.emit("SubRemove", { | |
subs: subsArr | |
}); | |
}; | |
socket.on("m", function(message) { | |
console.log(message); | |
// var messageType = message.substring(0, message.indexOf("~")); | |
}); | |
init(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> | |
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> | |
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> | |
<!--[if gt IE 8]><!--> | |
<html class="no-js"> | |
<!--<![endif]--> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>CryptoCompare Example</title> | |
<meta name="description" content=""> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<h2>CryptoCompare WebSocket CURRENT VALUE</h2> | |
<!--[if lt IE 7]> | |
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p> | |
<![endif]--> | |
<div class="grid-container-4"> | |
<div class="grid-item"> | |
<div class="grid-container-2"> | |
<div class="grid-item"> | |
<label for="fsym">From Coin</label> | |
<br> | |
<select id="fsym"> | |
<option value="">Loading...</option> | |
</select> | |
</div> | |
<div class="grid-item"> | |
<label for="tsym">To Coin</label> | |
<br> | |
<select id="tsym"> | |
<option value="">Loading...</option> | |
</select> | |
</div> | |
</div> | |
</div> | |
<div class="grid-item"> | |
Aggregated Exchanges | |
<br> | |
<div id="exchanges">Loading...</div> | |
</div> | |
<div class="grid-item"> | |
WS Subscription | |
<br> | |
<div id="wsoutput2"> | |
</div> | |
</div> | |
<div class="grid-item"> | |
<button class="subscribe">Subscribe</button> | |
<button class="addsub">Add to Sub</button> | |
<button class="unsubscribe">Unsubscribe All</button> | |
</div> | |
</div> | |
<div class="grid-container-4"> | |
<div id="container" class="grid-item"> | |
</div> | |
<div class="grid-item"></div> | |
<div class="grid-item"></div> | |
<div class="grid-item"></div> | |
</div> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.slim.js'></script> | |
<script src="ccc.js" async defer></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.inline { | |
display: inline-block; | |
vertical-align: top; | |
text-align: center; | |
} | |
.twenty5 { | |
width: 20vw; | |
} | |
.fifty { | |
max-width: 30%; | |
} | |
#wsoutput { | |
min-width: 200px; | |
} | |
#exchange-container { | |
min-width: 200px; | |
max-width: 400px; | |
} | |
#exchanges { | |
max-height: 200px; | |
overflow-y: scroll; | |
} | |
.exchange-item { | |
cursor: pointer; | |
text-decoration: none; | |
} | |
.grid-container-4 { | |
display: grid; | |
grid-template-columns: auto auto auto auto; | |
background-color: #2196F3; | |
grid-gap: 10px; | |
padding: 5px; | |
} | |
.grid-container-2 { | |
display: grid; | |
grid-template-columns: auto auto; | |
background-color: #2196F3; | |
grid-gap: 10px; | |
padding: 5px; | |
} | |
.grid-item { | |
background-color: rgba(255, 255, 255, 0.8); | |
padding: 2px; | |
font-size: 10px; | |
text-align: center; | |
} | |
#wsoutput2 { | |
overflow-y: scroll; | |
max-height: 200px; | |
} | |
.coinlogo { | |
max-width: 20px !important; | |
max-height: 20px !important; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment