From 92c3b86afbb847f94ecc379b37cf62a86ba79a5f Mon Sep 17 00:00:00 2001 From: jiuxia211 <2064166368@qq.com> Date: Sun, 9 Feb 2025 04:04:18 +0800 Subject: [PATCH] feat: cache in academic scores --- api/model/api/api.go | 2 + api/model/model/model.go | 1 + api/router/api/api.go | 1 + cmd/academic/main.go | 11 ++++-- internal/academic/handler.go | 34 +++++++++-------- internal/academic/service/get_credit_test.go | 2 +- internal/academic/service/get_gpa_test.go | 2 +- internal/academic/service/get_scores.go | 23 +++++++---- internal/academic/service/get_scores_test.go | 2 +- internal/academic/service/get_unified_test.go | 2 +- internal/academic/service/service.go | 11 ++++-- kitex_gen/model/model.go | 3 +- kitex_gen/paper/paper.go | 4 +- kitex_gen/paper/paperservice/client.go | 2 + kitex_gen/paper/paperservice/paperservice.go | 2 + kitex_gen/paper/paperservice/server.go | 1 + pkg/cache/academic/academic.go | 29 ++++++++++++++ pkg/cache/academic/get_scores.go | 38 +++++++++++++++++++ pkg/cache/academic/set_scores.go | 38 +++++++++++++++++++ pkg/cache/cache.go | 3 ++ pkg/constants/redis.go | 2 + 21 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 pkg/cache/academic/academic.go create mode 100644 pkg/cache/academic/get_scores.go create mode 100644 pkg/cache/academic/set_scores.go diff --git a/api/model/api/api.go b/api/model/api/api.go index b2d4ee83..3a9e68bb 100644 --- a/api/model/api/api.go +++ b/api/model/api/api.go @@ -21,7 +21,9 @@ package api import ( "context" "fmt" + "github.com/apache/thrift/lib/go/thrift" + "github.com/west2-online/fzuhelper-server/api/model/model" ) diff --git a/api/model/model/model.go b/api/model/model/model.go index 66c45a01..0afec452 100644 --- a/api/model/model/model.go +++ b/api/model/model/model.go @@ -20,6 +20,7 @@ package model import ( "fmt" + "github.com/apache/thrift/lib/go/thrift" ) diff --git a/api/router/api/api.go b/api/router/api/api.go index 2834c9f1..f55defe1 100644 --- a/api/router/api/api.go +++ b/api/router/api/api.go @@ -20,6 +20,7 @@ package api import ( "github.com/cloudwego/hertz/pkg/app/server" + api "github.com/west2-online/fzuhelper-server/api/handler/api" ) diff --git a/cmd/academic/main.go b/cmd/academic/main.go index 966e7b8a..18187968 100644 --- a/cmd/academic/main.go +++ b/cmd/academic/main.go @@ -27,18 +27,23 @@ import ( "github.com/west2-online/fzuhelper-server/config" "github.com/west2-online/fzuhelper-server/internal/academic" "github.com/west2-online/fzuhelper-server/kitex_gen/academic/academicservice" + "github.com/west2-online/fzuhelper-server/pkg/base" "github.com/west2-online/fzuhelper-server/pkg/constants" "github.com/west2-online/fzuhelper-server/pkg/logger" "github.com/west2-online/fzuhelper-server/pkg/utils" ) -var serviceName = constants.AcademicServiceName +var ( + serviceName = constants.AcademicServiceName + clientSet *base.ClientSet +) func init() { config.Init(serviceName) logger.Init(serviceName, config.GetLoggerLevel()) // eshook.InitLoggerWithHook(serviceName) - // dal.Init() // TODO 增加成绩信息持久化开始推送 + clientSet = base.NewClientSet(base.WithRedisClient(constants.RedisDBAcademic)) + // TODO 增加成绩信息持久化开始推送 } func main() { @@ -56,7 +61,7 @@ func main() { } svr := academicservice.NewServer( - new(academic.AcademicServiceImpl), + academic.NewAcademicService(clientSet), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ ServiceName: serviceName, }), diff --git a/internal/academic/handler.go b/internal/academic/handler.go index 3a1c1aa7..91c0f303 100644 --- a/internal/academic/handler.go +++ b/internal/academic/handler.go @@ -28,15 +28,22 @@ import ( ) // AcademicServiceImpl implements the last service interface defined in the IDL. -type AcademicServiceImpl struct{} +type AcademicServiceImpl struct { + ClientSet *base.ClientSet +} + +func NewAcademicService(clientSet *base.ClientSet) *AcademicServiceImpl { + return &AcademicServiceImpl{ + ClientSet: clientSet, + } +} // GetScores implements the AcademicServiceImpl interface. -func (s *AcademicServiceImpl) GetScores(ctx context.Context, req *academic.GetScoresRequest) (resp *academic.GetScoresResponse, err error) { +func (s *AcademicServiceImpl) GetScores(ctx context.Context, _ *academic.GetScoresRequest) (resp *academic.GetScoresResponse, err error) { resp = academic.NewGetScoresResponse() var scores []*jwch.Mark - l := service.NewAcademicService(ctx) - scores, err = l.GetScores() + scores, err = service.NewAcademicService(ctx, s.ClientSet).GetScores() if err != nil { logger.Infof("Academic.GetScores: GetScores failed, err: %v", err) resp.Base = base.BuildBaseResp(err) @@ -49,12 +56,11 @@ func (s *AcademicServiceImpl) GetScores(ctx context.Context, req *academic.GetSc } // GetGPA implements the AcademicServiceImpl interface. -func (s *AcademicServiceImpl) GetGPA(ctx context.Context, req *academic.GetGPARequest) (resp *academic.GetGPAResponse, err error) { +func (s *AcademicServiceImpl) GetGPA(ctx context.Context, _ *academic.GetGPARequest) (resp *academic.GetGPAResponse, err error) { resp = academic.NewGetGPAResponse() var gpa *jwch.GPABean - l := service.NewAcademicService(ctx) - gpa, err = l.GetGPA() + gpa, err = service.NewAcademicService(ctx, s.ClientSet).GetGPA() if err != nil { logger.Infof("Academic.GetGPA: GetGPA failed, err: %v", err) resp.Base = base.BuildBaseResp(err) @@ -66,12 +72,11 @@ func (s *AcademicServiceImpl) GetGPA(ctx context.Context, req *academic.GetGPARe } // GetCredit implements the AcademicServiceImpl interface. -func (s *AcademicServiceImpl) GetCredit(ctx context.Context, req *academic.GetCreditRequest) (resp *academic.GetCreditResponse, err error) { +func (s *AcademicServiceImpl) GetCredit(ctx context.Context, _ *academic.GetCreditRequest) (resp *academic.GetCreditResponse, err error) { resp = academic.NewGetCreditResponse() var credit []*jwch.CreditStatistics - l := service.NewAcademicService(ctx) - credit, err = l.GetCredit() + credit, err = service.NewAcademicService(ctx, s.ClientSet).GetCredit() if err != nil { logger.Infof("Academic.GetCredit: GetCredit failed, err: %v", err) resp.Base = base.BuildBaseResp(err) @@ -84,12 +89,11 @@ func (s *AcademicServiceImpl) GetCredit(ctx context.Context, req *academic.GetCr } // GetUnifiedExam implements the AcademicServiceImpl interface. -func (s *AcademicServiceImpl) GetUnifiedExam(ctx context.Context, req *academic.GetUnifiedExamRequest) (resp *academic.GetUnifiedExamResponse, err error) { +func (s *AcademicServiceImpl) GetUnifiedExam(ctx context.Context, _ *academic.GetUnifiedExamRequest) (resp *academic.GetUnifiedExamResponse, err error) { resp = academic.NewGetUnifiedExamResponse() var unifiedExam []*jwch.UnifiedExam - l := service.NewAcademicService(ctx) - unifiedExam, err = l.GetUnifiedExam() + unifiedExam, err = service.NewAcademicService(ctx, s.ClientSet).GetUnifiedExam() if err != nil { logger.Infof("Academic.GetUnifiedExam: GetUnifiedExam failed, err: %v", err) resp.Base = base.BuildBaseResp(err) @@ -102,9 +106,9 @@ func (s *AcademicServiceImpl) GetUnifiedExam(ctx context.Context, req *academic. } // GetPlan implements the AcademicServiceImpl interface. -func (s *AcademicServiceImpl) GetPlan(ctx context.Context, req *academic.GetPlanRequest) (resp *academic.GetPlanResponse, err error) { +func (s *AcademicServiceImpl) GetPlan(ctx context.Context, _ *academic.GetPlanRequest) (resp *academic.GetPlanResponse, err error) { resp = new(academic.GetPlanResponse) - plan, err := service.NewAcademicService(ctx).GetPlan() + plan, err := service.NewAcademicService(ctx, s.ClientSet).GetPlan() if err != nil { resp.Base = base.BuildBaseResp(err) return resp, nil diff --git a/internal/academic/service/get_credit_test.go b/internal/academic/service/get_credit_test.go index 744798bf..c8947195 100644 --- a/internal/academic/service/get_credit_test.go +++ b/internal/academic/service/get_credit_test.go @@ -72,7 +72,7 @@ func TestAcademicService_GetCredit(t *testing.T) { Cookies: "", }, nil }).Build() - academicService := NewAcademicService(context.Background()) + academicService := AcademicService{} result, err := academicService.GetCredit() if tc.expectingError { assert.Nil(t, result) diff --git a/internal/academic/service/get_gpa_test.go b/internal/academic/service/get_gpa_test.go index 297beb9e..b42c8477 100644 --- a/internal/academic/service/get_gpa_test.go +++ b/internal/academic/service/get_gpa_test.go @@ -78,7 +78,7 @@ func TestAcademicService_GetGPA(t *testing.T) { Cookies: "", }, nil }).Build() - academicService := NewAcademicService(context.Background()) + academicService := AcademicService{} result, err := academicService.GetGPA() if tc.expectingError { assert.Nil(t, result) diff --git a/internal/academic/service/get_scores.go b/internal/academic/service/get_scores.go index d5801cea..e925fac5 100644 --- a/internal/academic/service/get_scores.go +++ b/internal/academic/service/get_scores.go @@ -18,7 +18,6 @@ package service import ( "fmt" - "github.com/west2-online/fzuhelper-server/pkg/base" "github.com/west2-online/fzuhelper-server/pkg/base/context" "github.com/west2-online/fzuhelper-server/pkg/utils" @@ -30,11 +29,21 @@ func (s *AcademicService) GetScores() ([]*jwch.Mark, error) { if err != nil { return nil, fmt.Errorf("service.GetScores: Get login data fail %w", err) } - stu := jwch.NewStudent().WithLoginData(loginData.Id, utils.ParseCookies(loginData.Cookies)) - scores, err := stu.GetMarks() - if err = base.HandleJwchError(err); err != nil { - return nil, fmt.Errorf("service.GetScores: Get scores info fail %w", err) - } - return scores, nil + key := fmt.Sprintf("scores:%s", loginData.Id) + if ok := s.cache.IsKeyExist(s.ctx, key); ok { + scores, err := s.cache.Academic.GetScoresCache(s.ctx, key) + if err = base.HandleJwchError(err); err != nil { + return nil, fmt.Errorf("service.GetScores: Get scores info from redis error %w", err) + } + return scores, nil + } else { + stu := jwch.NewStudent().WithLoginData(loginData.Id, utils.ParseCookies(loginData.Cookies)) + scores, err := stu.GetMarks() + if err = base.HandleJwchError(err); err != nil { + return nil, fmt.Errorf("service.GetScores: Get scores info fail %w", err) + } + go s.cache.Academic.SetScoresCache(s.ctx, key, scores) + return scores, nil + } } diff --git a/internal/academic/service/get_scores_test.go b/internal/academic/service/get_scores_test.go index 5305c99d..3fd5d681 100644 --- a/internal/academic/service/get_scores_test.go +++ b/internal/academic/service/get_scores_test.go @@ -80,7 +80,7 @@ func TestAcademicService_GetScores(t *testing.T) { Cookies: "", }, nil }).Build() - academicService := NewAcademicService(context.Background()) + academicService := AcademicService{} result, err := academicService.GetScores() if tc.expectingError { assert.Nil(t, result) diff --git a/internal/academic/service/get_unified_test.go b/internal/academic/service/get_unified_test.go index df61e13c..e169f5e7 100644 --- a/internal/academic/service/get_unified_test.go +++ b/internal/academic/service/get_unified_test.go @@ -96,7 +96,7 @@ func TestAcademicService_GetUnifiedExam(t *testing.T) { Cookies: "", }, nil }).Build() - academicService := NewAcademicService(context.Background()) + academicService := AcademicService{} result, err := academicService.GetUnifiedExam() if tc.expectingError { assert.Nil(t, result) diff --git a/internal/academic/service/service.go b/internal/academic/service/service.go index 392cb363..9a66bdd8 100644 --- a/internal/academic/service/service.go +++ b/internal/academic/service/service.go @@ -18,14 +18,19 @@ package service import ( "context" + + "github.com/west2-online/fzuhelper-server/pkg/base" + "github.com/west2-online/fzuhelper-server/pkg/cache" ) type AcademicService struct { - ctx context.Context + ctx context.Context + cache *cache.Cache } -func NewAcademicService(ctx context.Context) *AcademicService { +func NewAcademicService(ctx context.Context, clientset *base.ClientSet) *AcademicService { return &AcademicService{ - ctx: ctx, + ctx: ctx, + cache: clientset.CacheClient, } } diff --git a/kitex_gen/model/model.go b/kitex_gen/model/model.go index c2a2049a..f89dd35a 100644 --- a/kitex_gen/model/model.go +++ b/kitex_gen/model/model.go @@ -20,8 +20,9 @@ package model import ( "fmt" - thrift "github.com/cloudwego/kitex/pkg/protocol/bthrift/apache" "strings" + + thrift "github.com/cloudwego/kitex/pkg/protocol/bthrift/apache" ) type BaseResp struct { diff --git a/kitex_gen/paper/paper.go b/kitex_gen/paper/paper.go index cdec178c..24459985 100644 --- a/kitex_gen/paper/paper.go +++ b/kitex_gen/paper/paper.go @@ -21,9 +21,11 @@ package paper import ( "context" "fmt" + "strings" + thrift "github.com/cloudwego/kitex/pkg/protocol/bthrift/apache" + "github.com/west2-online/fzuhelper-server/kitex_gen/model" - "strings" ) type ListDirFilesRequest struct { diff --git a/kitex_gen/paper/paperservice/client.go b/kitex_gen/paper/paperservice/client.go index 78511c8c..362cb824 100644 --- a/kitex_gen/paper/paperservice/client.go +++ b/kitex_gen/paper/paperservice/client.go @@ -20,8 +20,10 @@ package paperservice import ( "context" + client "github.com/cloudwego/kitex/client" callopt "github.com/cloudwego/kitex/client/callopt" + paper "github.com/west2-online/fzuhelper-server/kitex_gen/paper" ) diff --git a/kitex_gen/paper/paperservice/paperservice.go b/kitex_gen/paper/paperservice/paperservice.go index 4f4c16c5..95a8beb8 100644 --- a/kitex_gen/paper/paperservice/paperservice.go +++ b/kitex_gen/paper/paperservice/paperservice.go @@ -21,8 +21,10 @@ package paperservice import ( "context" "errors" + client "github.com/cloudwego/kitex/client" kitex "github.com/cloudwego/kitex/pkg/serviceinfo" + paper "github.com/west2-online/fzuhelper-server/kitex_gen/paper" ) diff --git a/kitex_gen/paper/paperservice/server.go b/kitex_gen/paper/paperservice/server.go index 5829a074..62b02f35 100644 --- a/kitex_gen/paper/paperservice/server.go +++ b/kitex_gen/paper/paperservice/server.go @@ -19,6 +19,7 @@ package paperservice import ( server "github.com/cloudwego/kitex/server" + paper "github.com/west2-online/fzuhelper-server/kitex_gen/paper" ) diff --git a/pkg/cache/academic/academic.go b/pkg/cache/academic/academic.go new file mode 100644 index 00000000..7c7818f9 --- /dev/null +++ b/pkg/cache/academic/academic.go @@ -0,0 +1,29 @@ +/* +Copyright 2024 The west2-online Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package academic + +import "github.com/redis/go-redis/v9" + +type CacheAcademic struct { + client *redis.Client +} + +func NewCacheAcademic(client *redis.Client) *CacheAcademic { + return &CacheAcademic{ + client: client, + } +} diff --git a/pkg/cache/academic/get_scores.go b/pkg/cache/academic/get_scores.go new file mode 100644 index 00000000..9986526f --- /dev/null +++ b/pkg/cache/academic/get_scores.go @@ -0,0 +1,38 @@ +/* +Copyright 2024 The west2-online Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package academic + +import ( + "context" + + "github.com/bytedance/sonic" + + "github.com/west2-online/fzuhelper-server/pkg/errno" + "github.com/west2-online/jwch" +) + +func (c *CacheAcademic) GetScoresCache(ctx context.Context, key string) (scores []*jwch.Mark, err error) { + data, err := c.client.Get(ctx, key).Bytes() + if err != nil { + return nil, errno.Errorf(errno.InternalJSONErrorCode, "dal.GetScoresCache: Get scores info failed: %v", err) + } + err = sonic.Unmarshal(data, &scores) + if err != nil { + return nil, errno.Errorf(errno.InternalJSONErrorCode, "dal.GetScoresCache: Unmarshal scores info failed: %v", err) + } + return scores, nil +} diff --git a/pkg/cache/academic/set_scores.go b/pkg/cache/academic/set_scores.go new file mode 100644 index 00000000..38dc9ca9 --- /dev/null +++ b/pkg/cache/academic/set_scores.go @@ -0,0 +1,38 @@ +/* +Copyright 2024 The west2-online Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package academic + +import ( + "context" + + "github.com/bytedance/sonic" + + "github.com/west2-online/fzuhelper-server/pkg/constants" + "github.com/west2-online/fzuhelper-server/pkg/logger" + "github.com/west2-online/jwch" +) + +func (c *CacheAcademic) SetScoresCache(ctx context.Context, key string, scores []*jwch.Mark) { + data, err := sonic.Marshal(scores) + if err != nil { + logger.Errorf("dal.SetScoresCache: Marshal scores info failed: %v", err) + } + err = c.client.Set(ctx, key, data, constants.AcademicScoresExpire).Err() + if err != nil { + logger.Errorf("dal.SetScoresCache: Set scores info failed: %v", err) + } +} diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index e7ef78e5..c87f7ffe 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -21,6 +21,7 @@ import ( "github.com/redis/go-redis/v9" + "github.com/west2-online/fzuhelper-server/pkg/cache/academic" "github.com/west2-online/fzuhelper-server/pkg/cache/classroom" "github.com/west2-online/fzuhelper-server/pkg/cache/launch_screen" "github.com/west2-online/fzuhelper-server/pkg/cache/paper" @@ -31,6 +32,7 @@ type Cache struct { Classroom *classroom.CacheClassroom Paper *paper.CachePaper LaunchScreen *launch_screen.CacheLaunchScreen + Academic *academic.CacheAcademic } func NewCache(client *redis.Client) *Cache { @@ -39,6 +41,7 @@ func NewCache(client *redis.Client) *Cache { Classroom: classroom.NewCacheClassroom(client), LaunchScreen: launch_screen.NewCacheLaunchScreen(client), Paper: paper.NewCachePaper(client), + Academic: academic.NewCacheAcademic(client), } } diff --git a/pkg/constants/redis.go b/pkg/constants/redis.go index 1f9b9dc2..9147498c 100644 --- a/pkg/constants/redis.go +++ b/pkg/constants/redis.go @@ -27,6 +27,7 @@ const ( ClassroomKeyExpire = 2 * 24 * time.Hour LaunchScreenKeyExpire = 2 * 24 * time.Hour LastLaunchScreenIdKey = "last_launch_screen_id" + AcademicScoresExpire = 5 * time.Minute ) // Redis DB Name @@ -34,4 +35,5 @@ const ( RedisDBEmptyRoom = 0 RedisDBLaunchScreen = 1 RedisDBPaper = 2 + RedisDBAcademic = 3 )