feat(grpc): add support for fetching empty classrooms
All checks were successful
Build / build (push) Successful in 1m31s

Implement the `TASK_TYPE_GET_EMPTY_CLASSROOM` task type to allow users to fetch available classroom information.

- Add `TASK_TYPE_GET_EMPTY_CLASSROOM` to the `TaskType` enum in protobuf.
- Define `GetEmptyClassroomPayload` and `EmptyClassroomResultData` messages.
- Implement `getEmptyClassrooms`
This commit is contained in:
2026-06-02 13:59:30 +08:00
parent d64f2fa20b
commit ee5c36f3ac
7 changed files with 663 additions and 53 deletions

View File

@@ -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,
},