microsite.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package microsite
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "path"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/hashicorp/go-multierror"
  13. archiver "github.com/mholt/archiver/v4"
  14. "github.com/qor/oss"
  15. "github.com/qor5/admin/microsite/utils"
  16. "github.com/qor5/admin/publish"
  17. "gorm.io/gorm"
  18. )
  19. type MicroSite struct {
  20. gorm.Model
  21. publish.Status
  22. publish.Schedule
  23. publish.Version
  24. PrePath string
  25. Package FileSystem `gorm:"type:text"`
  26. FilesList string `gorm:"type:text"`
  27. UnixKey string
  28. }
  29. func (this *MicroSite) PermissionRN() []string {
  30. return []string{"microsite_models", strconv.Itoa(int(this.ID)), this.Version.Version}
  31. }
  32. func (this *MicroSite) PrimarySlug() string {
  33. return fmt.Sprintf("%v_%v", this.ID, this.Version.Version)
  34. }
  35. func (this *MicroSite) PrimaryColumnValuesBySlug(slug string) map[string]string {
  36. segs := strings.Split(slug, "_")
  37. if len(segs) != 2 {
  38. panic("wrong slug")
  39. }
  40. return map[string]string{
  41. "id": segs[0],
  42. "version": segs[1],
  43. }
  44. }
  45. func (this MicroSite) GetID() uint {
  46. return this.ID
  47. }
  48. func (this MicroSite) GetUnixKey() string {
  49. return this.UnixKey
  50. }
  51. func (this *MicroSite) SetUnixKey() {
  52. this.UnixKey = strconv.FormatInt(time.Now().UnixMilli(), 10)
  53. return
  54. }
  55. func (this MicroSite) GetPackagePath(fileName string) string {
  56. return strings.TrimPrefix(path.Join(PackageAndPreviewPrepath, "__package__", this.GetUnixKey(), fileName), "/")
  57. }
  58. func (this MicroSite) GetPreviewPath(fileName string) string {
  59. return strings.TrimPrefix(path.Join(PackageAndPreviewPrepath, "__preview__", this.GetUnixKey(), fileName), "/")
  60. }
  61. func (this MicroSite) GetPreviewUrl(domain, fileName string) string {
  62. return strings.TrimSuffix(domain, "/") + "/" + this.GetPreviewPath(fileName)
  63. }
  64. func (this MicroSite) GetPublishedPath(fileName string) string {
  65. return path.Join(strings.TrimPrefix(strings.TrimSuffix(this.PrePath, "/"), "/"), fileName)
  66. }
  67. func (this MicroSite) GetPublishedUrl(domain, fileName string) string {
  68. return strings.TrimSuffix(domain, "/") + "/" + this.GetPublishedPath(fileName)
  69. }
  70. func (this MicroSite) GetPackageUrl(domain string) string {
  71. return strings.TrimSuffix(domain, "/") + "/" + strings.TrimPrefix(this.Package.Url, "/")
  72. }
  73. func (this MicroSite) GetFileList() (arr []string) {
  74. json.Unmarshal([]byte(this.FilesList), &arr)
  75. return
  76. }
  77. func (this *MicroSite) SetFilesList(filesList []string) {
  78. list, err := json.Marshal(filesList)
  79. if err != nil {
  80. return
  81. }
  82. this.FilesList = string(list)
  83. return
  84. }
  85. func (this *MicroSite) GetPackage() FileSystem {
  86. return this.Package
  87. }
  88. func (this *MicroSite) SetPackage(fileName, url string) {
  89. this.Package.FileName = fileName
  90. this.Package.Url = url
  91. return
  92. }
  93. func (this *MicroSite) GetPublishActions(db *gorm.DB, ctx context.Context, storage oss.StorageInterface) (objs []*publish.PublishAction, err error) {
  94. if len(this.GetFileList()) > 0 {
  95. var previewPaths []string
  96. var wg = sync.WaitGroup{}
  97. var copyError error
  98. var mutex sync.Mutex
  99. for _, v := range this.GetFileList() {
  100. wg.Add(1)
  101. copySemaphore <- struct{}{}
  102. go func(v string) {
  103. defer func() {
  104. wg.Done()
  105. <-copySemaphore
  106. }()
  107. err = utils.Copy(storage, this.GetPreviewPath(v), this.GetPublishedPath(v))
  108. if err != nil {
  109. mutex.Lock()
  110. copyError = multierror.Append(copyError, err).ErrorOrNil()
  111. mutex.Unlock()
  112. return
  113. }
  114. mutex.Lock()
  115. previewPaths = append(previewPaths, this.GetPreviewPath(v))
  116. mutex.Unlock()
  117. }(v)
  118. }
  119. wg.Wait()
  120. if len(previewPaths) > 0 {
  121. err = utils.DeleteObjects(storage, previewPaths)
  122. }
  123. err = multierror.Append(err, copyError).ErrorOrNil()
  124. }
  125. return
  126. }
  127. func (this *MicroSite) GetUnPublishActions(db *gorm.DB, ctx context.Context, storage oss.StorageInterface) (objs []*publish.PublishAction, err error) {
  128. var paths []string
  129. for _, v := range this.GetFileList() {
  130. paths = append(paths, this.GetPublishedPath(v))
  131. }
  132. err = utils.DeleteObjects(storage, paths)
  133. if err != nil {
  134. return
  135. }
  136. return
  137. }
  138. func (this *MicroSite) UnArchiveAndPublish(getPath func(string) string, fileName string, f io.Reader, storage oss.StorageInterface) (filesList []string, err error) {
  139. format, reader, err := archiver.Identify(fileName, f)
  140. if err != nil {
  141. if err == archiver.ErrNoMatch {
  142. err = utils.Upload(storage, getPath(fileName), f)
  143. return
  144. }
  145. return
  146. }
  147. var wg = sync.WaitGroup{}
  148. var putError error
  149. var mutex sync.Mutex
  150. err = format.(archiver.Extractor).Extract(context.Background(), reader, nil, func(ctx context.Context, f archiver.File) (err error) {
  151. if f.IsDir() {
  152. return
  153. }
  154. rc, err := f.Open()
  155. if err != nil {
  156. return
  157. }
  158. defer rc.Close()
  159. filesList = append(filesList, f.NameInArchive)
  160. publishedPath := getPath(f.NameInArchive)
  161. wg.Add(1)
  162. putSemaphore <- struct{}{}
  163. go func() {
  164. defer func() {
  165. <-putSemaphore
  166. wg.Done()
  167. }()
  168. err2 := utils.Upload(storage, publishedPath, rc)
  169. if err2 != nil {
  170. mutex.Lock()
  171. putError = multierror.Append(putError, err2).ErrorOrNil()
  172. mutex.Unlock()
  173. }
  174. }()
  175. return
  176. })
  177. wg.Wait()
  178. err = multierror.Append(err, putError).ErrorOrNil()
  179. return
  180. }