feat: Add stats bar component to display miner performance metrics and update dashboard layout
This commit is contained in:
parent
aefe328254
commit
7d6e6e9c42
10 changed files with 824 additions and 90 deletions
245
docs/docs.go
245
docs/docs.go
|
|
@ -615,6 +615,9 @@ const docTemplate = `{
|
||||||
"configPath": {
|
"configPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"full_stats": {
|
||||||
|
"$ref": "#/definitions/mining.XMRigSummary"
|
||||||
|
},
|
||||||
"hashrateHistory": {
|
"hashrateHistory": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|
@ -646,6 +649,248 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"mining.XMRigSummary": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"algo": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"algorithms": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connection": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"accepted": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"algo": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avg_time": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"avg_time_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"diff": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"failures": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hashes_total": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rejected": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tls-fingerprint": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"uptime_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"64_bit": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"aes": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"arch": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"assembly": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avx2": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"cores": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"family": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"l2": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"l3": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"msr": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodes": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"proc_info": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"stepping": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"threads": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"x64": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"donate_level": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hashrate": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"highest": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hugepages": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"paused": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hardware_concurrency": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"load_average": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"free": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"resident_set_memory": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"restricted": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"avg_time": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"avg_time_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"best": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diff_current": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hashes_total": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"shares_good": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"shares_total": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ua": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"worker_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
|
||||||
|
|
@ -609,6 +609,9 @@
|
||||||
"configPath": {
|
"configPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"full_stats": {
|
||||||
|
"$ref": "#/definitions/mining.XMRigSummary"
|
||||||
|
},
|
||||||
"hashrateHistory": {
|
"hashrateHistory": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|
@ -640,6 +643,248 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"mining.XMRigSummary": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"algo": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"algorithms": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connection": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"accepted": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"algo": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avg_time": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"avg_time_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"diff": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"failures": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hashes_total": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pool": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rejected": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tls-fingerprint": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"uptime_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"64_bit": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"aes": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"arch": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"assembly": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"avx2": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"cores": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"family": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"l2": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"l3": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"msr": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodes": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"proc_info": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"stepping": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"threads": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"x64": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"donate_level": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hashrate": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"highest": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hugepages": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"paused": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hardware_concurrency": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"load_average": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"free": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"resident_set_memory": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"restricted": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"avg_time": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"avg_time_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"best": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diff_current": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hashes_total": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"shares_good": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"shares_total": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ua": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"worker_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +93,8 @@ definitions:
|
||||||
$ref: '#/definitions/mining.API'
|
$ref: '#/definitions/mining.API'
|
||||||
configPath:
|
configPath:
|
||||||
type: string
|
type: string
|
||||||
|
full_stats:
|
||||||
|
$ref: '#/definitions/mining.XMRigSummary'
|
||||||
hashrateHistory:
|
hashrateHistory:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/mining.HashratePoint'
|
$ref: '#/definitions/mining.HashratePoint'
|
||||||
|
|
@ -114,6 +116,165 @@ definitions:
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
mining.XMRigSummary:
|
||||||
|
properties:
|
||||||
|
algo:
|
||||||
|
type: string
|
||||||
|
algorithms:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
connection:
|
||||||
|
properties:
|
||||||
|
accepted:
|
||||||
|
type: integer
|
||||||
|
algo:
|
||||||
|
type: string
|
||||||
|
avg_time:
|
||||||
|
type: integer
|
||||||
|
avg_time_ms:
|
||||||
|
type: integer
|
||||||
|
diff:
|
||||||
|
type: integer
|
||||||
|
failures:
|
||||||
|
type: integer
|
||||||
|
hashes_total:
|
||||||
|
type: integer
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
ping:
|
||||||
|
type: integer
|
||||||
|
pool:
|
||||||
|
type: string
|
||||||
|
rejected:
|
||||||
|
type: integer
|
||||||
|
tls:
|
||||||
|
type: string
|
||||||
|
tls-fingerprint:
|
||||||
|
type: string
|
||||||
|
uptime:
|
||||||
|
type: integer
|
||||||
|
uptime_ms:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
cpu:
|
||||||
|
properties:
|
||||||
|
64_bit:
|
||||||
|
type: boolean
|
||||||
|
aes:
|
||||||
|
type: boolean
|
||||||
|
arch:
|
||||||
|
type: string
|
||||||
|
assembly:
|
||||||
|
type: string
|
||||||
|
avx2:
|
||||||
|
type: boolean
|
||||||
|
backend:
|
||||||
|
type: string
|
||||||
|
brand:
|
||||||
|
type: string
|
||||||
|
cores:
|
||||||
|
type: integer
|
||||||
|
family:
|
||||||
|
type: integer
|
||||||
|
flags:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
l2:
|
||||||
|
type: integer
|
||||||
|
l3:
|
||||||
|
type: integer
|
||||||
|
model:
|
||||||
|
type: integer
|
||||||
|
msr:
|
||||||
|
type: string
|
||||||
|
nodes:
|
||||||
|
type: integer
|
||||||
|
packages:
|
||||||
|
type: integer
|
||||||
|
proc_info:
|
||||||
|
type: integer
|
||||||
|
stepping:
|
||||||
|
type: integer
|
||||||
|
threads:
|
||||||
|
type: integer
|
||||||
|
x64:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
donate_level:
|
||||||
|
type: integer
|
||||||
|
features:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
hashrate:
|
||||||
|
properties:
|
||||||
|
highest:
|
||||||
|
type: number
|
||||||
|
total:
|
||||||
|
items:
|
||||||
|
type: number
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
hugepages:
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
paused:
|
||||||
|
type: boolean
|
||||||
|
resources:
|
||||||
|
properties:
|
||||||
|
hardware_concurrency:
|
||||||
|
type: integer
|
||||||
|
load_average:
|
||||||
|
items:
|
||||||
|
type: number
|
||||||
|
type: array
|
||||||
|
memory:
|
||||||
|
properties:
|
||||||
|
free:
|
||||||
|
type: integer
|
||||||
|
resident_set_memory:
|
||||||
|
type: integer
|
||||||
|
total:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
restricted:
|
||||||
|
type: boolean
|
||||||
|
results:
|
||||||
|
properties:
|
||||||
|
avg_time:
|
||||||
|
type: integer
|
||||||
|
avg_time_ms:
|
||||||
|
type: integer
|
||||||
|
best:
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
diff_current:
|
||||||
|
type: integer
|
||||||
|
hashes_total:
|
||||||
|
type: integer
|
||||||
|
shares_good:
|
||||||
|
type: integer
|
||||||
|
shares_total:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
ua:
|
||||||
|
type: string
|
||||||
|
uptime:
|
||||||
|
type: integer
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
worker_id:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:8080
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
|
|
|
||||||
|
|
@ -139,17 +139,82 @@ type API struct {
|
||||||
ListenPort int `json:"listenPort"`
|
ListenPort int `json:"listenPort"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// XMRigSummary represents the summary of an XMRig miner's performance.
|
// XMRigSummary represents the full JSON response from the XMRig API.
|
||||||
type XMRigSummary struct {
|
type XMRigSummary struct {
|
||||||
Hashrate struct {
|
ID string `json:"id"`
|
||||||
Total []float64 `json:"total"`
|
WorkerID string `json:"worker_id"`
|
||||||
} `json:"hashrate"`
|
Uptime int `json:"uptime"`
|
||||||
Results struct {
|
Restricted bool `json:"restricted"`
|
||||||
SharesGood uint64 `json:"shares_good"`
|
Resources struct {
|
||||||
SharesTotal uint64 `json:"shares_total"`
|
Memory struct {
|
||||||
|
Free int64 `json:"free"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
ResidentSetMemory int64 `json:"resident_set_memory"`
|
||||||
|
} `json:"memory"`
|
||||||
|
LoadAverage []float64 `json:"load_average"`
|
||||||
|
HardwareConcurrency int `json:"hardware_concurrency"`
|
||||||
|
} `json:"resources"`
|
||||||
|
Features []string `json:"features"`
|
||||||
|
Results struct {
|
||||||
|
DiffCurrent int `json:"diff_current"`
|
||||||
|
SharesGood int `json:"shares_good"`
|
||||||
|
SharesTotal int `json:"shares_total"`
|
||||||
|
AvgTime int `json:"avg_time"`
|
||||||
|
AvgTimeMS int `json:"avg_time_ms"`
|
||||||
|
HashesTotal int `json:"hashes_total"`
|
||||||
|
Best []int `json:"best"`
|
||||||
} `json:"results"`
|
} `json:"results"`
|
||||||
Uptime uint64 `json:"uptime"`
|
Algo string `json:"algo"`
|
||||||
Algorithm string `json:"algorithm"`
|
Connection struct {
|
||||||
|
Pool string `json:"pool"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Uptime int `json:"uptime"`
|
||||||
|
UptimeMS int `json:"uptime_ms"`
|
||||||
|
Ping int `json:"ping"`
|
||||||
|
Failures int `json:"failures"`
|
||||||
|
TLS string `json:"tls"`
|
||||||
|
TLSFingerprint string `json:"tls-fingerprint"`
|
||||||
|
Algo string `json:"algo"`
|
||||||
|
Diff int `json:"diff"`
|
||||||
|
Accepted int `json:"accepted"`
|
||||||
|
Rejected int `json:"rejected"`
|
||||||
|
AvgTime int `json:"avg_time"`
|
||||||
|
AvgTimeMS int `json:"avg_time_ms"`
|
||||||
|
HashesTotal int `json:"hashes_total"`
|
||||||
|
} `json:"connection"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
UA string `json:"ua"`
|
||||||
|
CPU struct {
|
||||||
|
Brand string `json:"brand"`
|
||||||
|
Family int `json:"family"`
|
||||||
|
Model int `json:"model"`
|
||||||
|
Stepping int `json:"stepping"`
|
||||||
|
ProcInfo int `json:"proc_info"`
|
||||||
|
AES bool `json:"aes"`
|
||||||
|
AVX2 bool `json:"avx2"`
|
||||||
|
X64 bool `json:"x64"`
|
||||||
|
Is64Bit bool `json:"64_bit"`
|
||||||
|
L2 int `json:"l2"`
|
||||||
|
L3 int `json:"l3"`
|
||||||
|
Cores int `json:"cores"`
|
||||||
|
Threads int `json:"threads"`
|
||||||
|
Packages int `json:"packages"`
|
||||||
|
Nodes int `json:"nodes"`
|
||||||
|
Backend string `json:"backend"`
|
||||||
|
MSR string `json:"msr"`
|
||||||
|
Assembly string `json:"assembly"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Flags []string `json:"flags"`
|
||||||
|
} `json:"cpu"`
|
||||||
|
DonateLevel int `json:"donate_level"`
|
||||||
|
Paused bool `json:"paused"`
|
||||||
|
Algorithms []string `json:"algorithms"`
|
||||||
|
Hashrate struct {
|
||||||
|
Total []float64 `json:"total"`
|
||||||
|
Highest float64 `json:"highest"`
|
||||||
|
} `json:"hashrate"`
|
||||||
|
Hugepages []int `json:"hugepages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvailableMiner represents a miner that is available for use.
|
// AvailableMiner represents a miner that is available for use.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
// XMRigMiner represents an XMRig miner, embedding the BaseMiner for common functionality.
|
// XMRigMiner represents an XMRig miner, embedding the BaseMiner for common functionality.
|
||||||
type XMRigMiner struct {
|
type XMRigMiner struct {
|
||||||
BaseMiner
|
BaseMiner
|
||||||
|
FullStats *XMRigSummary `json:"full_stats,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpClient = &http.Client{
|
var httpClient = &http.Client{
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ func addCliArgs(config *Config, args *[]string) {
|
||||||
if config.TLS {
|
if config.TLS {
|
||||||
*args = append(*args, "--tls")
|
*args = append(*args, "--tls")
|
||||||
}
|
}
|
||||||
|
*args = append(*args, "--donate-level", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// createConfig creates a JSON configuration file for the XMRig miner.
|
// createConfig creates a JSON configuration file for the XMRig miner.
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the full summary in the miner struct
|
||||||
|
m.FullStats = &summary
|
||||||
|
|
||||||
var hashrate int
|
var hashrate int
|
||||||
if len(summary.Hashrate.Total) > 0 {
|
if len(summary.Hashrate.Total) > 0 {
|
||||||
hashrate = int(summary.Hashrate.Total[0])
|
hashrate = int(summary.Hashrate.Total[0])
|
||||||
|
|
@ -41,9 +44,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) {
|
||||||
|
|
||||||
return &PerformanceMetrics{
|
return &PerformanceMetrics{
|
||||||
Hashrate: hashrate,
|
Hashrate: hashrate,
|
||||||
Shares: int(summary.Results.SharesGood),
|
Shares: summary.Results.SharesGood,
|
||||||
Rejected: int(summary.Results.SharesTotal - summary.Results.SharesGood),
|
Rejected: summary.Results.SharesTotal - summary.Results.SharesGood,
|
||||||
Uptime: int(summary.Uptime),
|
Uptime: summary.Uptime,
|
||||||
Algorithm: summary.Algorithm,
|
Algorithm: summary.Algo,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
<div class="dashboard-view">
|
<div class="dashboard-view">
|
||||||
<div class="header-title">
|
|
||||||
<wa-icon name="cpu" style="font-size: 1.5rem;"></wa-icon>
|
|
||||||
<span>Mining Control</span>
|
|
||||||
<wa-button variant="neutral" appearance="plain" (click)="toggleProfileManager()">
|
|
||||||
<wa-icon name="list-alt" label="Profile Manager"></wa-icon>
|
|
||||||
</wa-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (error()) {
|
@if (error()) {
|
||||||
<wa-card class="card-error">
|
<wa-card class="card-error">
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
|
|
@ -17,75 +9,15 @@
|
||||||
</wa-card>
|
</wa-card>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if(showProfileManager()) {
|
<!-- Consolidated Chart for All Running Miners -->
|
||||||
<div class="profile-manager-view">
|
@if (state().runningMiners.length > 0) {
|
||||||
<snider-mining-profile-list></snider-mining-profile-list>
|
<div class="dashboard-charts">
|
||||||
<snider-mining-profile-create></snider-mining-profile-create>
|
<snider-mining-stats-bar [stats]="state().runningMiners[0]?.full_stats"></snider-mining-stats-bar>
|
||||||
|
<snider-mining-chart></snider-mining-chart>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<!-- Miner Summary and Controls -->
|
<div class="centered-container">
|
||||||
@if (state().installedMiners.length > 0) {
|
<p>No miners running.</p>
|
||||||
<div class="dashboard-summary">
|
</div>
|
||||||
@for (miner of state().installedMiners; track miner.path) {
|
|
||||||
<div class="miner-summary-item">
|
|
||||||
<span class="miner-name">
|
|
||||||
{{ miner.type }}
|
|
||||||
<wa-tooltip>
|
|
||||||
<div slot="content">Version: {{ miner.version }}</div>
|
|
||||||
<wa-icon name="info-circle"></wa-icon>
|
|
||||||
</wa-tooltip>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
@if (isMinerRunning(miner)) {
|
|
||||||
<wa-button
|
|
||||||
variant="danger"
|
|
||||||
[disabled]="actionInProgress() === 'stop-' + miner.type"
|
|
||||||
(click)="stopMiner(miner)">
|
|
||||||
@if (actionInProgress() === 'stop-' + miner.type) {
|
|
||||||
<wa-spinner class="button-spinner"></wa-spinner>
|
|
||||||
} @else {
|
|
||||||
<wa-icon name="stop-circle" slot="prefix"></wa-icon>
|
|
||||||
Stop
|
|
||||||
}
|
|
||||||
</wa-button>
|
|
||||||
} @else {
|
|
||||||
@if(miner.type) {
|
|
||||||
<div class="start-buttons">
|
|
||||||
<wa-select
|
|
||||||
[value]="selectedProfileIds().get(miner.type) ?? ''"
|
|
||||||
(change)="handleProfileSelection(miner.type, $event)">
|
|
||||||
<span slot="label">Profile</span>
|
|
||||||
@for(profile of state().profiles; track profile.id) {
|
|
||||||
@if(profile.minerType === miner.type) {
|
|
||||||
<wa-option [value]="profile.id">{{ profile.name }}</wa-option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</wa-select>
|
|
||||||
<wa-button
|
|
||||||
variant="primary"
|
|
||||||
[disabled]="!selectedProfileIds().get(miner.type) || actionInProgress()?.startsWith('start-')"
|
|
||||||
(click)="startMiner(miner.type)">
|
|
||||||
<wa-icon name="play-circle" slot="prefix"></wa-icon>
|
|
||||||
Start
|
|
||||||
</wa-button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Consolidated Chart for All Running Miners -->
|
|
||||||
@if (state().runningMiners.length > 0) {
|
|
||||||
<div class="dashboard-charts">
|
|
||||||
<snider-mining-chart></snider-mining-chart>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
} @else {
|
|
||||||
<div class="centered-container">
|
|
||||||
<p>No miners installed. Open the Admin Panel to install one.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { MinerService } from './miner.service';
|
||||||
import { ChartComponent } from './chart.component';
|
import { ChartComponent } from './chart.component';
|
||||||
import { ProfileListComponent } from './profile-list.component';
|
import { ProfileListComponent } from './profile-list.component';
|
||||||
import { ProfileCreateComponent } from './profile-create.component';
|
import { ProfileCreateComponent } from './profile-create.component';
|
||||||
|
import { StatsBarComponent } from './stats-bar.component';
|
||||||
|
|
||||||
// Import Web Awesome components
|
// Import Web Awesome components
|
||||||
import "@awesome.me/webawesome/dist/webawesome.js";
|
import "@awesome.me/webawesome/dist/webawesome.js";
|
||||||
|
|
@ -21,7 +22,7 @@ import '@awesome.me/webawesome/dist/components/select/select.js';
|
||||||
selector: 'snider-mining-dashboard',
|
selector: 'snider-mining-dashboard',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent],
|
imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent, StatsBarComponent],
|
||||||
templateUrl: './dashboard.component.html',
|
templateUrl: './dashboard.component.html',
|
||||||
styleUrls: ['./dashboard.component.css']
|
styleUrls: ['./dashboard.component.css']
|
||||||
})
|
})
|
||||||
|
|
|
||||||
80
ui/src/app/stats-bar.component.ts
Normal file
80
ui/src/app/stats-bar.component.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
import { Component, Input, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'snider-mining-stats-bar',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
template: `
|
||||||
|
@if(stats) {
|
||||||
|
<div class="stats-bar">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Hashrate:</span>
|
||||||
|
<span class="value">{{ stats.hashrate?.total[0] | number:'1.0-2' }} H/s</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Algorithm:</span>
|
||||||
|
<span class="value">{{ stats.algo }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Difficulty:</span>
|
||||||
|
<span class="value">{{ stats.connection?.diff | number }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Accepted:</span>
|
||||||
|
<span class="value">{{ stats.results?.shares_good }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Rejected:</span>
|
||||||
|
<span class="value">{{ stats.connection?.rejected }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Avg Time:</span>
|
||||||
|
<span class="value">{{ stats.results?.avg_time | number }}s</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Uptime:</span>
|
||||||
|
<span class="value">{{ stats.uptime | number }}s</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">Pool Uptime:</span>
|
||||||
|
<span class="value">{{ stats.connection?.uptime | number }}s</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
styles: [`
|
||||||
|
.stats-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
`]
|
||||||
|
})
|
||||||
|
export class StatsBarComponent {
|
||||||
|
@Input() stats: any;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue