Files
smartmate/backend/services/task_class/rpc/errors.go
Losita 7ed8adf8d1 Version: 0.9.72.dev.260505
后端:
1.task-class 服务边界落地
- 新增 cmd/task-class 独立进程入口,落地 services/task_class dao/rpc/sv
- 新增 gateway/client/taskclass、shared/contracts/taskclass 和 shared/ports task-class port
- 将 /api/v1/task-class/* HTTP 门面切到 task-class zrpc,gateway 只保留鉴权、幂等、参数绑定和响应透传
- 保留 task-class 迁移期直写 schedule_events / schedules 权限,维持 insert/apply 与 item 状态更新的本地事务语义
- 修复 task-class 删除已排入日程任务块时 schedules / schedule_events 的外键删除顺序
- 补充 taskClass.rpc 示例配置与阶段 5 文档基线、切流点、残留依赖和 smoke 记录
- 忽略根目录 .tmp 临时烟测产物
2026-05-05 11:24:16 +08:00

84 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package rpc
import (
"errors"
"log"
"strings"
"github.com/LoveLosita/smartflow/backend/respond"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const taskClassErrorDomain = "smartflow.taskclass"
// grpcErrorFromServiceError 负责把 task-class 内部错误转换为 gRPC status。
//
// 职责边界:
// 1. respond.Response 保留项目内部 status/info供 gateway 反解;
// 2. 未分类错误只暴露通用内部错误,详细信息留在服务日志;
// 3. 不在 RPC 层重判业务规则,业务语义仍由 sv/dao 决定。
func grpcErrorFromServiceError(err error) error {
if err == nil {
return nil
}
var resp respond.Response
if errors.As(err, &resp) {
return grpcErrorFromResponse(resp)
}
log.Printf("task-class rpc internal error: %v", err)
return status.Error(codes.Internal, "task-class service internal error")
}
func grpcErrorFromResponse(resp respond.Response) error {
code := grpcCodeFromRespondStatus(resp.Status)
message := strings.TrimSpace(resp.Info)
if message == "" {
message = strings.TrimSpace(resp.Status)
}
st := status.New(code, message)
detail := &errdetails.ErrorInfo{
Domain: taskClassErrorDomain,
Reason: resp.Status,
Metadata: map[string]string{
"info": resp.Info,
},
}
withDetails, err := st.WithDetails(detail)
if err != nil {
return st.Err()
}
return withDetails.Err()
}
func grpcCodeFromRespondStatus(statusValue string) codes.Code {
switch strings.TrimSpace(statusValue) {
case respond.MissingToken.Status, respond.InvalidToken.Status, respond.InvalidClaims.Status,
respond.ErrUnauthorized.Status, respond.WrongTokenType.Status, respond.UserLoggedOut.Status:
return codes.Unauthenticated
case respond.UserTaskClassForbidden.Status, respond.TaskClassNotBelongToUser.Status,
respond.TaskClassItemNotBelongToUser.Status, respond.CourseNotBelongToUser.Status:
return codes.PermissionDenied
case respond.UserTaskClassNotFound.Status, respond.TaskClassItemNotFound.Status:
return codes.NotFound
case respond.MissingParam.Status, respond.WrongParamType.Status, respond.ParamTooLong.Status,
respond.WrongUserID.Status, respond.WrongTaskClassID.Status, respond.WrongTaskID.Status,
respond.InvalidSectionNumber.Status, respond.InvalidWeekOrDayOfWeek.Status,
respond.InvalidSectionRange.Status, respond.MissingParamForAutoScheduling.Status,
respond.InvalidDateRange.Status, respond.TaskClassModeNotAuto.Status,
respond.TimeNotEnoughForAutoScheduling.Status, respond.TaskClassItemNotBelongToTaskClass.Status,
respond.TaskClassItemTryingToInsertOutOfTimeRange.Status, respond.TaskClassItemAlreadyArranged.Status,
respond.CourseAlreadyEmbeddedByOtherTaskBlock.Status, respond.ScheduleConflict.Status,
respond.WrongCourseID.Status, respond.CourseTimeNotMatch.Status, respond.InsertCourseTwice.Status,
respond.WeekOutOfRange.Status, respond.WrongScheduleEventID.Status,
respond.TargetScheduleNotHaveEmbeddedTask.Status, respond.TargetTaskNotEmbeddedInAnySchedule.Status,
respond.TimeOutOfRangeOfThisSemester.Status:
return codes.InvalidArgument
}
if strings.HasPrefix(strings.TrimSpace(statusValue), "5") {
return codes.Internal
}
return codes.InvalidArgument
}