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.

switch.go 5.0 kB

2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package ioswitch
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "sync"
  7. "gitlink.org.cn/cloudream/common/pkgs/future"
  8. "gitlink.org.cn/cloudream/common/pkgs/logger"
  9. "gitlink.org.cn/cloudream/common/utils/lo2"
  10. )
  11. var ErrPlanFinished = errors.New("plan is finished")
  12. var ErrPlanNotFound = errors.New("plan not found")
  13. type OpState string
  14. const (
  15. OpPending OpState = "Pending"
  16. OpFinished OpState = "Finished"
  17. )
  18. type Oping struct {
  19. State OpState
  20. }
  21. type PlanResult struct {
  22. Values map[string]any `json:"values"`
  23. }
  24. type Planning struct {
  25. plan Plan
  26. opings []Oping
  27. resultValues map[string]any
  28. callback *future.SetValueFuture[PlanResult]
  29. readys map[StreamID]Stream
  30. waittings []*Watting
  31. }
  32. func NewPlanning(plan Plan) Planning {
  33. planning := Planning{
  34. plan: plan,
  35. resultValues: make(map[string]any),
  36. callback: future.NewSetValue[PlanResult](),
  37. readys: make(map[StreamID]Stream),
  38. }
  39. for range plan.Ops {
  40. oping := Oping{
  41. State: OpPending,
  42. }
  43. planning.opings = append(planning.opings, oping)
  44. }
  45. return planning
  46. }
  47. func (p *Planning) IsCompleted() bool {
  48. for _, oping := range p.opings {
  49. if oping.State != OpFinished {
  50. return false
  51. }
  52. }
  53. return true
  54. }
  55. func (p *Planning) MakeResult() PlanResult {
  56. return PlanResult{
  57. Values: p.resultValues,
  58. }
  59. }
  60. type Watting struct {
  61. WaitIDs []StreamID
  62. Readys []Stream
  63. Callback *future.SetValueFuture[[]Stream]
  64. }
  65. func (w *Watting) TryReady(str Stream) bool {
  66. for i, id := range w.WaitIDs {
  67. if id == str.ID {
  68. w.Readys[i] = str
  69. return true
  70. }
  71. }
  72. return false
  73. }
  74. func (c *Watting) IsAllReady() bool {
  75. for _, s := range c.Readys {
  76. if s.Stream == nil {
  77. return false
  78. }
  79. }
  80. return true
  81. }
  82. func (w *Watting) Complete() {
  83. w.Callback.SetValue(w.Readys)
  84. }
  85. func (w *Watting) Cancel(err error) {
  86. w.Callback.SetError(err)
  87. }
  88. type Switch struct {
  89. lock sync.Mutex
  90. plannings map[PlanID]*Planning
  91. }
  92. func NewSwitch() Switch {
  93. return Switch{
  94. plannings: make(map[PlanID]*Planning),
  95. }
  96. }
  97. func (s *Switch) SetupPlan(plan Plan) error {
  98. s.lock.Lock()
  99. defer s.lock.Unlock()
  100. if _, ok := s.plannings[plan.ID]; ok {
  101. return fmt.Errorf("plan id exists")
  102. }
  103. planning := NewPlanning(plan)
  104. s.plannings[plan.ID] = &planning
  105. return nil
  106. }
  107. func (s *Switch) ExecutePlan(id PlanID) (PlanResult, error) {
  108. s.lock.Lock()
  109. planning, ok := s.plannings[id]
  110. if !ok {
  111. s.lock.Unlock()
  112. return PlanResult{}, fmt.Errorf("plan not found")
  113. }
  114. for i, op := range planning.plan.Ops {
  115. idx := i
  116. o := op
  117. go func() {
  118. err := o.Execute(s, id)
  119. s.lock.Lock()
  120. defer s.lock.Unlock()
  121. if err != nil {
  122. logger.Std.Warnf("exeucting op: %s", err.Error())
  123. s.cancelPlan(id)
  124. return
  125. }
  126. planning.opings[idx].State = OpFinished
  127. if planning.IsCompleted() {
  128. s.completePlan(id)
  129. }
  130. }()
  131. }
  132. s.lock.Unlock()
  133. return planning.callback.WaitValue(context.TODO())
  134. }
  135. func (s *Switch) CancelPlan(id PlanID) {
  136. s.lock.Lock()
  137. defer s.lock.Unlock()
  138. s.cancelPlan(id)
  139. }
  140. func (s *Switch) cancelPlan(id PlanID) {
  141. plan, ok := s.plannings[id]
  142. if !ok {
  143. return
  144. }
  145. delete(s.plannings, id)
  146. for _, s := range plan.readys {
  147. s.Stream.Close()
  148. }
  149. for _, c := range plan.waittings {
  150. c.Callback.SetError(ErrPlanFinished)
  151. }
  152. plan.callback.SetError(fmt.Errorf("plan cancelled"))
  153. }
  154. func (s *Switch) completePlan(id PlanID) {
  155. plan, ok := s.plannings[id]
  156. if !ok {
  157. return
  158. }
  159. delete(s.plannings, id)
  160. for _, s := range plan.readys {
  161. s.Stream.Close()
  162. }
  163. for _, c := range plan.waittings {
  164. c.Callback.SetError(ErrPlanFinished)
  165. }
  166. plan.callback.SetValue(plan.MakeResult())
  167. }
  168. func (s *Switch) StreamReady(planID PlanID, stream Stream) {
  169. s.lock.Lock()
  170. defer s.lock.Unlock()
  171. plan, ok := s.plannings[planID]
  172. if !ok {
  173. //TODO 处理错误
  174. return
  175. }
  176. for i, wa := range plan.waittings {
  177. if !wa.TryReady(stream) {
  178. continue
  179. }
  180. if !wa.IsAllReady() {
  181. return
  182. }
  183. plan.waittings = lo2.RemoveAt(plan.waittings, i)
  184. wa.Complete()
  185. return
  186. }
  187. plan.readys[stream.ID] = stream
  188. }
  189. func (s *Switch) WaitStreams(planID PlanID, streamIDs ...StreamID) ([]Stream, error) {
  190. s.lock.Lock()
  191. plan, ok := s.plannings[planID]
  192. if !ok {
  193. s.lock.Unlock()
  194. return nil, ErrPlanNotFound
  195. }
  196. allReady := true
  197. readys := make([]Stream, len(streamIDs))
  198. for i, id := range streamIDs {
  199. str, ok := plan.readys[id]
  200. if !ok {
  201. allReady = false
  202. continue
  203. }
  204. readys[i] = str
  205. delete(plan.readys, id)
  206. }
  207. if allReady {
  208. s.lock.Unlock()
  209. return readys, nil
  210. }
  211. callback := future.NewSetValue[[]Stream]()
  212. plan.waittings = append(plan.waittings, &Watting{
  213. WaitIDs: streamIDs,
  214. Readys: readys,
  215. Callback: callback,
  216. })
  217. s.lock.Unlock()
  218. return callback.WaitValue(context.TODO())
  219. }
  220. func (s *Switch) AddResultValue(planID PlanID, rets ...ResultKV) {
  221. s.lock.Lock()
  222. defer s.lock.Unlock()
  223. plan, ok := s.plannings[planID]
  224. if !ok {
  225. return
  226. }
  227. for _, ret := range rets {
  228. plan.resultValues[ret.Key] = ret.Value
  229. }
  230. }

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