fix: update dependencies and add new mining bridge functionality
This commit is contained in:
parent
9360430226
commit
b332f91559
14 changed files with 418 additions and 27 deletions
|
|
@ -56,7 +56,7 @@ require (
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||||
github.com/ebitengine/purego v0.9.1 // indirect
|
github.com/ebitengine/purego v0.9.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.11.0 // indirect
|
github.com/gin-gonic/gin v1.11.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
|
|
@ -66,7 +66,7 @@ require (
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.2.0 // indirect
|
github.com/godbus/dbus/v5 v5.2.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
|
|
@ -84,7 +84,7 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modelcontextprotocol/go-sdk v1.2.0 // indirect
|
github.com/modelcontextprotocol/go-sdk v1.2.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.6.1 // indirect
|
github.com/nicksnyder/go-i18n/v2 v2.6.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@ github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o
|
||||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||||
|
|
@ -64,8 +63,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
||||||
|
|
@ -117,8 +115,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s=
|
github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s=
|
||||||
github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
|
github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ=
|
github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ=
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export {
|
||||||
|
HashratePoint,
|
||||||
|
Manager
|
||||||
|
} from "./models.js";
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import { Create as $Create } from "@wailsio/runtime";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as time$0 from "../../../../../time/models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HashratePoint represents a single hashrate measurement at a specific time.
|
||||||
|
*/
|
||||||
|
export class HashratePoint {
|
||||||
|
"timestamp": time$0.Time;
|
||||||
|
"hashrate": number;
|
||||||
|
|
||||||
|
/** Creates a new HashratePoint instance. */
|
||||||
|
constructor($$source: Partial<HashratePoint> = {}) {
|
||||||
|
if (!("timestamp" in $$source)) {
|
||||||
|
this["timestamp"] = null;
|
||||||
|
}
|
||||||
|
if (!("hashrate" in $$source)) {
|
||||||
|
this["hashrate"] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new HashratePoint instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): HashratePoint {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new HashratePoint($$parsedSource as Partial<HashratePoint>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager handles the lifecycle and operations of multiple miners.
|
||||||
|
*/
|
||||||
|
export class Manager {
|
||||||
|
|
||||||
|
/** Creates a new Manager instance. */
|
||||||
|
constructor($$source: Partial<Manager> = {}) {
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Manager instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): Manager {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new Manager($$parsedSource as Partial<Manager>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Engine
|
Engine,
|
||||||
|
RouterGroup
|
||||||
} from "./models.js";
|
} from "./models.js";
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,35 @@ export type HandlerFunc = any;
|
||||||
*/
|
*/
|
||||||
export type HandlersChain = HandlerFunc[];
|
export type HandlersChain = HandlerFunc[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RouterGroup is used internally to configure router, a RouterGroup is associated with
|
||||||
|
* a prefix and an array of handlers (middleware).
|
||||||
|
*/
|
||||||
|
export class RouterGroup {
|
||||||
|
"Handlers": HandlersChain;
|
||||||
|
|
||||||
|
/** Creates a new RouterGroup instance. */
|
||||||
|
constructor($$source: Partial<RouterGroup> = {}) {
|
||||||
|
if (!("Handlers" in $$source)) {
|
||||||
|
this["Handlers"] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new RouterGroup instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): RouterGroup {
|
||||||
|
const $$createField0_0 = $$createType0;
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
if ("Handlers" in $$parsedSource) {
|
||||||
|
$$parsedSource["Handlers"] = $$createField0_0($$parsedSource["Handlers"]);
|
||||||
|
}
|
||||||
|
return new RouterGroup($$parsedSource as Partial<RouterGroup>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
var $$createType0 = (function $$initCreateType0(...args: any[]): any {
|
var $$createType0 = (function $$initCreateType0(...args: any[]): any {
|
||||||
if ($$createType0 === $$initCreateType0) {
|
if ($$createType0 === $$initCreateType0) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,14 @@
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
import * as MCPBridge from "./mcpbridge.js";
|
import * as MCPBridge from "./mcpbridge.js";
|
||||||
|
import * as MiningBridge from "./miningbridge.js";
|
||||||
export {
|
export {
|
||||||
MCPBridge
|
MCPBridge,
|
||||||
|
MiningBridge
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
AvailableMiner,
|
||||||
|
MinerInfo,
|
||||||
|
MinerStats
|
||||||
|
} from "./models.js";
|
||||||
|
|
|
||||||
128
cmd/lthn-desktop/frontend/bindings/lthn-desktop/miningbridge.ts
Normal file
128
cmd/lthn-desktop/frontend/bindings/lthn-desktop/miningbridge.ts
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MiningBridge wraps the Mining service for integration with lthn-desktop.
|
||||||
|
* It implements module.GinModule to register routes with the module registry.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as module$0 from "../github.com/Snider/Core/pkg/module/models.js";
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as mining$0 from "../github.com/Snider/Mining/pkg/mining/models.js";
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as gin$0 from "../github.com/gin-gonic/gin/models.js";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import * as $models from "./models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetAvailableMiners returns available miner types with their installation status.
|
||||||
|
*/
|
||||||
|
export function GetAvailableMiners(): $CancellablePromise<$models.AvailableMiner[]> {
|
||||||
|
return $Call.ByID(1684715444).then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetHashrateHistory returns hashrate history for a miner.
|
||||||
|
*/
|
||||||
|
export function GetHashrateHistory(name: string): $CancellablePromise<mining$0.HashratePoint[]> {
|
||||||
|
return $Call.ByID(2225670265, name).then(($result: any) => {
|
||||||
|
return $$createType3($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetManager returns the mining manager for direct access.
|
||||||
|
*/
|
||||||
|
export function GetManager(): $CancellablePromise<mining$0.Manager | null> {
|
||||||
|
return $Call.ByID(1181057080).then(($result: any) => {
|
||||||
|
return $$createType5($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetMinerStats returns stats for a specific miner.
|
||||||
|
*/
|
||||||
|
export function GetMinerStats(name: string): $CancellablePromise<$models.MinerStats | null> {
|
||||||
|
return $Call.ByID(4276052451, name).then(($result: any) => {
|
||||||
|
return $$createType7($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InstallMiner installs a miner by type.
|
||||||
|
*/
|
||||||
|
export function InstallMiner(minerType: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(3804132133, minerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ListMiners returns a list of running miners.
|
||||||
|
*/
|
||||||
|
export function ListMiners(): $CancellablePromise<$models.MinerInfo[]> {
|
||||||
|
return $Call.ByID(3810820203).then(($result: any) => {
|
||||||
|
return $$createType9($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModuleConfig returns the module configuration for registration.
|
||||||
|
*/
|
||||||
|
export function ModuleConfig(): $CancellablePromise<module$0.Config> {
|
||||||
|
return $Call.ByID(3066014105).then(($result: any) => {
|
||||||
|
return $$createType10($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegisterRoutes implements module.GinModule to register mining API routes.
|
||||||
|
*/
|
||||||
|
export function RegisterRoutes(group: gin$0.RouterGroup | null): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2353404544, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StartMiner starts a miner with the given configuration.
|
||||||
|
*/
|
||||||
|
export function StartMiner(minerType: string, pool: string, wallet: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(4178811420, minerType, pool, wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StopMiner stops a running miner.
|
||||||
|
*/
|
||||||
|
export function StopMiner(name: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2305106234, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UninstallMiner uninstalls a miner by type.
|
||||||
|
*/
|
||||||
|
export function UninstallMiner(minerType: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2255064918, minerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private type creation functions
|
||||||
|
const $$createType0 = $models.AvailableMiner.createFrom;
|
||||||
|
const $$createType1 = $Create.Array($$createType0);
|
||||||
|
const $$createType2 = mining$0.HashratePoint.createFrom;
|
||||||
|
const $$createType3 = $Create.Array($$createType2);
|
||||||
|
const $$createType4 = mining$0.Manager.createFrom;
|
||||||
|
const $$createType5 = $Create.Nullable($$createType4);
|
||||||
|
const $$createType6 = $models.MinerStats.createFrom;
|
||||||
|
const $$createType7 = $Create.Nullable($$createType6);
|
||||||
|
const $$createType8 = $models.MinerInfo.createFrom;
|
||||||
|
const $$createType9 = $Create.Array($$createType8);
|
||||||
|
const $$createType10 = module$0.Config.createFrom;
|
||||||
110
cmd/lthn-desktop/frontend/bindings/lthn-desktop/models.ts
Normal file
110
cmd/lthn-desktop/frontend/bindings/lthn-desktop/models.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import { Create as $Create } from "@wailsio/runtime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AvailableMiner represents an available miner for installation.
|
||||||
|
*/
|
||||||
|
export class AvailableMiner {
|
||||||
|
"name": string;
|
||||||
|
"description": string;
|
||||||
|
|
||||||
|
/** Creates a new AvailableMiner instance. */
|
||||||
|
constructor($$source: Partial<AvailableMiner> = {}) {
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("description" in $$source)) {
|
||||||
|
this["description"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new AvailableMiner instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): AvailableMiner {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new AvailableMiner($$parsedSource as Partial<AvailableMiner>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinerInfo represents basic miner information for the frontend.
|
||||||
|
*/
|
||||||
|
export class MinerInfo {
|
||||||
|
"name": string;
|
||||||
|
"type": string;
|
||||||
|
"isRunning": boolean;
|
||||||
|
|
||||||
|
/** Creates a new MinerInfo instance. */
|
||||||
|
constructor($$source: Partial<MinerInfo> = {}) {
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("type" in $$source)) {
|
||||||
|
this["type"] = "";
|
||||||
|
}
|
||||||
|
if (!("isRunning" in $$source)) {
|
||||||
|
this["isRunning"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new MinerInfo instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): MinerInfo {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new MinerInfo($$parsedSource as Partial<MinerInfo>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinerStats represents miner statistics for the frontend.
|
||||||
|
*/
|
||||||
|
export class MinerStats {
|
||||||
|
"hashrate": number;
|
||||||
|
"shares": number;
|
||||||
|
"rejected": number;
|
||||||
|
"uptime": number;
|
||||||
|
"lastShare": number;
|
||||||
|
"algorithm": string;
|
||||||
|
|
||||||
|
/** Creates a new MinerStats instance. */
|
||||||
|
constructor($$source: Partial<MinerStats> = {}) {
|
||||||
|
if (!("hashrate" in $$source)) {
|
||||||
|
this["hashrate"] = 0;
|
||||||
|
}
|
||||||
|
if (!("shares" in $$source)) {
|
||||||
|
this["shares"] = 0;
|
||||||
|
}
|
||||||
|
if (!("rejected" in $$source)) {
|
||||||
|
this["rejected"] = 0;
|
||||||
|
}
|
||||||
|
if (!("uptime" in $$source)) {
|
||||||
|
this["uptime"] = 0;
|
||||||
|
}
|
||||||
|
if (!("lastShare" in $$source)) {
|
||||||
|
this["lastShare"] = 0;
|
||||||
|
}
|
||||||
|
if (!("algorithm" in $$source)) {
|
||||||
|
this["algorithm"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new MinerStats instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): MinerStats {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new MinerStats($$parsedSource as Partial<MinerStats>);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
cmd/lthn-desktop/frontend/bindings/time/index.ts
Normal file
6
cmd/lthn-desktop/frontend/bindings/time/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export type {
|
||||||
|
Time
|
||||||
|
} from "./models.js";
|
||||||
51
cmd/lthn-desktop/frontend/bindings/time/models.ts
Normal file
51
cmd/lthn-desktop/frontend/bindings/time/models.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: Unused imports
|
||||||
|
import { Create as $Create } from "@wailsio/runtime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Time represents an instant in time with nanosecond precision.
|
||||||
|
*
|
||||||
|
* Programs using times should typically store and pass them as values,
|
||||||
|
* not pointers. That is, time variables and struct fields should be of
|
||||||
|
* type [time.Time], not *time.Time.
|
||||||
|
*
|
||||||
|
* A Time value can be used by multiple goroutines simultaneously except
|
||||||
|
* that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and
|
||||||
|
* [Time.UnmarshalText] are not concurrency-safe.
|
||||||
|
*
|
||||||
|
* Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods.
|
||||||
|
* The [Time.Sub] method subtracts two instants, producing a [Duration].
|
||||||
|
* The [Time.Add] method adds a Time and a Duration, producing a Time.
|
||||||
|
*
|
||||||
|
* The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC.
|
||||||
|
* As this time is unlikely to come up in practice, the [Time.IsZero] method gives
|
||||||
|
* a simple way of detecting a time that has not been initialized explicitly.
|
||||||
|
*
|
||||||
|
* Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a
|
||||||
|
* Time with a specific Location. Changing the Location of a Time value with
|
||||||
|
* these methods does not change the actual instant it represents, only the time
|
||||||
|
* zone in which to interpret it.
|
||||||
|
*
|
||||||
|
* Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], [Time.AppendBinary],
|
||||||
|
* [Time.MarshalJSON], [Time.MarshalText] and [Time.AppendText] methods store the [Time.Location]'s offset,
|
||||||
|
* but not the location name. They therefore lose information about Daylight Saving Time.
|
||||||
|
*
|
||||||
|
* In addition to the required “wall clock” reading, a Time may contain an optional
|
||||||
|
* reading of the current process's monotonic clock, to provide additional precision
|
||||||
|
* for comparison or subtraction.
|
||||||
|
* See the “Monotonic Clocks” section in the package documentation for details.
|
||||||
|
*
|
||||||
|
* Note that the Go == operator compares not just the time instant but also the
|
||||||
|
* Location and the monotonic clock reading. Therefore, Time values should not
|
||||||
|
* be used as map or database keys without first guaranteeing that the
|
||||||
|
* identical Location has been set for all values, which can be achieved
|
||||||
|
* through use of the UTC or Local method, and that the monotonic clock reading
|
||||||
|
* has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u)
|
||||||
|
* to t == u, since t.Equal uses the most accurate comparison available and
|
||||||
|
* correctly handles the case when only one of its arguments has a monotonic
|
||||||
|
* clock reading.
|
||||||
|
*/
|
||||||
|
export type Time = any;
|
||||||
|
|
@ -31,20 +31,17 @@ func (m *MiningBridge) ServiceStartup(ctx context.Context, options application.S
|
||||||
// Create the mining manager
|
// Create the mining manager
|
||||||
m.manager = mining.NewManager()
|
m.manager = mining.NewManager()
|
||||||
|
|
||||||
// Create the service - empty addresses since we're embedding, not serving standalone
|
// Create the service - we use a dummy address since we're not starting the server
|
||||||
service, err := mining.NewService(m.manager, "", "", "/api/mining")
|
// The Mining service will register routes on its Router which we can proxy to
|
||||||
|
service, err := mining.NewService(m.manager, "127.0.0.1:0", "127.0.0.1:0", "/api/mining")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.service = service
|
m.service = service
|
||||||
|
|
||||||
// Start the service which initializes the router and sets up routes
|
// Note: We don't call ServiceStartup() as that starts a standalone HTTP server
|
||||||
// We use a background context since we don't want it to be canceled with the startup context
|
// The mining routes are already registered on m.service.Router by NewService
|
||||||
go func() {
|
// Frontend can use the Wails-bound methods directly
|
||||||
// Note: ServiceStartup runs the HTTP server which we don't need when embedded
|
|
||||||
// The routes are already registered on m.service.Router
|
|
||||||
_ = m.service.ServiceStartup(context.Background())
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
go.mod
6
go.mod
|
|
@ -23,7 +23,7 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/ebitengine/purego v0.9.1 // indirect
|
github.com/ebitengine/purego v0.9.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||||
|
|
@ -32,7 +32,7 @@ require (
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.2.0 // indirect
|
github.com/godbus/dbus/v5 v5.2.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
|
|
@ -48,7 +48,7 @@ require (
|
||||||
github.com/lmittmann/tint v1.1.2 // indirect
|
github.com/lmittmann/tint v1.1.2 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||||
|
|
|
||||||
8
go.sum
8
go.sum
|
|
@ -34,8 +34,7 @@ github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o
|
||||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||||
|
|
@ -59,8 +58,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
||||||
|
|
@ -104,8 +102,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue