plugins_manage.go 13 KB

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