You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

space_syncer.go 4.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package spacesyncer
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "gitlink.org.cn/cloudream/common/pkgs/async"
  7. "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
  9. "gitlink.org.cn/cloudream/jcs-pub/client/internal/metacache"
  10. stgpool "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
  11. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  12. )
  13. const (
  14. logMod = "SpaceSyncer"
  15. )
  16. type SpaceSyncerEvent interface {
  17. IsSpaceSyncerEvent() bool
  18. }
  19. type SpaceSyncer struct {
  20. db *db.DB
  21. stgPool *stgpool.Pool
  22. spaceMeta *metacache.UserSpaceMeta
  23. lock sync.Mutex
  24. tasks map[jcstypes.SpaceSyncTaskID]*task
  25. }
  26. func New(db *db.DB, stgPool *stgpool.Pool, spaceMeta *metacache.UserSpaceMeta) *SpaceSyncer {
  27. return &SpaceSyncer{
  28. db: db,
  29. stgPool: stgPool,
  30. spaceMeta: spaceMeta,
  31. tasks: make(map[jcstypes.SpaceSyncTaskID]*task),
  32. }
  33. }
  34. func (s *SpaceSyncer) Start() *async.UnboundChannel[SpaceSyncerEvent] {
  35. s.lock.Lock()
  36. defer s.lock.Unlock()
  37. log := logger.WithField("Mod", logMod)
  38. ch := async.NewUnboundChannel[SpaceSyncerEvent]()
  39. allTask, err := db.DoTx01(s.db, s.db.SpaceSyncTask().GetAll)
  40. if err != nil {
  41. log.Warnf("load task from db: %v", err)
  42. } else {
  43. var rms []jcstypes.SpaceSyncTaskID
  44. for _, t := range allTask {
  45. ctx, cancel := context.WithCancel(context.Background())
  46. tsk := task{
  47. Task: t,
  48. Context: ctx,
  49. CancelFn: cancel,
  50. }
  51. switch tr := t.Trigger.(type) {
  52. case *jcstypes.SpaceSyncTriggerOnce:
  53. // Once类型的任务没有执行完也不执行了
  54. rms = append(rms, t.TaskID)
  55. case *jcstypes.SpaceSyncTriggerInterval:
  56. triggerInterval(s, &tsk, tr)
  57. case *jcstypes.SpaceSyncTriggerAt:
  58. triggerAt(s, &tsk, tr)
  59. }
  60. log.Infof("load task %v from db", t.TaskID)
  61. }
  62. if len(rms) > 0 {
  63. err := s.db.SpaceSyncTask().BatchDelete(s.db.DefCtx(), rms)
  64. if err != nil {
  65. log.Warnf("batch delete task: %v", err)
  66. } else {
  67. log.Infof("%v once task deleted", len(rms))
  68. }
  69. }
  70. }
  71. return ch
  72. }
  73. func (s *SpaceSyncer) Stop() {
  74. s.lock.Lock()
  75. defer s.lock.Unlock()
  76. for _, t := range s.tasks {
  77. t.CancelFn()
  78. }
  79. s.tasks = make(map[jcstypes.SpaceSyncTaskID]*task)
  80. }
  81. func (s *SpaceSyncer) CreateTask(t jcstypes.SpaceSyncTask) (*TaskInfo, error) {
  82. log := logger.WithField("Mod", logMod)
  83. d := s.db
  84. err := d.DoTx(func(tx db.SQLContext) error {
  85. err := d.SpaceSyncTask().Create(tx, &t)
  86. if err != nil {
  87. return err
  88. }
  89. return nil
  90. })
  91. if err != nil {
  92. return nil, fmt.Errorf("creating space sync task: %w", err)
  93. }
  94. ctx, cancel := context.WithCancel(context.Background())
  95. tsk := task{
  96. Task: t,
  97. Context: ctx,
  98. CancelFn: cancel,
  99. }
  100. s.lock.Lock()
  101. s.tasks[t.TaskID] = &tsk
  102. s.lock.Unlock()
  103. switch tr := t.Trigger.(type) {
  104. case *jcstypes.SpaceSyncTriggerOnce:
  105. triggerOnce(s, &tsk)
  106. case *jcstypes.SpaceSyncTriggerInterval:
  107. triggerInterval(s, &tsk, tr)
  108. case *jcstypes.SpaceSyncTriggerAt:
  109. triggerAt(s, &tsk, tr)
  110. }
  111. log.Infof("task %v created", t.TaskID)
  112. return &TaskInfo{
  113. Task: t,
  114. }, nil
  115. }
  116. func (s *SpaceSyncer) CancelTask(taskID jcstypes.SpaceSyncTaskID) {
  117. log := logger.WithField("Mod", logMod)
  118. s.lock.Lock()
  119. defer s.lock.Unlock()
  120. t := s.tasks[taskID]
  121. if t == nil {
  122. log.Infof("task %v not found, cancel aborted", taskID)
  123. return
  124. }
  125. t.CancelFn()
  126. delete(s.tasks, taskID)
  127. err := s.db.SpaceSyncTask().Delete(s.db.DefCtx(), taskID)
  128. if err != nil {
  129. log.Warnf("delete task %v from db: %v", taskID, err)
  130. }
  131. log.Infof("task %v canceled", taskID)
  132. }
  133. func (s *SpaceSyncer) GetTask(taskID jcstypes.SpaceSyncTaskID) *jcstypes.SpaceSyncTask {
  134. s.lock.Lock()
  135. defer s.lock.Unlock()
  136. tsk := s.tasks[taskID]
  137. if tsk == nil {
  138. return nil
  139. }
  140. // TODO 考虑复制一份状态,防止修改
  141. t := tsk.Task
  142. return &t
  143. }
  144. type TaskInfo struct {
  145. Task jcstypes.SpaceSyncTask
  146. }
  147. type task struct {
  148. Task jcstypes.SpaceSyncTask
  149. Context context.Context
  150. CancelFn func()
  151. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。