refactor: introduce service layer and migrate gRPC handlers to use it
All checks were successful
Build / build (push) Successful in 2m17s
All checks were successful
Build / build (push) Successful in 2m17s
Extract business logic from gRPC handlers into a dedicated service package. Add context support throughout for cancellation and timeouts. Move models to their own package, remove hardcoded credentials from config, and simplify parsers to only handle HTML parsing.
This commit is contained in:
75
service/schedule.go
Normal file
75
service/schedule.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"schedule_converter/client"
|
||||
"schedule_converter/config"
|
||||
"schedule_converter/models"
|
||||
"schedule_converter/parser"
|
||||
apperr "schedule_converter/pkg/errors"
|
||||
|
||||
pb "schedule_converter/proto/runner"
|
||||
)
|
||||
|
||||
// GetSchedule 获取课表:登录 → POST 查询 → 解析 → 转换为 pb 结果。
|
||||
func (s *Service) GetSchedule(ctx context.Context, req *pb.GetSchedulePayload) (*pb.ScheduleResultData, error) {
|
||||
httpClient, err := s.newAuthenticatedClient(ctx, req.Username, req.Password, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
semester := req.Semester
|
||||
if semester == "" {
|
||||
semester = config.Get().Semester
|
||||
}
|
||||
|
||||
data := fmt.Sprintf("xnxq=%s", semester)
|
||||
html, err := client.FetchHTML(ctx, httpClient, "POST", "/kbcx/queryGrkb", strings.NewReader(data), "application/x-www-form-urlencoded", "")
|
||||
if err != nil {
|
||||
return nil, apperr.New("fetch_schedule", err, "获取课表失败")
|
||||
}
|
||||
|
||||
courses, err := parser.ParseScheduleHTML(html)
|
||||
if err != nil {
|
||||
return nil, apperr.New("parse_schedule", err, "解析课表失败")
|
||||
}
|
||||
|
||||
return &pb.ScheduleResultData{
|
||||
StudentId: req.Username,
|
||||
Semester: semester,
|
||||
Courses: convertCourses(courses),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// convertCourses 将内部课程模型转换为 pb.Course 列表。
|
||||
func convertCourses(courses []models.Course) []*pb.Course {
|
||||
result := make([]*pb.Course, len(courses))
|
||||
for i, c := range courses {
|
||||
schedule := make([]*pb.ScheduleTime, len(c.Schedule))
|
||||
for j, sc := range c.Schedule {
|
||||
schedule[j] = &pb.ScheduleTime{
|
||||
Day: sc.Day,
|
||||
Sections: toInt32Slice(sc.Section),
|
||||
Weeks: toInt32Slice(sc.Weeks),
|
||||
}
|
||||
}
|
||||
result[i] = &pb.Course{
|
||||
Name: c.Name,
|
||||
Teacher: c.Teacher,
|
||||
Room: c.Room,
|
||||
Schedule: schedule,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toInt32Slice(arr []int) []int32 {
|
||||
result := make([]int32, len(arr))
|
||||
for i, v := range arr {
|
||||
result[i] = int32(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user