Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON API #20

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ install(TARGETS datum_gateway DESTINATION bin)

set(WEB_RESOURCES
www/home.html
www/clients_top.html
www/coinbaser_top.html
www/threads_top.html
www/clients.html
www/coinbaser.html
www/threads.html
www/foot.html
www/assets/style.css
www/assets/icons/datum_logo.svg
Expand Down
614 changes: 392 additions & 222 deletions src/datum_api.c

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions www/clients.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>DATUM Gateway Status</title>
<link rel="icon" type="image/x-icon" href="/assets/icons/favicon.ico" />
<link rel="stylesheet" type="text/css" href="./assets/style.css" />
</head>
<body>
<div class="container">
<div class="header">
<h1>
<img
src="/assets/icons/datum_logo.svg"
alt="(DATUM Logo)"
style="vertical-align: text-top"
width="28"
height="33"
/>
DATUM <span>GATEWAY</span>
</h1>
</div>
<div class="menu-container">
<a href="/">Status</a>
<a href="/clients" style="background-color: darkslategrey">Clients</a>
<a href="/threads">Threads</a>
<a href="/coinbaser">Coinbaser</a>
</div>
</div>

<div class="tables-container">
<div class="table-wrapper">
<div class="table-container">
<h2>Stratum Client List</h2>
<table id="clients">
<tr>
<td><u>TID/CID</u></td>
<td><u>RemHost</u></td>
<td><u>Auth Username</u></td>
<td><u>Subbed</u></td>
<td><u>Last Accepted</u></td>
<td><u>VDiff</u></td>
<td><u>DiffA (A)</u></td>
<td><u>DiffR (R)</u></td>
<td><u>Hashrate (age)</u></td>
<td><u>Coinbase</u></td>
<td><u>UserAgent</u></td>
<td><u>Command</u></td>
</tr>
<tbody>
<tr>

</tr>
</tbody>
</table>
<center>Total active hashrate estimate: <span id="total_hashrate">0.00</span> Th/s</center>
<script>
function sendPostRequest(url, data){fetch(url,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});}

function updateClientsTable() {
fetch('/api/v1/clients')
.then(response => response.json())
.then(data => {
const table = document.getElementById('clients');
const tbody = table.querySelector('tbody') || table;

// Clear existing rows except the header
while (tbody.rows.length > 1) {
tbody.deleteRow(1);
}

// Add new rows
data.clients.forEach(client => {
const row = tbody.insertRow();
row.innerHTML = `
<td>${client.tid}/${client.cid}</td>
<td>${client.rem_host}</td>
<td>${client.auth_username}</td>
<td>
<span style="font-family: monospace">${client.sid.toString(16).padStart(8, '0')}</span>
${client.subscribe_age.toFixed(1)}s
</td>
<td>${client.last_accepted ? new Date(client.last_accepted * 1000).toLocaleString() : 'N/A'}</td>
<td>${client.v_diff}</td>
<td>${client.diff_A} (${client.shares_A})</td>
<td>${client.diff_R} (${client.shares_R}) ${(client.reject_rate * 100).toFixed(2)}%</td>
<td>${client.hashrate.toFixed(2)} Th/s</td>
<td>${client.coinbase}</td>
<td>${client.useragent}</td>
<td>
<button onclick="sendPostRequest('/cmd', {cmd:'kill_client',tid:${client.tid},cid:${client.cid}})">
Kick
</button>
</td>
`;
});

// Update total hashrate
document.getElementById('total_hashrate').textContent = data.total_hashrate.toFixed(2);
})
.catch(error => console.error('Error:', error));
}

// Call the function to update the table
updateClientsTable();

// Optionally, update the table every 10 seconds
setInterval(updateClientsTable, 10000);
</script>
</div>
</div>
</div>
</body>
</html>
25 changes: 0 additions & 25 deletions www/clients_top.html

This file was deleted.

87 changes: 87 additions & 0 deletions www/coinbaser.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DATUM Gateway Status</title>
<link rel="icon" type="image/x-icon" href="/assets/icons/favicon.ico">
<link rel="stylesheet" type="text/css" href="./assets/style.css">
<style type="text/css">
.table-wrapper {
justify-content: center;
}

