mirror of
https://github.com/Retropex/custom-ocean.xyz-dashboard.git
synced 2025-05-12 19:20:45 +02:00
Removed Console
This commit is contained in:
parent
695e4cfb95
commit
a4178d0a9b
6
App.py
6
App.py
@ -807,12 +807,6 @@ class RobustMiddleware:
|
||||
logging.exception("Unhandled exception in WSGI app")
|
||||
start_response("500 Internal Server Error", [("Content-Type", "text/html")])
|
||||
return [b"<h1>Internal Server Error</h1>"]
|
||||
# Add Console page route
|
||||
@app.route("/console")
|
||||
def console_page():
|
||||
"""Serve the retro console log page."""
|
||||
current_time = datetime.now(ZoneInfo("America/Los_Angeles")).strftime("%Y-%m-%d %H:%M:%S")
|
||||
return render_template("console.html", current_time=current_time)
|
||||
|
||||
# Add the middleware
|
||||
app.wsgi_app = RobustMiddleware(app.wsgi_app)
|
||||
|
3
setup.py
3
setup.py
@ -60,7 +60,6 @@ FILE_MAPPINGS = {
|
||||
'retro-refresh.css': 'static/css/retro-refresh.css',
|
||||
'blocks.css': 'static/css/blocks.css',
|
||||
'notifications.css': 'static/css/notifications.css',
|
||||
'console.css': 'static/css/console.css', # Added console.css
|
||||
|
||||
# JS files
|
||||
'main.js': 'static/js/main.js',
|
||||
@ -68,7 +67,6 @@ FILE_MAPPINGS = {
|
||||
'blocks.js': 'static/js/blocks.js',
|
||||
'BitcoinProgressBar.js': 'static/js/BitcoinProgressBar.js',
|
||||
'notifications.js': 'static/js/notifications.js',
|
||||
'console.js': 'static/js/console.js', # Added console.js
|
||||
|
||||
# Template files
|
||||
'base.html': 'templates/base.html',
|
||||
@ -78,7 +76,6 @@ FILE_MAPPINGS = {
|
||||
'error.html': 'templates/error.html',
|
||||
'blocks.html': 'templates/blocks.html',
|
||||
'notifications.html': 'templates/notifications.html',
|
||||
'console.html': 'templates/console.html', # Added console.html
|
||||
}
|
||||
|
||||
# Default configuration
|
||||
|
@ -1,439 +0,0 @@
|
||||
/* console.css - Enhanced with retro CRT styling */
|
||||
:root {
|
||||
--console-bg: #121212;
|
||||
--console-bg-gradient: linear-gradient(135deg, #121212, #000000);
|
||||
--console-text: #f7931a;
|
||||
--console-header: #0a0a0a;
|
||||
--console-warning: #ffd700;
|
||||
--console-error: #ff2d2d;
|
||||
--console-success: #39ff14;
|
||||
--console-info: #00dfff;
|
||||
--terminal-glow: 0 0 10px rgba(247, 147, 26, 0.4);
|
||||
}
|
||||
|
||||
/* Adjust the height of the body to allow space for other elements */
|
||||
body {
|
||||
background: var(--console-bg-gradient);
|
||||
color: var(--console-text);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'VT323', 'Share Tech Mono', monospace;
|
||||
font-size: 20px;
|
||||
line-height: 1.4;
|
||||
overflow-x: hidden;
|
||||
text-shadow: var(--terminal-glow);
|
||||
height: auto; /* Changed from 100vh to auto */
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* CRT Screen Effect */
|
||||
body::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.1) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.03), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.03));
|
||||
background-size: 100% 2px, 3px 100%;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
opacity: 0.15;
|
||||
}
|
||||
|
||||
/* Flicker Animation */
|
||||
@keyframes flicker {
|
||||
0% {
|
||||
opacity: 0.97;
|
||||
}
|
||||
|
||||
5% {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
10% {
|
||||
opacity: 0.97;
|
||||
}
|
||||
|
||||
15% {
|
||||
opacity: 0.94;
|
||||
}
|
||||
|
||||
20% {
|
||||
opacity: 0.98;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
80% {
|
||||
opacity: 0.96;
|
||||
}
|
||||
|
||||
90% {
|
||||
opacity: 0.94;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.98;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix the console container to use a controlled height */
|
||||
.console-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 50vh; /* Change from 100vh to 50vh to make it half height */
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background: transparent;
|
||||
animation: flicker 4s infinite;
|
||||
margin: 20px auto; /* Add some margin top and bottom */
|
||||
max-height: 500px; /* Add a maximum height */
|
||||
}
|
||||
|
||||
.console-header {
|
||||
background-color: var(--console-header);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
border-bottom: 1px solid var(--console-text);
|
||||
box-shadow: 0 0 15px rgba(247, 147, 26, 0.5);
|
||||
}
|
||||
|
||||
.console-title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 0 10px rgba(247, 147, 26, 0.8);
|
||||
}
|
||||
|
||||
.console-info {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Fix the console wrapper to be a controlled height */
|
||||
.console-wrapper {
|
||||
flex: 0 1 auto;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--console-text) var(--console-bg);
|
||||
padding: 10px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--console-bg);
|
||||
/* Control the height precisely */
|
||||
height: calc(100% - 130px); /* Account for header and footer height */
|
||||
min-height: 150px; /* Set a minimum height */
|
||||
}
|
||||
|
||||
.console-wrapper::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.console-wrapper::-webkit-scrollbar-track {
|
||||
background: var(--console-bg);
|
||||
}
|
||||
|
||||
.console-wrapper::-webkit-scrollbar-thumb {
|
||||
background-color: var(--console-text);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
}
|
||||
|
||||
/* Update the console output */
|
||||
.console-output {
|
||||
font-size: 20px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
position: relative; /* Change to relative positioning */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.console-line {
|
||||
margin-bottom: 4px;
|
||||
position: relative;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.console-line::before {
|
||||
content: ">";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--console-text);
|
||||
text-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
}
|
||||
|
||||
/* Make the stats bar stay at the bottom */
|
||||
.console-stats {
|
||||
border-top: 1px solid var(--console-text);
|
||||
padding: 15px;
|
||||
box-shadow: 0 0 15px rgba(247, 147, 26, 0.5);
|
||||
background-color: var(--console-header);
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-top: auto; /* Push to the bottom of flexbox */
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat-box {
|
||||
margin: 0 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 0 10px rgba(247, 147, 26, 0.8);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Neon-inspired color classes */
|
||||
.green, .success {
|
||||
color: var(--console-success) !important;
|
||||
text-shadow: 0 0 10px var(--console-success), 0 0 20px var(--console-success);
|
||||
}
|
||||
|
||||
.blue, .info {
|
||||
color: var(--console-info) !important;
|
||||
text-shadow: 0 0 10px var(--console-info), 0 0 20px var(--console-info);
|
||||
}
|
||||
|
||||
.yellow, .warning {
|
||||
color: var(--console-warning) !important;
|
||||
text-shadow: 0 0 8px var(--console-warning), 0 0 16px var(--console-warning);
|
||||
}
|
||||
|
||||
.white {
|
||||
color: #ffffff !important;
|
||||
text-shadow: 0 0 8px #ffffff, 0 0 16px #ffffff;
|
||||
}
|
||||
|
||||
.red, .error {
|
||||
color: var(--console-error) !important;
|
||||
text-shadow: 0 0 10px var(--console-error), 0 0 20px var(--console-error);
|
||||
}
|
||||
|
||||
.magenta {
|
||||
color: #ff2d95 !important;
|
||||
text-shadow: 0 0 10px #ff2d95, 0 0 20px #ff2d95;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 16px;
|
||||
background-color: var(--console-text);
|
||||
animation: blink-animation 1s step-end infinite;
|
||||
vertical-align: middle;
|
||||
box-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
}
|
||||
|
||||
@keyframes blink-animation {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bitcoin Logo styling */
|
||||
#bitcoin-logo {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 10px auto;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
color: var(--console-text);
|
||||
text-shadow: 0 0 10px rgba(247, 147, 26, 0.8);
|
||||
white-space: pre;
|
||||
width: 260px;
|
||||
padding: 10px;
|
||||
border: 2px solid var(--console-text);
|
||||
background-color: var(--console-header);
|
||||
box-shadow: 0 0 15px rgba(247, 147, 26, 0.5);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* Skip Button */
|
||||
#skip-button {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background-color: var(--console-text);
|
||||
color: #000;
|
||||
border: none;
|
||||
padding: 10px 15px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-family: 'VT323', monospace;
|
||||
font-size: 16px;
|
||||
box-shadow: 0 0 8px rgba(247, 147, 26, 0.5);
|
||||
transition: all 0.2s ease;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#skip-button:hover {
|
||||
background-color: #ffa32e;
|
||||
box-shadow: 0 0 12px rgba(247, 147, 26, 0.7);
|
||||
}
|
||||
|
||||
/* Prompt Styling */
|
||||
#prompt-container {
|
||||
white-space: nowrap;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#prompt-text {
|
||||
color: var(--console-text);
|
||||
margin-right: 5px;
|
||||
text-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#user-input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--console-text);
|
||||
font-family: 'VT323', monospace;
|
||||
font-size: 20px;
|
||||
caret-color: transparent;
|
||||
outline: none;
|
||||
width: 35px;
|
||||
height: 33px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.prompt-cursor {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 16px;
|
||||
background-color: var(--console-text);
|
||||
animation: blink-animation 1s step-end infinite;
|
||||
vertical-align: middle;
|
||||
box-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
/* Loading and Debug Info */
|
||||
#loading-message {
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
text-shadow: 0 0 5px rgba(247, 147, 26, 0.8);
|
||||
}
|
||||
|
||||
#debug-info {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* Mobile Responsiveness */
|
||||
@media (max-width: 600px) {
|
||||
body {
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.console-wrapper {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.console-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* CRT screen effect - Retain existing effects with new styling */
|
||||
.glitch {
|
||||
position: relative;
|
||||
animation: glitch-skew 1s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch::before,
|
||||
.glitch::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.glitch::before {
|
||||
color: #ff00ff;
|
||||
animation: glitch-anim 5s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch::after {
|
||||
color: #00ffff;
|
||||
animation: glitch-anim2 1s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
@keyframes glitch-anim {
|
||||
0% {
|
||||
clip: rect(42px, 9999px, 44px, 0);
|
||||
transform: skew(0.65deg);
|
||||
}
|
||||
/* Rest of the keyframes remain unchanged */
|
||||
100% {
|
||||
clip: rect(7px, 9999px, 12px, 0);
|
||||
transform: skew(0.5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch-anim2 {
|
||||
0% {
|
||||
clip: rect(65px, 9999px, 100px, 0);
|
||||
transform: skew(0.4deg);
|
||||
}
|
||||
/* Rest of the keyframes remain unchanged */
|
||||
100% {
|
||||
clip: rect(31px, 9999px, 93px, 0);
|
||||
transform: skew(0.6deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch-skew {
|
||||
0% {
|
||||
transform: skew(1deg);
|
||||
}
|
||||
/* Rest of the keyframes remain unchanged */
|
||||
100% {
|
||||
transform: skew(0deg);
|
||||
}
|
||||
}
|
@ -1,384 +0,0 @@
|
||||
/**
|
||||
* Bitcoin Mining Console Log - Real-time Mining Data Display
|
||||
* Displays actual mining metrics rather than simulated logs
|
||||
*/
|
||||
|
||||
// Message type constants
|
||||
const MSG_TYPE = {
|
||||
SYSTEM: 'system',
|
||||
INFO: 'info',
|
||||
WARNING: 'warning',
|
||||
ERROR: 'error',
|
||||
SUCCESS: 'success',
|
||||
HASH: 'hash',
|
||||
SHARE: 'share',
|
||||
BLOCK: 'block',
|
||||
NETWORK: 'network'
|
||||
};
|
||||
|
||||
// Global settings and state
|
||||
const consoleSettings = {
|
||||
maxLines: 500, // Maximum number of lines to keep in the console
|
||||
autoScroll: true, // Auto-scroll to bottom on new messages
|
||||
refreshInterval: 15000, // Refresh metrics every 15 seconds
|
||||
glitchProbability: 0.05 // 5% chance of text glitch effect for retro feel
|
||||
};
|
||||
|
||||
// Cache for metrics data and tracking changes
|
||||
let cachedMetrics = null;
|
||||
let previousMetrics = null;
|
||||
let lastBlockHeight = null;
|
||||
let lastUpdateTime = null;
|
||||
let logUpdateQueue = []; // Queue to store log updates
|
||||
let logInterval = 2000; // Interval to process log updates (2 seconds)
|
||||
|
||||
// Initialize console
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
console.log('Bitcoin Mining Console initialized');
|
||||
|
||||
// Update clock
|
||||
updateClock();
|
||||
setInterval(updateClock, 1000);
|
||||
|
||||
// Fetch initial metrics
|
||||
fetchMetrics();
|
||||
|
||||
// Setup event source for real-time updates
|
||||
setupEventSource();
|
||||
|
||||
// Periodic full refresh as backup
|
||||
setInterval(fetchMetrics, consoleSettings.refreshInterval);
|
||||
|
||||
// Process queued metric updates regularly
|
||||
setInterval(processLogQueue, logInterval);
|
||||
|
||||
// Add layout adjustment
|
||||
adjustConsoleLayout();
|
||||
window.addEventListener('resize', adjustConsoleLayout);
|
||||
|
||||
// Add initial system message
|
||||
addConsoleMessage("BITCOIN MINING CONSOLE INITIALIZED - CONNECTING TO DATA SOURCES...", MSG_TYPE.SYSTEM);
|
||||
});
|
||||
|
||||
/**
|
||||
* Format date for console display
|
||||
*/
|
||||
function formatDate(date) {
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the clock in the console header
|
||||
*/
|
||||
function updateClock() {
|
||||
const now = new Date();
|
||||
document.getElementById('current-time').textContent = formatDate(now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up Server-Sent Events for real-time updates
|
||||
*/
|
||||
function setupEventSource() {
|
||||
const eventSource = new EventSource('/stream');
|
||||
|
||||
eventSource.onmessage = function (event) {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.type === "ping" || data.type === "timeout_warning" || data.type === "timeout") {
|
||||
return; // Ignore ping and timeout messages
|
||||
}
|
||||
|
||||
// Store previous metrics for comparison
|
||||
previousMetrics = cachedMetrics ? { ...cachedMetrics } : null;
|
||||
|
||||
// Update cached metrics
|
||||
cachedMetrics = data;
|
||||
|
||||
// Check for significant changes and log them
|
||||
processMetricChanges(previousMetrics, cachedMetrics);
|
||||
|
||||
// Update dashboard stats
|
||||
updateDashboardStats(data);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error processing SSE data:', error);
|
||||
addConsoleMessage(`DATA STREAM ERROR: ${error.message}`, MSG_TYPE.ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
eventSource.onerror = function () {
|
||||
console.error('SSE connection error');
|
||||
addConsoleMessage("CONNECTION ERROR: METRICS STREAM INTERRUPTED - ATTEMPTING RECONNECTION...", MSG_TYPE.ERROR);
|
||||
// Reconnect after 5 seconds
|
||||
setTimeout(setupEventSource, 5000);
|
||||
};
|
||||
|
||||
// Log successful connection
|
||||
addConsoleMessage("REAL-TIME DATA STREAM ESTABLISHED", MSG_TYPE.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch metrics via API
|
||||
*/
|
||||
function fetchMetrics() {
|
||||
fetch('/api/metrics')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Store previous metrics for comparison
|
||||
previousMetrics = cachedMetrics ? { ...cachedMetrics } : null;
|
||||
|
||||
// Update cached metrics
|
||||
cachedMetrics = data;
|
||||
lastUpdateTime = new Date();
|
||||
|
||||
// Check for significant changes and log them
|
||||
processMetricChanges(previousMetrics, cachedMetrics);
|
||||
|
||||
// Update dashboard stats
|
||||
updateDashboardStats(data);
|
||||
|
||||
// Log first connection
|
||||
if (!previousMetrics) {
|
||||
addConsoleMessage("CONNECTED TO MINING DATA SOURCE - MONITORING METRICS", MSG_TYPE.SUCCESS);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching metrics:', error);
|
||||
addConsoleMessage(`METRICS FETCH ERROR: ${error.message} - RETRYING...`, MSG_TYPE.ERROR);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process changes between old and new metrics
|
||||
*/
|
||||
function processMetricChanges(oldMetrics, newMetrics) {
|
||||
if (!oldMetrics || !newMetrics) return;
|
||||
|
||||
// Check for block height change (new block found)
|
||||
if (oldMetrics.block_number !== newMetrics.block_number) {
|
||||
const message = `BLOCKCHAIN UPDATE: NEW BLOCK #${numberWithCommas(newMetrics.block_number)} DETECTED`;
|
||||
queueLogUpdate(message, MSG_TYPE.BLOCK);
|
||||
lastBlockHeight = newMetrics.block_number;
|
||||
}
|
||||
|
||||
// Check for worker count changes
|
||||
if (oldMetrics.workers_hashing !== newMetrics.workers_hashing) {
|
||||
let message;
|
||||
if (newMetrics.workers_hashing > oldMetrics.workers_hashing) {
|
||||
const diff = newMetrics.workers_hashing - oldMetrics.workers_hashing;
|
||||
message = `WORKER STATUS: ${diff} ADDITIONAL WORKER${diff > 1 ? 'S' : ''} CAME ONLINE - NOW ${newMetrics.workers_hashing} ACTIVE`;
|
||||
queueLogUpdate(message, MSG_TYPE.SUCCESS);
|
||||
} else {
|
||||
const diff = oldMetrics.workers_hashing - newMetrics.workers_hashing;
|
||||
message = `WORKER STATUS: ${diff} WORKER${diff > 1 ? 'S' : ''} WENT OFFLINE - NOW ${newMetrics.workers_hashing} ACTIVE`;
|
||||
queueLogUpdate(message, MSG_TYPE.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for significant hashrate changes (>5%)
|
||||
const oldHashrate = oldMetrics.hashrate_10min || oldMetrics.hashrate_3hr || 0;
|
||||
const newHashrate = newMetrics.hashrate_10min || newMetrics.hashrate_3hr || 0;
|
||||
const hashrateUnit = newMetrics.hashrate_10min_unit || newMetrics.hashrate_3hr_unit || 'TH/s';
|
||||
|
||||
if (oldHashrate > 0 && Math.abs((newHashrate - oldHashrate) / oldHashrate) > 0.05) {
|
||||
const pctChange = ((newHashrate - oldHashrate) / oldHashrate * 100).toFixed(1);
|
||||
const direction = newHashrate > oldHashrate ? 'INCREASE' : 'DECREASE';
|
||||
const message = `HASHRATE ${direction}: ${newHashrate.toFixed(2)} ${hashrateUnit} - ${Math.abs(pctChange)}% CHANGE`;
|
||||
queueLogUpdate(message, newHashrate > oldHashrate ? MSG_TYPE.SUCCESS : MSG_TYPE.INFO);
|
||||
}
|
||||
|
||||
// Check for BTC price changes
|
||||
if (Math.abs((newMetrics.btc_price - oldMetrics.btc_price) / oldMetrics.btc_price) > 0.005) {
|
||||
const direction = newMetrics.btc_price > oldMetrics.btc_price ? 'UP' : 'DOWN';
|
||||
const pctChange = ((newMetrics.btc_price - oldMetrics.btc_price) / oldMetrics.btc_price * 100).toFixed(2);
|
||||
const message = `MARKET UPDATE: BTC ${direction} ${Math.abs(pctChange)}% - NOW $${numberWithCommas(newMetrics.btc_price.toFixed(2))}`;
|
||||
queueLogUpdate(message, newMetrics.btc_price > oldMetrics.btc_price ? MSG_TYPE.SUCCESS : MSG_TYPE.INFO);
|
||||
}
|
||||
|
||||
// Check mining profitability changes
|
||||
if (newMetrics.daily_profit_usd !== oldMetrics.daily_profit_usd) {
|
||||
if ((oldMetrics.daily_profit_usd < 0 && newMetrics.daily_profit_usd >= 0) ||
|
||||
(oldMetrics.daily_profit_usd >= 0 && newMetrics.daily_profit_usd < 0)) {
|
||||
const message = newMetrics.daily_profit_usd >= 0
|
||||
? `PROFITABILITY ALERT: MINING NOW PROFITABLE AT $${newMetrics.daily_profit_usd.toFixed(2)}/DAY`
|
||||
: `PROFITABILITY ALERT: MINING NOW UNPROFITABLE - LOSING $${Math.abs(newMetrics.daily_profit_usd).toFixed(2)}/DAY`;
|
||||
queueLogUpdate(message, newMetrics.daily_profit_usd >= 0 ? MSG_TYPE.SUCCESS : MSG_TYPE.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
// Log difficulty changes
|
||||
if (oldMetrics.difficulty && newMetrics.difficulty &&
|
||||
Math.abs((newMetrics.difficulty - oldMetrics.difficulty) / oldMetrics.difficulty) > 0.001) {
|
||||
const direction = newMetrics.difficulty > oldMetrics.difficulty ? 'INCREASED' : 'DECREASED';
|
||||
const pctChange = ((newMetrics.difficulty - oldMetrics.difficulty) / oldMetrics.difficulty * 100).toFixed(2);
|
||||
const message = `NETWORK DIFFICULTY ${direction} BY ${Math.abs(pctChange)}% - NOW ${numberWithCommas(Math.round(newMetrics.difficulty))}`;
|
||||
queueLogUpdate(message, MSG_TYPE.NETWORK);
|
||||
}
|
||||
|
||||
// Add periodic stats summary regardless of changes
|
||||
if (!lastUpdateTime || (new Date() - lastUpdateTime) > 60000) { // Every minute
|
||||
logCurrentStats(newMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a log update to be shown (prevents flooding)
|
||||
*/
|
||||
function queueLogUpdate(message, type = MSG_TYPE.INFO) {
|
||||
logUpdateQueue.push({ message, type });
|
||||
}
|
||||
|
||||
/**
|
||||
* Process queued log updates
|
||||
*/
|
||||
function processLogQueue() {
|
||||
if (logUpdateQueue.length > 0) {
|
||||
const update = logUpdateQueue.shift(); // Get the next update
|
||||
addConsoleMessage(update.message, update.type); // Display it
|
||||
} else {
|
||||
// If the queue is empty, log periodic stats
|
||||
logCurrentStats(cachedMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log current mining stats periodically
|
||||
*/
|
||||
function logCurrentStats(metrics) {
|
||||
if (!metrics) return;
|
||||
|
||||
// Define an array of possible log messages with corrected formatting
|
||||
const logMessages = [
|
||||
`HASHRATE: ${metrics.hashrate_60sec || metrics.hashrate_10min || metrics.hashrate_3hr || 0} ${metrics.hashrate_60sec_unit || metrics.hashrate_10min_unit || metrics.hashrate_3hr_unit || 'TH/s'}`,
|
||||
`BLOCK HEIGHT: ${numberWithCommas(metrics.block_number || 0)}`,
|
||||
`WORKERS ONLINE: ${metrics.workers_hashing || 0}`,
|
||||
`BTC PRICE: $${numberWithCommas(parseFloat(metrics.btc_price || 0).toFixed(2))}`,
|
||||
`DAILY PROFIT: $${metrics.daily_profit_usd ? metrics.daily_profit_usd.toFixed(2) : '0.00'}`,
|
||||
// Convert SATS to BTC (1 BTC = 100,000,000 SATS) and format with 8 decimal places
|
||||
`UNPAID EARNINGS: ${(parseFloat(metrics.unpaid_earnings || 0) / 100000000).toFixed(8)} BTC`,
|
||||
`NETWORK DIFFICULTY: ${numberWithCommas(Math.round(metrics.difficulty || 0))}`,
|
||||
// Fix power consumption to show 0W instead of N/AW when not available
|
||||
`POWER CONSUMPTION: ${metrics.power_usage || '0'} WATTS`,
|
||||
];
|
||||
|
||||
// Randomize the order of log messages
|
||||
shuffleArray(logMessages);
|
||||
|
||||
// Queue the first few messages for display
|
||||
logMessages.slice(0, 3).forEach(message => queueLogUpdate(message, MSG_TYPE.INFO));
|
||||
|
||||
// Update the last update time
|
||||
lastUpdateTime = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle an array in place
|
||||
*/
|
||||
function shuffleArray(array) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the dashboard stats display in the footer
|
||||
*/
|
||||
function updateDashboardStats(data) {
|
||||
if (!data) return;
|
||||
|
||||
// Update hashrate
|
||||
const hashrate = data.hashrate_60sec || data.hashrate_10min || data.hashrate_3hr || 0;
|
||||
const hashrateUnit = (data.hashrate_60sec_unit || data.hashrate_10min_unit || data.hashrate_3hr_unit || 'TH/s').toUpperCase();
|
||||
document.getElementById('current-hashrate').textContent = `${hashrate} ${hashrateUnit}`;
|
||||
|
||||
// Update block height
|
||||
document.getElementById('block-height').textContent = numberWithCommas(data.block_number || 0);
|
||||
|
||||
// Update workers online
|
||||
document.getElementById('workers-online').textContent = data.workers_hashing || 0;
|
||||
|
||||
// Update BTC price
|
||||
document.getElementById('btc-price').textContent = `$${numberWithCommas(parseFloat(data.btc_price || 0).toFixed(2))}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format number with commas
|
||||
*/
|
||||
function numberWithCommas(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message to the console output
|
||||
*/
|
||||
function addConsoleMessage(message, type = MSG_TYPE.SYSTEM) {
|
||||
const consoleOutput = document.getElementById('console-output');
|
||||
const now = new Date();
|
||||
const timestamp = formatDate(now);
|
||||
|
||||
// Create the message element
|
||||
const lineElement = document.createElement('div');
|
||||
lineElement.className = 'console-line';
|
||||
|
||||
// Add timestamp
|
||||
const timestampSpan = document.createElement('span');
|
||||
timestampSpan.className = 'timestamp';
|
||||
timestampSpan.textContent = `[${timestamp}] `;
|
||||
lineElement.appendChild(timestampSpan);
|
||||
|
||||
// Add message with appropriate class based on type
|
||||
const messageSpan = document.createElement('span');
|
||||
messageSpan.className = type;
|
||||
messageSpan.textContent = message;
|
||||
|
||||
// Apply glitch effect occasionally for retro aesthetic
|
||||
if (Math.random() < consoleSettings.glitchProbability) {
|
||||
messageSpan.classList.add('glitch');
|
||||
messageSpan.setAttribute('data-text', message);
|
||||
}
|
||||
|
||||
lineElement.appendChild(messageSpan);
|
||||
|
||||
// Add to console
|
||||
consoleOutput.appendChild(lineElement);
|
||||
|
||||
// Limit the number of lines in the console
|
||||
while (consoleOutput.children.length > consoleSettings.maxLines) {
|
||||
consoleOutput.removeChild(consoleOutput.firstChild);
|
||||
}
|
||||
|
||||
// Auto-scroll to bottom
|
||||
if (consoleSettings.autoScroll) {
|
||||
const consoleWrapper = document.querySelector('.console-wrapper');
|
||||
consoleWrapper.scrollTop = consoleWrapper.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust console layout to ensure proper proportions
|
||||
*/
|
||||
function adjustConsoleLayout() {
|
||||
const container = document.querySelector('.console-container');
|
||||
const header = document.querySelector('.console-header');
|
||||
const stats = document.querySelector('.console-stats');
|
||||
const wrapper = document.querySelector('.console-wrapper');
|
||||
|
||||
if (container && header && stats && wrapper) {
|
||||
// Calculate the proper height for wrapper
|
||||
const containerHeight = container.clientHeight;
|
||||
const headerHeight = header.clientHeight;
|
||||
const statsHeight = stats.clientHeight;
|
||||
|
||||
// Set the wrapper height to fill the space between header and stats
|
||||
const wrapperHeight = containerHeight - headerHeight - statsHeight;
|
||||
wrapper.style.height = `${Math.max(wrapperHeight, 150)}px`; // Min height of 150px
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}BITCOIN MINING CONSOLE LOG{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/console.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="console-container">
|
||||
<div class="console-header">
|
||||
<div class="console-title">BITCOIN MINING TERMINAL v1.0</div>
|
||||
<div class="console-info">
|
||||
<span id="current-time">{{ current_time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="console-wrapper">
|
||||
<div id="console-output" class="console-output">
|
||||
<!-- Console logs will be appended here by JavaScript -->
|
||||
<div class="console-line">BTC OS - MINING TERMINAL [Version 21.0000]</div>
|
||||
<div class="console-line">Copyright (C) 2025 BTC Mining Operations</div>
|
||||
<div class="console-line">-----------------------------------------</div>
|
||||
<div class="console-line">INITIALIZING SYSTEM COMPONENTS...</div>
|
||||
<div class="console-line">BLOCKCHAIN CONNECTION: <span class="success">ESTABLISHED</span></div>
|
||||
<div class="console-line">MINING POOL CONNECTION: <span class="success">ONLINE</span></div>
|
||||
<div class="console-line">SYSTEM READY. BEGINNING CONSOLE LOG...</div>
|
||||
<div class="console-line">-----------------------------------------</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="console-stats">
|
||||
<div class="stats-container">
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">HASHRATE</div>
|
||||
<div class="stat-value" id="current-hashrate">0 TH/s</div>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">BLOCK HEIGHT</div>
|
||||
<div class="stat-value" id="block-height">0</div>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">WORKERS ONLINE</div>
|
||||
<div class="stat-value" id="workers-online">0</div>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<div class="stat-label">BTC PRICE</div>
|
||||
<div class="stat-value" id="btc-price">$0.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Script imports -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/console.js') }}"></script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user