diff --git a/app/ai-event-handler/nsq.go b/app/ai-event-handler/nsq.go index f8e9e03c..3f891490 100644 --- a/app/ai-event-handler/nsq.go +++ b/app/ai-event-handler/nsq.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + "fmt" "log" "strings" "time" @@ -27,8 +28,8 @@ func init() { } type NSQConfig struct { - Addr string `json:"addr"` - TopicPrefix string `json:"topic_prefix"` + Addr string `json:"addr" yaml:"addr"` + TopicPrefix string `json:"topic_prefix" yaml:"topic_prefix"` } // 定义 NSQ 消息结构 @@ -78,6 +79,11 @@ func convertInt(value interface{}) int { } } +func genAIKey(key string, provider string) string { + keys := strings.Split(key, "@") + return strings.TrimSuffix(keys[0], fmt.Sprintf("-%s", provider)) +} + // HandleMessage 处理从 NSQ 读取的消息 func (h *NSQHandler) HandleMessage(message *nsq.Message) error { log.Printf("Received message: %s", string(message.Body)) @@ -87,14 +93,14 @@ func (h *NSQHandler) HandleMessage(message *nsq.Message) error { err := json.Unmarshal(message.Body, &data) if err != nil { log.Printf("Failed to unmarshal message: %v", err) - return err + return nil } // 将时间字符串转换为 time.Time timestamp, err := time.Parse(time.RFC3339, data.TimeISO8601) if err != nil { log.Printf("Failed to parse timestamp: %v", err) - return err + return nil } day := time.Date(timestamp.Year(), timestamp.Month(), timestamp.Day(), 0, 0, 0, 0, timestamp.Location()) @@ -104,14 +110,13 @@ func (h *NSQHandler) HandleMessage(message *nsq.Message) error { finalStatus := &AIProviderStatus{} for _, s := range data.AI.ProviderStats { status := ToKeyStatus(s.Status).Int() - keys := strings.Split(s.Key, "@") - key := keys[0] + key := genAIKey(s.Key, s.Provider) err = h.aiKeyService.Save(ctx, key, &ai_key.Edit{ Status: &status, }) if err != nil { log.Printf("Failed to save AI key: %v", err) - return err + return nil } if s.Provider != data.AI.Provider { @@ -128,11 +133,12 @@ func (h *NSQHandler) HandleMessage(message *nsq.Message) error { finalStatus = &s } if finalStatus != nil { - keys := strings.Split(finalStatus.Key, "@") - err = h.aiKeyService.IncrUseToken(ctx, keys[0], convertInt(data.AI.TotalToken)) + //keys := strings.Split(finalStatus.Key, "@") + key := genAIKey(finalStatus.Key, finalStatus.Provider) + err = h.aiKeyService.IncrUseToken(ctx, key, convertInt(data.AI.TotalToken)) if err != nil { log.Printf("Failed to increment AI key token: %v", err) - return err + return nil } } @@ -151,7 +157,7 @@ func (h *NSQHandler) HandleMessage(message *nsq.Message) error { }) if err != nil { log.Printf("Failed to call AI API: %v", err) - return err + return nil } log.Printf("Message processed and saved to MySQL: %+v", data) diff --git a/gateway/apinto/plugin/apinto_plugin.yml b/gateway/apinto/plugin/apinto_plugin.yml index 4bd3765a..b3c3c6d8 100644 --- a/gateway/apinto/plugin/apinto_plugin.yml +++ b/gateway/apinto/plugin/apinto_plugin.yml @@ -28,7 +28,7 @@ b: "subscription_service:#{application}" response: status_code: 403 - content_typ: "text/plan" + content_type: "text/plan" charset: "utf-8" body: "Forbidden" diff --git a/init.go b/init.go index 74592a3a..af7b6ca9 100644 --- a/init.go +++ b/init.go @@ -5,6 +5,7 @@ import ( _ "github.com/APIParkLab/APIPark/frontend" _ "github.com/APIParkLab/APIPark/gateway/apinto" _ "github.com/APIParkLab/APIPark/plugins/core" + _ "github.com/APIParkLab/APIPark/plugins/openapi" _ "github.com/APIParkLab/APIPark/plugins/permit" _ "github.com/APIParkLab/APIPark/plugins/publish_flow" _ "github.com/APIParkLab/APIPark/resources/locale" diff --git a/plugins/openapi/authorization.go b/plugins/openapi/authorization.go new file mode 100644 index 00000000..d6f37e8a --- /dev/null +++ b/plugins/openapi/authorization.go @@ -0,0 +1,18 @@ +package openapi + +import ( + "net/http" + + "github.com/eolinker/go-common/pm3" +) + +func (p *plugin) appAuthorizationApis() []pm3.Api { + return []pm3.Api{ + pm3.CreateApiWidthDoc(http.MethodPost, "/openapi/v1/app/authorization", []string{"context", "query:app", "body"}, []string{"authorization"}, p.authorizationController.AddAuthorization), + pm3.CreateApiWidthDoc(http.MethodPut, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization", "body"}, []string{"authorization"}, p.authorizationController.EditAuthorization), + pm3.CreateApiWidthDoc(http.MethodDelete, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization"}, nil, p.authorizationController.DeleteAuthorization), + pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorization", []string{"context", "query:app", "query:authorization"}, []string{"authorization"}, p.authorizationController.Info), + pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorizations", []string{"context", "query:app"}, []string{"authorizations"}, p.authorizationController.Authorizations), + pm3.CreateApiWidthDoc(http.MethodGet, "/openapi/v1/app/authorization/details", []string{"context", "query:app", "query:authorization"}, []string{"details"}, p.authorizationController.Detail), + } +} diff --git a/plugins/openapi/check.go b/plugins/openapi/check.go new file mode 100644 index 00000000..4f5f50f7 --- /dev/null +++ b/plugins/openapi/check.go @@ -0,0 +1,45 @@ +package openapi + +import ( + "strings" + + "github.com/eolinker/eosc/env" + + "github.com/gin-gonic/gin" +) + +var ( + defaultAPIKey = "37eb0ebf" + openCheck = newOpenapiCheck() +) + +type openapiCheck struct { + apikey string +} + +func newOpenapiCheck() *openapiCheck { + apikey, has := env.GetEnv("API_KEY") + if !has { + apikey = defaultAPIKey + } + return &openapiCheck{apikey: apikey} +} + +func (o *openapiCheck) Check(method string, path string) (bool, []gin.HandlerFunc) { + if strings.HasPrefix(path, "/openapi/") { + return true, []gin.HandlerFunc{o.Handler} + } + return false, nil +} + +func (o *openapiCheck) Sort() int { + return -1 +} + +func (o *openapiCheck) Handler(ginCtx *gin.Context) { + authorization := ginCtx.GetHeader("Authorization") + if authorization == "" { + ginCtx.AbortWithStatusJSON(403, gin.H{"code": -8, "msg": "invalid token", "success": "fail"}) + return + } +} diff --git a/plugins/openapi/driver.go b/plugins/openapi/driver.go new file mode 100644 index 00000000..9e9997a6 --- /dev/null +++ b/plugins/openapi/driver.go @@ -0,0 +1,19 @@ +package openapi + +import ( + "github.com/eolinker/go-common/autowire" + "github.com/eolinker/go-common/pm3" +) + +func init() { + pm3.Register("openapi", new(Driver)) +} + +type Driver struct { +} + +func (d *Driver) Create() (pm3.IPlugin, error) { + p := new(plugin) + autowire.Autowired(p) + return p, nil +} diff --git a/plugins/openapi/plugin.go b/plugins/openapi/plugin.go new file mode 100644 index 00000000..3082fb84 --- /dev/null +++ b/plugins/openapi/plugin.go @@ -0,0 +1,33 @@ +package openapi + +import ( + application_authorization "github.com/APIParkLab/APIPark/controller/application-authorization" + "github.com/eolinker/go-common/pm3" +) + +var ( + _ pm3.IPlugin = (*plugin)(nil) + _ pm3.IPluginMiddleware = (*plugin)(nil) +) + +type plugin struct { + apis []pm3.Api + authorizationController application_authorization.IAuthorizationController `autowired:""` +} + +func (p *plugin) Middlewares() []pm3.IMiddleware { + return []pm3.IMiddleware{ + openCheck, + } +} + +func (p *plugin) APis() []pm3.Api { + return p.apis +} + +func (p *plugin) Name() string { + return "openapi" +} +func (p *plugin) OnComplete() { + p.apis = p.appAuthorizationApis() +} diff --git a/resources/plugin/plugin.yml b/resources/plugin/plugin.yml index f731a53f..73aa40bb 100644 --- a/resources/plugin/plugin.yml +++ b/resources/plugin/plugin.yml @@ -1,4 +1,4 @@ -version: v7 +version: v8 sort: - "access_log" - "monitor" @@ -41,7 +41,7 @@ plugin: b: "subscription_service:#{application}" response: status_code: 403 - content_typ: "text/plan" + content_type: "text/plan" charset: "utf-8" body: "Forbidden" diff --git a/scripts/Dockerfile b/scripts/Dockerfile index 71b5c4e3..6e712a47 100755 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -8,8 +8,8 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ARG APP -ENV NSQ_ADDR=nsq:4150 -ENV NSQ_TOPIC_PREFIX=apipark +ENV NSQ_ADDR=${APP}-nsq:4150 +ENV NSQ_TOPIC_PREFIX=${APP} RUN mkdir -p /${APP} diff --git a/scripts/docker_build.sh b/scripts/docker_build.sh index 2a43ba84..5c51a097 100755 --- a/scripts/docker_build.sh +++ b/scripts/docker_build.sh @@ -17,7 +17,7 @@ source ./scripts/common.sh APP="apipark" -mkdir -p scripts/cmd/ && cp cmd/${APP} scripts/cmd/ +mkdir -p scripts/cmd/ && cp cmd/${APP} scripts/cmd/ && cp cmd/apipark_ai_event_listen scripts/cmd/ VERSION=$(gen_version) diff --git a/scripts/resource/docker_run.sh b/scripts/resource/docker_run.sh index f8c56e54..255f7243 100755 --- a/scripts/resource/docker_run.sh +++ b/scripts/resource/docker_run.sh @@ -27,7 +27,7 @@ echo -e " - $s" >> config.yml done echo -e "nsq:" >> config.yml echo -e " addr: ${NSQ_ADDR}" >> config.yml -echo -e " topic: ${NSQ_TOPIC}" >> config.yml +echo -e " topic_prefix: ${NSQ_TOPIC_PREFIX}" >> config.yml echo -e "port: 8288" >> config.yml echo -e "error_log:" >> config.yml echo -e " dir: ${ERROR_DIR}" >> config.yml diff --git a/stores/ai/model.go b/stores/ai/model.go index 1f1ee178..b25f4c29 100644 --- a/stores/ai/model.go +++ b/stores/ai/model.go @@ -8,7 +8,7 @@ type Provider struct { Name string `gorm:"type:varchar(100);not null;column:name;comment:name"` DefaultLLM string `gorm:"type:varchar(255);not null;column:default_llm;comment:默认模型ID"` Config string `gorm:"type:text;not null;column:config;comment:配置信息"` - Status int `gorm:"type:tinyint(1);not null;column:status;comment:状态,0:停用;1:启用,2:异常"` + Status int `gorm:"type:tinyint(1);not null;column:status;comment:状态,0:停用;1:启用,2:异常;default:1"` Priority int `gorm:"type:int;not null;column:priority;comment:优先级,值越小优先级越高"` Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"` // 创建人 Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"` // 更新人