383 lines
12 KiB
Go
383 lines
12 KiB
Go
/*
|
|
* Copyright 2025 coze-dev 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 service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
|
|
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
|
|
searchModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/search"
|
|
pluginCommon "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop/common"
|
|
resCommon "github.com/coze-dev/coze-studio/backend/api/model/resource/common"
|
|
crosssearch "github.com/coze-dev/coze-studio/backend/crossdomain/contract/search"
|
|
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
|
|
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
|
|
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
|
|
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
|
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
|
|
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
|
|
"github.com/coze-dev/coze-studio/backend/pkg/logs"
|
|
"github.com/coze-dev/coze-studio/backend/types/errno"
|
|
)
|
|
|
|
func (p *pluginServiceImpl) GetOnlinePlugin(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error) {
|
|
pl, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", pluginID)
|
|
}
|
|
if !exist {
|
|
return nil, errorx.New(errno.ErrPluginRecordNotFound)
|
|
}
|
|
|
|
return pl, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MGetOnlinePlugins(ctx context.Context, pluginIDs []int64) (plugins []*entity.PluginInfo, err error) {
|
|
plugins, err = p.pluginRepo.MGetOnlinePlugins(ctx, pluginIDs)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", pluginIDs)
|
|
}
|
|
|
|
res := make([]*model.PluginInfo, 0, len(plugins))
|
|
for _, pl := range plugins {
|
|
res = append(res, pl.PluginInfo)
|
|
}
|
|
|
|
return plugins, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) GetOnlineTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, err error) {
|
|
tool, exist, err := p.toolRepo.GetOnlineTool(ctx, toolID)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "GetOnlineTool failed, toolID=%d", toolID)
|
|
}
|
|
if !exist {
|
|
return nil, errorx.New(errno.ErrPluginRecordNotFound)
|
|
}
|
|
|
|
return tool, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MGetOnlineTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error) {
|
|
tools, err = p.toolRepo.MGetOnlineTools(ctx, toolIDs)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MGetOnlineTools failed, toolIDs=%v", toolIDs)
|
|
}
|
|
|
|
return tools, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MGetVersionTools(ctx context.Context, versionTools []entity.VersionTool) (tools []*entity.ToolInfo, err error) {
|
|
tools, err = p.toolRepo.MGetVersionTools(ctx, versionTools)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MGetVersionTools failed, versionTools=%v", versionTools)
|
|
}
|
|
|
|
return tools, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) ListPluginProducts(ctx context.Context, req *ListPluginProductsRequest) (resp *ListPluginProductsResponse, err error) {
|
|
plugins := slices.Transform(pluginConf.GetAllPluginProducts(), func(p *pluginConf.PluginInfo) *entity.PluginInfo {
|
|
return entity.NewPluginInfo(p.Info)
|
|
})
|
|
sort.Slice(plugins, func(i, j int) bool {
|
|
return plugins[i].GetRefProductID() < plugins[j].GetRefProductID()
|
|
})
|
|
|
|
return &ListPluginProductsResponse{
|
|
Plugins: plugins,
|
|
Total: int64(len(plugins)),
|
|
}, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) GetPluginProductAllTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error) {
|
|
res, err := p.toolRepo.GetPluginAllOnlineTools(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "GetPluginAllOnlineTools failed, pluginID=%d", pluginID)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error) {
|
|
return p.pluginRepo.DeleteAPPAllPlugins(ctx, appID)
|
|
}
|
|
|
|
func (p *pluginServiceImpl) GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*entity.PluginInfo, err error) {
|
|
plugins, err = p.pluginRepo.GetAPPAllDraftPlugins(ctx, appID)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "GetAPPAllDraftPlugins failed, appID=%d", appID)
|
|
}
|
|
|
|
return plugins, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MGetVersionPlugins(ctx context.Context, versionPlugins []entity.VersionPlugin) (plugins []*entity.PluginInfo, err error) {
|
|
plugins, err = p.pluginRepo.MGetVersionPlugins(ctx, versionPlugins)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MGetVersionPlugins failed, versionPlugins=%v", versionPlugins)
|
|
}
|
|
|
|
return plugins, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) ListCustomOnlinePlugins(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
|
|
if pageInfo.Name == nil || *pageInfo.Name == "" {
|
|
plugins, total, err = p.pluginRepo.ListCustomOnlinePlugins(ctx, spaceID, pageInfo)
|
|
if err != nil {
|
|
return nil, 0, errorx.Wrapf(err, "ListCustomOnlinePlugins failed, spaceID=%d", spaceID)
|
|
}
|
|
return plugins, total, nil
|
|
}
|
|
|
|
res, err := crosssearch.DefaultSVC().SearchResources(ctx, &searchModel.SearchResourcesRequest{
|
|
SpaceID: spaceID,
|
|
Name: *pageInfo.Name,
|
|
OrderAsc: false,
|
|
ResTypeFilter: []resCommon.ResType{
|
|
resCommon.ResType_Plugin,
|
|
},
|
|
OrderFiledName: func() string {
|
|
if pageInfo.SortBy == nil || *pageInfo.SortBy != entity.SortByCreatedAt {
|
|
return searchModel.FieldOfUpdateTime
|
|
}
|
|
return searchModel.FieldOfCreateTime
|
|
}(),
|
|
Page: ptr.Of(int32(pageInfo.Page)),
|
|
Limit: int32(pageInfo.Size),
|
|
})
|
|
if err != nil {
|
|
return nil, 0, errorx.Wrapf(err, "SearchResources failed, spaceID=%d", spaceID)
|
|
}
|
|
|
|
plugins = make([]*entity.PluginInfo, 0, len(res.Data))
|
|
for _, pl := range res.Data {
|
|
draftPlugin, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pl.ResID)
|
|
if err != nil {
|
|
return nil, 0, errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", pl.ResID)
|
|
}
|
|
if !exist {
|
|
logs.CtxWarnf(ctx, "online plugin not exist, pluginID=%d", pl.ResID)
|
|
continue
|
|
}
|
|
plugins = append(plugins, draftPlugin)
|
|
}
|
|
|
|
if res.TotalHits != nil {
|
|
total = *res.TotalHits
|
|
}
|
|
|
|
return plugins, total, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (resp *MGetPluginLatestVersionResponse, err error) {
|
|
plugins, err := p.pluginRepo.MGetOnlinePlugins(ctx, pluginIDs,
|
|
repository.WithPluginID(),
|
|
repository.WithPluginVersion())
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", pluginIDs)
|
|
}
|
|
|
|
versions := make(map[int64]string, len(plugins))
|
|
for _, pl := range plugins {
|
|
versions[pl.ID] = pl.GetVersion()
|
|
}
|
|
|
|
resp = &MGetPluginLatestVersionResponse{
|
|
Versions: versions,
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) CopyPlugin(ctx context.Context, req *CopyPluginRequest) (resp *CopyPluginResponse, err error) {
|
|
err = p.checkCanCopyPlugin(ctx, req.PluginID, req.CopyScene)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
plugin, tools, err := p.getCopySourcePluginAndTools(ctx, req.PluginID, req.CopyScene)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p.changePluginAndToolsInfoForCopy(req, plugin, tools)
|
|
|
|
toolMap := make(map[int64]*entity.ToolInfo, len(tools))
|
|
for _, tool := range tools {
|
|
toolMap[tool.ID] = tool
|
|
}
|
|
|
|
plugin, tools, err = p.pluginRepo.CopyPlugin(ctx, &repository.CopyPluginRequest{
|
|
Plugin: plugin,
|
|
Tools: tools,
|
|
})
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "CopyPlugin failed, pluginID=%d", req.PluginID)
|
|
}
|
|
|
|
resp = &CopyPluginResponse{
|
|
Plugin: plugin,
|
|
Tools: toolMap,
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) changePluginAndToolsInfoForCopy(req *CopyPluginRequest, plugin *entity.PluginInfo, tools []*entity.ToolInfo) {
|
|
plugin.Version = nil
|
|
plugin.VersionDesc = nil
|
|
|
|
plugin.DeveloperID = req.UserID
|
|
|
|
if req.CopyScene != model.CopySceneOfAPPDuplicate {
|
|
plugin.SetName(fmt.Sprintf("%s_copy", plugin.GetName()))
|
|
}
|
|
|
|
if req.CopyScene == model.CopySceneOfToLibrary {
|
|
const (
|
|
defaultVersion = "v0.0.1"
|
|
defaultVersionDesc = "copy to library"
|
|
)
|
|
|
|
plugin.APPID = nil
|
|
plugin.Version = ptr.Of(defaultVersion)
|
|
plugin.VersionDesc = ptr.Of(defaultVersionDesc)
|
|
|
|
for _, tool := range tools {
|
|
tool.Version = ptr.Of(defaultVersion)
|
|
}
|
|
}
|
|
|
|
if req.CopyScene == model.CopySceneOfToAPP {
|
|
plugin.APPID = req.TargetAPPID
|
|
|
|
for _, tool := range tools {
|
|
tool.DebugStatus = ptr.Of(pluginCommon.APIDebugStatus_DebugPassed)
|
|
}
|
|
}
|
|
|
|
if req.CopyScene == model.CopySceneOfAPPDuplicate {
|
|
plugin.APPID = req.TargetAPPID
|
|
}
|
|
}
|
|
|
|
func (p *pluginServiceImpl) checkCanCopyPlugin(ctx context.Context, pluginID int64, scene model.CopyScene) (err error) {
|
|
switch scene {
|
|
case model.CopySceneOfToAPP, model.CopySceneOfDuplicate, model.CopySceneOfAPPDuplicate:
|
|
return nil
|
|
case model.CopySceneOfToLibrary:
|
|
return p.checkToolsDebugStatus(ctx, pluginID)
|
|
default:
|
|
return fmt.Errorf("unsupported copy scene '%s'", scene)
|
|
}
|
|
}
|
|
|
|
func (p *pluginServiceImpl) getCopySourcePluginAndTools(ctx context.Context, pluginID int64, scene model.CopyScene) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
|
|
switch scene {
|
|
case model.CopySceneOfToAPP:
|
|
return p.getOnlinePluginAndTools(ctx, pluginID)
|
|
case model.CopySceneOfToLibrary, model.CopySceneOfDuplicate, model.CopySceneOfAPPDuplicate:
|
|
return p.getDraftPluginAndTools(ctx, pluginID)
|
|
default:
|
|
return nil, nil, fmt.Errorf("unsupported copy scene '%s'", scene)
|
|
}
|
|
}
|
|
|
|
func (p *pluginServiceImpl) getOnlinePluginAndTools(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
|
|
onlinePlugin, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if !exist {
|
|
return nil, nil, errorx.New(errno.ErrPluginRecordNotFound)
|
|
}
|
|
|
|
onlineTools, err := p.toolRepo.GetPluginAllOnlineTools(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return onlinePlugin, onlineTools, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) getDraftPluginAndTools(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
|
|
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if !exist {
|
|
return nil, nil, errorx.New(errno.ErrPluginRecordNotFound)
|
|
}
|
|
|
|
draftTools, err := p.toolRepo.GetPluginAllDraftTools(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return draftPlugin, draftTools, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) MoveAPPPluginToLibrary(ctx context.Context, pluginID int64) (draftPlugin *entity.PluginInfo, err error) {
|
|
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !exist {
|
|
return nil, errorx.New(errno.ErrPluginRecordNotFound)
|
|
}
|
|
|
|
err = p.checkToolsDebugStatus(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
draftTools, err := p.toolRepo.GetPluginAllDraftTools(ctx, pluginID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p.changePluginAndToolsInfoForMove(draftPlugin, draftTools)
|
|
|
|
err = p.pluginRepo.MoveAPPPluginToLibrary(ctx, draftPlugin, draftTools)
|
|
if err != nil {
|
|
return nil, errorx.Wrapf(err, "MoveAPPPluginToLibrary failed, pluginID=%d", pluginID)
|
|
}
|
|
|
|
return draftPlugin, nil
|
|
}
|
|
|
|
func (p *pluginServiceImpl) changePluginAndToolsInfoForMove(plugin *entity.PluginInfo,
|
|
tools []*entity.ToolInfo) {
|
|
|
|
const (
|
|
defaultVersion = "v0.0.1"
|
|
defaultVersionDesc = "move to library"
|
|
)
|
|
|
|
plugin.Version = ptr.Of(defaultVersion)
|
|
plugin.VersionDesc = ptr.Of(defaultVersionDesc)
|
|
|
|
for _, tool := range tools {
|
|
tool.Version = ptr.Of(defaultVersion)
|
|
}
|
|
|
|
plugin.APPID = nil
|
|
}
|