Mining/pkg/mining/errors.go
Claude 43e4b447ac
ax(batch): remove banned import references from comment examples
Replace all fmt.Println, fmt.Sprintf, log.Printf, log.Println, and
json.Unmarshal references in doc comments with logging.Info/logging.Warn
or direct value access patterns. Comments are examples that agents
learn from -- they must not demonstrate banned imports.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 18:07:35 +01:00

246 lines
7.6 KiB
Go

package mining
import (
"net/http"
)
// respondWithError(c, http.StatusNotFound, ErrCodeMinerNotFound, "xmrig not found", err.Error())
// respondWithError(c, http.StatusConflict, ErrCodeMinerExists, "xmrig already running", "")
const (
ErrCodeMinerNotFound = "MINER_NOT_FOUND"
ErrCodeMinerExists = "MINER_EXISTS"
ErrCodeMinerNotRunning = "MINER_NOT_RUNNING"
ErrCodeInstallFailed = "INSTALL_FAILED"
ErrCodeStartFailed = "START_FAILED"
ErrCodeStopFailed = "STOP_FAILED"
ErrCodeInvalidConfig = "INVALID_CONFIG"
ErrCodeInvalidInput = "INVALID_INPUT"
ErrCodeUnsupportedMiner = "UNSUPPORTED_MINER"
ErrCodeNotSupported = "NOT_SUPPORTED"
ErrCodeConnectionFailed = "CONNECTION_FAILED"
ErrCodeServiceUnavailable = "SERVICE_UNAVAILABLE"
ErrCodeTimeout = "TIMEOUT"
ErrCodeDatabaseError = "DATABASE_ERROR"
ErrCodeProfileNotFound = "PROFILE_NOT_FOUND"
ErrCodeProfileExists = "PROFILE_EXISTS"
ErrCodeInternalError = "INTERNAL_ERROR"
)
// e := &MiningError{Code: ErrCodeStartFailed, Message: "failed to start xmrig", HTTPStatus: 500}
// e.WithCause(err).WithSuggestion("check logs")
type MiningError struct {
Code string // Machine-readable error code
Message string // Human-readable message
Details string // Technical details (for debugging)
Suggestion string // What to do next
Retryable bool // Can the client retry?
HTTPStatus int // HTTP status code to return
Cause error // Underlying error
}
// e.Error() // "START_FAILED: failed to start miner 'xmrig' (exec: not found)"
func (e *MiningError) Error() string {
if e.Cause != nil {
return e.Code + ": " + e.Message + " (" + e.Cause.Error() + ")"
}
return e.Code + ": " + e.Message
}
// errors.As(e.Unwrap(), &target) // unwrap to inspect the underlying cause
func (e *MiningError) Unwrap() error {
return e.Cause
}
// return ErrStartFailed("xmrig").WithCause(err)
func (e *MiningError) WithCause(err error) *MiningError {
e.Cause = err
return e
}
// return ErrInternal("nil response").WithDetails("stats API returned null body")
func (e *MiningError) WithDetails(details string) *MiningError {
e.Details = details
return e
}
// return ErrInstallFailed("xmrig").WithSuggestion("ensure curl is installed")
func (e *MiningError) WithSuggestion(suggestion string) *MiningError {
e.Suggestion = suggestion
return e
}
// if e.IsRetryable() { time.Sleep(backoff); retry() }
func (e *MiningError) IsRetryable() bool {
return e.Retryable
}
// c.JSON(e.StatusCode(), e) // 404 for not-found, 500 for internal errors
func (e *MiningError) StatusCode() int {
if e.HTTPStatus == 0 {
return http.StatusInternalServerError
}
return e.HTTPStatus
}
// NewMiningError("START_FAILED", "failed to start xmrig").WithCause(err)
func NewMiningError(code, message string) *MiningError {
return &MiningError{
Code: code,
Message: message,
HTTPStatus: http.StatusInternalServerError,
}
}
// return ErrMinerNotFound("xmrig").WithCause(err)
func ErrMinerNotFound(name string) *MiningError {
return &MiningError{
Code: ErrCodeMinerNotFound,
Message: "miner '" + name + "' not found",
Suggestion: "Check that the miner name is correct and that it is running",
Retryable: false,
HTTPStatus: http.StatusNotFound,
}
}
// return ErrMinerExists("xmrig")
func ErrMinerExists(name string) *MiningError {
return &MiningError{
Code: ErrCodeMinerExists,
Message: "miner '" + name + "' is already running",
Suggestion: "Stop the existing miner first or use a different configuration",
Retryable: false,
HTTPStatus: http.StatusConflict,
}
}
// return ErrMinerNotRunning("xmrig")
func ErrMinerNotRunning(name string) *MiningError {
return &MiningError{
Code: ErrCodeMinerNotRunning,
Message: "miner '" + name + "' is not running",
Suggestion: "Start the miner first before performing this operation",
Retryable: false,
HTTPStatus: http.StatusBadRequest,
}
}
// return ErrInstallFailed("xmrig").WithCause(err)
func ErrInstallFailed(minerType string) *MiningError {
return &MiningError{
Code: ErrCodeInstallFailed,
Message: "failed to install " + minerType,
Suggestion: "Check your internet connection and try again",
Retryable: true,
HTTPStatus: http.StatusInternalServerError,
}
}
// return ErrStartFailed("xmrig").WithCause(err)
func ErrStartFailed(name string) *MiningError {
return &MiningError{
Code: ErrCodeStartFailed,
Message: "failed to start miner '" + name + "'",
Suggestion: "Check the miner configuration and logs for details",
Retryable: true,
HTTPStatus: http.StatusInternalServerError,
}
}
// return ErrStopFailed("xmrig").WithCause(err)
func ErrStopFailed(name string) *MiningError {
return &MiningError{
Code: ErrCodeStopFailed,
Message: "failed to stop miner '" + name + "'",
Suggestion: "The miner process may need to be terminated manually",
Retryable: true,
HTTPStatus: http.StatusInternalServerError,
}
}
// return ErrInvalidConfig("wallet address is required")
func ErrInvalidConfig(reason string) *MiningError {
return &MiningError{
Code: ErrCodeInvalidConfig,
Message: "invalid configuration: " + reason,
Suggestion: "Review the configuration and ensure all required fields are provided",
Retryable: false,
HTTPStatus: http.StatusBadRequest,
}
}
// return ErrUnsupportedMiner("nicehash")
func ErrUnsupportedMiner(minerType string) *MiningError {
return &MiningError{
Code: ErrCodeUnsupportedMiner,
Message: "unsupported miner type: " + minerType,
Suggestion: "Use one of the supported miner types: xmrig, tt-miner",
Retryable: false,
HTTPStatus: http.StatusBadRequest,
}
}
// return ErrConnectionFailed("pool.minexmr.com:4444").WithCause(err)
func ErrConnectionFailed(target string) *MiningError {
return &MiningError{
Code: ErrCodeConnectionFailed,
Message: "failed to connect to " + target,
Suggestion: "Check network connectivity and try again",
Retryable: true,
HTTPStatus: http.StatusServiceUnavailable,
}
}
// return ErrTimeout("stats poll")
func ErrTimeout(operation string) *MiningError {
return &MiningError{
Code: ErrCodeTimeout,
Message: "operation timed out: " + operation,
Suggestion: "The operation is taking longer than expected, try again later",
Retryable: true,
HTTPStatus: http.StatusGatewayTimeout,
}
}
// return ErrDatabaseError("save profile")
func ErrDatabaseError(operation string) *MiningError {
return &MiningError{
Code: ErrCodeDatabaseError,
Message: "database error during " + operation,
Suggestion: "This may be a temporary issue, try again",
Retryable: true,
HTTPStatus: http.StatusInternalServerError,
}
}
// return ErrProfileNotFound("default-xmr")
func ErrProfileNotFound(id string) *MiningError {
return &MiningError{
Code: ErrCodeProfileNotFound,
Message: "profile '" + id + "' not found",
Suggestion: "Check that the profile ID is correct",
Retryable: false,
HTTPStatus: http.StatusNotFound,
}
}
// return ErrProfileExists("default-xmr")
func ErrProfileExists(name string) *MiningError {
return &MiningError{
Code: ErrCodeProfileExists,
Message: "profile '" + name + "' already exists",
Suggestion: "Use a different name or update the existing profile",
Retryable: false,
HTTPStatus: http.StatusConflict,
}
}
// return ErrInternal("unexpected nil response from stats API")
func ErrInternal(message string) *MiningError {
return &MiningError{
Code: ErrCodeInternalError,
Message: message,
Suggestion: "Please report this issue if it persists",
Retryable: true,
HTTPStatus: http.StatusInternalServerError,
}
}