diff --git a/internal/handler/empty_classroom_handler.go b/internal/handler/empty_classroom_handler.go new file mode 100644 index 0000000..59adda3 --- /dev/null +++ b/internal/handler/empty_classroom_handler.go @@ -0,0 +1,87 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + + "with_you/internal/pkg/response" + "with_you/internal/repository" + "with_you/internal/service" +) + +type EmptyClassroomHandler struct { + classroomSyncService service.EmptyClassroomSyncService + classroomRepo repository.EmptyClassroomRepository +} + +func NewEmptyClassroomHandler( + classroomSyncService service.EmptyClassroomSyncService, + classroomRepo repository.EmptyClassroomRepository, +) *EmptyClassroomHandler { + return &EmptyClassroomHandler{ + classroomSyncService: classroomSyncService, + classroomRepo: classroomRepo, + } +} + +type syncEmptyClassroomsRequest struct { + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` + Semester string `json:"semester"` + WeekStart string `json:"week_start"` + WeekEnd string `json:"week_end"` + CampusCode string `json:"campus_code"` +} + +func (h *EmptyClassroomHandler) SyncEmptyClassrooms(c *gin.Context) { + userID := c.GetString("user_id") + if userID == "" { + response.Unauthorized(c, "") + return + } + + var req syncEmptyClassroomsRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.BadRequest(c, "invalid request: "+err.Error()) + return + } + + result, err := h.classroomSyncService.SyncUserEmptyClassrooms(c.Request.Context(), userID, &service.SyncEmptyClassroomsRequest{ + Username: req.Username, + Password: req.Password, + Semester: req.Semester, + WeekStart: req.WeekStart, + WeekEnd: req.WeekEnd, + CampusCode: req.CampusCode, + }) + if err != nil { + response.HandleError(c, err, "failed to sync empty classrooms") + return + } + + if !result.Success { + response.Success(c, result) + return + } + response.SuccessWithMessage(c, result.Message, result) +} + +func (h *EmptyClassroomHandler) ListEmptyClassrooms(c *gin.Context) { + userID := c.GetString("user_id") + if userID == "" { + response.Unauthorized(c, "") + return + } + semester := c.Query("semester") + if semester == "" { + response.BadRequest(c, "semester is required") + return + } + + classrooms, err := h.classroomRepo.ListByUserAndSemester(userID, semester) + if err != nil { + response.HandleError(c, err, "failed to list empty classrooms") + return + } + + response.Success(c, gin.H{"classrooms": classrooms}) +} diff --git a/internal/model/empty_classroom.go b/internal/model/empty_classroom.go new file mode 100644 index 0000000..182248e --- /dev/null +++ b/internal/model/empty_classroom.go @@ -0,0 +1,26 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +type EmptyClassroom struct { + ID string `json:"id" gorm:"type:varchar(36);primaryKey"` + UserID string `json:"user_id" gorm:"type:varchar(36);index;not null"` + Semester string `json:"semester" gorm:"type:varchar(30);not null"` + Classroom string `json:"classroom" gorm:"type:varchar(60);not null"` + Weekday string `json:"weekday" gorm:"type:varchar(100)"` + Periods string `json:"periods" gorm:"type:text"` + Weeks string `json:"weeks" gorm:"type:varchar(30)"` + CreatedAt time.Time + UpdatedAt time.Time +} + +func (e *EmptyClassroom) BeforeCreate(tx *gorm.DB) error { + SetUUIDIfEmpty(&e.ID) + return nil +} + +func (EmptyClassroom) TableName() string { return "empty_classrooms" } diff --git a/internal/model/init.go b/internal/model/init.go index 712e0a3..ab81ff9 100644 --- a/internal/model/init.go +++ b/internal/model/init.go @@ -193,6 +193,7 @@ func autoMigrate(db *gorm.DB) error { &Grade{}, &GpaSummary{}, &Exam{}, + &EmptyClassroom{}, // 用户活跃相关 &UserActiveLog{}, diff --git a/internal/repository/empty_classroom_repo.go b/internal/repository/empty_classroom_repo.go new file mode 100644 index 0000000..d355e2b --- /dev/null +++ b/internal/repository/empty_classroom_repo.go @@ -0,0 +1,41 @@ +package repository + +import ( + "context" + + "with_you/internal/model" + + "gorm.io/gorm" +) + +type EmptyClassroomRepository interface { + ListByUserAndSemester(userID, semester string) ([]*model.EmptyClassroom, error) + DeleteByUserAndSemester(ctx context.Context, userID, semester string) error + BatchCreate(ctx context.Context, classrooms []*model.EmptyClassroom) error +} + +type emptyClassroomRepository struct { + db *gorm.DB +} + +func NewEmptyClassroomRepository(db *gorm.DB) EmptyClassroomRepository { + return &emptyClassroomRepository{db: db} +} + +func (r *emptyClassroomRepository) ListByUserAndSemester(userID, semester string) ([]*model.EmptyClassroom, error) { + var classrooms []*model.EmptyClassroom + err := r.db.Where("user_id = ? AND semester = ?", userID, semester). + Order("classroom ASC, weekday ASC"). + Find(&classrooms).Error + return classrooms, err +} + +func (r *emptyClassroomRepository) DeleteByUserAndSemester(ctx context.Context, userID, semester string) error { + return r.db.WithContext(ctx). + Where("user_id = ? AND semester = ?", userID, semester). + Delete(&model.EmptyClassroom{}).Error +} + +func (r *emptyClassroomRepository) BatchCreate(ctx context.Context, classrooms []*model.EmptyClassroom) error { + return r.db.WithContext(ctx).CreateInBatches(classrooms, 100).Error +} diff --git a/internal/router/router.go b/internal/router/router.go index c4f57ac..2da1412 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -28,6 +28,7 @@ type RouterDeps struct { ScheduleHandler *handler.ScheduleHandler GradeHandler *handler.GradeHandler ExamHandler *handler.ExamHandler + EmptyClassroomHandler *handler.EmptyClassroomHandler RoleHandler *handler.RoleHandler AdminUserHandler *handler.AdminUserHandler AdminPostHandler *handler.AdminPostHandler @@ -71,6 +72,7 @@ type Router struct { scheduleHandler *handler.ScheduleHandler gradeHandler *handler.GradeHandler examHandler *handler.ExamHandler + emptyClassroomHandler *handler.EmptyClassroomHandler roleHandler *handler.RoleHandler adminUserHandler *handler.AdminUserHandler adminPostHandler *handler.AdminPostHandler @@ -117,6 +119,7 @@ func New(deps RouterDeps) *Router { scheduleHandler: deps.ScheduleHandler, gradeHandler: deps.GradeHandler, examHandler: deps.ExamHandler, + emptyClassroomHandler: deps.EmptyClassroomHandler, roleHandler: deps.RoleHandler, adminUserHandler: deps.AdminUserHandler, adminPostHandler: deps.AdminPostHandler, @@ -372,6 +375,16 @@ func (r *Router) setupRoutes() { } } + // 空教室路由 + if r.emptyClassroomHandler != nil { + classrooms := v1.Group("/classrooms") + classrooms.Use(authMiddleware) + { + classrooms.GET("", r.emptyClassroomHandler.ListEmptyClassrooms) + classrooms.POST("/sync", r.emptyClassroomHandler.SyncEmptyClassrooms) + } + } + // 学习资料路由(公开) if r.materialHandler != nil { materials := v1.Group("/materials") diff --git a/internal/service/empty_classroom_sync_service.go b/internal/service/empty_classroom_sync_service.go new file mode 100644 index 0000000..e45446b --- /dev/null +++ b/internal/service/empty_classroom_sync_service.go @@ -0,0 +1,135 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + + "with_you/internal/grpc/runner" + "with_you/internal/model" + "with_you/internal/repository" + pb "with_you/proto/runner" + + "github.com/google/uuid" + "go.uber.org/zap" +) + +type SyncEmptyClassroomsRequest struct { + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` + Semester string `json:"semester"` + WeekStart string `json:"week_start"` + WeekEnd string `json:"week_end"` + CampusCode string `json:"campus_code"` +} + +type SyncEmptyClassroomsResult struct { + Success bool `json:"success"` + Message string `json:"message"` + SyncedCount int `json:"synced_count"` + ErrorMessage string `json:"error_message,omitempty"` +} + +type EmptyClassroomSyncService interface { + SyncUserEmptyClassrooms(ctx context.Context, userID string, req *SyncEmptyClassroomsRequest) (*SyncEmptyClassroomsResult, error) +} + +type emptyClassroomSyncService struct { + taskManager *runner.TaskManager + classroomRepo repository.EmptyClassroomRepository + logger *zap.Logger +} + +func NewEmptyClassroomSyncService( + taskManager *runner.TaskManager, + classroomRepo repository.EmptyClassroomRepository, + logger *zap.Logger, +) EmptyClassroomSyncService { + return &emptyClassroomSyncService{ + taskManager: taskManager, + classroomRepo: classroomRepo, + logger: logger, + } +} + +func (s *emptyClassroomSyncService) SyncUserEmptyClassrooms(ctx context.Context, userID string, req *SyncEmptyClassroomsRequest) (*SyncEmptyClassroomsResult, error) { + payload := &pb.GetEmptyClassroomPayload{ + Username: req.Username, + Password: req.Password, + Semester: req.Semester, + WeekStart: req.WeekStart, + WeekEnd: req.WeekEnd, + CampusCode: req.CampusCode, + } + + taskResult, err := s.taskManager.SubmitTaskSync(ctx, pb.TaskType_TASK_TYPE_GET_EMPTY_CLASSROOM, payload) + if err != nil { + s.logger.Error("failed to submit empty classroom sync task", + zap.String("user_id", userID), + zap.Error(err)) + return nil, fmt.Errorf("failed to submit task: %w", err) + } + + if taskResult.Status != pb.TaskStatus_TASK_STATUS_SUCCESS { + return &SyncEmptyClassroomsResult{ + Success: false, + Message: "空教室查询失败", + ErrorMessage: taskResult.ErrorMessage, + }, nil + } + + var resultData pb.EmptyClassroomResultData + if err := json.Unmarshal(taskResult.Data, &resultData); err != nil { + s.logger.Error("failed to parse empty classroom result", + zap.String("user_id", userID), + zap.Error(err)) + return nil, fmt.Errorf("failed to parse result: %w", err) + } + + classrooms := s.convertClassrooms(userID, &resultData) + if err := s.saveClassrooms(ctx, userID, resultData.Semester, classrooms); err != nil { + s.logger.Error("failed to save empty classrooms", + zap.String("user_id", userID), + zap.Error(err)) + return nil, fmt.Errorf("failed to save classrooms: %w", err) + } + + s.logger.Info("empty classrooms sync completed", + zap.String("user_id", userID), + zap.Int("classroom_count", len(classrooms))) + + return &SyncEmptyClassroomsResult{ + Success: true, + Message: "空教室查询成功", + SyncedCount: len(classrooms), + }, nil +} + +func (s *emptyClassroomSyncService) convertClassrooms(userID string, data *pb.EmptyClassroomResultData) []*model.EmptyClassroom { + classrooms := make([]*model.EmptyClassroom, 0, len(data.Classrooms)) + for _, c := range data.Classrooms { + classrooms = append(classrooms, &model.EmptyClassroom{ + ID: uuid.New().String(), + UserID: userID, + Semester: data.Semester, + Classroom: c.Classroom, + Weekday: c.Weekday, + Periods: c.Periods, + Weeks: c.Weeks, + }) + } + return classrooms +} + +func (s *emptyClassroomSyncService) saveClassrooms(ctx context.Context, userID, semester string, classrooms []*model.EmptyClassroom) error { + if err := s.classroomRepo.DeleteByUserAndSemester(ctx, userID, semester); err != nil { + return fmt.Errorf("failed to delete old classrooms: %w", err) + } + if len(classrooms) == 0 { + return nil + } + if err := s.classroomRepo.BatchCreate(ctx, classrooms); err != nil { + return fmt.Errorf("failed to create classrooms: %w", err) + } + return nil +} diff --git a/internal/wire/handler.go b/internal/wire/handler.go index 27e6ff6..24b6397 100644 --- a/internal/wire/handler.go +++ b/internal/wire/handler.go @@ -37,6 +37,7 @@ var HandlerSet = wire.NewSet( handler.NewTradeHandler, handler.NewGradeHandler, handler.NewExamHandler, + handler.NewEmptyClassroomHandler, // 需要特殊处理的 Handler ProvideUserHandler, diff --git a/internal/wire/repository.go b/internal/wire/repository.go index 7e47c60..e1884fb 100644 --- a/internal/wire/repository.go +++ b/internal/wire/repository.go @@ -26,6 +26,7 @@ var RepositorySet = wire.NewSet( repository.NewScheduleRepository, repository.NewGradeRepository, repository.NewExamRepository, + repository.NewEmptyClassroomRepository, repository.NewMaterialSubjectRepository, repository.NewMaterialFileRepository, repository.NewCallRepository, diff --git a/internal/wire/service.go b/internal/wire/service.go index 2c2fd6c..d1dc3b7 100644 --- a/internal/wire/service.go +++ b/internal/wire/service.go @@ -48,6 +48,7 @@ var ServiceSet = wire.NewSet( ProvideScheduleSyncService, ProvideGradeSyncService, ProvideExamSyncService, + ProvideEmptyClassroomSyncService, ProvideGroupService, ProvideUploadService, ProvideUserActivityService, @@ -263,6 +264,15 @@ func ProvideExamSyncService( return service.NewExamSyncService(taskManager, examRepo, logger) } +// ProvideEmptyClassroomSyncService 提供空教室同步服务 +func ProvideEmptyClassroomSyncService( + taskManager *runner.TaskManager, + classroomRepo repository.EmptyClassroomRepository, + logger *zap.Logger, +) service.EmptyClassroomSyncService { + return service.NewEmptyClassroomSyncService(taskManager, classroomRepo, logger) +} + // ProvideGroupService 提供群组服务 func ProvideGroupService( groupRepo repository.GroupRepository, diff --git a/proto/runner/proto/runner/runner.pb.go b/proto/runner/proto/runner/runner.pb.go new file mode 100644 index 0000000..dff09e9 --- /dev/null +++ b/proto/runner/proto/runner/runner.pb.go @@ -0,0 +1,2229 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v7.34.1 +// source: proto/runner/runner.proto + +package runner + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// TaskType 任务类型枚举 +type TaskType int32 + +const ( + TaskType_TASK_TYPE_UNKNOWN TaskType = 0 // 未知类型 + TaskType_TASK_TYPE_LOGIN TaskType = 1 // 登录验证 + TaskType_TASK_TYPE_GET_SCHEDULE TaskType = 2 // 获取课表 + TaskType_TASK_TYPE_GET_GRADES TaskType = 3 // 获取成绩 + TaskType_TASK_TYPE_GET_EXAMS TaskType = 4 // 获取考试安排 + TaskType_TASK_TYPE_GET_USER_INFO TaskType = 5 // 获取用户信息 + TaskType_TASK_TYPE_GET_EMPTY_CLASSROOM TaskType = 6 // 获取空教室 +) + +// Enum value maps for TaskType. +var ( + TaskType_name = map[int32]string{ + 0: "TASK_TYPE_UNKNOWN", + 1: "TASK_TYPE_LOGIN", + 2: "TASK_TYPE_GET_SCHEDULE", + 3: "TASK_TYPE_GET_GRADES", + 4: "TASK_TYPE_GET_EXAMS", + 5: "TASK_TYPE_GET_USER_INFO", + 6: "TASK_TYPE_GET_EMPTY_CLASSROOM", + } + TaskType_value = map[string]int32{ + "TASK_TYPE_UNKNOWN": 0, + "TASK_TYPE_LOGIN": 1, + "TASK_TYPE_GET_SCHEDULE": 2, + "TASK_TYPE_GET_GRADES": 3, + "TASK_TYPE_GET_EXAMS": 4, + "TASK_TYPE_GET_USER_INFO": 5, + "TASK_TYPE_GET_EMPTY_CLASSROOM": 6, + } +) + +func (x TaskType) Enum() *TaskType { + p := new(TaskType) + *p = x + return p +} + +func (x TaskType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TaskType) Descriptor() protoreflect.EnumDescriptor { + return file_proto_runner_runner_proto_enumTypes[0].Descriptor() +} + +func (TaskType) Type() protoreflect.EnumType { + return &file_proto_runner_runner_proto_enumTypes[0] +} + +func (x TaskType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TaskType.Descriptor instead. +func (TaskType) EnumDescriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{0} +} + +// TaskStatus 任务状态枚举 +type TaskStatus int32 + +const ( + TaskStatus_TASK_STATUS_UNKNOWN TaskStatus = 0 // 未知状态 + TaskStatus_TASK_STATUS_SUCCESS TaskStatus = 1 // 成功 + TaskStatus_TASK_STATUS_FAILED TaskStatus = 2 // 失败 + TaskStatus_TASK_STATUS_TIMEOUT TaskStatus = 3 // 超时 + TaskStatus_TASK_STATUS_CANCELLED TaskStatus = 4 // 已取消 +) + +// Enum value maps for TaskStatus. +var ( + TaskStatus_name = map[int32]string{ + 0: "TASK_STATUS_UNKNOWN", + 1: "TASK_STATUS_SUCCESS", + 2: "TASK_STATUS_FAILED", + 3: "TASK_STATUS_TIMEOUT", + 4: "TASK_STATUS_CANCELLED", + } + TaskStatus_value = map[string]int32{ + "TASK_STATUS_UNKNOWN": 0, + "TASK_STATUS_SUCCESS": 1, + "TASK_STATUS_FAILED": 2, + "TASK_STATUS_TIMEOUT": 3, + "TASK_STATUS_CANCELLED": 4, + } +) + +func (x TaskStatus) Enum() *TaskStatus { + p := new(TaskStatus) + *p = x + return p +} + +func (x TaskStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TaskStatus) Descriptor() protoreflect.EnumDescriptor { + return file_proto_runner_runner_proto_enumTypes[1].Descriptor() +} + +func (TaskStatus) Type() protoreflect.EnumType { + return &file_proto_runner_runner_proto_enumTypes[1] +} + +func (x TaskStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TaskStatus.Descriptor instead. +func (TaskStatus) EnumDescriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{1} +} + +// StreamMessage 双向流消息包装 +type StreamMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Message: + // + // *StreamMessage_Register + // *StreamMessage_RegisterResponse + // *StreamMessage_Heartbeat + // *StreamMessage_HeartbeatAck + // *StreamMessage_Task + // *StreamMessage_Result + // *StreamMessage_TaskCancel + Message isStreamMessage_Message `protobuf_oneof:"message"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StreamMessage) Reset() { + *x = StreamMessage{} + mi := &file_proto_runner_runner_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StreamMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamMessage) ProtoMessage() {} + +func (x *StreamMessage) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamMessage.ProtoReflect.Descriptor instead. +func (*StreamMessage) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{0} +} + +func (x *StreamMessage) GetMessage() isStreamMessage_Message { + if x != nil { + return x.Message + } + return nil +} + +func (x *StreamMessage) GetRegister() *RegisterRequest { + if x != nil { + if x, ok := x.Message.(*StreamMessage_Register); ok { + return x.Register + } + } + return nil +} + +func (x *StreamMessage) GetRegisterResponse() *RegisterResponse { + if x != nil { + if x, ok := x.Message.(*StreamMessage_RegisterResponse); ok { + return x.RegisterResponse + } + } + return nil +} + +func (x *StreamMessage) GetHeartbeat() *Heartbeat { + if x != nil { + if x, ok := x.Message.(*StreamMessage_Heartbeat); ok { + return x.Heartbeat + } + } + return nil +} + +func (x *StreamMessage) GetHeartbeatAck() *HeartbeatAck { + if x != nil { + if x, ok := x.Message.(*StreamMessage_HeartbeatAck); ok { + return x.HeartbeatAck + } + } + return nil +} + +func (x *StreamMessage) GetTask() *Task { + if x != nil { + if x, ok := x.Message.(*StreamMessage_Task); ok { + return x.Task + } + } + return nil +} + +func (x *StreamMessage) GetResult() *TaskResult { + if x != nil { + if x, ok := x.Message.(*StreamMessage_Result); ok { + return x.Result + } + } + return nil +} + +func (x *StreamMessage) GetTaskCancel() *TaskCancel { + if x != nil { + if x, ok := x.Message.(*StreamMessage_TaskCancel); ok { + return x.TaskCancel + } + } + return nil +} + +type isStreamMessage_Message interface { + isStreamMessage_Message() +} + +type StreamMessage_Register struct { + Register *RegisterRequest `protobuf:"bytes,1,opt,name=register,proto3,oneof"` // Runner 注册请求 +} + +type StreamMessage_RegisterResponse struct { + RegisterResponse *RegisterResponse `protobuf:"bytes,2,opt,name=register_response,json=registerResponse,proto3,oneof"` // 注册响应 +} + +type StreamMessage_Heartbeat struct { + Heartbeat *Heartbeat `protobuf:"bytes,3,opt,name=heartbeat,proto3,oneof"` // 心跳请求 +} + +type StreamMessage_HeartbeatAck struct { + HeartbeatAck *HeartbeatAck `protobuf:"bytes,4,opt,name=heartbeat_ack,json=heartbeatAck,proto3,oneof"` // 心跳响应 +} + +type StreamMessage_Task struct { + Task *Task `protobuf:"bytes,5,opt,name=task,proto3,oneof"` // 下发的任务 +} + +type StreamMessage_Result struct { + Result *TaskResult `protobuf:"bytes,6,opt,name=result,proto3,oneof"` // 任务结果 +} + +type StreamMessage_TaskCancel struct { + TaskCancel *TaskCancel `protobuf:"bytes,7,opt,name=task_cancel,json=taskCancel,proto3,oneof"` // 取消任务 +} + +func (*StreamMessage_Register) isStreamMessage_Message() {} + +func (*StreamMessage_RegisterResponse) isStreamMessage_Message() {} + +func (*StreamMessage_Heartbeat) isStreamMessage_Message() {} + +func (*StreamMessage_HeartbeatAck) isStreamMessage_Message() {} + +func (*StreamMessage_Task) isStreamMessage_Message() {} + +func (*StreamMessage_Result) isStreamMessage_Message() {} + +func (*StreamMessage_TaskCancel) isStreamMessage_Message() {} + +// RegisterRequest Runner 注册请求 +type RegisterRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"` // Runner 唯一标识 (UUID) + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` // Runner 版本号 + Capabilities map[string]string `protobuf:"bytes,3,rep,name=capabilities,proto3" json:"capabilities,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // 能力标签 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterRequest) Reset() { + *x = RegisterRequest{} + mi := &file_proto_runner_runner_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequest) ProtoMessage() {} + +func (x *RegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{1} +} + +func (x *RegisterRequest) GetRunnerId() string { + if x != nil { + return x.RunnerId + } + return "" +} + +func (x *RegisterRequest) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *RegisterRequest) GetCapabilities() map[string]string { + if x != nil { + return x.Capabilities + } + return nil +} + +// RegisterResponse 注册响应 +type RegisterResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // 是否成功 + SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` // 会话ID,用于标识本次连接 + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` // 消息说明 + HeartbeatInterval int32 `protobuf:"varint,4,opt,name=heartbeat_interval,json=heartbeatInterval,proto3" json:"heartbeat_interval,omitempty"` // 心跳间隔 (秒) + TaskTimeout int32 `protobuf:"varint,5,opt,name=task_timeout,json=taskTimeout,proto3" json:"task_timeout,omitempty"` // 默认任务超时时间 (秒) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterResponse) Reset() { + *x = RegisterResponse{} + mi := &file_proto_runner_runner_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterResponse) ProtoMessage() {} + +func (x *RegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. +func (*RegisterResponse) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{2} +} + +func (x *RegisterResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *RegisterResponse) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +func (x *RegisterResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *RegisterResponse) GetHeartbeatInterval() int32 { + if x != nil { + return x.HeartbeatInterval + } + return 0 +} + +func (x *RegisterResponse) GetTaskTimeout() int32 { + if x != nil { + return x.TaskTimeout + } + return 0 +} + +// Heartbeat 心跳请求 +type Heartbeat struct { + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // 客户端时间戳 (毫秒) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Heartbeat) Reset() { + *x = Heartbeat{} + mi := &file_proto_runner_runner_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Heartbeat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Heartbeat) ProtoMessage() {} + +func (x *Heartbeat) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Heartbeat.ProtoReflect.Descriptor instead. +func (*Heartbeat) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{3} +} + +func (x *Heartbeat) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +// HeartbeatAck 心跳响应 +type HeartbeatAck struct { + state protoimpl.MessageState `protogen:"open.v1"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // 服务端时间戳 (毫秒) + Latency int64 `protobuf:"varint,2,opt,name=latency,proto3" json:"latency,omitempty"` // 往返延迟 (毫秒) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HeartbeatAck) Reset() { + *x = HeartbeatAck{} + mi := &file_proto_runner_runner_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HeartbeatAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeartbeatAck) ProtoMessage() {} + +func (x *HeartbeatAck) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeartbeatAck.ProtoReflect.Descriptor instead. +func (*HeartbeatAck) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{4} +} + +func (x *HeartbeatAck) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *HeartbeatAck) GetLatency() int64 { + if x != nil { + return x.Latency + } + return 0 +} + +// Task 任务定义 +type Task struct { + state protoimpl.MessageState `protogen:"open.v1"` + TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` // 任务唯一ID (UUID) + Type TaskType `protobuf:"varint,2,opt,name=type,proto3,enum=runner.TaskType" json:"type,omitempty"` // 任务类型 + CreatedAt int64 `protobuf:"varint,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // 创建时间戳 (毫秒) + TimeoutSeconds int32 `protobuf:"varint,4,opt,name=timeout_seconds,json=timeoutSeconds,proto3" json:"timeout_seconds,omitempty"` // 超时时间 (秒) + Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"` // 任务载荷 (JSON 编码) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Task) Reset() { + *x = Task{} + mi := &file_proto_runner_runner_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Task) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Task) ProtoMessage() {} + +func (x *Task) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Task.ProtoReflect.Descriptor instead. +func (*Task) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{5} +} + +func (x *Task) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +func (x *Task) GetType() TaskType { + if x != nil { + return x.Type + } + return TaskType_TASK_TYPE_UNKNOWN +} + +func (x *Task) GetCreatedAt() int64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *Task) GetTimeoutSeconds() int32 { + if x != nil { + return x.TimeoutSeconds + } + return 0 +} + +func (x *Task) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +// TaskCancel 取消任务 +type TaskCancel struct { + state protoimpl.MessageState `protogen:"open.v1"` + TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` // 要取消的任务ID + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` // 取消原因 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TaskCancel) Reset() { + *x = TaskCancel{} + mi := &file_proto_runner_runner_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TaskCancel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TaskCancel) ProtoMessage() {} + +func (x *TaskCancel) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TaskCancel.ProtoReflect.Descriptor instead. +func (*TaskCancel) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{6} +} + +func (x *TaskCancel) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +func (x *TaskCancel) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +// TaskResult 任务结果 +type TaskResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` // 任务ID + Status TaskStatus `protobuf:"varint,2,opt,name=status,proto3,enum=runner.TaskStatus" json:"status,omitempty"` // 执行状态 + CompletedAt int64 `protobuf:"varint,3,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"` // 完成时间戳 (毫秒) + Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` // 结果数据 (JSON 编码) + ErrorCode string `protobuf:"bytes,5,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` // 错误码 + ErrorMessage string `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` // 错误消息 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TaskResult) Reset() { + *x = TaskResult{} + mi := &file_proto_runner_runner_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TaskResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TaskResult) ProtoMessage() {} + +func (x *TaskResult) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead. +func (*TaskResult) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{7} +} + +func (x *TaskResult) GetTaskId() string { + if x != nil { + return x.TaskId + } + return "" +} + +func (x *TaskResult) GetStatus() TaskStatus { + if x != nil { + return x.Status + } + return TaskStatus_TASK_STATUS_UNKNOWN +} + +func (x *TaskResult) GetCompletedAt() int64 { + if x != nil { + return x.CompletedAt + } + return 0 +} + +func (x *TaskResult) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +func (x *TaskResult) GetErrorCode() string { + if x != nil { + return x.ErrorCode + } + return "" +} + +func (x *TaskResult) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + +// LoginPayload 登录任务载荷 +type LoginPayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Twfid string `protobuf:"bytes,3,opt,name=twfid,proto3" json:"twfid,omitempty"` // 初始 Cookie (可选) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoginPayload) Reset() { + *x = LoginPayload{} + mi := &file_proto_runner_runner_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoginPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginPayload) ProtoMessage() {} + +func (x *LoginPayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginPayload.ProtoReflect.Descriptor instead. +func (*LoginPayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{8} +} + +func (x *LoginPayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *LoginPayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *LoginPayload) GetTwfid() string { + if x != nil { + return x.Twfid + } + return "" +} + +// GetSchedulePayload 获取课表任务载荷 +type GetSchedulePayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Semester string `protobuf:"bytes,3,opt,name=semester,proto3" json:"semester,omitempty"` // 学期,如 "2025-20262" + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSchedulePayload) Reset() { + *x = GetSchedulePayload{} + mi := &file_proto_runner_runner_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSchedulePayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSchedulePayload) ProtoMessage() {} + +func (x *GetSchedulePayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSchedulePayload.ProtoReflect.Descriptor instead. +func (*GetSchedulePayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{9} +} + +func (x *GetSchedulePayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetSchedulePayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetSchedulePayload) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +// GetGradesPayload 获取成绩任务载荷 +type GetGradesPayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Semester string `protobuf:"bytes,3,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 (可选,为空则获取全部) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetGradesPayload) Reset() { + *x = GetGradesPayload{} + mi := &file_proto_runner_runner_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetGradesPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetGradesPayload) ProtoMessage() {} + +func (x *GetGradesPayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetGradesPayload.ProtoReflect.Descriptor instead. +func (*GetGradesPayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{10} +} + +func (x *GetGradesPayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetGradesPayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetGradesPayload) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +// GetExamsPayload 获取考试安排任务载荷 +type GetExamsPayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Semester string `protobuf:"bytes,3,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetExamsPayload) Reset() { + *x = GetExamsPayload{} + mi := &file_proto_runner_runner_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetExamsPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetExamsPayload) ProtoMessage() {} + +func (x *GetExamsPayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetExamsPayload.ProtoReflect.Descriptor instead. +func (*GetExamsPayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{11} +} + +func (x *GetExamsPayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetExamsPayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetExamsPayload) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +// ScheduleResultData 课表结果数据 +type ScheduleResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + StudentId string `protobuf:"bytes,2,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + StudentName string `protobuf:"bytes,3,opt,name=student_name,json=studentName,proto3" json:"student_name,omitempty"` // 学生姓名 + Courses []*Course `protobuf:"bytes,4,rep,name=courses,proto3" json:"courses,omitempty"` // 课程列表 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScheduleResultData) Reset() { + *x = ScheduleResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScheduleResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduleResultData) ProtoMessage() {} + +func (x *ScheduleResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduleResultData.ProtoReflect.Descriptor instead. +func (*ScheduleResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{12} +} + +func (x *ScheduleResultData) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *ScheduleResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *ScheduleResultData) GetStudentName() string { + if x != nil { + return x.StudentName + } + return "" +} + +func (x *ScheduleResultData) GetCourses() []*Course { + if x != nil { + return x.Courses + } + return nil +} + +// Course 课程信息 +type Course struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` // 课程代码 + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 课程名称 + Teacher string `protobuf:"bytes,3,opt,name=teacher,proto3" json:"teacher,omitempty"` // 授课教师 + Room string `protobuf:"bytes,4,opt,name=room,proto3" json:"room,omitempty"` // 教室 + Credit float32 `protobuf:"fixed32,5,opt,name=credit,proto3" json:"credit,omitempty"` // 学分 + Schedule []*ScheduleTime `protobuf:"bytes,6,rep,name=schedule,proto3" json:"schedule,omitempty"` // 上课时间安排 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Course) Reset() { + *x = Course{} + mi := &file_proto_runner_runner_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Course) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Course) ProtoMessage() {} + +func (x *Course) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Course.ProtoReflect.Descriptor instead. +func (*Course) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{13} +} + +func (x *Course) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *Course) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Course) GetTeacher() string { + if x != nil { + return x.Teacher + } + return "" +} + +func (x *Course) GetRoom() string { + if x != nil { + return x.Room + } + return "" +} + +func (x *Course) GetCredit() float32 { + if x != nil { + return x.Credit + } + return 0 +} + +func (x *Course) GetSchedule() []*ScheduleTime { + if x != nil { + return x.Schedule + } + return nil +} + +// ScheduleTime 上课时间安排 +type ScheduleTime struct { + state protoimpl.MessageState `protogen:"open.v1"` + Day string `protobuf:"bytes,1,opt,name=day,proto3" json:"day,omitempty"` // 星期几,"0"-"6" 表示周日到周六 + Sections []int32 `protobuf:"varint,2,rep,packed,name=sections,proto3" json:"sections,omitempty"` // 节次,如 [1, 2, 3] + Weeks []int32 `protobuf:"varint,3,rep,packed,name=weeks,proto3" json:"weeks,omitempty"` // 周次,如 [1, 2, 3, 4, 5] + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ScheduleTime) Reset() { + *x = ScheduleTime{} + mi := &file_proto_runner_runner_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ScheduleTime) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScheduleTime) ProtoMessage() {} + +func (x *ScheduleTime) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScheduleTime.ProtoReflect.Descriptor instead. +func (*ScheduleTime) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{14} +} + +func (x *ScheduleTime) GetDay() string { + if x != nil { + return x.Day + } + return "" +} + +func (x *ScheduleTime) GetSections() []int32 { + if x != nil { + return x.Sections + } + return nil +} + +func (x *ScheduleTime) GetWeeks() []int32 { + if x != nil { + return x.Weeks + } + return nil +} + +// GpaSummary 学分绩汇总信息 +type GpaSummary struct { + state protoimpl.MessageState `protogen:"open.v1"` + AverageGpa string `protobuf:"bytes,1,opt,name=average_gpa,json=averageGpa,proto3" json:"average_gpa,omitempty"` // 平均学分绩 + Rank string `protobuf:"bytes,2,opt,name=rank,proto3" json:"rank,omitempty"` // 专业排名 + ExamTotalGpa string `protobuf:"bytes,3,opt,name=exam_total_gpa,json=examTotalGpa,proto3" json:"exam_total_gpa,omitempty"` // 考试课学分绩 + ExamTotalCredits string `protobuf:"bytes,4,opt,name=exam_total_credits,json=examTotalCredits,proto3" json:"exam_total_credits,omitempty"` // 考试课学分数 + FailCredits string `protobuf:"bytes,5,opt,name=fail_credits,json=failCredits,proto3" json:"fail_credits,omitempty"` // 考查课不及格学分 + Semesters string `protobuf:"bytes,6,opt,name=semesters,proto3" json:"semesters,omitempty"` // 计算学期数 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GpaSummary) Reset() { + *x = GpaSummary{} + mi := &file_proto_runner_runner_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GpaSummary) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GpaSummary) ProtoMessage() {} + +func (x *GpaSummary) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GpaSummary.ProtoReflect.Descriptor instead. +func (*GpaSummary) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{15} +} + +func (x *GpaSummary) GetAverageGpa() string { + if x != nil { + return x.AverageGpa + } + return "" +} + +func (x *GpaSummary) GetRank() string { + if x != nil { + return x.Rank + } + return "" +} + +func (x *GpaSummary) GetExamTotalGpa() string { + if x != nil { + return x.ExamTotalGpa + } + return "" +} + +func (x *GpaSummary) GetExamTotalCredits() string { + if x != nil { + return x.ExamTotalCredits + } + return "" +} + +func (x *GpaSummary) GetFailCredits() string { + if x != nil { + return x.FailCredits + } + return "" +} + +func (x *GpaSummary) GetSemesters() string { + if x != nil { + return x.Semesters + } + return "" +} + +// GradesResultData 成绩结果数据 +type GradesResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + StudentId string `protobuf:"bytes,2,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + Grades []*Grade `protobuf:"bytes,3,rep,name=grades,proto3" json:"grades,omitempty"` // 成绩列表 + GpaSummary *GpaSummary `protobuf:"bytes,4,opt,name=gpa_summary,json=gpaSummary,proto3" json:"gpa_summary,omitempty"` // 学分绩汇总 (可选) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GradesResultData) Reset() { + *x = GradesResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GradesResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GradesResultData) ProtoMessage() {} + +func (x *GradesResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GradesResultData.ProtoReflect.Descriptor instead. +func (*GradesResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{16} +} + +func (x *GradesResultData) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *GradesResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *GradesResultData) GetGrades() []*Grade { + if x != nil { + return x.Grades + } + return nil +} + +func (x *GradesResultData) GetGpaSummary() *GpaSummary { + if x != nil { + return x.GpaSummary + } + return nil +} + +// Grade 成绩信息 +type Grade struct { + state protoimpl.MessageState `protogen:"open.v1"` + Term string `protobuf:"bytes,1,opt,name=term,proto3" json:"term,omitempty"` // 学期 + CourseCode string `protobuf:"bytes,2,opt,name=course_code,json=courseCode,proto3" json:"course_code,omitempty"` // 课程代码 + CourseName string `protobuf:"bytes,3,opt,name=course_name,json=courseName,proto3" json:"course_name,omitempty"` // 课程名称 + Nature string `protobuf:"bytes,4,opt,name=nature,proto3" json:"nature,omitempty"` // 课程性质 + Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` // 课程类别 + Credit string `protobuf:"bytes,6,opt,name=credit,proto3" json:"credit,omitempty"` // 学分 + Score string `protobuf:"bytes,7,opt,name=score,proto3" json:"score,omitempty"` // 成绩 (可能是等级或分数) + GradePoint string `protobuf:"bytes,8,opt,name=grade_point,json=gradePoint,proto3" json:"grade_point,omitempty"` // 绩点 + IsExam string `protobuf:"bytes,9,opt,name=is_exam,json=isExam,proto3" json:"is_exam,omitempty"` // 是否考试课 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Grade) Reset() { + *x = Grade{} + mi := &file_proto_runner_runner_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Grade) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Grade) ProtoMessage() {} + +func (x *Grade) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Grade.ProtoReflect.Descriptor instead. +func (*Grade) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{17} +} + +func (x *Grade) GetTerm() string { + if x != nil { + return x.Term + } + return "" +} + +func (x *Grade) GetCourseCode() string { + if x != nil { + return x.CourseCode + } + return "" +} + +func (x *Grade) GetCourseName() string { + if x != nil { + return x.CourseName + } + return "" +} + +func (x *Grade) GetNature() string { + if x != nil { + return x.Nature + } + return "" +} + +func (x *Grade) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *Grade) GetCredit() string { + if x != nil { + return x.Credit + } + return "" +} + +func (x *Grade) GetScore() string { + if x != nil { + return x.Score + } + return "" +} + +func (x *Grade) GetGradePoint() string { + if x != nil { + return x.GradePoint + } + return "" +} + +func (x *Grade) GetIsExam() string { + if x != nil { + return x.IsExam + } + return "" +} + +// ExamsResultData 考试安排结果数据 +type ExamsResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + StudentId string `protobuf:"bytes,2,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + Exams []*Exam `protobuf:"bytes,3,rep,name=exams,proto3" json:"exams,omitempty"` // 考试列表 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExamsResultData) Reset() { + *x = ExamsResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExamsResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExamsResultData) ProtoMessage() {} + +func (x *ExamsResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExamsResultData.ProtoReflect.Descriptor instead. +func (*ExamsResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{18} +} + +func (x *ExamsResultData) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *ExamsResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *ExamsResultData) GetExams() []*Exam { + if x != nil { + return x.Exams + } + return nil +} + +// Exam 考试信息 +type Exam struct { + state protoimpl.MessageState `protogen:"open.v1"` + CourseName string `protobuf:"bytes,1,opt,name=course_name,json=courseName,proto3" json:"course_name,omitempty"` // 课程名称 + ExamType string `protobuf:"bytes,2,opt,name=exam_type,json=examType,proto3" json:"exam_type,omitempty"` // 考试类型 (期末/期中/补考) + Date string `protobuf:"bytes,3,opt,name=date,proto3" json:"date,omitempty"` // 考试日期 + Time string `protobuf:"bytes,4,opt,name=time,proto3" json:"time,omitempty"` // 考试时间 + Week string `protobuf:"bytes,5,opt,name=week,proto3" json:"week,omitempty"` // 考试周次 + Weekday string `protobuf:"bytes,6,opt,name=weekday,proto3" json:"weekday,omitempty"` // 星期几 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Exam) Reset() { + *x = Exam{} + mi := &file_proto_runner_runner_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Exam) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Exam) ProtoMessage() {} + +func (x *Exam) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exam.ProtoReflect.Descriptor instead. +func (*Exam) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{19} +} + +func (x *Exam) GetCourseName() string { + if x != nil { + return x.CourseName + } + return "" +} + +func (x *Exam) GetExamType() string { + if x != nil { + return x.ExamType + } + return "" +} + +func (x *Exam) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *Exam) GetTime() string { + if x != nil { + return x.Time + } + return "" +} + +func (x *Exam) GetWeek() string { + if x != nil { + return x.Week + } + return "" +} + +func (x *Exam) GetWeekday() string { + if x != nil { + return x.Weekday + } + return "" +} + +// UserInfoResultData 用户信息结果数据 +type UserInfoResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + StudentId string `protobuf:"bytes,1,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 姓名 + Gender string `protobuf:"bytes,3,opt,name=gender,proto3" json:"gender,omitempty"` // 性别 + College string `protobuf:"bytes,4,opt,name=college,proto3" json:"college,omitempty"` // 学院 + Major string `protobuf:"bytes,5,opt,name=major,proto3" json:"major,omitempty"` // 专业 + ClassName string `protobuf:"bytes,6,opt,name=class_name,json=className,proto3" json:"class_name,omitempty"` // 班级 + Grade string `protobuf:"bytes,7,opt,name=grade,proto3" json:"grade,omitempty"` // 年级 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UserInfoResultData) Reset() { + *x = UserInfoResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UserInfoResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserInfoResultData) ProtoMessage() {} + +func (x *UserInfoResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserInfoResultData.ProtoReflect.Descriptor instead. +func (*UserInfoResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{20} +} + +func (x *UserInfoResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *UserInfoResultData) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UserInfoResultData) GetGender() string { + if x != nil { + return x.Gender + } + return "" +} + +func (x *UserInfoResultData) GetCollege() string { + if x != nil { + return x.College + } + return "" +} + +func (x *UserInfoResultData) GetMajor() string { + if x != nil { + return x.Major + } + return "" +} + +func (x *UserInfoResultData) GetClassName() string { + if x != nil { + return x.ClassName + } + return "" +} + +func (x *UserInfoResultData) GetGrade() string { + if x != nil { + return x.Grade + } + return "" +} + +// GetEmptyClassroomPayload 获取空教室任务载荷 +type GetEmptyClassroomPayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Semester string `protobuf:"bytes,3,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + WeekStart string `protobuf:"bytes,4,opt,name=week_start,json=weekStart,proto3" json:"week_start,omitempty"` // 起始周次 + WeekEnd string `protobuf:"bytes,5,opt,name=week_end,json=weekEnd,proto3" json:"week_end,omitempty"` // 结束周次 + CampusCode string `protobuf:"bytes,6,opt,name=campus_code,json=campusCode,proto3" json:"campus_code,omitempty"` // 校区代码 + BuildingCode string `protobuf:"bytes,7,opt,name=building_code,json=buildingCode,proto3" json:"building_code,omitempty"` // 楼号代码(可选) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEmptyClassroomPayload) Reset() { + *x = GetEmptyClassroomPayload{} + mi := &file_proto_runner_runner_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEmptyClassroomPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEmptyClassroomPayload) ProtoMessage() {} + +func (x *GetEmptyClassroomPayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEmptyClassroomPayload.ProtoReflect.Descriptor instead. +func (*GetEmptyClassroomPayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{21} +} + +func (x *GetEmptyClassroomPayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetWeekStart() string { + if x != nil { + return x.WeekStart + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetWeekEnd() string { + if x != nil { + return x.WeekEnd + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetCampusCode() string { + if x != nil { + return x.CampusCode + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetBuildingCode() string { + if x != nil { + return x.BuildingCode + } + return "" +} + +// EmptyClassroomResultData 空教室结果数据 +type EmptyClassroomResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + StudentId string `protobuf:"bytes,2,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + Classrooms []*EmptyClassroomEntry `protobuf:"bytes,3,rep,name=classrooms,proto3" json:"classrooms,omitempty"` // 空教室列表 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EmptyClassroomResultData) Reset() { + *x = EmptyClassroomResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EmptyClassroomResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyClassroomResultData) ProtoMessage() {} + +func (x *EmptyClassroomResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmptyClassroomResultData.ProtoReflect.Descriptor instead. +func (*EmptyClassroomResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{22} +} + +func (x *EmptyClassroomResultData) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *EmptyClassroomResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *EmptyClassroomResultData) GetClassrooms() []*EmptyClassroomEntry { + if x != nil { + return x.Classrooms + } + return nil +} + +// EmptyClassroomEntry 空教室条目 +type EmptyClassroomEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Classroom string `protobuf:"bytes,1,opt,name=classroom,proto3" json:"classroom,omitempty"` // 教室名称 + Weekday string `protobuf:"bytes,2,opt,name=weekday,proto3" json:"weekday,omitempty"` // 星期几 + Periods string `protobuf:"bytes,3,opt,name=periods,proto3" json:"periods,omitempty"` // 可用节次 + Term string `protobuf:"bytes,4,opt,name=term,proto3" json:"term,omitempty"` // 学期描述 + Weeks string `protobuf:"bytes,5,opt,name=weeks,proto3" json:"weeks,omitempty"` // 周次范围 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EmptyClassroomEntry) Reset() { + *x = EmptyClassroomEntry{} + mi := &file_proto_runner_runner_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EmptyClassroomEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyClassroomEntry) ProtoMessage() {} + +func (x *EmptyClassroomEntry) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmptyClassroomEntry.ProtoReflect.Descriptor instead. +func (*EmptyClassroomEntry) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{23} +} + +func (x *EmptyClassroomEntry) GetClassroom() string { + if x != nil { + return x.Classroom + } + return "" +} + +func (x *EmptyClassroomEntry) GetWeekday() string { + if x != nil { + return x.Weekday + } + return "" +} + +func (x *EmptyClassroomEntry) GetPeriods() string { + if x != nil { + return x.Periods + } + return "" +} + +func (x *EmptyClassroomEntry) GetTerm() string { + if x != nil { + return x.Term + } + return "" +} + +func (x *EmptyClassroomEntry) GetWeeks() string { + if x != nil { + return x.Weeks + } + return "" +} + +var File_proto_runner_runner_proto protoreflect.FileDescriptor + +const file_proto_runner_runner_proto_rawDesc = "" + + "\n" + + "\x19proto/runner/runner.proto\x12\x06runner\"\x93\x03\n" + + "\rStreamMessage\x125\n" + + "\bregister\x18\x01 \x01(\v2\x17.runner.RegisterRequestH\x00R\bregister\x12G\n" + + "\x11register_response\x18\x02 \x01(\v2\x18.runner.RegisterResponseH\x00R\x10registerResponse\x121\n" + + "\theartbeat\x18\x03 \x01(\v2\x11.runner.HeartbeatH\x00R\theartbeat\x12;\n" + + "\rheartbeat_ack\x18\x04 \x01(\v2\x14.runner.HeartbeatAckH\x00R\fheartbeatAck\x12\"\n" + + "\x04task\x18\x05 \x01(\v2\f.runner.TaskH\x00R\x04task\x12,\n" + + "\x06result\x18\x06 \x01(\v2\x12.runner.TaskResultH\x00R\x06result\x125\n" + + "\vtask_cancel\x18\a \x01(\v2\x12.runner.TaskCancelH\x00R\n" + + "taskCancelB\t\n" + + "\amessage\"\xd8\x01\n" + + "\x0fRegisterRequest\x12\x1b\n" + + "\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\x12M\n" + + "\fcapabilities\x18\x03 \x03(\v2).runner.RegisterRequest.CapabilitiesEntryR\fcapabilities\x1a?\n" + + "\x11CapabilitiesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xb7\x01\n" + + "\x10RegisterResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1d\n" + + "\n" + + "session_id\x18\x02 \x01(\tR\tsessionId\x12\x18\n" + + "\amessage\x18\x03 \x01(\tR\amessage\x12-\n" + + "\x12heartbeat_interval\x18\x04 \x01(\x05R\x11heartbeatInterval\x12!\n" + + "\ftask_timeout\x18\x05 \x01(\x05R\vtaskTimeout\")\n" + + "\tHeartbeat\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\"F\n" + + "\fHeartbeatAck\x12\x1c\n" + + "\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x18\n" + + "\alatency\x18\x02 \x01(\x03R\alatency\"\xa7\x01\n" + + "\x04Task\x12\x17\n" + + "\atask_id\x18\x01 \x01(\tR\x06taskId\x12$\n" + + "\x04type\x18\x02 \x01(\x0e2\x10.runner.TaskTypeR\x04type\x12\x1d\n" + + "\n" + + "created_at\x18\x03 \x01(\x03R\tcreatedAt\x12'\n" + + "\x0ftimeout_seconds\x18\x04 \x01(\x05R\x0etimeoutSeconds\x12\x18\n" + + "\apayload\x18\x05 \x01(\fR\apayload\"=\n" + + "\n" + + "TaskCancel\x12\x17\n" + + "\atask_id\x18\x01 \x01(\tR\x06taskId\x12\x16\n" + + "\x06reason\x18\x02 \x01(\tR\x06reason\"\xcc\x01\n" + + "\n" + + "TaskResult\x12\x17\n" + + "\atask_id\x18\x01 \x01(\tR\x06taskId\x12*\n" + + "\x06status\x18\x02 \x01(\x0e2\x12.runner.TaskStatusR\x06status\x12!\n" + + "\fcompleted_at\x18\x03 \x01(\x03R\vcompletedAt\x12\x12\n" + + "\x04data\x18\x04 \x01(\fR\x04data\x12\x1d\n" + + "\n" + + "error_code\x18\x05 \x01(\tR\terrorCode\x12#\n" + + "\rerror_message\x18\x06 \x01(\tR\ferrorMessage\"\\\n" + + "\fLoginPayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x14\n" + + "\x05twfid\x18\x03 \x01(\tR\x05twfid\"h\n" + + "\x12GetSchedulePayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" + + "\bsemester\x18\x03 \x01(\tR\bsemester\"f\n" + + "\x10GetGradesPayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" + + "\bsemester\x18\x03 \x01(\tR\bsemester\"e\n" + + "\x0fGetExamsPayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" + + "\bsemester\x18\x03 \x01(\tR\bsemester\"\x9c\x01\n" + + "\x12ScheduleResultData\x12\x1a\n" + + "\bsemester\x18\x01 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "student_id\x18\x02 \x01(\tR\tstudentId\x12!\n" + + "\fstudent_name\x18\x03 \x01(\tR\vstudentName\x12(\n" + + "\acourses\x18\x04 \x03(\v2\x0e.runner.CourseR\acourses\"\xa8\x01\n" + + "\x06Course\x12\x12\n" + + "\x04code\x18\x01 \x01(\tR\x04code\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + + "\ateacher\x18\x03 \x01(\tR\ateacher\x12\x12\n" + + "\x04room\x18\x04 \x01(\tR\x04room\x12\x16\n" + + "\x06credit\x18\x05 \x01(\x02R\x06credit\x120\n" + + "\bschedule\x18\x06 \x03(\v2\x14.runner.ScheduleTimeR\bschedule\"R\n" + + "\fScheduleTime\x12\x10\n" + + "\x03day\x18\x01 \x01(\tR\x03day\x12\x1a\n" + + "\bsections\x18\x02 \x03(\x05R\bsections\x12\x14\n" + + "\x05weeks\x18\x03 \x03(\x05R\x05weeks\"\xd6\x01\n" + + "\n" + + "GpaSummary\x12\x1f\n" + + "\vaverage_gpa\x18\x01 \x01(\tR\n" + + "averageGpa\x12\x12\n" + + "\x04rank\x18\x02 \x01(\tR\x04rank\x12$\n" + + "\x0eexam_total_gpa\x18\x03 \x01(\tR\fexamTotalGpa\x12,\n" + + "\x12exam_total_credits\x18\x04 \x01(\tR\x10examTotalCredits\x12!\n" + + "\ffail_credits\x18\x05 \x01(\tR\vfailCredits\x12\x1c\n" + + "\tsemesters\x18\x06 \x01(\tR\tsemesters\"\xa9\x01\n" + + "\x10GradesResultData\x12\x1a\n" + + "\bsemester\x18\x01 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "student_id\x18\x02 \x01(\tR\tstudentId\x12%\n" + + "\x06grades\x18\x03 \x03(\v2\r.runner.GradeR\x06grades\x123\n" + + "\vgpa_summary\x18\x04 \x01(\v2\x12.runner.GpaSummaryR\n" + + "gpaSummary\"\xf9\x01\n" + + "\x05Grade\x12\x12\n" + + "\x04term\x18\x01 \x01(\tR\x04term\x12\x1f\n" + + "\vcourse_code\x18\x02 \x01(\tR\n" + + "courseCode\x12\x1f\n" + + "\vcourse_name\x18\x03 \x01(\tR\n" + + "courseName\x12\x16\n" + + "\x06nature\x18\x04 \x01(\tR\x06nature\x12\x1a\n" + + "\bcategory\x18\x05 \x01(\tR\bcategory\x12\x16\n" + + "\x06credit\x18\x06 \x01(\tR\x06credit\x12\x14\n" + + "\x05score\x18\a \x01(\tR\x05score\x12\x1f\n" + + "\vgrade_point\x18\b \x01(\tR\n" + + "gradePoint\x12\x17\n" + + "\ais_exam\x18\t \x01(\tR\x06isExam\"p\n" + + "\x0fExamsResultData\x12\x1a\n" + + "\bsemester\x18\x01 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "student_id\x18\x02 \x01(\tR\tstudentId\x12\"\n" + + "\x05exams\x18\x03 \x03(\v2\f.runner.ExamR\x05exams\"\x9a\x01\n" + + "\x04Exam\x12\x1f\n" + + "\vcourse_name\x18\x01 \x01(\tR\n" + + "courseName\x12\x1b\n" + + "\texam_type\x18\x02 \x01(\tR\bexamType\x12\x12\n" + + "\x04date\x18\x03 \x01(\tR\x04date\x12\x12\n" + + "\x04time\x18\x04 \x01(\tR\x04time\x12\x12\n" + + "\x04week\x18\x05 \x01(\tR\x04week\x12\x18\n" + + "\aweekday\x18\x06 \x01(\tR\aweekday\"\xc4\x01\n" + + "\x12UserInfoResultData\x12\x1d\n" + + "\n" + + "student_id\x18\x01 \x01(\tR\tstudentId\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n" + + "\x06gender\x18\x03 \x01(\tR\x06gender\x12\x18\n" + + "\acollege\x18\x04 \x01(\tR\acollege\x12\x14\n" + + "\x05major\x18\x05 \x01(\tR\x05major\x12\x1d\n" + + "\n" + + "class_name\x18\x06 \x01(\tR\tclassName\x12\x14\n" + + "\x05grade\x18\a \x01(\tR\x05grade\"\xee\x01\n" + + "\x18GetEmptyClassroomPayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" + + "\bsemester\x18\x03 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "week_start\x18\x04 \x01(\tR\tweekStart\x12\x19\n" + + "\bweek_end\x18\x05 \x01(\tR\aweekEnd\x12\x1f\n" + + "\vcampus_code\x18\x06 \x01(\tR\n" + + "campusCode\x12#\n" + + "\rbuilding_code\x18\a \x01(\tR\fbuildingCode\"\x92\x01\n" + + "\x18EmptyClassroomResultData\x12\x1a\n" + + "\bsemester\x18\x01 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "student_id\x18\x02 \x01(\tR\tstudentId\x12;\n" + + "\n" + + "classrooms\x18\x03 \x03(\v2\x1b.runner.EmptyClassroomEntryR\n" + + "classrooms\"\x91\x01\n" + + "\x13EmptyClassroomEntry\x12\x1c\n" + + "\tclassroom\x18\x01 \x01(\tR\tclassroom\x12\x18\n" + + "\aweekday\x18\x02 \x01(\tR\aweekday\x12\x18\n" + + "\aperiods\x18\x03 \x01(\tR\aperiods\x12\x12\n" + + "\x04term\x18\x04 \x01(\tR\x04term\x12\x14\n" + + "\x05weeks\x18\x05 \x01(\tR\x05weeks*\xc5\x01\n" + + "\bTaskType\x12\x15\n" + + "\x11TASK_TYPE_UNKNOWN\x10\x00\x12\x13\n" + + "\x0fTASK_TYPE_LOGIN\x10\x01\x12\x1a\n" + + "\x16TASK_TYPE_GET_SCHEDULE\x10\x02\x12\x18\n" + + "\x14TASK_TYPE_GET_GRADES\x10\x03\x12\x17\n" + + "\x13TASK_TYPE_GET_EXAMS\x10\x04\x12\x1b\n" + + "\x17TASK_TYPE_GET_USER_INFO\x10\x05\x12!\n" + + "\x1dTASK_TYPE_GET_EMPTY_CLASSROOM\x10\x06*\x8a\x01\n" + + "\n" + + "TaskStatus\x12\x17\n" + + "\x13TASK_STATUS_UNKNOWN\x10\x00\x12\x17\n" + + "\x13TASK_STATUS_SUCCESS\x10\x01\x12\x16\n" + + "\x12TASK_STATUS_FAILED\x10\x02\x12\x17\n" + + "\x13TASK_STATUS_TIMEOUT\x10\x03\x12\x19\n" + + "\x15TASK_STATUS_CANCELLED\x10\x042H\n" + + "\tRunnerHub\x12;\n" + + "\aConnect\x12\x15.runner.StreamMessage\x1a\x15.runner.StreamMessage(\x010\x01B(Z&schedule_converter/proto/runner;runnerb\x06proto3" + +var ( + file_proto_runner_runner_proto_rawDescOnce sync.Once + file_proto_runner_runner_proto_rawDescData []byte +) + +func file_proto_runner_runner_proto_rawDescGZIP() []byte { + file_proto_runner_runner_proto_rawDescOnce.Do(func() { + file_proto_runner_runner_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_runner_runner_proto_rawDesc), len(file_proto_runner_runner_proto_rawDesc))) + }) + return file_proto_runner_runner_proto_rawDescData +} + +var file_proto_runner_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_proto_runner_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_proto_runner_runner_proto_goTypes = []any{ + (TaskType)(0), // 0: runner.TaskType + (TaskStatus)(0), // 1: runner.TaskStatus + (*StreamMessage)(nil), // 2: runner.StreamMessage + (*RegisterRequest)(nil), // 3: runner.RegisterRequest + (*RegisterResponse)(nil), // 4: runner.RegisterResponse + (*Heartbeat)(nil), // 5: runner.Heartbeat + (*HeartbeatAck)(nil), // 6: runner.HeartbeatAck + (*Task)(nil), // 7: runner.Task + (*TaskCancel)(nil), // 8: runner.TaskCancel + (*TaskResult)(nil), // 9: runner.TaskResult + (*LoginPayload)(nil), // 10: runner.LoginPayload + (*GetSchedulePayload)(nil), // 11: runner.GetSchedulePayload + (*GetGradesPayload)(nil), // 12: runner.GetGradesPayload + (*GetExamsPayload)(nil), // 13: runner.GetExamsPayload + (*ScheduleResultData)(nil), // 14: runner.ScheduleResultData + (*Course)(nil), // 15: runner.Course + (*ScheduleTime)(nil), // 16: runner.ScheduleTime + (*GpaSummary)(nil), // 17: runner.GpaSummary + (*GradesResultData)(nil), // 18: runner.GradesResultData + (*Grade)(nil), // 19: runner.Grade + (*ExamsResultData)(nil), // 20: runner.ExamsResultData + (*Exam)(nil), // 21: runner.Exam + (*UserInfoResultData)(nil), // 22: runner.UserInfoResultData + (*GetEmptyClassroomPayload)(nil), // 23: runner.GetEmptyClassroomPayload + (*EmptyClassroomResultData)(nil), // 24: runner.EmptyClassroomResultData + (*EmptyClassroomEntry)(nil), // 25: runner.EmptyClassroomEntry + nil, // 26: runner.RegisterRequest.CapabilitiesEntry +} +var file_proto_runner_runner_proto_depIdxs = []int32{ + 3, // 0: runner.StreamMessage.register:type_name -> runner.RegisterRequest + 4, // 1: runner.StreamMessage.register_response:type_name -> runner.RegisterResponse + 5, // 2: runner.StreamMessage.heartbeat:type_name -> runner.Heartbeat + 6, // 3: runner.StreamMessage.heartbeat_ack:type_name -> runner.HeartbeatAck + 7, // 4: runner.StreamMessage.task:type_name -> runner.Task + 9, // 5: runner.StreamMessage.result:type_name -> runner.TaskResult + 8, // 6: runner.StreamMessage.task_cancel:type_name -> runner.TaskCancel + 26, // 7: runner.RegisterRequest.capabilities:type_name -> runner.RegisterRequest.CapabilitiesEntry + 0, // 8: runner.Task.type:type_name -> runner.TaskType + 1, // 9: runner.TaskResult.status:type_name -> runner.TaskStatus + 15, // 10: runner.ScheduleResultData.courses:type_name -> runner.Course + 16, // 11: runner.Course.schedule:type_name -> runner.ScheduleTime + 19, // 12: runner.GradesResultData.grades:type_name -> runner.Grade + 17, // 13: runner.GradesResultData.gpa_summary:type_name -> runner.GpaSummary + 21, // 14: runner.ExamsResultData.exams:type_name -> runner.Exam + 25, // 15: runner.EmptyClassroomResultData.classrooms:type_name -> runner.EmptyClassroomEntry + 2, // 16: runner.RunnerHub.Connect:input_type -> runner.StreamMessage + 2, // 17: runner.RunnerHub.Connect:output_type -> runner.StreamMessage + 17, // [17:18] is the sub-list for method output_type + 16, // [16:17] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name +} + +func init() { file_proto_runner_runner_proto_init() } +func file_proto_runner_runner_proto_init() { + if File_proto_runner_runner_proto != nil { + return + } + file_proto_runner_runner_proto_msgTypes[0].OneofWrappers = []any{ + (*StreamMessage_Register)(nil), + (*StreamMessage_RegisterResponse)(nil), + (*StreamMessage_Heartbeat)(nil), + (*StreamMessage_HeartbeatAck)(nil), + (*StreamMessage_Task)(nil), + (*StreamMessage_Result)(nil), + (*StreamMessage_TaskCancel)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_runner_runner_proto_rawDesc), len(file_proto_runner_runner_proto_rawDesc)), + NumEnums: 2, + NumMessages: 25, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_runner_runner_proto_goTypes, + DependencyIndexes: file_proto_runner_runner_proto_depIdxs, + EnumInfos: file_proto_runner_runner_proto_enumTypes, + MessageInfos: file_proto_runner_runner_proto_msgTypes, + }.Build() + File_proto_runner_runner_proto = out.File + file_proto_runner_runner_proto_goTypes = nil + file_proto_runner_runner_proto_depIdxs = nil +} diff --git a/proto/runner/proto/runner/runner_grpc.pb.go b/proto/runner/proto/runner/runner_grpc.pb.go new file mode 100644 index 0000000..3adf82f --- /dev/null +++ b/proto/runner/proto/runner/runner_grpc.pb.go @@ -0,0 +1,125 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc v7.34.1 +// source: proto/runner/runner.proto + +package runner + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + RunnerHub_Connect_FullMethodName = "/runner.RunnerHub/Connect" +) + +// RunnerHubClient is the client API for RunnerHub service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// RunnerHub 服务 - 由 Backend 服务器实现 +// Runner 作为客户端主动连接,建立双向流通信 +type RunnerHubClient interface { + // Connect 建立双向流连接 + // Runner 通过此连接注册、接收任务、返回结果 + Connect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamMessage, StreamMessage], error) +} + +type runnerHubClient struct { + cc grpc.ClientConnInterface +} + +func NewRunnerHubClient(cc grpc.ClientConnInterface) RunnerHubClient { + return &runnerHubClient{cc} +} + +func (c *runnerHubClient) Connect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[StreamMessage, StreamMessage], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &RunnerHub_ServiceDesc.Streams[0], RunnerHub_Connect_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[StreamMessage, StreamMessage]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type RunnerHub_ConnectClient = grpc.BidiStreamingClient[StreamMessage, StreamMessage] + +// RunnerHubServer is the server API for RunnerHub service. +// All implementations must embed UnimplementedRunnerHubServer +// for forward compatibility. +// +// RunnerHub 服务 - 由 Backend 服务器实现 +// Runner 作为客户端主动连接,建立双向流通信 +type RunnerHubServer interface { + // Connect 建立双向流连接 + // Runner 通过此连接注册、接收任务、返回结果 + Connect(grpc.BidiStreamingServer[StreamMessage, StreamMessage]) error + mustEmbedUnimplementedRunnerHubServer() +} + +// UnimplementedRunnerHubServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedRunnerHubServer struct{} + +func (UnimplementedRunnerHubServer) Connect(grpc.BidiStreamingServer[StreamMessage, StreamMessage]) error { + return status.Error(codes.Unimplemented, "method Connect not implemented") +} +func (UnimplementedRunnerHubServer) mustEmbedUnimplementedRunnerHubServer() {} +func (UnimplementedRunnerHubServer) testEmbeddedByValue() {} + +// UnsafeRunnerHubServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RunnerHubServer will +// result in compilation errors. +type UnsafeRunnerHubServer interface { + mustEmbedUnimplementedRunnerHubServer() +} + +func RegisterRunnerHubServer(s grpc.ServiceRegistrar, srv RunnerHubServer) { + // If the following call panics, it indicates UnimplementedRunnerHubServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&RunnerHub_ServiceDesc, srv) +} + +func _RunnerHub_Connect_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(RunnerHubServer).Connect(&grpc.GenericServerStream[StreamMessage, StreamMessage]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type RunnerHub_ConnectServer = grpc.BidiStreamingServer[StreamMessage, StreamMessage] + +// RunnerHub_ServiceDesc is the grpc.ServiceDesc for RunnerHub service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var RunnerHub_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "runner.RunnerHub", + HandlerType: (*RunnerHubServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Connect", + Handler: _RunnerHub_Connect_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "proto/runner/runner.proto", +} diff --git a/proto/runner/runner.pb.go b/proto/runner/runner.pb.go index 53e154a..dff09e9 100644 --- a/proto/runner/runner.pb.go +++ b/proto/runner/runner.pb.go @@ -25,12 +25,13 @@ const ( type TaskType int32 const ( - TaskType_TASK_TYPE_UNKNOWN TaskType = 0 // 未知类型 - TaskType_TASK_TYPE_LOGIN TaskType = 1 // 登录验证 - TaskType_TASK_TYPE_GET_SCHEDULE TaskType = 2 // 获取课表 - TaskType_TASK_TYPE_GET_GRADES TaskType = 3 // 获取成绩 - TaskType_TASK_TYPE_GET_EXAMS TaskType = 4 // 获取考试安排 - TaskType_TASK_TYPE_GET_USER_INFO TaskType = 5 // 获取用户信息 + TaskType_TASK_TYPE_UNKNOWN TaskType = 0 // 未知类型 + TaskType_TASK_TYPE_LOGIN TaskType = 1 // 登录验证 + TaskType_TASK_TYPE_GET_SCHEDULE TaskType = 2 // 获取课表 + TaskType_TASK_TYPE_GET_GRADES TaskType = 3 // 获取成绩 + TaskType_TASK_TYPE_GET_EXAMS TaskType = 4 // 获取考试安排 + TaskType_TASK_TYPE_GET_USER_INFO TaskType = 5 // 获取用户信息 + TaskType_TASK_TYPE_GET_EMPTY_CLASSROOM TaskType = 6 // 获取空教室 ) // Enum value maps for TaskType. @@ -42,14 +43,16 @@ var ( 3: "TASK_TYPE_GET_GRADES", 4: "TASK_TYPE_GET_EXAMS", 5: "TASK_TYPE_GET_USER_INFO", + 6: "TASK_TYPE_GET_EMPTY_CLASSROOM", } TaskType_value = map[string]int32{ - "TASK_TYPE_UNKNOWN": 0, - "TASK_TYPE_LOGIN": 1, - "TASK_TYPE_GET_SCHEDULE": 2, - "TASK_TYPE_GET_GRADES": 3, - "TASK_TYPE_GET_EXAMS": 4, - "TASK_TYPE_GET_USER_INFO": 5, + "TASK_TYPE_UNKNOWN": 0, + "TASK_TYPE_LOGIN": 1, + "TASK_TYPE_GET_SCHEDULE": 2, + "TASK_TYPE_GET_GRADES": 3, + "TASK_TYPE_GET_EXAMS": 4, + "TASK_TYPE_GET_USER_INFO": 5, + "TASK_TYPE_GET_EMPTY_CLASSROOM": 6, } ) @@ -1711,6 +1714,237 @@ func (x *UserInfoResultData) GetGrade() string { return "" } +// GetEmptyClassroomPayload 获取空教室任务载荷 +type GetEmptyClassroomPayload struct { + state protoimpl.MessageState `protogen:"open.v1"` + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // 学号 + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // 密码 + Semester string `protobuf:"bytes,3,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + WeekStart string `protobuf:"bytes,4,opt,name=week_start,json=weekStart,proto3" json:"week_start,omitempty"` // 起始周次 + WeekEnd string `protobuf:"bytes,5,opt,name=week_end,json=weekEnd,proto3" json:"week_end,omitempty"` // 结束周次 + CampusCode string `protobuf:"bytes,6,opt,name=campus_code,json=campusCode,proto3" json:"campus_code,omitempty"` // 校区代码 + BuildingCode string `protobuf:"bytes,7,opt,name=building_code,json=buildingCode,proto3" json:"building_code,omitempty"` // 楼号代码(可选) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEmptyClassroomPayload) Reset() { + *x = GetEmptyClassroomPayload{} + mi := &file_proto_runner_runner_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEmptyClassroomPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEmptyClassroomPayload) ProtoMessage() {} + +func (x *GetEmptyClassroomPayload) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEmptyClassroomPayload.ProtoReflect.Descriptor instead. +func (*GetEmptyClassroomPayload) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{21} +} + +func (x *GetEmptyClassroomPayload) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetWeekStart() string { + if x != nil { + return x.WeekStart + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetWeekEnd() string { + if x != nil { + return x.WeekEnd + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetCampusCode() string { + if x != nil { + return x.CampusCode + } + return "" +} + +func (x *GetEmptyClassroomPayload) GetBuildingCode() string { + if x != nil { + return x.BuildingCode + } + return "" +} + +// EmptyClassroomResultData 空教室结果数据 +type EmptyClassroomResultData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Semester string `protobuf:"bytes,1,opt,name=semester,proto3" json:"semester,omitempty"` // 学期 + StudentId string `protobuf:"bytes,2,opt,name=student_id,json=studentId,proto3" json:"student_id,omitempty"` // 学号 + Classrooms []*EmptyClassroomEntry `protobuf:"bytes,3,rep,name=classrooms,proto3" json:"classrooms,omitempty"` // 空教室列表 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EmptyClassroomResultData) Reset() { + *x = EmptyClassroomResultData{} + mi := &file_proto_runner_runner_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EmptyClassroomResultData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyClassroomResultData) ProtoMessage() {} + +func (x *EmptyClassroomResultData) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmptyClassroomResultData.ProtoReflect.Descriptor instead. +func (*EmptyClassroomResultData) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{22} +} + +func (x *EmptyClassroomResultData) GetSemester() string { + if x != nil { + return x.Semester + } + return "" +} + +func (x *EmptyClassroomResultData) GetStudentId() string { + if x != nil { + return x.StudentId + } + return "" +} + +func (x *EmptyClassroomResultData) GetClassrooms() []*EmptyClassroomEntry { + if x != nil { + return x.Classrooms + } + return nil +} + +// EmptyClassroomEntry 空教室条目 +type EmptyClassroomEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Classroom string `protobuf:"bytes,1,opt,name=classroom,proto3" json:"classroom,omitempty"` // 教室名称 + Weekday string `protobuf:"bytes,2,opt,name=weekday,proto3" json:"weekday,omitempty"` // 星期几 + Periods string `protobuf:"bytes,3,opt,name=periods,proto3" json:"periods,omitempty"` // 可用节次 + Term string `protobuf:"bytes,4,opt,name=term,proto3" json:"term,omitempty"` // 学期描述 + Weeks string `protobuf:"bytes,5,opt,name=weeks,proto3" json:"weeks,omitempty"` // 周次范围 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EmptyClassroomEntry) Reset() { + *x = EmptyClassroomEntry{} + mi := &file_proto_runner_runner_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EmptyClassroomEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyClassroomEntry) ProtoMessage() {} + +func (x *EmptyClassroomEntry) ProtoReflect() protoreflect.Message { + mi := &file_proto_runner_runner_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmptyClassroomEntry.ProtoReflect.Descriptor instead. +func (*EmptyClassroomEntry) Descriptor() ([]byte, []int) { + return file_proto_runner_runner_proto_rawDescGZIP(), []int{23} +} + +func (x *EmptyClassroomEntry) GetClassroom() string { + if x != nil { + return x.Classroom + } + return "" +} + +func (x *EmptyClassroomEntry) GetWeekday() string { + if x != nil { + return x.Weekday + } + return "" +} + +func (x *EmptyClassroomEntry) GetPeriods() string { + if x != nil { + return x.Periods + } + return "" +} + +func (x *EmptyClassroomEntry) GetTerm() string { + if x != nil { + return x.Term + } + return "" +} + +func (x *EmptyClassroomEntry) GetWeeks() string { + if x != nil { + return x.Weeks + } + return "" +} + var File_proto_runner_runner_proto protoreflect.FileDescriptor const file_proto_runner_runner_proto_rawDesc = "" + @@ -1849,14 +2083,38 @@ const file_proto_runner_runner_proto_rawDesc = "" + "\x05major\x18\x05 \x01(\tR\x05major\x12\x1d\n" + "\n" + "class_name\x18\x06 \x01(\tR\tclassName\x12\x14\n" + - "\x05grade\x18\a \x01(\tR\x05grade*\xa2\x01\n" + + "\x05grade\x18\a \x01(\tR\x05grade\"\xee\x01\n" + + "\x18GetEmptyClassroomPayload\x12\x1a\n" + + "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" + + "\bpassword\x18\x02 \x01(\tR\bpassword\x12\x1a\n" + + "\bsemester\x18\x03 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "week_start\x18\x04 \x01(\tR\tweekStart\x12\x19\n" + + "\bweek_end\x18\x05 \x01(\tR\aweekEnd\x12\x1f\n" + + "\vcampus_code\x18\x06 \x01(\tR\n" + + "campusCode\x12#\n" + + "\rbuilding_code\x18\a \x01(\tR\fbuildingCode\"\x92\x01\n" + + "\x18EmptyClassroomResultData\x12\x1a\n" + + "\bsemester\x18\x01 \x01(\tR\bsemester\x12\x1d\n" + + "\n" + + "student_id\x18\x02 \x01(\tR\tstudentId\x12;\n" + + "\n" + + "classrooms\x18\x03 \x03(\v2\x1b.runner.EmptyClassroomEntryR\n" + + "classrooms\"\x91\x01\n" + + "\x13EmptyClassroomEntry\x12\x1c\n" + + "\tclassroom\x18\x01 \x01(\tR\tclassroom\x12\x18\n" + + "\aweekday\x18\x02 \x01(\tR\aweekday\x12\x18\n" + + "\aperiods\x18\x03 \x01(\tR\aperiods\x12\x12\n" + + "\x04term\x18\x04 \x01(\tR\x04term\x12\x14\n" + + "\x05weeks\x18\x05 \x01(\tR\x05weeks*\xc5\x01\n" + "\bTaskType\x12\x15\n" + "\x11TASK_TYPE_UNKNOWN\x10\x00\x12\x13\n" + "\x0fTASK_TYPE_LOGIN\x10\x01\x12\x1a\n" + "\x16TASK_TYPE_GET_SCHEDULE\x10\x02\x12\x18\n" + "\x14TASK_TYPE_GET_GRADES\x10\x03\x12\x17\n" + "\x13TASK_TYPE_GET_EXAMS\x10\x04\x12\x1b\n" + - "\x17TASK_TYPE_GET_USER_INFO\x10\x05*\x8a\x01\n" + + "\x17TASK_TYPE_GET_USER_INFO\x10\x05\x12!\n" + + "\x1dTASK_TYPE_GET_EMPTY_CLASSROOM\x10\x06*\x8a\x01\n" + "\n" + "TaskStatus\x12\x17\n" + "\x13TASK_STATUS_UNKNOWN\x10\x00\x12\x17\n" + @@ -1880,32 +2138,35 @@ func file_proto_runner_runner_proto_rawDescGZIP() []byte { } var file_proto_runner_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_proto_runner_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 22) +var file_proto_runner_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_proto_runner_runner_proto_goTypes = []any{ - (TaskType)(0), // 0: runner.TaskType - (TaskStatus)(0), // 1: runner.TaskStatus - (*StreamMessage)(nil), // 2: runner.StreamMessage - (*RegisterRequest)(nil), // 3: runner.RegisterRequest - (*RegisterResponse)(nil), // 4: runner.RegisterResponse - (*Heartbeat)(nil), // 5: runner.Heartbeat - (*HeartbeatAck)(nil), // 6: runner.HeartbeatAck - (*Task)(nil), // 7: runner.Task - (*TaskCancel)(nil), // 8: runner.TaskCancel - (*TaskResult)(nil), // 9: runner.TaskResult - (*LoginPayload)(nil), // 10: runner.LoginPayload - (*GetSchedulePayload)(nil), // 11: runner.GetSchedulePayload - (*GetGradesPayload)(nil), // 12: runner.GetGradesPayload - (*GetExamsPayload)(nil), // 13: runner.GetExamsPayload - (*ScheduleResultData)(nil), // 14: runner.ScheduleResultData - (*Course)(nil), // 15: runner.Course - (*ScheduleTime)(nil), // 16: runner.ScheduleTime - (*GpaSummary)(nil), // 17: runner.GpaSummary - (*GradesResultData)(nil), // 18: runner.GradesResultData - (*Grade)(nil), // 19: runner.Grade - (*ExamsResultData)(nil), // 20: runner.ExamsResultData - (*Exam)(nil), // 21: runner.Exam - (*UserInfoResultData)(nil), // 22: runner.UserInfoResultData - nil, // 23: runner.RegisterRequest.CapabilitiesEntry + (TaskType)(0), // 0: runner.TaskType + (TaskStatus)(0), // 1: runner.TaskStatus + (*StreamMessage)(nil), // 2: runner.StreamMessage + (*RegisterRequest)(nil), // 3: runner.RegisterRequest + (*RegisterResponse)(nil), // 4: runner.RegisterResponse + (*Heartbeat)(nil), // 5: runner.Heartbeat + (*HeartbeatAck)(nil), // 6: runner.HeartbeatAck + (*Task)(nil), // 7: runner.Task + (*TaskCancel)(nil), // 8: runner.TaskCancel + (*TaskResult)(nil), // 9: runner.TaskResult + (*LoginPayload)(nil), // 10: runner.LoginPayload + (*GetSchedulePayload)(nil), // 11: runner.GetSchedulePayload + (*GetGradesPayload)(nil), // 12: runner.GetGradesPayload + (*GetExamsPayload)(nil), // 13: runner.GetExamsPayload + (*ScheduleResultData)(nil), // 14: runner.ScheduleResultData + (*Course)(nil), // 15: runner.Course + (*ScheduleTime)(nil), // 16: runner.ScheduleTime + (*GpaSummary)(nil), // 17: runner.GpaSummary + (*GradesResultData)(nil), // 18: runner.GradesResultData + (*Grade)(nil), // 19: runner.Grade + (*ExamsResultData)(nil), // 20: runner.ExamsResultData + (*Exam)(nil), // 21: runner.Exam + (*UserInfoResultData)(nil), // 22: runner.UserInfoResultData + (*GetEmptyClassroomPayload)(nil), // 23: runner.GetEmptyClassroomPayload + (*EmptyClassroomResultData)(nil), // 24: runner.EmptyClassroomResultData + (*EmptyClassroomEntry)(nil), // 25: runner.EmptyClassroomEntry + nil, // 26: runner.RegisterRequest.CapabilitiesEntry } var file_proto_runner_runner_proto_depIdxs = []int32{ 3, // 0: runner.StreamMessage.register:type_name -> runner.RegisterRequest @@ -1915,7 +2176,7 @@ var file_proto_runner_runner_proto_depIdxs = []int32{ 7, // 4: runner.StreamMessage.task:type_name -> runner.Task 9, // 5: runner.StreamMessage.result:type_name -> runner.TaskResult 8, // 6: runner.StreamMessage.task_cancel:type_name -> runner.TaskCancel - 23, // 7: runner.RegisterRequest.capabilities:type_name -> runner.RegisterRequest.CapabilitiesEntry + 26, // 7: runner.RegisterRequest.capabilities:type_name -> runner.RegisterRequest.CapabilitiesEntry 0, // 8: runner.Task.type:type_name -> runner.TaskType 1, // 9: runner.TaskResult.status:type_name -> runner.TaskStatus 15, // 10: runner.ScheduleResultData.courses:type_name -> runner.Course @@ -1923,13 +2184,14 @@ var file_proto_runner_runner_proto_depIdxs = []int32{ 19, // 12: runner.GradesResultData.grades:type_name -> runner.Grade 17, // 13: runner.GradesResultData.gpa_summary:type_name -> runner.GpaSummary 21, // 14: runner.ExamsResultData.exams:type_name -> runner.Exam - 2, // 15: runner.RunnerHub.Connect:input_type -> runner.StreamMessage - 2, // 16: runner.RunnerHub.Connect:output_type -> runner.StreamMessage - 16, // [16:17] is the sub-list for method output_type - 15, // [15:16] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 25, // 15: runner.EmptyClassroomResultData.classrooms:type_name -> runner.EmptyClassroomEntry + 2, // 16: runner.RunnerHub.Connect:input_type -> runner.StreamMessage + 2, // 17: runner.RunnerHub.Connect:output_type -> runner.StreamMessage + 17, // [17:18] is the sub-list for method output_type + 16, // [16:17] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name } func init() { file_proto_runner_runner_proto_init() } @@ -1952,7 +2214,7 @@ func file_proto_runner_runner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_runner_runner_proto_rawDesc), len(file_proto_runner_runner_proto_rawDesc)), NumEnums: 2, - NumMessages: 22, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/runner/runner.proto b/proto/runner/runner.proto index 415d6d7..7e51a55 100644 --- a/proto/runner/runner.proto +++ b/proto/runner/runner.proto @@ -81,6 +81,7 @@ enum TaskType { TASK_TYPE_GET_GRADES = 3; // 获取成绩 TASK_TYPE_GET_EXAMS = 4; // 获取考试安排 TASK_TYPE_GET_USER_INFO = 5; // 获取用户信息 + TASK_TYPE_GET_EMPTY_CLASSROOM = 6; // 获取空教室 } // TaskStatus 任务状态枚举 @@ -236,3 +237,30 @@ message UserInfoResultData { string class_name = 6; // 班级 string grade = 7; // 年级 } + +// GetEmptyClassroomPayload 获取空教室任务载荷 +message GetEmptyClassroomPayload { + string username = 1; // 学号 + string password = 2; // 密码 + string semester = 3; // 学期 + string week_start = 4; // 起始周次 + string week_end = 5; // 结束周次 + string campus_code = 6; // 校区代码 + string building_code = 7; // 楼号代码(可选) +} + +// EmptyClassroomResultData 空教室结果数据 +message EmptyClassroomResultData { + string semester = 1; // 学期 + string student_id = 2; // 学号 + repeated EmptyClassroomEntry classrooms = 3; // 空教室列表 +} + +// EmptyClassroomEntry 空教室条目 +message EmptyClassroomEntry { + string classroom = 1; // 教室名称 + string weekday = 2; // 星期几 + string periods = 3; // 可用节次 + string term = 4; // 学期描述 + string weeks = 5; // 周次范围 +}