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")
|
logging.exception("Unhandled exception in WSGI app")
|
||||||
start_response("500 Internal Server Error", [("Content-Type", "text/html")])
|
start_response("500 Internal Server Error", [("Content-Type", "text/html")])
|
||||||
return [b"<h1>Internal Server Error</h1>"]
|
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
|
# Add the middleware
|
||||||
app.wsgi_app = RobustMiddleware(app.wsgi_app)
|
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',
|
'retro-refresh.css': 'static/css/retro-refresh.css',
|
||||||
'blocks.css': 'static/css/blocks.css',
|
'blocks.css': 'static/css/blocks.css',
|
||||||
'notifications.css': 'static/css/notifications.css',
|
'notifications.css': 'static/css/notifications.css',
|
||||||
'console.css': 'static/css/console.css', # Added console.css
|
|
||||||
|
|
||||||
# JS files
|
# JS files
|
||||||
'main.js': 'static/js/main.js',
|
'main.js': 'static/js/main.js',
|
||||||
@ -68,7 +67,6 @@ FILE_MAPPINGS = {
|
|||||||
'blocks.js': 'static/js/blocks.js',
|
'blocks.js': 'static/js/blocks.js',
|
||||||
'BitcoinProgressBar.js': 'static/js/BitcoinProgressBar.js',
|
'BitcoinProgressBar.js': 'static/js/BitcoinProgressBar.js',
|
||||||
'notifications.js': 'static/js/notifications.js',
|
'notifications.js': 'static/js/notifications.js',
|
||||||
'console.js': 'static/js/console.js', # Added console.js
|
|
||||||
|
|
||||||
# Template files
|
# Template files
|
||||||
'base.html': 'templates/base.html',
|
'base.html': 'templates/base.html',
|
||||||
@ -78,7 +76,6 @@ FILE_MAPPINGS = {
|
|||||||
'error.html': 'templates/error.html',
|
'error.html': 'templates/error.html',
|
||||||
'blocks.html': 'templates/blocks.html',
|
'blocks.html': 'templates/blocks.html',
|
||||||
'notifications.html': 'templates/notifications.html',
|
'notifications.html': 'templates/notifications.html',
|
||||||
'console.html': 'templates/console.html', # Added console.html
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Default configuration
|
# 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