From d8c1de3f3d11095460565584f770954893ed3bdb Mon Sep 17 00:00:00 2001 From: axiangcoding Date: Thu, 23 Feb 2023 18:25:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=92=8C=E5=88=B7=E6=96=B0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api-system/api/docs.go | 50 ++++++++++ api-system/api/swagger.json | 50 ++++++++++ api-system/api/swagger.yaml | 32 ++++++ .../controller/http/v1/game_user_cotroller.go | 98 +++++++++++++++++++ .../controller/http/v1/mission_controller.go | 32 ++++++ .../internal/controller/http/v1/router.go | 5 + api-system/pkg/crawler/crawler.go | 6 +- 7 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 api-system/internal/controller/http/v1/mission_controller.go diff --git a/api-system/api/docs.go b/api-system/api/docs.go index 6bad4af..ebab3a7 100644 --- a/api-system/api/docs.go +++ b/api-system/api/docs.go @@ -100,6 +100,31 @@ var doc = `{ } } }, + "/v1/mission": { + "get": { + "tags": [ + "Mission API" + ], + "summary": "获取执行任务状态", + "parameters": [ + { + "type": "string", + "description": "mission id", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.ApiJson" + } + } + } + } + }, "/v1/system/info": { "get": { "tags": [ @@ -140,6 +165,31 @@ var doc = `{ } } } + }, + "/v1/wt/profile/update": { + "post": { + "tags": [ + "GameUser API" + ], + "summary": "更新游戏内玩家数据", + "parameters": [ + { + "type": "string", + "description": "user nickname", + "name": "nick", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.ApiJson" + } + } + } + } } }, "definitions": { diff --git a/api-system/api/swagger.json b/api-system/api/swagger.json index b0c3d63..eac580d 100644 --- a/api-system/api/swagger.json +++ b/api-system/api/swagger.json @@ -84,6 +84,31 @@ } } }, + "/v1/mission": { + "get": { + "tags": [ + "Mission API" + ], + "summary": "获取执行任务状态", + "parameters": [ + { + "type": "string", + "description": "mission id", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.ApiJson" + } + } + } + } + }, "/v1/system/info": { "get": { "tags": [ @@ -124,6 +149,31 @@ } } } + }, + "/v1/wt/profile/update": { + "post": { + "tags": [ + "GameUser API" + ], + "summary": "更新游戏内玩家数据", + "parameters": [ + { + "type": "string", + "description": "user nickname", + "name": "nick", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.ApiJson" + } + } + } + } } }, "definitions": { diff --git a/api-system/api/swagger.yaml b/api-system/api/swagger.yaml index bc58693..a6407fb 100644 --- a/api-system/api/swagger.yaml +++ b/api-system/api/swagger.yaml @@ -58,6 +58,22 @@ paths: summary: 获取cqhttp的最新状态 tags: - CQHttp API + /v1/mission: + get: + parameters: + - description: mission id + in: query + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/app.ApiJson' + summary: 获取执行任务状态 + tags: + - Mission API /v1/system/info: get: responses: @@ -84,6 +100,22 @@ paths: summary: 获取游戏内玩家数据 tags: - GameUser API + /v1/wt/profile/update: + post: + parameters: + - description: user nickname + in: query + name: nick + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/app.ApiJson' + summary: 更新游戏内玩家数据 + tags: + - GameUser API produces: - application/json securityDefinitions: diff --git a/api-system/internal/controller/http/v1/game_user_cotroller.go b/api-system/internal/controller/http/v1/game_user_cotroller.go index 51da51a..57730ea 100644 --- a/api-system/internal/controller/http/v1/game_user_cotroller.go +++ b/api-system/internal/controller/http/v1/game_user_cotroller.go @@ -3,10 +3,15 @@ package v1 import ( "errors" "github.com/axiangcoding/antonstar-bot/internal/data/display" + "github.com/axiangcoding/antonstar-bot/internal/data/table" "github.com/axiangcoding/antonstar-bot/internal/entity/app" "github.com/axiangcoding/antonstar-bot/internal/entity/e" "github.com/axiangcoding/antonstar-bot/internal/service" + "github.com/axiangcoding/antonstar-bot/pkg/crawler" + "github.com/axiangcoding/antonstar-bot/pkg/logging" "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/panjf2000/ants/v2" "gorm.io/gorm" ) @@ -40,3 +45,96 @@ func GameUserProfile(c *gin.Context) { Profile: &displayGameUser, }) } + +// UpdateGameUserProfile +// @Summary 更新游戏内玩家数据 +// @Tags GameUser API +// @Param nick query string true "user nickname" +// @Success 200 {object} app.ApiJson "" +// @Router /v1/wt/profile/update [post] +func UpdateGameUserProfile(c *gin.Context) { + nickname := c.Query("nick") + + if !service.IsValidNickname(nickname) { + app.Success(c, map[string]any{ + "refresh": false, + "reason": "not a valid nickname", + }) + return + } + if !service.CanBeRefresh(nickname) { + app.Success(c, map[string]any{ + "refresh": false, + "reason": "refresh too often", + }) + return + } + + missionId := uuid.NewString() + form := service.ScheduleForm{ + Nick: nickname, + } + if err := service.SubmitMissionWithDetail(missionId, table.MissionTypeUserInfo, form); err != nil { + app.BizFailed(c, e.Error, err) + return + } + if err := ants.Submit(func() { + if err := crawler.GetProfileFromWTOfficial(nickname, + func(status int, user *table.GameUser) { + switch status { + case crawler.StatusQueryFailed: + service.MustFinishMissionWithResult(missionId, table.MissionStatusFailed, service.CrawlerResult{ + Found: false, + Nick: nickname, + }) + case crawler.StatusNotFound: + service.MustPutRefreshFlag(nickname) + service.MustFinishMissionWithResult(missionId, table.MissionStatusSuccess, service.CrawlerResult{ + Found: false, + Nick: nickname, + }) + case crawler.StatusFound: + // live, psn等用户的昵称在html中会被cf认为是邮箱而隐藏,这里需要覆盖爬取来的数据 + user.Nick = nickname + _, err := service.FindGameProfile(nickname) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + service.MustSaveGameProfile(user) + } else { + logging.L().Warn("find game profile failed", logging.Error(err)) + } + } else { + service.MustUpdateGameProfile(nickname, user) + } + + if err := crawler.GetProfileFromThunderskill(nickname, func(status int, skill *crawler.ThunderSkillResp) { + skillData := skill.Stats + data, err := service.FindGameProfile(nickname) + data.TsSBRate = skillData.S.Kpd + data.TsRBRate = skillData.R.Kpd + data.TsABRate = skillData.A.Kpd + if err == nil { + service.MustUpdateGameProfile(nickname, data) + } + }); err != nil { + logging.L().Warn("failed on update thunder skill profile. ", logging.Error(err)) + } + service.MustPutRefreshFlag(nickname) + service.MustFinishMissionWithResult(missionId, table.MissionStatusSuccess, service.CrawlerResult{ + Found: true, + Nick: nickname, + Data: *user}, + ) + } + }); err != nil { + logging.L().Warn("start crawler failed. ", logging.Error(err)) + } + }); err != nil { + app.BizFailed(c, e.Error, err) + return + } + app.Success(c, map[string]any{ + "refresh": true, + "missionId": missionId, + }) +} diff --git a/api-system/internal/controller/http/v1/mission_controller.go b/api-system/internal/controller/http/v1/mission_controller.go new file mode 100644 index 0000000..f40314b --- /dev/null +++ b/api-system/internal/controller/http/v1/mission_controller.go @@ -0,0 +1,32 @@ +package v1 + +import ( + "github.com/axiangcoding/antonstar-bot/internal/entity/app" + "github.com/axiangcoding/antonstar-bot/internal/entity/e" + "github.com/axiangcoding/antonstar-bot/internal/service" + "github.com/gin-gonic/gin" +) + +// GetMission +// @Summary 获取执行任务状态 +// @Tags Mission API +// @Param id query string true "mission id" +// @Success 200 {object} app.ApiJson "" +// @Router /v1/mission [get] +func GetMission(c *gin.Context) { + id := c.Query("id") + mission, err := service.FindMission(id) + if err != nil { + app.BizFailed(c, e.Error, err) + return + } + app.Success(c, map[string]any{ + "mission_id": mission.MissionId, + "created_at": mission.CreatedAt, + "updated_at": mission.UpdatedAt, + "status": mission.Status, + "process": mission.Process, + "finished_time": mission.FinishedTime, + }) + +} diff --git a/api-system/internal/controller/http/v1/router.go b/api-system/internal/controller/http/v1/router.go index 92880d1..870b128 100644 --- a/api-system/internal/controller/http/v1/router.go +++ b/api-system/internal/controller/http/v1/router.go @@ -81,6 +81,11 @@ func setRouterApiV1(r *gin.RouterGroup) { wt := groupV1.Group("/wt") { wt.GET("/profile", GameUserProfile) + wt.POST("/profile/update", UpdateGameUserProfile) + } + mission := groupV1.Group("/mission") + { + mission.GET("/", GetMission) } } } diff --git a/api-system/pkg/crawler/crawler.go b/api-system/pkg/crawler/crawler.go index 643cd3e..3b495eb 100644 --- a/api-system/pkg/crawler/crawler.go +++ b/api-system/pkg/crawler/crawler.go @@ -3,7 +3,7 @@ package crawler import ( "encoding/json" "fmt" - table2 "github.com/axiangcoding/antonstar-bot/internal/data/table" + "github.com/axiangcoding/antonstar-bot/internal/data/table" "github.com/axiangcoding/antonstar-bot/pkg/logging" "github.com/gocolly/colly/v2" "github.com/gocolly/colly/v2/extensions" @@ -16,7 +16,7 @@ const ( StatusFound = 3 ) -func GetProfileFromWTOfficial(nick string, callback func(status int, user *table2.GameUser)) error { +func GetProfileFromWTOfficial(nick string, callback func(status int, user *table.GameUser)) error { urlTemplate := "https://warthunder.com/zh/community/userinfo/?nick=%s" queryUrl := fmt.Sprintf(urlTemplate, url.QueryEscape(nick)) @@ -92,7 +92,7 @@ func GetProfileFromThunderskill(nick string, callback func(status int, skill *Th return nil } -func GetFirstPageNewsFromWTOfficial(callback func(news []table2.GameNew)) error { +func GetFirstPageNewsFromWTOfficial(callback func(news []table.GameNew)) error { baseUrl := "https://warthunder.com/zh/news/" c := colly.NewCollector( colly.AllowedDomains("warthunder.com"),