.table-container {
max-width: 800px;
}

table {
border-collapse: collapse;
}

td {
word-break: break-all;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1><img src="/assets/icons/datum_logo.svg" alt="(DATUM Logo)" style="vertical-align: text-top" width="28" height="33"> DATUM <span>GATEWAY</span></h1>
</div>
<div class="menu-container">
<a href="/">Status</a>
<a href="/clients">Clients</a>
<a href="/threads">Threads</a>
<a href="/coinbaser" style="background-color: darkslategrey;">Coinbaser</a>
</div>
</div>

<div class="tables-container">
<div class="table-wrapper">
<div class="table-container">
<h2>Current Coinbaser</h2>
<table id="coinbaser">
<tr>
<td><u>Value</u></td>
<td><u>Address</u></td>
</tr>
</table>
<script>
function updateCoinbaserTable() {
fetch('/api/v1/coinbaser')
.then(response => response.json())
.then(data => {
const table = document.getElementById('coinbaser');
const tbody = table.querySelector('tbody') || table;

// Clear existing rows except the header
while (tbody.rows.length > 1) {
tbody.deleteRow(1);
}

// Sort data by value in descending order
data.sort((a, b) => b.value - a.value);

// Add new rows
data.forEach(item => {
const row = tbody.insertRow();
row.innerHTML = `
<td>${item.value.toFixed(8)} BTC</td>
<td>${item.address}</td>
`;
});
})
.catch(error => console.error('Error:', error));
}

// Call the function to update the table
updateCoinbaserTable();

// Optionally, update the table every 60 seconds
setInterval(updateCoinbaserTable, 60000);
</script>
</div>
</div>
</div>
</body>
</html>
42 changes: 0 additions & 42 deletions www/coinbaser_top.html

This file was deleted.

2 changes: 0 additions & 2 deletions www/foot.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
</div>
</div>
</div>
<BR>
<CENTER><SMALL>Note: This page does not automatically refresh</SMALL></CENTER>
</body>
</html>
57 changes: 54 additions & 3 deletions www/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ <h2>Decentralized Client Stats</h2>
<td>${DATUM_SHARES_REJECTED}</td>
</tr>
<tr>
<td class="label">Status:</td>
<td>${DATUM_CONNECTION_STATUS}</td>
<td class="label">Is Active:</td>
<td>${DATUM_IS_ACTIVE}</td>
</tr>
<tr>
<td class="label">Pool Host:</td>
Expand Down Expand Up @@ -171,6 +171,57 @@ <h2>Current Stratum Job</h2>
</div>
</div>
<BR>
<CENTER><SMALL>Note: This page does not automatically refresh</SMALL></CENTER>
<script>
// Define the API endpoints and their corresponding placeholder prefixes
const apiEndpoints = [
{ url: '/api/v1/client_stats', prefix: 'DATUM_' },
{ url: '/api/v1/stratum_server_info', prefix: 'STRATUM_' },
{ url: '/api/v1/current_stratum_job', prefix: 'STRATUM_JOB_' }
];

// Function to replace placeholders in the template
function replacePlaceholders(template, data, prefix) {
const regex = new RegExp(`\\$\{${prefix}(\\w+)}`, 'g');


return template.replace(regex, (match, key) => {
if (data[key] == 0)
data[key] = "0";
return data[key] || match
});
}

// Function to update the DOM
function updateDOM(html) {
document.body.innerHTML = html;
}

function updateAllData() {
// Fetch all data concurrently
Promise.all(apiEndpoints.map(endpoint =>
fetch(endpoint.url)
.then(response => response.json())
.then(data => ({ data, prefix: endpoint.prefix }))
))
.then(results => {
let template = document.body.innerHTML;

// Apply all replacements
results.forEach(({ data, prefix }) => {
template = replacePlaceholders(template, data, prefix);
});

// Update the DOM once
updateDOM(template);
})
.catch(error => console.error('Error:', error));
}

// Initial update
updateAllData();

// Set interval to update every 30 seconds
setInterval(updateAllData, 30000);
</script>
</body>
</html>
Loading