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" ) // miningError := &MiningError{Code: ErrCodeStartFailed, Message: "failed to start xmrig", HTTPStatus: 500} // miningError.WithCause(err).WithSuggestion("check logs") type MiningError struct { Code string Message string Details string Suggestion string Retryable bool HTTPStatus int Cause 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, } }