diff --git a/docs/docs.go b/docs/docs.go index cd764e4..4d363d1 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -615,6 +615,9 @@ const docTemplate = `{ "configPath": { "type": "string" }, + "full_stats": { + "$ref": "#/definitions/mining.XMRigSummary" + }, "hashrateHistory": { "type": "array", "items": { @@ -646,6 +649,248 @@ const docTemplate = `{ "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" + } + } } } }` diff --git a/docs/swagger.json b/docs/swagger.json index 432ed77..157348b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -609,6 +609,9 @@ "configPath": { "type": "string" }, + "full_stats": { + "$ref": "#/definitions/mining.XMRigSummary" + }, "hashrateHistory": { "type": "array", "items": { @@ -640,6 +643,248 @@ "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" + } + } } } } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index a35e2e3..c734675 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -93,6 +93,8 @@ definitions: $ref: '#/definitions/mining.API' configPath: type: string + full_stats: + $ref: '#/definitions/mining.XMRigSummary' hashrateHistory: items: $ref: '#/definitions/mining.HashratePoint' @@ -114,6 +116,165 @@ definitions: version: type: string 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 info: contact: {} diff --git a/pkg/mining/mining.go b/pkg/mining/mining.go index e14947c..931a7bd 100644 --- a/pkg/mining/mining.go +++ b/pkg/mining/mining.go @@ -139,17 +139,82 @@ type API struct { 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 { - Hashrate struct { - Total []float64 `json:"total"` - } `json:"hashrate"` - Results struct { - SharesGood uint64 `json:"shares_good"` - SharesTotal uint64 `json:"shares_total"` + ID string `json:"id"` + WorkerID string `json:"worker_id"` + Uptime int `json:"uptime"` + Restricted bool `json:"restricted"` + Resources struct { + 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"` - Uptime uint64 `json:"uptime"` - Algorithm string `json:"algorithm"` + Algo string `json:"algo"` + 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. diff --git a/pkg/mining/xmrig.go b/pkg/mining/xmrig.go index 26191e1..dda6d93 100644 --- a/pkg/mining/xmrig.go +++ b/pkg/mining/xmrig.go @@ -19,6 +19,7 @@ import ( // XMRigMiner represents an XMRig miner, embedding the BaseMiner for common functionality. type XMRigMiner struct { BaseMiner + FullStats *XMRigSummary `json:"full_stats,omitempty"` } var httpClient = &http.Client{ diff --git a/pkg/mining/xmrig_start.go b/pkg/mining/xmrig_start.go index 40e9fb2..42e993f 100644 --- a/pkg/mining/xmrig_start.go +++ b/pkg/mining/xmrig_start.go @@ -100,6 +100,7 @@ func addCliArgs(config *Config, args *[]string) { if config.TLS { *args = append(*args, "--tls") } + *args = append(*args, "--donate-level", "1") } // createConfig creates a JSON configuration file for the XMRig miner. diff --git a/pkg/mining/xmrig_stats.go b/pkg/mining/xmrig_stats.go index 27335a4..2f58429 100644 --- a/pkg/mining/xmrig_stats.go +++ b/pkg/mining/xmrig_stats.go @@ -34,6 +34,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) { return nil, err } + // Store the full summary in the miner struct + m.FullStats = &summary + var hashrate int if len(summary.Hashrate.Total) > 0 { hashrate = int(summary.Hashrate.Total[0]) @@ -41,9 +44,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) { return &PerformanceMetrics{ Hashrate: hashrate, - Shares: int(summary.Results.SharesGood), - Rejected: int(summary.Results.SharesTotal - summary.Results.SharesGood), - Uptime: int(summary.Uptime), - Algorithm: summary.Algorithm, + Shares: summary.Results.SharesGood, + Rejected: summary.Results.SharesTotal - summary.Results.SharesGood, + Uptime: summary.Uptime, + Algorithm: summary.Algo, }, nil } diff --git a/ui/src/app/dashboard.component.html b/ui/src/app/dashboard.component.html index 62cecaf..052948d 100644 --- a/ui/src/app/dashboard.component.html +++ b/ui/src/app/dashboard.component.html @@ -1,12 +1,4 @@
-
- - Mining Control - - - -
- @if (error()) {
@@ -17,75 +9,15 @@ } - @if(showProfileManager()) { -
- - + + @if (state().runningMiners.length > 0) { +
+ +
} @else { - - @if (state().installedMiners.length > 0) { -
- @for (miner of state().installedMiners; track miner.path) { -
- - {{ miner.type }} - -
Version: {{ miner.version }}
- -
-
- - @if (isMinerRunning(miner)) { - - @if (actionInProgress() === 'stop-' + miner.type) { - - } @else { - - Stop - } - - } @else { - @if(miner.type) { -
- - Profile - @for(profile of state().profiles; track profile.id) { - @if(profile.minerType === miner.type) { - {{ profile.name }} - } - } - - - - Start - -
- } - } -
- } -
- - - @if (state().runningMiners.length > 0) { -
- -
- } - - } @else { -
-

No miners installed. Open the Admin Panel to install one.

-
- } +
+

No miners running.

+
}
diff --git a/ui/src/app/dashboard.component.ts b/ui/src/app/dashboard.component.ts index f53f424..bd5264e 100644 --- a/ui/src/app/dashboard.component.ts +++ b/ui/src/app/dashboard.component.ts @@ -6,6 +6,7 @@ import { MinerService } from './miner.service'; import { ChartComponent } from './chart.component'; import { ProfileListComponent } from './profile-list.component'; import { ProfileCreateComponent } from './profile-create.component'; +import { StatsBarComponent } from './stats-bar.component'; // Import Web Awesome components import "@awesome.me/webawesome/dist/webawesome.js"; @@ -21,7 +22,7 @@ import '@awesome.me/webawesome/dist/components/select/select.js'; selector: 'snider-mining-dashboard', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], - imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent], + imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent, StatsBarComponent], templateUrl: './dashboard.component.html', styleUrls: ['./dashboard.component.css'] }) diff --git a/ui/src/app/stats-bar.component.ts b/ui/src/app/stats-bar.component.ts new file mode 100644 index 0000000..0b136bd --- /dev/null +++ b/ui/src/app/stats-bar.component.ts @@ -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) { +
+
+ Hashrate: + {{ stats.hashrate?.total[0] | number:'1.0-2' }} H/s +
+
+ Algorithm: + {{ stats.algo }} +
+
+ Difficulty: + {{ stats.connection?.diff | number }} +
+
+ Accepted: + {{ stats.results?.shares_good }} +
+
+ Rejected: + {{ stats.connection?.rejected }} +
+
+ Avg Time: + {{ stats.results?.avg_time | number }}s +
+
+ Uptime: + {{ stats.uptime | number }}s +
+
+ Pool Uptime: + {{ stats.connection?.uptime | number }}s +
+
+ } + `, + 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; +}