chore: init bj_power monorepo (dashboard/mes/wms/wms_client/workstation), clear subproject git metadata and align naming to folder names
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
package errorx
|
||||
|
||||
type code = uint32
|
||||
|
||||
type CodeError struct {
|
||||
code uint32
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *CodeError) Code() uint32 {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e *CodeError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func NewCodeError(code code, msg string) *CodeError {
|
||||
message[code] = msg
|
||||
return &CodeError{
|
||||
code: code,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
TefNotFound = NewCodeError(1000001, "设备不存在")
|
||||
)
|
||||
|
||||
// OK 成功
|
||||
const OK code = 0
|
||||
|
||||
// 公共错误 100+
|
||||
|
||||
const (
|
||||
ServiceUnavailable = 100001 + iota // 服务不可用
|
||||
RequestParamInvalidWithField // 请求参数错误
|
||||
RequestParamInvalid // 请求参数错误
|
||||
TokenInvalid // token错误
|
||||
DbError // 数据库错误
|
||||
RedisError // 缓存错误
|
||||
RefreshTokenInvalid // RefreshToken错误
|
||||
)
|
||||
|
||||
// login 200+
|
||||
const (
|
||||
BadUsernameOrPassword = 200001 + iota // 用户名或密码错误
|
||||
BadMobileOrPassword // 手机号或密码错误
|
||||
NeedVerifyCode // 请进行人机校验
|
||||
BadVerifyCode // 人机校验失败
|
||||
AccountLocked // 账号已锁定,请15分钟后再试
|
||||
MultipleRoles // 请选择角色
|
||||
NoRole // 用户暂未分配角色
|
||||
RoleNotMatch // 用户无此角色
|
||||
NoPassword // 用户未设置密码,请使用其它方式登录
|
||||
BadMobileOrSms // 手机号或短信验证码错误
|
||||
)
|
||||
|
||||
// permission 300+
|
||||
const (
|
||||
PermissionNotFound = 300001 + iota // 未找到接口权限
|
||||
PermissionAlreadyExists // 权限已存在
|
||||
)
|
||||
|
||||
// role 301+
|
||||
const (
|
||||
RoleNotFound = 301001 + iota // 未找到角色
|
||||
RoleAlreadyExists // 角色已存在
|
||||
RoleHasUsers // 角色已分配角色
|
||||
RoleHasPermissions // 角色已分配权限
|
||||
)
|
||||
|
||||
// api 302+
|
||||
const (
|
||||
ApiNotFound = 302001 + iota // 未找到接口
|
||||
ApiAlreadyExists // 接口已存在
|
||||
ApiHasPermissions // 接口已分配权限
|
||||
)
|
||||
|
||||
// user 400+
|
||||
const (
|
||||
UserNotFound = 400001 + iota // 未找到用户
|
||||
UserAlreadyExists // 用户已存在
|
||||
UserNotAllow
|
||||
UserPasswordNotMatch
|
||||
)
|
||||
|
||||
// dept 401+
|
||||
const (
|
||||
DeptNotFound = 401001 + iota // 未找到部门
|
||||
DeptAlreadyExists // 部门已存在
|
||||
DeptHasUsers // 部门下有用户
|
||||
)
|
||||
|
||||
// line 500+
|
||||
const (
|
||||
LineNotFound = 500001 + iota // 未找到产线
|
||||
LineAlreadyExists // 产线已存在
|
||||
)
|
||||
|
||||
// equipment 600+
|
||||
const (
|
||||
EquipmentNotFound = 600001 + iota // 未找到设备
|
||||
EquipmentAlreadyExists // 设备已存在
|
||||
)
|
||||
|
||||
// cnc machine 610+
|
||||
const (
|
||||
CncMachineNotFound = 610001 + iota // 未找到机床
|
||||
CncMachineAlreadyExists // 机床已存在
|
||||
)
|
||||
|
||||
// robot 620+
|
||||
const (
|
||||
RobotNotFound = 620001 + iota // 未找到机器人
|
||||
RobotAlreadyExists // 机器人已存在
|
||||
)
|
||||
|
||||
// plc 630+
|
||||
const (
|
||||
PLCNotFound = 630001 + iota // 未找到PLC
|
||||
PLCAlreadyExists // PLC已存在
|
||||
PLCNotConnect // PLC未连接
|
||||
)
|
||||
|
||||
// process 700+
|
||||
const (
|
||||
ProcessNotFound = 700001 + iota // 未找到工艺流程
|
||||
ProcessAlreadyExists // 工艺流程已存在
|
||||
)
|
||||
|
||||
// step 710+
|
||||
const (
|
||||
StepNotFound = 710001 + iota // 未找到工步
|
||||
StepAlreadyExists // 工步已存在
|
||||
)
|
||||
|
||||
// program 800+
|
||||
const (
|
||||
ProgramNotFound = 800001 + iota // 未找到数控程序
|
||||
ProgramAlreadyExists // 数控程序已存在
|
||||
)
|
||||
|
||||
// other 900+
|
||||
const (
|
||||
EquipmentCategoryNotFound = 900001 + iota
|
||||
EquipmentCategoryAlreadyExists
|
||||
)
|
||||
|
||||
// work order 1000+
|
||||
const (
|
||||
WorkOrderNotFound = 1000001 + iota // 未找到工单
|
||||
WorkOrderAlreadyExists // 工单已存在
|
||||
WorkOrderConcurrentlyInProcess // 已有工单在执行
|
||||
WorkOrderAlreadyPausing // 工单正在暂停中
|
||||
WorkOrderAlreadyPaused // 工单已暂停
|
||||
)
|
||||
|
||||
// work order 1100+
|
||||
const (
|
||||
TaskNotFound = 1100001 + iota // 未找到工单
|
||||
TaskAlreadyExists // 工单已存在
|
||||
)
|
||||
|
||||
// workpiece 1200+
|
||||
const (
|
||||
WorkpieceNotFound = 1200001 + iota // 未找到工件
|
||||
WorkpieceAlreadyExists // 工件已存在 = 1200001 + iota // 未找到工件
|
||||
OrderProcessorNotReady // 工单处理器未就绪
|
||||
)
|
||||
|
||||
// material 1210+
|
||||
const (
|
||||
MaterialNotFound = 1210001 + iota // 未找到物料
|
||||
MaterialAlreadyExists // 物料已存在 = 1200001 + iota // 未找到工件
|
||||
)
|
||||
|
||||
// fixture type 1220+
|
||||
const (
|
||||
FixtureTypeNotFound = 1220001 + iota
|
||||
FixtureTypeAlreadyExists
|
||||
)
|
||||
|
||||
// rack 1300+
|
||||
const (
|
||||
RackNotFound = 1300001 + iota // 未找到料架
|
||||
RackAlreadyExists // 料架已存在
|
||||
RackLocationUsed // 料架位置已被占用
|
||||
RackLocationEmpty // 料架位置无料
|
||||
RackLocationExceedCapacity // 料架位置无料
|
||||
)
|
||||
|
||||
const (
|
||||
DockNotFound = 1400001 + iota
|
||||
DockAlreadyExists
|
||||
DockLocationExceedCapacity
|
||||
)
|
||||
|
||||
// Tool
|
||||
const (
|
||||
ToolNotFound = 1500001 + iota // 未找到刀具
|
||||
ToolAlreadyExists // 刀具已存在
|
||||
)
|
||||
|
||||
// ToolRack
|
||||
const (
|
||||
ToolRackNotFound = 1500001 + iota // 未找到刀具库
|
||||
ToolRackAlreadyExists // 刀具库已存在
|
||||
)
|
||||
|
||||
// ToolType
|
||||
const (
|
||||
ToolTypeNotFound = 1510001 + iota // 未找到刀具类型
|
||||
ToolTypeAlreadyExists // 刀具类型已存在
|
||||
)
|
||||
|
||||
const (
|
||||
MachineNotFound = 1600001 + iota // 未找到料架
|
||||
MachineUsed // 机床已被占用
|
||||
MachineFixtureExist // 夹具已存在
|
||||
MachineFixtureTypeNotMatch // 夹具类型不匹配
|
||||
)
|
||||
|
||||
const (
|
||||
MillingTempStationLineError = 1700001 + iota // 未找到料架
|
||||
MillingTempStationHasWorkpiece
|
||||
MillingTempStationNotFound
|
||||
)
|
||||
|
||||
const (
|
||||
DockEquipmentTypeNotFound = 1800001 + iota // 未找到接驳台设备类型
|
||||
DockEquipmentTypeAlreadyExists // 接驳台设备类型已存在
|
||||
)
|
||||
|
||||
const (
|
||||
// CommonErrCode 未知错误
|
||||
CommonErrCode code = 900000
|
||||
// DirectErrCode 直接显示错误信息
|
||||
DirectErrCode code = 900001
|
||||
)
|
||||
|
||||
const (
|
||||
DockErrorNotFound = 1900001 + iota // 接驳台查找错误
|
||||
DockFrontHasSmallTray // 接驳台前方有小工件
|
||||
DockReadError // 读取接驳台错误
|
||||
)
|
||||
|
||||
var message = make(map[code]string)
|
||||
|
||||
func init() {
|
||||
|
||||
message[OK] = "OK"
|
||||
message[CommonErrCode] = "服务器开小差啦, 稍后再来试一试"
|
||||
|
||||
message[ServiceUnavailable] = "服务不可用"
|
||||
message[RequestParamInvalidWithField] = "参数错误"
|
||||
message[RequestParamInvalid] = "参数错误"
|
||||
message[TokenInvalid] = "token错误"
|
||||
message[DbError] = "数据库繁忙, 请稍后再试"
|
||||
message[RedisError] = "缓存错误, 请稍后再试"
|
||||
message[RefreshTokenInvalid] = "RefreshToken错误"
|
||||
|
||||
message[BadUsernameOrPassword] = "用户名或密码错误"
|
||||
message[BadMobileOrPassword] = "手机号或密码错误"
|
||||
message[NeedVerifyCode] = "请输入验证码"
|
||||
message[BadVerifyCode] = "验证码错误"
|
||||
message[AccountLocked] = "账号已锁定,请15分钟后再试"
|
||||
message[MultipleRoles] = "请选择角色"
|
||||
message[NoRole] = "用户暂未分配角色"
|
||||
message[RoleNotMatch] = "角色不匹配"
|
||||
message[NoPassword] = "用户未设置密码,请使用其它方式登录"
|
||||
message[BadMobileOrSms] = "手机号或短信验证码错误"
|
||||
|
||||
message[PermissionNotFound] = "抱歉, 您的权限不足"
|
||||
message[PermissionAlreadyExists] = "权限已存在"
|
||||
message[RoleNotFound] = "未找到角色"
|
||||
message[RoleAlreadyExists] = "角色已存在"
|
||||
message[RoleHasUsers] = "角色已分配角色"
|
||||
message[RoleHasPermissions] = "角色已分配权限"
|
||||
message[ApiNotFound] = "未找到接口"
|
||||
message[ApiAlreadyExists] = "接口已存在"
|
||||
message[ApiHasPermissions] = "接口已分配权限"
|
||||
|
||||
message[UserNotFound] = "未找到用户"
|
||||
message[UserAlreadyExists] = "用户已存在"
|
||||
message[UserNotAllow] = "用户没有权限"
|
||||
message[UserPasswordNotMatch] = "用户原密码不匹配"
|
||||
|
||||
message[DeptNotFound] = "未找到部门"
|
||||
message[DeptAlreadyExists] = "部门已存在"
|
||||
message[DeptHasUsers] = "部门下有用户"
|
||||
|
||||
message[LineNotFound] = "未找到产线"
|
||||
message[LineAlreadyExists] = "产线已存在"
|
||||
|
||||
message[EquipmentNotFound] = "未找到设备"
|
||||
message[EquipmentAlreadyExists] = "设备已存在"
|
||||
|
||||
message[CncMachineNotFound] = "未找到机床"
|
||||
message[CncMachineAlreadyExists] = "机床已存在"
|
||||
|
||||
message[RobotNotFound] = "未找到机器人"
|
||||
message[RobotAlreadyExists] = "机器人已存在"
|
||||
|
||||
message[PLCNotFound] = "未找到PLC"
|
||||
message[PLCAlreadyExists] = "PLC已存在"
|
||||
message[PLCNotConnect] = "PLC未连接"
|
||||
|
||||
message[ProcessNotFound] = "未找到工艺"
|
||||
message[ProcessAlreadyExists] = "工艺已存在"
|
||||
|
||||
message[StepNotFound] = "未找到工步"
|
||||
message[StepAlreadyExists] = "工步已存在"
|
||||
|
||||
message[ProgramNotFound] = "未找到数控程序"
|
||||
message[ProgramAlreadyExists] = "数控程序已存在"
|
||||
|
||||
message[WorkOrderNotFound] = "未找到工单"
|
||||
message[WorkOrderAlreadyExists] = "工单已存在"
|
||||
message[WorkOrderConcurrentlyInProcess] = "已有工单在执行"
|
||||
|
||||
message[RackNotFound] = "未找到料架"
|
||||
message[RackAlreadyExists] = "料架已存在"
|
||||
|
||||
message[RackLocationUsed] = "料架位置已被占用"
|
||||
message[RackLocationEmpty] = "料架位置无料"
|
||||
message[RackLocationExceedCapacity] = "位置超出料架容量"
|
||||
|
||||
message[TaskNotFound] = "未找到工单"
|
||||
message[TaskAlreadyExists] = "工单已存在"
|
||||
|
||||
message[WorkpieceNotFound] = "未找到工件"
|
||||
message[WorkpieceAlreadyExists] = "当前位置已占用"
|
||||
|
||||
message[MaterialNotFound] = "未找到物料"
|
||||
message[MaterialAlreadyExists] = "物料已存在"
|
||||
|
||||
message[FixtureTypeNotFound] = "未找到夹具类型"
|
||||
message[FixtureTypeAlreadyExists] = "夹具类型已存在"
|
||||
|
||||
message[DockNotFound] = "未找到接驳台"
|
||||
message[DockAlreadyExists] = "接驳台已存在"
|
||||
message[DockLocationExceedCapacity] = "位置超出接驳台容量"
|
||||
|
||||
message[ToolNotFound] = "未找到刀具"
|
||||
message[ToolAlreadyExists] = "刀具已存在"
|
||||
|
||||
message[ToolRackNotFound] = "未找到刀具库"
|
||||
message[ToolRackAlreadyExists] = "刀具库已存在"
|
||||
|
||||
message[ToolTypeNotFound] = "未找到刀具类型"
|
||||
message[ToolTypeAlreadyExists] = "刀具类型已存在"
|
||||
|
||||
message[MachineNotFound] = "机床未找到"
|
||||
message[MachineUsed] = "机床已被占用"
|
||||
message[MachineFixtureExist] = "夹具已存在"
|
||||
message[MachineFixtureTypeNotMatch] = "夹具类型不匹配"
|
||||
|
||||
message[MillingTempStationLineError] = "铣线只能选择铣线Robot"
|
||||
message[MillingTempStationHasWorkpiece] = "铣线只能选择铣线Robot"
|
||||
|
||||
message[DockEquipmentTypeNotFound] = "未找到接驳台设备类型"
|
||||
message[DockEquipmentTypeAlreadyExists] = "接驳台设备类型已存在"
|
||||
|
||||
message[DockErrorNotFound] = "接驳台查找错误"
|
||||
message[DockFrontHasSmallTray] = "此位置前面有小工件,请重新扫描接驳台后再操作"
|
||||
message[DockReadError] = "读取接驳台"
|
||||
}
|
||||
|
||||
func MapErrMsg(errCode code, msg ...string) string {
|
||||
if errCode == DirectErrCode {
|
||||
return msg[0]
|
||||
}
|
||||
if msg, ok := message[errCode]; ok {
|
||||
return msg
|
||||
} else {
|
||||
return "服务器开小差啦,稍后再来试一试"
|
||||
}
|
||||
}
|
||||
|
||||
func IsCodeErr(errCode code) bool {
|
||||
if _, ok := message[errCode]; ok {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
package errorx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ServiceError interface {
|
||||
Code() code
|
||||
Error() string
|
||||
}
|
||||
|
||||
type ServiceFieldError interface {
|
||||
ServiceError
|
||||
Field() string
|
||||
}
|
||||
|
||||
type ServiceFieldErrors interface {
|
||||
Errors() []error
|
||||
}
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(code code, message ...string) error {
|
||||
msg := strings.Join(message, " ")
|
||||
return &fundamental{
|
||||
code: code,
|
||||
msg: msg,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDirectError(message ...string) error {
|
||||
return New(DirectErrCode, message...)
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(code code, format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
code: code,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
code code
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Code() code { return f.code }
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
_, _ = io.WriteString(s, fmt.Sprintf("%d", f.code))
|
||||
_, _ = io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
_, _ = io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
_, _ = fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
func NewFieldError(field string, message string) error {
|
||||
return &fieldError{
|
||||
fundamental: fundamental{
|
||||
code: RequestParamInvalidWithField,
|
||||
msg: message,
|
||||
},
|
||||
field: field,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFieldErrorf(field string, format string, args ...interface{}) error {
|
||||
return &fieldError{
|
||||
fundamental: fundamental{
|
||||
code: RequestParamInvalidWithField,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
},
|
||||
field: field,
|
||||
}
|
||||
}
|
||||
|
||||
type fieldError struct {
|
||||
fundamental
|
||||
field string
|
||||
}
|
||||
|
||||
func (f *fieldError) Code() code { return f.code }
|
||||
|
||||
func (f *fieldError) Error() string { return f.msg }
|
||||
|
||||
func (f *fieldError) Field() string { return f.field }
|
||||
|
||||
func NewFieldErrors(fields map[string]string) error {
|
||||
err := &fieldErrors{
|
||||
fundamental: fundamental{
|
||||
code: RequestParamInvalidWithField,
|
||||
},
|
||||
}
|
||||
for field, msg := range fields {
|
||||
err.errors = append(err.errors, NewFieldError(field, msg))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type fieldErrors struct {
|
||||
fundamental
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (f *fieldErrors) Errors() []error { return f.errors }
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error, code code) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
code,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
code
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Code() code { return w.code }
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withStack) Unwrap() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
_, _ = fmt.Fprintf(s, "%+v", w.Cause())
|
||||
_, _ = io.WriteString(s, fmt.Sprintf(" code: %d", w.code))
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
_, _ = io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
_, _ = fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, code code, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
code: code,
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
code,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, code code, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
code: code,
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
code,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, code uint32, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
code: code,
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, code uint32, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
code: code,
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
code code
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Code() code {
|
||||
return w.code
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string {
|
||||
return fmt.Sprintf("%d", w.code) + ": " + w.msg + ": " + w.cause.Error()
|
||||
}
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withMessage) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
_, _ = fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
_, _ = io.WriteString(s, fmt.Sprintf("code: %d ", w.code))
|
||||
_, _ = io.WriteString(s, fmt.Sprintf(", msg: %s\n", w.msg))
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
_, _ = io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package errorx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
// For historical reasons if Frame is interpreted as a uintptr
|
||||
// its value represents the program counter + 1.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// name returns the name of this function, if known.
|
||||
func (f Frame) name() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
return fn.Name()
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
_, _ = io.WriteString(s, f.name())
|
||||
_, _ = io.WriteString(s, "\n\t")
|
||||
_, _ = io.WriteString(s, f.file())
|
||||
default:
|
||||
_, _ = io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
_, _ = io.WriteString(s, strconv.Itoa(f.line()))
|
||||
case 'n':
|
||||
_, _ = io.WriteString(s, funcname(f.name()))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
_, _ = io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
||||
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
||||
func (f Frame) MarshalText() ([]byte, error) {
|
||||
name := f.name()
|
||||
if name == "unknown" {
|
||||
return []byte(name), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
_, _ = io.WriteString(s, "\n")
|
||||
f.Format(s, verb)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
_, _ = fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
case 's':
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
}
|
||||
|
||||
// formatSlice will format this StackTrace into the given buffer as a slice of
|
||||
// Frame, only valid when called with '%s' or '%v'.
|
||||
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
||||
_, _ = io.WriteString(s, "[")
|
||||
for i, f := range st {
|
||||
if i > 0 {
|
||||
_, _ = io.WriteString(s, " ")
|
||||
}
|
||||
f.Format(s, verb)
|
||||
}
|
||||
_, _ = io.WriteString(s, "]")
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
_, _ = fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
||||
Reference in New Issue
Block a user