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.

urchinfs.go 6.8 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package urchin
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "io/ioutil"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "code.gitea.io/gitea/modules/urfs_client/config"
  11. urfs "code.gitea.io/gitea/modules/urfs_client/dfstore"
  12. )
  13. type Urchinfs interface {
  14. //// schedule source dataset to target peer
  15. //ScheduleDataToPeer(sourceUrl, destPeerHost string) (*PeerResult, error)
  16. //
  17. //// check schedule data to peer task status
  18. //CheckScheduleTaskStatus(sourceUrl, destPeerHost string) (*PeerResult, error)
  19. ScheduleDataToPeerByKey(endpoint, bucketName, objectKey, destPeerHost string) (*PeerResult, error)
  20. CheckScheduleTaskStatusByKey(endpoint, bucketName, objectKey, destPeerHost string) (*PeerResult, error)
  21. }
  22. type urchinfs struct {
  23. // Initialize default urfs config.
  24. cfg *config.DfstoreConfig
  25. }
  26. // New urchinfs instance.
  27. func New() Urchinfs {
  28. urfs := &urchinfs{
  29. cfg: config.NewDfstore(),
  30. }
  31. return urfs
  32. }
  33. const (
  34. // UrfsScheme if the scheme of object storage.
  35. UrfsScheme = "urfs"
  36. )
  37. /*
  38. func (urfs *urchinfs) ScheduleDataToPeer(sourceUrl, destPeerHost string) (*PeerResult, error) {
  39. ctx, cancel := context.WithCancel(context.Background())
  40. defer cancel()
  41. if err := urfs.cfg.Validate(); err != nil {
  42. return nil, err
  43. }
  44. if err := validateSchedulelArgs(sourceUrl, destPeerHost); err != nil {
  45. return nil, err
  46. }
  47. // Copy object storage to local file.
  48. endpoint, bucketName, objectKey, err := parseUrfsURL(sourceUrl)
  49. if err != nil {
  50. return nil, err
  51. }
  52. peerResult, err := processScheduleDataToPeer(ctx, urfs.cfg, endpoint, bucketName, objectKey, destPeerHost)
  53. if err != nil {
  54. return nil, err
  55. }
  56. return peerResult, err
  57. }
  58. */
  59. func (urfs *urchinfs) ScheduleDataToPeerByKey(endpoint, bucketName, objectKey, destPeerHost string) (*PeerResult, error) {
  60. ctx, cancel := context.WithCancel(context.Background())
  61. defer cancel()
  62. peerResult, err := processScheduleDataToPeer(ctx, urfs.cfg, endpoint, bucketName, objectKey, destPeerHost)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return peerResult, err
  67. }
  68. /*
  69. func (urfs *urchinfs) CheckScheduleTaskStatus(sourceUrl, destPeerHost string) (*PeerResult, error) {
  70. ctx, cancel := context.WithCancel(context.Background())
  71. defer cancel()
  72. if err := urfs.cfg.Validate(); err != nil {
  73. return nil, err
  74. }
  75. if err := validateSchedulelArgs(sourceUrl, destPeerHost); err != nil {
  76. return nil, err
  77. }
  78. // Copy object storage to local file.
  79. endpoint, bucketName, objectKey, err := parseUrfsURL(sourceUrl)
  80. if err != nil {
  81. return nil, err
  82. }
  83. peerResult, err := processCheckScheduleTaskStatus(ctx, urfs.cfg, endpoint, bucketName, objectKey, destPeerHost)
  84. if err != nil {
  85. return nil, err
  86. }
  87. return peerResult, err
  88. }
  89. */
  90. func (urfs *urchinfs) CheckScheduleTaskStatusByKey(endpoint, bucketName, objectKey, destPeerHost string) (*PeerResult, error) {
  91. ctx, cancel := context.WithCancel(context.Background())
  92. defer cancel()
  93. peerResult, err := processCheckScheduleTaskStatus(ctx, urfs.cfg, endpoint, bucketName, objectKey, destPeerHost)
  94. if err != nil {
  95. return nil, err
  96. }
  97. return peerResult, err
  98. }
  99. // isUrfsURL determines whether the raw url is urfs url.
  100. func isUrfsURL(rawURL string) bool {
  101. u, err := url.ParseRequestURI(rawURL)
  102. if err != nil {
  103. return false
  104. }
  105. if u.Scheme != UrfsScheme || u.Host == "" || u.Path == "" {
  106. return false
  107. }
  108. return true
  109. }
  110. // Validate copy arguments.
  111. func validateSchedulelArgs(sourceUrl, destPeer string) error {
  112. if !isUrfsURL(sourceUrl) {
  113. return errors.New("source url should be urfs:// protocol")
  114. }
  115. return nil
  116. }
  117. /*
  118. // Parse object storage url. eg: urfs://源数据$endpoint/源数据$bucket/源数据filepath
  119. func parseUrfsURL(rawURL string) (string, string, string, error) {
  120. u, err := url.ParseRequestURI(rawURL)
  121. if err != nil {
  122. return "", "", "", err
  123. }
  124. if u.Scheme != UrfsScheme {
  125. return "", "", "", fmt.Errorf("invalid scheme, e.g. %s://endpoint/bucket_name/object_key", UrfsScheme)
  126. }
  127. if u.Host == "" {
  128. return "", "", "", errors.New("empty endpoint name")
  129. }
  130. if u.Path == "" {
  131. return "", "", "", errors.New("empty object path")
  132. }
  133. bucket, key, found := strings.Cut(strings.Trim(u.Path, "/"), "/")
  134. if found == false {
  135. return "", "", "", errors.New("invalid bucket and object key " + u.Path)
  136. }
  137. return u.Host, bucket, key, nil
  138. }
  139. */
  140. // Schedule object storage to peer.
  141. func processScheduleDataToPeer(ctx context.Context, cfg *config.DfstoreConfig, endpoint, bucketName, objectKey, dstPeer string) (*PeerResult, error) {
  142. dfs := urfs.New(cfg.Endpoint)
  143. meta, err := dfs.GetUrfsMetadataWithContext(ctx, &urfs.GetUrfsMetadataInput{
  144. Endpoint: endpoint,
  145. BucketName: bucketName,
  146. ObjectKey: objectKey,
  147. DstPeer: dstPeer,
  148. })
  149. if err != nil {
  150. return nil, err
  151. }
  152. reader, err := dfs.GetUrfsWithContext(ctx, &urfs.GetUrfsInput{
  153. Endpoint: endpoint,
  154. BucketName: bucketName,
  155. ObjectKey: objectKey,
  156. DstPeer: dstPeer,
  157. })
  158. if err != nil {
  159. return nil, err
  160. }
  161. defer reader.Close()
  162. body, err := ioutil.ReadAll(reader)
  163. var peerResult PeerResult
  164. if err == nil {
  165. err = json.Unmarshal((body), &peerResult)
  166. }
  167. peerResult.SignedUrl = strings.ReplaceAll(peerResult.SignedUrl, "\\u0026", "&")
  168. fileContentLength, err := strconv.ParseInt(peerResult.ContentLength, 10, 64)
  169. if err != nil {
  170. return nil, err
  171. }
  172. if fileContentLength != meta.ContentLength {
  173. return nil, errors.New("content length inconsistent with meta")
  174. }
  175. return &peerResult, err
  176. }
  177. // check schedule task status.
  178. func processCheckScheduleTaskStatus(ctx context.Context, cfg *config.DfstoreConfig, endpoint, bucketName, objectKey, dstPeer string) (*PeerResult, error) {
  179. dfs := urfs.New(cfg.Endpoint)
  180. meta, err := dfs.GetUrfsMetadataWithContext(ctx, &urfs.GetUrfsMetadataInput{
  181. Endpoint: endpoint,
  182. BucketName: bucketName,
  183. ObjectKey: objectKey,
  184. DstPeer: dstPeer,
  185. })
  186. if err != nil {
  187. return nil, err
  188. }
  189. reader, err := dfs.GetUrfsStatusWithContext(ctx, &urfs.GetUrfsInput{
  190. Endpoint: endpoint,
  191. BucketName: bucketName,
  192. ObjectKey: objectKey,
  193. DstPeer: dstPeer,
  194. })
  195. if err != nil {
  196. return nil, err
  197. }
  198. defer reader.Close()
  199. body, err := ioutil.ReadAll(reader)
  200. var peerResult PeerResult
  201. if err == nil {
  202. err = json.Unmarshal((body), &peerResult)
  203. }
  204. peerResult.SignedUrl = strings.ReplaceAll(peerResult.SignedUrl, "\\u0026", "&")
  205. fileContentLength, err := strconv.ParseInt(peerResult.ContentLength, 10, 64)
  206. if err != nil {
  207. return nil, err
  208. }
  209. if fileContentLength != meta.ContentLength {
  210. return nil, err
  211. }
  212. return &peerResult, err
  213. }
  214. type PeerResult struct {
  215. ContentType string `json:"Content-Type"`
  216. ContentLength string `json:"Content-Length"`
  217. SignedUrl string
  218. DataRoot string
  219. DataPath string
  220. DataEndpoint string
  221. StatusCode int
  222. StatusMsg string
  223. TaskID string
  224. }