plugins_manage.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. // ==========================================================================
  2. // GFast自动生成业务逻辑层相关代码,只生成一次,按需修改,再次生成不会覆盖.
  3. // 生成日期:2021-08-31 17:58:43
  4. // 生成路径: gfast/app/system/service/plugins_manage.go
  5. // 生成人:gfast
  6. // ==========================================================================
  7. package service
  8. import (
  9. "context"
  10. "encoding/json"
  11. "fmt"
  12. "gfast/app/common/global"
  13. "gfast/app/system/dao"
  14. "gfast/app/system/model"
  15. "github.com/gogf/gf/container/garray"
  16. "github.com/gogf/gf/container/gmap"
  17. "github.com/gogf/gf/encoding/gcompress"
  18. "github.com/gogf/gf/encoding/gjson"
  19. "github.com/gogf/gf/encoding/gurl"
  20. "github.com/gogf/gf/errors/gerror"
  21. "github.com/gogf/gf/frame/g"
  22. "github.com/gogf/gf/net/ghttp"
  23. "github.com/gogf/gf/os/gfile"
  24. "github.com/gogf/gf/text/gstr"
  25. "github.com/gogf/gf/util/gconv"
  26. )
  27. type pluginsManage struct {
  28. }
  29. var PluginsManage = new(pluginsManage)
  30. // GetList 获取列表
  31. func (s *pluginsManage) GetList(req *dao.PluginsManageSearchReq) (total, page int, list []*dao.CsPluginListRes, err error) {
  32. //同步服务端插件商城
  33. total, page, list, err = s.syncFromStore(req)
  34. return
  35. }
  36. // GetInfoById 通过id获取
  37. func (s *pluginsManage) GetInfoById(ctx context.Context, id int64) (info *dao.PluginsManageInfoRes, err error) {
  38. if id == 0 {
  39. err = gerror.New("参数错误")
  40. return
  41. }
  42. var data *model.PluginsManage
  43. err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.Id, id).Scan(&data)
  44. if err != nil {
  45. g.Log().Error(err)
  46. }
  47. if data == nil || err != nil {
  48. err = gerror.New("获取信息失败")
  49. }
  50. info = &dao.PluginsManageInfoRes{
  51. Id: data.Id,
  52. StoreId: data.StoreId,
  53. PName: data.PName,
  54. PTitle: data.PTitle,
  55. PDescription: data.PDescription,
  56. PAuth: data.PAuth,
  57. IsInstall: data.IsInstall,
  58. Status: data.Status,
  59. Version: data.Version,
  60. Price: data.Price,
  61. DownloadTimes: data.DownloadTimes,
  62. }
  63. return
  64. }
  65. // Add 添加
  66. func (s *pluginsManage) Add(ctx context.Context, req *dao.PluginsManageAddReq) (err error) {
  67. _, err = dao.PluginsManage.Ctx(ctx).Insert(req)
  68. return
  69. }
  70. // Edit 修改
  71. func (s *pluginsManage) Edit(ctx context.Context, req *dao.PluginsManageEditReq) error {
  72. _, err := dao.PluginsManage.Ctx(ctx).FieldsEx(dao.PluginsManage.Columns.Id).Where(dao.PluginsManage.Columns.Id, req.Id).
  73. Update(req)
  74. return err
  75. }
  76. // DeleteByIds 删除
  77. func (s *pluginsManage) DeleteByIds(ctx context.Context, ids []int) (err error) {
  78. if len(ids) == 0 {
  79. err = gerror.New("参数错误")
  80. return
  81. }
  82. _, err = dao.PluginsManage.Ctx(ctx).Delete(dao.PluginsManage.Columns.Id+" in (?)", ids)
  83. if err != nil {
  84. g.Log().Error(err)
  85. err = gerror.New("删除失败")
  86. }
  87. return
  88. }
  89. // ChangeStatus 修改状态
  90. func (s *pluginsManage) ChangeStatus(ctx context.Context, req *dao.PluginsManageStatusReq) error {
  91. _, err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId, req.PluginId).Update(g.Map{
  92. dao.PluginsManage.Columns.Status: req.Status,
  93. })
  94. return err
  95. }
  96. //同步插件商城中的插件
  97. func (s *pluginsManage) syncFromStore(req *dao.PluginsManageSearchReq) (total, page int, csPluginList []*dao.CsPluginListRes, err error) {
  98. storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStore/pluginList"
  99. res := (*ghttp.ClientResponse)(nil)
  100. if req.PageNum == 0 {
  101. req.PageNum = 1
  102. }
  103. page = req.PageNum
  104. res, err = g.Client().Ctx(req.Ctx).Get(storeUrl, g.MapStrAny{
  105. "pageNum": req.PageNum,
  106. "PageSize": req.PageSize,
  107. "pluginName": req.PTitle,
  108. })
  109. if err != nil {
  110. g.Log().Error(err)
  111. err = gerror.New("获取插件数据失败")
  112. return
  113. }
  114. defer res.Close()
  115. var data map[string]interface{}
  116. b := res.ReadAll()
  117. err = json.Unmarshal(b, &data)
  118. if err != nil {
  119. g.Log().Error(err)
  120. err = gerror.New("获取插件数据失败")
  121. return
  122. }
  123. if gconv.Int(data["code"]) == 0 {
  124. err = gconv.Structs((data["data"].(g.Map))["list"], &csPluginList)
  125. if err != nil {
  126. return
  127. }
  128. csPluginList, err = s.updatePlugins(req.Ctx, csPluginList)
  129. if err != nil {
  130. return
  131. }
  132. total = gconv.Int((data["data"].(g.Map))["total"])
  133. } else {
  134. err = gerror.New(data["msg"].(string))
  135. return
  136. }
  137. return
  138. }
  139. // 更新插件数据
  140. func (s *pluginsManage) updatePlugins(ctx context.Context, csList []*dao.CsPluginListRes) (newList []*dao.CsPluginListRes, err error) {
  141. ids := make([]uint, len(csList))
  142. for k, v := range csList {
  143. ids[k] = v.PluginId
  144. }
  145. //查询插件信息
  146. var pluginList []*model.PluginsManage
  147. err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId+" in(?)", ids).Scan(&pluginList)
  148. if err != nil {
  149. return
  150. }
  151. hasIds := garray.NewArraySize(len(pluginList), 100)
  152. gmp := gmap.New()
  153. for k, v := range pluginList {
  154. hasIds.Set(k, v.StoreId)
  155. gmp.Set(v.StoreId, v)
  156. }
  157. for _, v := range csList {
  158. pluginId := gconv.Int(v.PluginId)
  159. if hasIds.Len() > 0 && hasIds.Contains(pluginId) {
  160. plugin := gmp.Get(pluginId).(*model.PluginsManage)
  161. //修改
  162. version := plugin.Version
  163. if plugin.IsInstall == 0 && len(v.PluginInfo) > 0 {
  164. version = v.PluginInfo[0].InfoVersion
  165. }
  166. err = s.Edit(ctx, &dao.PluginsManageEditReq{
  167. Id: plugin.Id,
  168. StoreId: pluginId,
  169. PName: v.CodeName,
  170. PTitle: v.PluginName,
  171. PDescription: v.Description,
  172. PAuth: v.MemName,
  173. Status: plugin.Status,
  174. Version: version,
  175. Price: v.PluginPrice,
  176. DownloadTimes: gconv.Uint(v.DownloadTimes),
  177. IsInstall: plugin.IsInstall,
  178. })
  179. v.Status = plugin.Status
  180. v.Version = version
  181. v.IsInstall = plugin.IsInstall
  182. v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
  183. } else {
  184. //新增
  185. version := ""
  186. if len(v.PluginInfo) > 0 {
  187. version = v.PluginInfo[0].InfoVersion
  188. }
  189. err = s.Add(ctx, &dao.PluginsManageAddReq{
  190. StoreId: pluginId,
  191. PName: v.CodeName,
  192. PTitle: v.PluginName,
  193. PDescription: v.Description,
  194. PAuth: v.MemName,
  195. Status: 0,
  196. Version: version,
  197. Price: v.PluginPrice,
  198. DownloadTimes: gconv.Uint(v.DownloadTimes),
  199. IsInstall: 0,
  200. })
  201. v.Status = 0
  202. v.Version = version
  203. v.IsInstall = 0
  204. v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
  205. }
  206. if err != nil {
  207. return
  208. }
  209. }
  210. newList = csList
  211. return
  212. }
  213. // DecimalToInt64 元转分
  214. func (s *pluginsManage) DecimalToInt64(decimal string) (i int64) {
  215. pos := gstr.PosR(decimal, ".")
  216. integer := gconv.Int64(gstr.SubStr(decimal, 0, pos)) * 100
  217. dec := int64(0)
  218. if pos > -1 {
  219. dec = gconv.Int64(gstr.SubStr(decimal, pos+1, 2))
  220. }
  221. i = integer + dec
  222. return
  223. }
  224. // Int64ToDecimal 分转元
  225. func (s *pluginsManage) Int64ToDecimal(i int64) (decimal string) {
  226. b := []byte(gconv.String(i))
  227. for {
  228. if len(b) >= 2 {
  229. break
  230. }
  231. b = append([]byte{'0'}, b...)
  232. }
  233. integer := b[:len(b)-2]
  234. if len(integer) == 0 {
  235. integer = []byte{'0'}
  236. }
  237. dec := b[len(b)-2:]
  238. decimal = fmt.Sprintf("%s.%s", integer, dec)
  239. return
  240. }
  241. // Install 插件安装
  242. func (s *pluginsManage) Install(ctx context.Context, req *dao.PluginsManageInstallReq) (err error) {
  243. //生成下载链接
  244. storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/getDownloadInfo"
  245. res := (*ghttp.ClientResponse)(nil)
  246. res, err = g.Client().Ctx(ctx).Get(fmt.Sprintf("%s?pluginId=%d&version=%s&token=%s", storeUrl, req.PluginId, req.Version,
  247. gurl.RawEncode(req.RToken)))
  248. if err != nil {
  249. return
  250. }
  251. defer res.Close()
  252. var data map[string]interface{}
  253. b := res.ReadAll()
  254. err = json.Unmarshal(b, &data)
  255. if err != nil {
  256. return
  257. }
  258. if gconv.Int(data["code"]) == 0 {
  259. url := fmt.Sprintf("%s/%s&token=%s", g.Cfg().GetString("plugin.serverUrl"),
  260. (data["data"]).(string), gurl.RawEncode(req.RToken))
  261. //下载插件并安装
  262. err = s.downloadAndInstall(ctx, url)
  263. } else {
  264. err = gerror.New(data["msg"].(string))
  265. }
  266. return
  267. }
  268. // GetCaptcha 获取验证码
  269. func (s *pluginsManage) GetCaptcha(ctx context.Context) (idKeyC, base64stringC string, err error) {
  270. storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/captcha/get"
  271. res := (*ghttp.ClientResponse)(nil)
  272. res, err = g.Client().Ctx(ctx).Get(storeUrl)
  273. if err != nil {
  274. g.Log().Error(err)
  275. err = gerror.New("获取验证码失败")
  276. return
  277. }
  278. defer res.Close()
  279. var data map[string]interface{}
  280. b := res.ReadAll()
  281. err = json.Unmarshal(b, &data)
  282. if err != nil {
  283. g.Log().Error(err)
  284. err = gerror.New("获取插件数据失败")
  285. return
  286. }
  287. if gconv.Int(data["code"]) == 0 {
  288. data = (data["data"]).(g.Map)
  289. idKeyC = gconv.String(data["idKeyC"])
  290. base64stringC = gconv.String(data["base64stringC"])
  291. } else {
  292. err = gerror.New(data["msg"].(string))
  293. }
  294. return
  295. }
  296. // LoginR 登录
  297. func (s *pluginsManage) LoginR(ctx context.Context, loginReq *dao.PluginRLoginFormReq) (userInfo g.Map, err error) {
  298. storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/login"
  299. res := (*ghttp.ClientResponse)(nil)
  300. res, err = g.Client().Ctx(ctx).Post(storeUrl, loginReq)
  301. if err != nil {
  302. g.Log().Error(err)
  303. err = gerror.New("获取验证码失败")
  304. return
  305. }
  306. defer res.Close()
  307. var data map[string]interface{}
  308. b := res.ReadAll()
  309. err = json.Unmarshal(b, &data)
  310. if err != nil {
  311. g.Log().Error(err)
  312. err = gerror.New("登录失败")
  313. return
  314. }
  315. if gconv.Int(data["code"]) == 0 {
  316. userInfo = (data["data"]).(g.Map)
  317. } else {
  318. err = gerror.New(data["msg"].(string))
  319. }
  320. return
  321. }
  322. // 下载并安装插件
  323. func (s *pluginsManage) downloadAndInstall(ctx context.Context, url string) error {
  324. res, err := g.Client().Ctx(ctx).Get(url)
  325. if err != nil {
  326. return err
  327. }
  328. defer res.Close()
  329. ct := res.Header.Get("Content-Type")
  330. if gstr.ContainsI(ct, "json") {
  331. var data map[string]interface{}
  332. b := res.ReadAll()
  333. err = json.Unmarshal(b, &data)
  334. if err != nil {
  335. return err
  336. }
  337. if gconv.Int(data["code"]) != 0 {
  338. err = gerror.New(data["msg"].(string))
  339. }
  340. return err
  341. } else {
  342. //安装
  343. //获取插件名称
  344. fileName := res.Header.Get("content-disposition")
  345. fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
  346. gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
  347. err = s.InstallFile(ctx, res.ReadAll(), fileName)
  348. if err != nil {
  349. return err
  350. }
  351. }
  352. return nil
  353. }
  354. // InstallFile 安装插件文件
  355. func (s *pluginsManage) InstallFile(ctx context.Context, data []byte, fileName string) (err error) {
  356. //获取插件下载路径
  357. downloadPath := gfile.MainPkgPath() + "/data/installPlugins"
  358. if !gfile.IsDir(downloadPath) {
  359. err = gfile.Mkdir(downloadPath)
  360. if err != nil {
  361. return
  362. }
  363. }
  364. g.Log().Debug(downloadPath, fileName)
  365. // 删除安装临时文件
  366. defer gfile.Remove(downloadPath + "/" + fileName)
  367. err = gcompress.UnZipContent(data, downloadPath)
  368. if err != nil {
  369. return
  370. }
  371. //获取插件配置信息
  372. var installCfg *gjson.Json
  373. installCfg, err = gjson.Load(downloadPath + "/" + fileName + "/install.json")
  374. if err != nil {
  375. return
  376. }
  377. mustGfastVersion := installCfg.GetString("minGfastVersion")
  378. if gstr.CompareVersion(mustGfastVersion, global.Version) > 0 {
  379. err = gerror.New(fmt.Sprintf("您的gfast版本过低,此插件要求gfast版本为:%s", mustGfastVersion))
  380. return
  381. }
  382. //获取本项目安装情况
  383. var plugin *model.PluginsManage
  384. err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, fileName).Limit(1).Scan(&plugin)
  385. if err != nil {
  386. return
  387. }
  388. if plugin == nil {
  389. err = gerror.New("插件信息不存在,请刷新页面后再安装。")
  390. return
  391. }
  392. //复制插件文件到对应目录
  393. //1.后端
  394. err = gfile.Copy(downloadPath+"/"+fileName+"/go/", gfile.MainPkgPath())
  395. if err != nil {
  396. return
  397. }
  398. //2.前端
  399. fontRoot := g.Cfg().GetString("gen.frontDir")
  400. if !gfile.IsDir(fontRoot) {
  401. err = gerror.New("前端路径不存在,请配置gen.frontDir")
  402. return
  403. }
  404. err = gfile.Copy(downloadPath+"/"+fileName+"/vue/", fontRoot+"/src")
  405. if err != nil {
  406. return
  407. }
  408. // 安装成功后修改插件安装状态及安装路径
  409. _, err = dao.PluginsManage.Ctx(ctx).WherePri(plugin.Id).Update(g.Map{
  410. dao.PluginsManage.Columns.IsInstall: 1,
  411. dao.PluginsManage.Columns.Status: 1,
  412. dao.PluginsManage.Columns.InstallPath: installCfg.GetString("installPath"),
  413. dao.PluginsManage.Columns.Version: installCfg.GetString("version"),
  414. })
  415. return
  416. }
  417. // PluginIsExists 判断插件是否存在
  418. func (s *pluginsManage) PluginIsExists(ctx context.Context, name string) error {
  419. info := (*model.PluginsManage)(nil)
  420. err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, name).Limit(1).
  421. Fields(dao.PluginsManage.Columns.Id).Scan(&info)
  422. if err != nil {
  423. return err
  424. }
  425. if info == nil {
  426. return gerror.New("不属于官方插件,无法安装。")
  427. }
  428. return nil
  429. }