mirror of
https://github.com/tiger1103/gfast.git
synced 2026-09-21 10:12:59 +00:00
后台插件管理器
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成控制器相关代码,只生成一次,按需修改,再次生成不会覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/api/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"gfast/app/system/dao"
|
||||
"gfast/app/system/service"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
type pluginsManage struct {
|
||||
SystemBase
|
||||
}
|
||||
|
||||
var PluginsManage = new(pluginsManage)
|
||||
|
||||
// List 列表
|
||||
func (c *pluginsManage) List(r *ghttp.Request) {
|
||||
var req *dao.PluginsManageSearchReq
|
||||
//获取参数
|
||||
if err := r.Parse(&req); err != nil {
|
||||
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
|
||||
}
|
||||
req.Ctx = r.GetCtx()
|
||||
total, page, list, err := service.PluginsManage.GetList(req)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
result := g.Map{
|
||||
"currentPage": page,
|
||||
"total": total,
|
||||
"list": list,
|
||||
}
|
||||
c.SusJsonExit(r, result)
|
||||
}
|
||||
|
||||
// Get 获取
|
||||
func (c *pluginsManage) Get(r *ghttp.Request) {
|
||||
id := r.GetInt64("id")
|
||||
info, err := service.PluginsManage.GetInfoById(r.GetCtx(), id)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
c.SusJsonExit(r, info)
|
||||
}
|
||||
|
||||
// ChangeStatus 修改状态
|
||||
func (c *pluginsManage) ChangeStatus(r *ghttp.Request) {
|
||||
var req *dao.PluginsManageStatusReq
|
||||
//获取参数
|
||||
if err := r.Parse(&req); err != nil {
|
||||
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
|
||||
}
|
||||
if err := service.PluginsManage.ChangeStatus(r.GetCtx(), req); err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
} else {
|
||||
c.SusJsonExit(r, "状态设置成功")
|
||||
}
|
||||
}
|
||||
|
||||
// Install 插件安装
|
||||
func (c *pluginsManage) Install(r *ghttp.Request) {
|
||||
var req *dao.PluginsManageInstallReq
|
||||
//获取参数
|
||||
if err := r.Parse(&req); err != nil {
|
||||
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
|
||||
}
|
||||
if req.RToken == "" {
|
||||
c.SusJsonExit(r, g.Map{
|
||||
"code": -401,
|
||||
"msg": "请登录",
|
||||
})
|
||||
}
|
||||
err := service.PluginsManage.Install(r.GetCtx(), req)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
c.SusJsonExit(r, "安装成功")
|
||||
}
|
||||
|
||||
// Captcha 获取验证码
|
||||
func (c *pluginsManage) Captcha(r *ghttp.Request) {
|
||||
idKeyC, base64stringC, err := service.PluginsManage.GetCaptcha(r.GetCtx())
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
c.SusJsonExit(r, g.Map{
|
||||
"base64stringC": base64stringC,
|
||||
"idKeyC": idKeyC,
|
||||
})
|
||||
}
|
||||
|
||||
// LoginR 登录插件服务
|
||||
func (c *pluginsManage) LoginR(r *ghttp.Request) {
|
||||
var req *dao.PluginRLoginFormReq
|
||||
// 通过Parse方法解析获取参数
|
||||
err := r.Parse(&req)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
|
||||
}
|
||||
var userInfo g.Map
|
||||
userInfo, err = service.PluginsManage.LoginR(r.GetCtx(), req)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
c.SusJsonExit(r, userInfo)
|
||||
}
|
||||
|
||||
// InstallOffLine 离线安装
|
||||
func (c *pluginsManage) InstallOffLine(r *ghttp.Request) {
|
||||
upFile := r.GetUploadFile("file")
|
||||
f, err := upFile.Open()
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
d := make([]byte, upFile.Size)
|
||||
_, err = f.Read(d)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
fileName := upFile.Filename
|
||||
fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
|
||||
gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
|
||||
err = service.PluginsManage.PluginIsExists(r.GetCtx(), fileName)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
err = service.PluginsManage.InstallFile(r.GetCtx(), d, fileName)
|
||||
if err != nil {
|
||||
c.FailJsonExit(r, err.Error())
|
||||
}
|
||||
c.SusJsonExit(r)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成dao internal操作代码,无需手动修改,重新生成会自动覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/dao/internal/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
// PluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
|
||||
type PluginsManageDao struct {
|
||||
Table string // Table is the underlying table name of the DAO.
|
||||
Group string // Group is the database configuration group name of current DAO.
|
||||
Columns PluginsManageColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// PluginsManageColumns defines and stores column names for table plugins_manage.
|
||||
type PluginsManageColumns struct {
|
||||
Id string // ID
|
||||
StoreId string // 插件在商城中的id
|
||||
PName string // 插件名称英文
|
||||
PTitle string // 插件名称
|
||||
PDescription string // 插件介绍
|
||||
PAuth string // 作者
|
||||
IsInstall string // 是否安装
|
||||
Status string // 状态
|
||||
Version string // 当前版本
|
||||
Price string // 价格
|
||||
DownloadTimes string // 下载次数
|
||||
InstallPath string // 安装路径
|
||||
}
|
||||
|
||||
var pluginsManageColumns = PluginsManageColumns{
|
||||
Id: "id",
|
||||
StoreId: "store_id",
|
||||
PName: "p_name",
|
||||
PTitle: "p_title",
|
||||
PDescription: "p_description",
|
||||
PAuth: "p_auth",
|
||||
IsInstall: "is_install",
|
||||
Status: "status",
|
||||
Version: "version",
|
||||
Price: "price",
|
||||
DownloadTimes: "download_times",
|
||||
InstallPath: "install_path",
|
||||
}
|
||||
|
||||
// NewPluginsManageDao creates and returns a new DAO object for table data access.
|
||||
func NewPluginsManageDao() *PluginsManageDao {
|
||||
return &PluginsManageDao{
|
||||
Group: "default",
|
||||
Table: "plugins_manage",
|
||||
Columns: pluginsManageColumns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *PluginsManageDao) DB() gdb.DB {
|
||||
return g.DB(dao.Group)
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *PluginsManageDao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.Table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *PluginsManageDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成dao操作代码,无需手动修改,重新生成不会自动覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/dao/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
comModel "gfast/app/common/model"
|
||||
"gfast/app/system/dao/internal"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// pluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type pluginsManageDao struct {
|
||||
*internal.PluginsManageDao
|
||||
}
|
||||
|
||||
var (
|
||||
// PluginsManage is globally public accessible object for table tools_gen_table operations.
|
||||
PluginsManage = pluginsManageDao{
|
||||
internal.NewPluginsManageDao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
||||
|
||||
// PluginsManageSearchReq 分页请求参数
|
||||
type PluginsManageSearchReq struct {
|
||||
PName string `p:"pName"` //插件名称英文
|
||||
PTitle string `p:"pTitle"` //插件名称
|
||||
PAuth string `p:"pAuth"` //作者
|
||||
Status string `p:"status"` //状态
|
||||
comModel.PageReq
|
||||
}
|
||||
|
||||
// PluginsManageAddReq 添加操作请求参数
|
||||
type PluginsManageAddReq struct {
|
||||
StoreId int `p:"storeId" `
|
||||
PName string `p:"pName" v:"required#插件名称英文不能为空"`
|
||||
PTitle string `p:"pTitle" `
|
||||
PDescription string `p:"pDescription" `
|
||||
PAuth string `p:"pAuth" `
|
||||
Status int `p:"status" v:"required#状态不能为空"`
|
||||
Version string `p:"version" `
|
||||
Price uint `p:"price" v:"required#价格不能为空"`
|
||||
DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
|
||||
IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
|
||||
}
|
||||
|
||||
// PluginsManageEditReq 修改操作请求参数
|
||||
type PluginsManageEditReq struct {
|
||||
Id uint `p:"id" v:"required#主键ID不能为空"`
|
||||
StoreId int `p:"storeId" `
|
||||
PName string `p:"pName" v:"required#插件名称英文不能为空"`
|
||||
PTitle string `p:"pTitle" `
|
||||
PDescription string `p:"pDescription" `
|
||||
PAuth string `p:"pAuth" `
|
||||
Status int `p:"status" v:"required#状态不能为空"`
|
||||
Version string `p:"version" `
|
||||
Price uint `p:"price" v:"required#价格不能为空"`
|
||||
DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
|
||||
IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
|
||||
}
|
||||
|
||||
// PluginsManageStatusReq 设置状态参数
|
||||
type PluginsManageStatusReq struct {
|
||||
PluginId uint `p:"pluginId" v:"required#pluginId不能为空"`
|
||||
Status int `p:"status" v:"required#状态不能为空"`
|
||||
}
|
||||
|
||||
// PluginsManageListRes 列表返回结果
|
||||
type PluginsManageListRes struct {
|
||||
Id uint `json:"id" `
|
||||
PName string `json:"pName" v:"required#插件名称英文不能为空"`
|
||||
PTitle string `json:"pTitle" `
|
||||
PDescription string `json:"pDescription" `
|
||||
PAuth string `json:"pAuth" `
|
||||
Status int `json:"status" v:"required#状态不能为空"`
|
||||
Version string `json:"version" `
|
||||
Price uint `json:"price" v:"required#价格不能为空"`
|
||||
DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
|
||||
}
|
||||
|
||||
// PluginsManageInfoRes 数据返回结果
|
||||
type PluginsManageInfoRes struct {
|
||||
Id uint `json:"id" `
|
||||
StoreId int `json:"storeId" `
|
||||
PName string `json:"pName" v:"required#插件名称英文不能为空"`
|
||||
PTitle string `json:"pTitle" `
|
||||
PDescription string `json:"pDescription" `
|
||||
PAuth string `json:"pAuth" `
|
||||
IsInstall int `json:"isInstall" v:"required#是否安装不能为空"`
|
||||
Status int `json:"status" v:"required#状态不能为空"`
|
||||
Version string `json:"version" `
|
||||
Price uint `json:"price" v:"required#价格不能为空"`
|
||||
DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
|
||||
}
|
||||
|
||||
// CsPluginListRes 插件商城获取的插件数据
|
||||
type CsPluginListRes struct {
|
||||
PluginId uint `orm:"plugin_id,primary" json:"pluginId"` // ID
|
||||
PluginCateId uint `orm:"plugin_cate_id" json:"pluginCateId"` // 分类ID
|
||||
PluginName string `orm:"plugin_name" json:"pluginName"` // 插件名称
|
||||
CodeName string `orm:"code_name" json:"CodeName"` // 代码名称
|
||||
PluginPrice uint `orm:"plugin_price" json:"pluginPrice"` // 售价
|
||||
PluginPriceStr string `json:"pluginPriceStr"` // 售价decimal
|
||||
PluginDiscount uint `orm:"plugin_discount" json:"pluginDiscount"` // 折扣
|
||||
PluginCreater uint `orm:"plugin_creater" json:"pluginCreater"` // 开发人员ID
|
||||
PublishDate *gtime.Time `orm:"publish_date" json:"publishDate"` // 发布日期
|
||||
PluginThumb string `orm:"plugin_thumb" json:"pluginThumb"` // 插件封面
|
||||
PluginImgs string `orm:"plugin_imgs" json:"pluginImgs"` // 插件预览图
|
||||
CreatedBy uint64 `orm:"created_by" json:"createdBy"` // 创建人
|
||||
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建日期
|
||||
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 修改日期
|
||||
DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除日期
|
||||
DownloadTimes uint64 `orm:"download_times" json:"downloadTimes"` //下载次数
|
||||
Description string `orm:"description" json:"description"` //插件描述
|
||||
PluginInfo []*struct {
|
||||
InfoId uint `json:"infoId"` // ID
|
||||
PluginId uint `json:"pluginId"` // 插件ID
|
||||
InfoVersion string `json:"infoVersion"` // 版本号
|
||||
} `json:"pluginInfo"`
|
||||
MemName string `json:"memName" orm:"mem_name"`
|
||||
Status int `json:"status"`
|
||||
Version string `json:"version" `
|
||||
IsInstall int `json:"isInstall"`
|
||||
}
|
||||
|
||||
// PluginsManageInstallReq 插件安装操作参数
|
||||
type PluginsManageInstallReq struct {
|
||||
PluginId uint `p:"pluginId" v:"required#插件ID不能为空"`
|
||||
Version string `p:"version"`
|
||||
RToken string `p:"rToken"`
|
||||
}
|
||||
|
||||
// PluginRLoginFormReq 远端登录请求参数
|
||||
type PluginRLoginFormReq struct {
|
||||
Username string `p:"username" v:"required#账号必须" json:"username"`
|
||||
Password string `p:"password" v:"required#密码不能为空" json:"password"`
|
||||
VerifyCode string `p:"verifyCode" v:"required#验证码不能为空" json:"verifyCode"`
|
||||
VerifyKey string `p:"verifyKey" json:"verifyKey"`
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成model代码,无需手动修改,重新生成会自动覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/model/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package model
|
||||
|
||||
// PluginsManage is the golang structure for table plugins_manage.
|
||||
type PluginsManage struct {
|
||||
Id uint `orm:"id,primary" json:"id"` // ID
|
||||
StoreId int `orm:"store_id" json:"storeId"` // 插件在商城中的id
|
||||
PName string `orm:"p_name" json:"pName"` // 插件名称英文
|
||||
PTitle string `orm:"p_title" json:"pTitle"` // 插件名称
|
||||
PDescription string `orm:"p_description" json:"pDescription"` // 插件介绍
|
||||
PAuth string `orm:"p_auth" json:"pAuth"` // 作者
|
||||
IsInstall int `orm:"is_install" json:"isInstall"` // 是否安装
|
||||
Status int `orm:"status" json:"status"` // 状态
|
||||
Version string `orm:"version" json:"version"` // 当前版本
|
||||
Price uint `orm:"price" json:"price"` // 价格
|
||||
DownloadTimes uint `orm:"download_times" json:"downloadTimes"` // 下载次数
|
||||
InstallPath string `orm:"install_oath" json:"installPath"` // 安装路径
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成路由代码,只生成一次,按需修改,再次生成不会覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/router/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"gfast/app/system/api"
|
||||
"gfast/middleware"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
//加载路由
|
||||
func init() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Group("/system", func(group *ghttp.RouterGroup) {
|
||||
group.Group("/pluginsManage", func(group *ghttp.RouterGroup) {
|
||||
//gToken拦截器
|
||||
api.GfToken.AuthMiddleware(group)
|
||||
//context拦截器
|
||||
group.Middleware(middleware.Ctx, middleware.Auth)
|
||||
group.GET("list", api.PluginsManage.List)
|
||||
group.GET("get", api.PluginsManage.Get)
|
||||
group.PUT("changeStatus", api.PluginsManage.ChangeStatus)
|
||||
group.POST("install", api.PluginsManage.Install)
|
||||
group.GET("captcha", api.PluginsManage.Captcha)
|
||||
group.POST("loginR", api.PluginsManage.LoginR)
|
||||
group.POST("installOffLine", api.PluginsManage.InstallOffLine)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,450 @@
|
||||
// ==========================================================================
|
||||
// GFast自动生成业务逻辑层相关代码,只生成一次,按需修改,再次生成不会覆盖.
|
||||
// 生成日期:2021-08-31 17:58:43
|
||||
// 生成路径: gfast/app/system/service/plugins_manage.go
|
||||
// 生成人:gfast
|
||||
// ==========================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gfast/app/common/global"
|
||||
"gfast/app/system/dao"
|
||||
"gfast/app/system/model"
|
||||
"gfast/library"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/encoding/gcompress"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
"github.com/gogf/gf/encoding/gurl"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
type pluginsManage struct {
|
||||
}
|
||||
|
||||
var PluginsManage = new(pluginsManage)
|
||||
|
||||
// GetList 获取列表
|
||||
func (s *pluginsManage) GetList(req *dao.PluginsManageSearchReq) (total, page int, list []*dao.CsPluginListRes, err error) {
|
||||
//同步服务端插件商城
|
||||
total, page, list, err = s.syncFromStore(req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetInfoById 通过id获取
|
||||
func (s *pluginsManage) GetInfoById(ctx context.Context, id int64) (info *dao.PluginsManageInfoRes, err error) {
|
||||
if id == 0 {
|
||||
err = gerror.New("参数错误")
|
||||
return
|
||||
}
|
||||
var data *model.PluginsManage
|
||||
err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.Id, id).Scan(&data)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
}
|
||||
if data == nil || err != nil {
|
||||
err = gerror.New("获取信息失败")
|
||||
}
|
||||
info = &dao.PluginsManageInfoRes{
|
||||
Id: data.Id,
|
||||
StoreId: data.StoreId,
|
||||
PName: data.PName,
|
||||
PTitle: data.PTitle,
|
||||
PDescription: data.PDescription,
|
||||
PAuth: data.PAuth,
|
||||
IsInstall: data.IsInstall,
|
||||
Status: data.Status,
|
||||
Version: data.Version,
|
||||
Price: data.Price,
|
||||
DownloadTimes: data.DownloadTimes,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Add 添加
|
||||
func (s *pluginsManage) Add(ctx context.Context, req *dao.PluginsManageAddReq) (err error) {
|
||||
_, err = dao.PluginsManage.Ctx(ctx).Insert(req)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 修改
|
||||
func (s *pluginsManage) Edit(ctx context.Context, req *dao.PluginsManageEditReq) error {
|
||||
_, err := dao.PluginsManage.Ctx(ctx).FieldsEx(dao.PluginsManage.Columns.Id).Where(dao.PluginsManage.Columns.Id, req.Id).
|
||||
Update(req)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteByIds 删除
|
||||
func (s *pluginsManage) DeleteByIds(ctx context.Context, ids []int) (err error) {
|
||||
if len(ids) == 0 {
|
||||
err = gerror.New("参数错误")
|
||||
return
|
||||
}
|
||||
_, err = dao.PluginsManage.Ctx(ctx).Delete(dao.PluginsManage.Columns.Id+" in (?)", ids)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("删除失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ChangeStatus 修改状态
|
||||
func (s *pluginsManage) ChangeStatus(ctx context.Context, req *dao.PluginsManageStatusReq) error {
|
||||
_, err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId, req.PluginId).Update(g.Map{
|
||||
dao.PluginsManage.Columns.Status: req.Status,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
//同步插件商城中的插件
|
||||
func (s *pluginsManage) syncFromStore(req *dao.PluginsManageSearchReq) (total, page int, csPluginList []*dao.CsPluginListRes, err error) {
|
||||
storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStore/pluginList"
|
||||
res := (*ghttp.ClientResponse)(nil)
|
||||
if req.PageNum == 0 {
|
||||
req.PageNum = 1
|
||||
}
|
||||
page = req.PageNum
|
||||
res, err = g.Client().Ctx(req.Ctx).Get(storeUrl, g.MapStrAny{
|
||||
"pageNum": req.PageNum,
|
||||
"PageSize": req.PageSize,
|
||||
"pluginName": req.PTitle,
|
||||
})
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("获取插件数据失败")
|
||||
return
|
||||
}
|
||||
defer res.Close()
|
||||
var data map[string]interface{}
|
||||
b := res.ReadAll()
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("获取插件数据失败")
|
||||
return
|
||||
}
|
||||
if gconv.Int(data["code"]) == 0 {
|
||||
err = gconv.Structs((data["data"].(g.Map))["list"], &csPluginList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
csPluginList, err = s.updatePlugins(req.Ctx, csPluginList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
total = gconv.Int((data["data"].(g.Map))["total"])
|
||||
} else {
|
||||
err = gerror.New(data["msg"].(string))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 更新插件数据
|
||||
func (s *pluginsManage) updatePlugins(ctx context.Context, csList []*dao.CsPluginListRes) (newList []*dao.CsPluginListRes, err error) {
|
||||
ids := make([]uint, len(csList))
|
||||
for k, v := range csList {
|
||||
ids[k] = v.PluginId
|
||||
}
|
||||
//查询插件信息
|
||||
var pluginList []*model.PluginsManage
|
||||
err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId+" in(?)", ids).Scan(&pluginList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hasIds := garray.NewArraySize(len(pluginList), 100)
|
||||
gmp := gmap.New()
|
||||
for k, v := range pluginList {
|
||||
hasIds.Set(k, v.StoreId)
|
||||
gmp.Set(v.StoreId, v)
|
||||
}
|
||||
for _, v := range csList {
|
||||
pluginId := gconv.Int(v.PluginId)
|
||||
if hasIds.Len() > 0 && hasIds.Contains(pluginId) {
|
||||
plugin := gmp.Get(pluginId).(*model.PluginsManage)
|
||||
//修改
|
||||
version := plugin.Version
|
||||
if plugin.IsInstall == 0 && len(v.PluginInfo) > 0 {
|
||||
version = v.PluginInfo[0].InfoVersion
|
||||
}
|
||||
err = s.Edit(ctx, &dao.PluginsManageEditReq{
|
||||
Id: plugin.Id,
|
||||
StoreId: pluginId,
|
||||
PName: v.CodeName,
|
||||
PTitle: v.PluginName,
|
||||
PDescription: v.Description,
|
||||
PAuth: v.MemName,
|
||||
Status: plugin.Status,
|
||||
Version: version,
|
||||
Price: v.PluginPrice,
|
||||
DownloadTimes: gconv.Uint(v.DownloadTimes),
|
||||
IsInstall: plugin.IsInstall,
|
||||
})
|
||||
v.Status = plugin.Status
|
||||
v.Version = version
|
||||
v.IsInstall = plugin.IsInstall
|
||||
v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
|
||||
} else {
|
||||
//新增
|
||||
version := ""
|
||||
if len(v.PluginInfo) > 0 {
|
||||
version = v.PluginInfo[0].InfoVersion
|
||||
}
|
||||
err = s.Add(ctx, &dao.PluginsManageAddReq{
|
||||
StoreId: pluginId,
|
||||
PName: v.CodeName,
|
||||
PTitle: v.PluginName,
|
||||
PDescription: v.Description,
|
||||
PAuth: v.MemName,
|
||||
Status: 0,
|
||||
Version: version,
|
||||
Price: v.PluginPrice,
|
||||
DownloadTimes: gconv.Uint(v.DownloadTimes),
|
||||
IsInstall: 0,
|
||||
})
|
||||
v.Status = 0
|
||||
v.Version = version
|
||||
v.IsInstall = 0
|
||||
v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
newList = csList
|
||||
return
|
||||
}
|
||||
|
||||
// DecimalToInt64 元转分
|
||||
func (s *pluginsManage) DecimalToInt64(decimal string) (i int64) {
|
||||
pos := gstr.PosR(decimal, ".")
|
||||
integer := gconv.Int64(gstr.SubStr(decimal, 0, pos)) * 100
|
||||
dec := int64(0)
|
||||
if pos > -1 {
|
||||
dec = gconv.Int64(gstr.SubStr(decimal, pos+1, 2))
|
||||
}
|
||||
i = integer + dec
|
||||
return
|
||||
}
|
||||
|
||||
// Int64ToDecimal 分转元
|
||||
func (s *pluginsManage) Int64ToDecimal(i int64) (decimal string) {
|
||||
b := []byte(gconv.String(i))
|
||||
for {
|
||||
if len(b) >= 2 {
|
||||
break
|
||||
}
|
||||
b = append([]byte{'0'}, b...)
|
||||
}
|
||||
integer := b[:len(b)-2]
|
||||
if len(integer) == 0 {
|
||||
integer = []byte{'0'}
|
||||
}
|
||||
dec := b[len(b)-2:]
|
||||
decimal = fmt.Sprintf("%s.%s", integer, dec)
|
||||
return
|
||||
}
|
||||
|
||||
// Install 插件安装
|
||||
func (s *pluginsManage) Install(ctx context.Context, req *dao.PluginsManageInstallReq) (err error) {
|
||||
//生成下载链接
|
||||
storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/getDownloadInfo"
|
||||
res := (*ghttp.ClientResponse)(nil)
|
||||
res, err = g.Client().Ctx(ctx).Get(fmt.Sprintf("%s?pluginId=%d&version=%s&token=%s", storeUrl, req.PluginId, req.Version,
|
||||
gurl.RawEncode(req.RToken)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Close()
|
||||
var data map[string]interface{}
|
||||
b := res.ReadAll()
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if gconv.Int(data["code"]) == 0 {
|
||||
url := fmt.Sprintf("%s/%s&token=%s", g.Cfg().GetString("plugin.serverUrl"),
|
||||
(data["data"]).(string), gurl.RawEncode(req.RToken))
|
||||
//下载插件并安装
|
||||
err = s.downloadAndInstall(ctx, url)
|
||||
} else {
|
||||
err = gerror.New(data["msg"].(string))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetCaptcha 获取验证码
|
||||
func (s *pluginsManage) GetCaptcha(ctx context.Context) (idKeyC, base64stringC string, err error) {
|
||||
storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/captcha/get"
|
||||
res := (*ghttp.ClientResponse)(nil)
|
||||
res, err = g.Client().Ctx(ctx).Get(storeUrl)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("获取验证码失败")
|
||||
return
|
||||
}
|
||||
defer res.Close()
|
||||
var data map[string]interface{}
|
||||
b := res.ReadAll()
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("获取插件数据失败")
|
||||
return
|
||||
}
|
||||
if gconv.Int(data["code"]) == 0 {
|
||||
data = (data["data"]).(g.Map)
|
||||
idKeyC = gconv.String(data["idKeyC"])
|
||||
base64stringC = gconv.String(data["base64stringC"])
|
||||
} else {
|
||||
err = gerror.New(data["msg"].(string))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// LoginR 登录
|
||||
func (s *pluginsManage) LoginR(ctx context.Context, loginReq *dao.PluginRLoginFormReq) (userInfo g.Map, err error) {
|
||||
storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/login"
|
||||
res := (*ghttp.ClientResponse)(nil)
|
||||
res, err = g.Client().Ctx(ctx).Post(storeUrl, loginReq)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("获取验证码失败")
|
||||
return
|
||||
}
|
||||
defer res.Close()
|
||||
var data map[string]interface{}
|
||||
b := res.ReadAll()
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
g.Log().Error(err)
|
||||
err = gerror.New("登录失败")
|
||||
return
|
||||
}
|
||||
if gconv.Int(data["code"]) == 0 {
|
||||
userInfo = (data["data"]).(g.Map)
|
||||
} else {
|
||||
err = gerror.New(data["msg"].(string))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 下载并安装插件
|
||||
func (s *pluginsManage) downloadAndInstall(ctx context.Context, url string) error {
|
||||
res, err := g.Client().Ctx(ctx).Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Close()
|
||||
ct := res.Header.Get("Content-Type")
|
||||
if gstr.ContainsI(ct, "json") {
|
||||
var data map[string]interface{}
|
||||
b := res.ReadAll()
|
||||
err = json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if gconv.Int(data["code"]) != 0 {
|
||||
err = gerror.New(data["msg"].(string))
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
//安装
|
||||
//获取插件名称
|
||||
fileName := res.Header.Get("content-disposition")
|
||||
fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
|
||||
gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
|
||||
err = s.InstallFile(ctx, res.ReadAll(), fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallFile 安装插件文件
|
||||
func (s *pluginsManage) InstallFile(ctx context.Context, data []byte, fileName string) (err error) {
|
||||
//获取插件下载路径
|
||||
downloadPath := library.GetExcPath() + "/data/installPlugins"
|
||||
if !gfile.IsDir(downloadPath) {
|
||||
err = gfile.Mkdir(downloadPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
g.Log().Debug(downloadPath, fileName)
|
||||
// 删除安装临时文件
|
||||
defer gfile.Remove(downloadPath + "/" + fileName)
|
||||
err = gcompress.UnZipContent(data, downloadPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//获取插件配置信息
|
||||
var installCfg *gjson.Json
|
||||
installCfg, err = gjson.Load(downloadPath + "/" + fileName + "/install.json")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mustGfastVersion := installCfg.GetString("minGfastVersion")
|
||||
if gstr.CompareVersion(mustGfastVersion, global.Version) > 0 {
|
||||
err = gerror.New(fmt.Sprintf("您的gfast版本过低,此插件要求gfast版本为:%s", mustGfastVersion))
|
||||
return
|
||||
}
|
||||
//获取本项目安装情况
|
||||
var plugin *model.PluginsManage
|
||||
err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, fileName).Limit(1).Scan(&plugin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if plugin == nil {
|
||||
err = gerror.New("插件信息不存在,请刷新页面后再安装。")
|
||||
return
|
||||
}
|
||||
//复制插件文件到对应目录
|
||||
//1.后端
|
||||
err = gfile.Copy(downloadPath+"/"+fileName+"/go/", library.GetExcPath())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//2.前端
|
||||
fontRoot := g.Cfg().GetString("gen.frontDir")
|
||||
if !gfile.IsDir(fontRoot) {
|
||||
err = gerror.New("前端路径不存在,请配置gen.frontDir")
|
||||
return
|
||||
}
|
||||
err = gfile.Copy(downloadPath+"/"+fileName+"/vue/", fontRoot+"/src")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 安装成功后修改插件安装状态及安装路径
|
||||
_, err = dao.PluginsManage.Ctx(ctx).WherePri(plugin.Id).Update(g.Map{
|
||||
dao.PluginsManage.Columns.IsInstall: 1,
|
||||
dao.PluginsManage.Columns.Status: 1,
|
||||
dao.PluginsManage.Columns.InstallPath: installCfg.GetString("installPath"),
|
||||
dao.PluginsManage.Columns.Version: installCfg.GetString("version"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// PluginIsExists 判断插件是否存在
|
||||
func (s *pluginsManage) PluginIsExists(ctx context.Context, name string) error {
|
||||
info := (*model.PluginsManage)(nil)
|
||||
err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, name).Limit(1).
|
||||
Fields(dao.PluginsManage.Columns.Id).Scan(&info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info == nil {
|
||||
return gerror.New("不属于官方插件,无法安装。")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -88,3 +88,8 @@
|
||||
SecretKey = "填写您的SecretKey"
|
||||
[upload.local] #本地上传配置
|
||||
UpPath = "/pub_upload/" #上传路径
|
||||
|
||||
|
||||
# 插件管理
|
||||
[plugin]
|
||||
serverUrl = "http://localhost:8199" #获取插件商城插件列表
|
||||
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -247,3 +250,13 @@ func CurrencyLong(currency interface{}) int64 {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetExcPath() string {
|
||||
file, _ := exec.LookPath(os.Args[0])
|
||||
// 获取包含可执行文件名称的路径
|
||||
path, _ := filepath.Abs(file)
|
||||
// 获取可执行文件所在目录
|
||||
index := strings.LastIndex(path, string(os.PathSeparator))
|
||||
ret := path[:index]
|
||||
return strings.Replace(ret, "\\", "/", -1)
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package packed
|
||||
import "github.com/gogf/gf/os/gres"
|
||||
|
||||
func init() {
|
||||
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GCoCVQMZkACIgycDMXlienpqUX6UFovqzg/LzSElYHxbaB+4pvIs3m33QT2PdfsyO1vU/mxIrl72Yml7f8WtN9oF7Vctk3w5Nl3m9ZmcXRcPGafm7vUN1eZY1bUi4VOgUf4Lmj4vl2mrzzpWbTIEo92ofpNXcnRWicmWxif/vns9kx+7aKvsxZpcD3KEuZ5sGLdHR7ehRs1WVy5H3+Xaf1+mvviLv0N65idS1l1w7ICDZSedbW+OvXq9FKpgqmCWh2pbBvfxx+PsfheNufdxO87nt+NLq9+/W6xo9FMhUWs6Rs9+7NmMq1W8rjgOcOe/dji4+wBTu5P3EW61eTdQ0INRbOEw0sFkuddmJ3KIysTMlvwolyyVuXS60fEua7ppO+y1nz9ycnqO0vncuvzc97N+//7+/L27HsHZ33+0Lp9q+Gf7c/XyS7qucr02kbctOjdv4d3apuWFBTcNjDI3s/GxjYnSo19nmeeRNDpUk1JmTV6ilcvJXBenXo0Ktcx0klKzGLH3siVIdOsJRXOyYl+s9HzET+292yC6omvYaHNokmTFMzXb/NoTry2rkZi6pRlevsuzZ6dK7t9zx5vs8qp23cyLM66PK1166qq17a9HN21Tpd1fXTtftv+yQtpKN9U/usR+3PH+h/Xtx+ezPz/oPnhxweXln68oqGRdoOBUUe+u4b/9herTMfA5bNuMOz0ELLbmJj5dpEG2/bcQw7Opa4G0vcO9HSY8QoWHexYOb9ebJPZGpF+ptfZHe5XfD9rypz7tm73dkMbuR63r5eWOCm9lxZtF/XMrAiN0eQJnhDHxZyZusFS/tSDPNvv5rsWf5TpfbW0sznmVZC8UOFSuydHzm6xu2Pw5X+zTc+/dXGdNk+W6z1VFAw/5ex3x+cUM3tY7kQewRmLv2fe868t/zxz8876W6/91/Msvrq4fFbw62aZhs8vDx9xEC159ER+3WTrc/n3d/5mrv/vL+ma2eB3pr9TUVF7e27C2zdhb1P093Uw/V3/+1/d/Ayjo5kOR3sPneBew2Pcxp06g8Pg09E3Ojp1coasLw5wbXGa51L+uu/zk0Cfpburn+TZT1OfEi+4OPh7V3nN/b8/xX8mMgTPfhnYUXiv6dtysdnzawvK60r+vdtVfX7u5HU+tWKXG/YG29iIh8fZZHz6avn/Tvm2bX/vBb9P8F1m11X644DZs2V23ze8/j5v1273TUdrXfbN+qu5yPc0y2UzqaMxZ1jC9DZsOG/5XjO78lTfuuL5mw7Hfwx/w9Jm+EKDVaP0X5/04awatlUzFrAFpgUmND3J8TtR/G+b75vTH35cr9k66QoXS3xSc5u8ulj2VpNYyb+iOftMjl08eKR+xz+tGYLxQRw8604zS+Sk1SuFGx2ruFW289pPfQaG//8DvNk5ZMLCYo4xMzBcU2RggBUIDAy1aAUCO6JAAJcB7wP1E0G6kdUEeDMyiTAjChRkk0EFCgxsawSReIsXhFHYnQIBAgz/HQVZGLA4jJUNJM/EwMTQycDA4M8C4gECAAD//+GYqUjuBAAA"); err != nil {
|
||||
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GA4xzstmAEJiDBwMhSXJ6anpxbpQ2m9rOL8vNAQVgbG0uZDiW8iz+bddhPY91yzI7e/TeXHiuTuZRwBXy7IfxH4vUHp+BUzpZ03Y7eF8jIa3vqxfO3aLStzWRyDuW1DNLpuMEotXXn3S6rLqZpuJ+1LE4/Ir31jMY3pk8q5M0X7fpY9u+wVs3dZ5qy2HXGs3BZa2eZLHaVWOwVsMag6P3FPfBzH9dpOX2EJreyMjQFczYIbw2VCroXF65k2vO4JcJTZLf/7X+mZ1vL849lyX+W2V32/9vfarv8rjOf4CAQ2b76R2P/uBtPrRfMXGKb8Y5Lgl7/friS7UD5QZ1WNSGDg8ZAXoTEmjj0VS8xPasjKlEwXDJRPzPrRtb5T70r85jkv8o6sOc398U6yyrx3Np9nVR+Ut58jt+4r37U97fpV0dJ3/0f9u6XoFaG74WRwoPL7d/Pv3VX34GQv1+Xe/MvSwODBlY2WH1yKUj00ry5VLdiwq6XkeINqyDUx76WsuZySEQ/+vT3rtHDDHQ+Gwm8aNz9bGM/tqZ590Mv+erQrc1iH76+dlRvdtHg2Vz1cvGGJRelF0ft3Ul6vePr0bsFk8cq53Bu6boheXXS6sdbhR8z2/PfPt+3/eeb2Hfvcrcvf3zr4qrFlzuZydcYFMxK5WTaUSEjO6bSaqnSMVXnbzKu9yW8q1Mv33N///bv1wX/xkadzck6yiBp0/uXcqKA944T7/bLGq5Nvb52454cRF8++TPbfuUkrRNIZRM2NlPU3Gp2RWJf+TCxhKfetyIgvNkncL+pTl7ktd7gq5PFl+7sKfznXkF+73f99Sy51+ilqaFW6/kvf+9/7/6yy40mQNrblEjwXHfD/TOLnzfz/zvnfs/etf7+z/FLIyvOJbBvKN7U//3Sqm813r937+7/vXSu7UHXLOiJ4ZX+SsF3J2p0rz9vnsK1d/u/dxKxC+cnr0+u7Mq5uPFi21stM3LhxKrfOHe5z1WdmlZw76X9L8lqm3y29tZY3NF5tv2fcUXBjuUndrWV+hyRjqtJe7PibF+HwPuX9l6P995rLvr9/v0ud/WBz/u7jc1/633v+Z6+FaVe37P7jFgUvS4NOi2zJ8FN353u25ZHEzPh8nrzdLY2Np2Yl6O1pkpS8PIf7vJOe3MOlXjcsjyi/WfZThC+/+vr92y/kytkW/7q1xEnxvbZou6hr5gyR6dyHRZY8P+SQxZlzrt3oR/T55t5nCTbsi3/dOuKoW7qO37lwp92SI2e32N3ZcMbcUY5Nv22di9yl4OefDESmn3b2ujP1dPMfkb0n5Q4ZMMkeZTjqonwrcfknyxdJPVIuM50bOSdtspz0/Euu9O3p7z7mv6xfqPWvsfOBdk7gz82ZG0O6Lk9VcYhYkp/hM+/J7UkPHv5SmaEY78Whk7eK+UWO2n616yHPCp12x2T/kWdg+P8/wJudo1B/1aqHzAwMtxQZGGBlBQPDRbSygh1RVoCLh+rmQ4kg3chqArwZmUSYEWUNssmgsgYGtjWCSLwlD8Io7E6BAAGG/446LAxYHMbKBpJnYmBi6GRgYMhiAfEAAQAA//8tF7e5CQUAAA=="); err != nil {
|
||||
panic("add binary content to resource manager failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user