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.

contentManager.go 4.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package notebook
  2. import (
  3. "crypto/tls"
  4. "encoding/base64"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "path"
  9. "strings"
  10. "github.com/go-resty/resty/v2"
  11. "code.gitea.io/gitea/models"
  12. "code.gitea.io/gitea/modules/cloudbrain"
  13. "code.gitea.io/gitea/modules/setting"
  14. "code.gitea.io/gitea/modules/log"
  15. )
  16. var restyClient *resty.Client
  17. type NotebookApiResponse struct {
  18. Name string `json:"name"`
  19. Path string `json:"path"`
  20. }
  21. type NotebookContent struct {
  22. Url string
  23. Path string
  24. Cookies []*http.Cookie
  25. Xsrf string
  26. PathType string //file directory
  27. Token string
  28. }
  29. func (c *NotebookContent) IsNotebookFileCanBrowser() bool {
  30. if c.Xsrf == "" {
  31. c.SetCookiesAndCsrf()
  32. }
  33. if c.Xsrf == "" {
  34. log.Warn("xsrf is empty, can not broswer url:" + c.Url)
  35. return false
  36. }
  37. return c.IsNoteBookContentsExist()
  38. }
  39. func (c *NotebookContent) SetCookiesAndCsrf() {
  40. log.Info("jupyter url:" + c.Url)
  41. var cookies []*http.Cookie
  42. const retryTimes = 10
  43. url := c.Url
  44. if c.Token != "" {
  45. url = c.Url + "?token=" + c.Token
  46. }
  47. for i := 0; i < retryTimes; i++ {
  48. res, err := http.Get(url)
  49. if err != nil {
  50. log.Error("browser jupyterUrl failed.", err)
  51. if i == retryTimes-1 {
  52. c.Cookies = cookies
  53. }
  54. } else {
  55. cookies = res.Cookies()
  56. xsrf := ""
  57. for _, cookie := range cookies {
  58. if cookie.Name == "_xsrf" {
  59. xsrf = cookie.Value
  60. if len(cookies) > 1 {
  61. break
  62. }
  63. }
  64. }
  65. if xsrf != "" {
  66. c.Cookies = cookies
  67. c.Xsrf = xsrf
  68. }
  69. }
  70. }
  71. c.Cookies = cookies
  72. }
  73. func (c *NotebookContent) IsNoteBookContentsExist() bool {
  74. client := getRestyClient()
  75. uploadUrl := getJupyterBaseUrl(c.Url) + "api/contents/" + c.Path + "?type=" + c.PathType
  76. res, err := client.R().
  77. SetCookies(c.Cookies).
  78. SetHeader("X-XSRFToken", c.Xsrf).
  79. Get(uploadUrl)
  80. if err != nil {
  81. log.Warn("browser url error:"+uploadUrl, err)
  82. return false
  83. }
  84. return res.StatusCode() == http.StatusOK
  85. }
  86. func (c *NotebookContent) UploadNoteBookFile(task *models.Cloudbrain) error {
  87. err := c.MakeNoteBookDir()
  88. if err != nil {
  89. return err
  90. }
  91. codePath := setting.JobPath + task.JobName + cloudbrain.CodeMountPath
  92. fileContents, err := ioutil.ReadFile(codePath + "/" + c.Path)
  93. if err != nil {
  94. log.Error("read jupyter file failed:%v", task.DisplayJobName, err)
  95. }
  96. base64Content := base64.StdEncoding.EncodeToString(fileContents)
  97. client := getRestyClient()
  98. uploadUrl := getJupyterBaseUrl(c.Url) + "api/contents/" + c.Path
  99. res, err := client.R().
  100. SetCookies(c.Cookies).
  101. SetHeader("X-XSRFToken", c.Xsrf).
  102. SetBody(map[string]interface{}{
  103. "type": "file",
  104. "format": "base64",
  105. "name": path.Base(c.Path),
  106. "path": c.Path,
  107. "content": base64Content}).
  108. Put(uploadUrl)
  109. if err != nil {
  110. log.Error("upload jupyter file failed:%v", task.DisplayJobName, err)
  111. return err
  112. } else if res.StatusCode() != http.StatusCreated {
  113. log.Error("upload jupyter file failed:%v, status is %s", task.DisplayJobName, res.Status(), err)
  114. return fmt.Errorf("status:", res.StatusCode())
  115. }
  116. return nil
  117. }
  118. /**
  119. if c.Path is a/b/c.txt
  120. makedir a/b
  121. if c.Path is a/b/c
  122. makedir a/b
  123. */
  124. func (c *NotebookContent) MakeNoteBookDir() error {
  125. filePaths := strings.Split(c.Path, "/")
  126. for i := 0; i < len(filePaths)-1; i++ {
  127. cTemp := &NotebookContent{
  128. Url: c.Url,
  129. Cookies: c.Cookies,
  130. Path: path.Join(filePaths[0 : i+1]...),
  131. PathType: "directory",
  132. Xsrf: c.Xsrf,
  133. }
  134. if !cTemp.IsNoteBookContentsExist() {
  135. createTempDirUrl := getJupyterBaseUrl(cTemp.Url) + "api/contents/" + cTemp.Path
  136. client := getRestyClient()
  137. var jobResult NotebookApiResponse
  138. res, err := client.R().
  139. SetCookies(c.Cookies).
  140. SetHeader("X-XSRFToken", c.Xsrf).
  141. SetBody(map[string]interface{}{
  142. "type": cTemp.PathType,
  143. "path": cTemp.Path,
  144. }).SetResult(&jobResult).
  145. Put(createTempDirUrl)
  146. if err != nil {
  147. return err
  148. }
  149. if res.StatusCode() != http.StatusCreated {
  150. return fmt.Errorf("status code:" + res.Status())
  151. }
  152. }
  153. }
  154. return nil
  155. }
  156. func getJupyterBaseUrl(url string) string {
  157. jupyterUrlLength := len(url)
  158. baseUrl := url
  159. if strings.HasSuffix(url, "lab") {
  160. baseUrl = url[0 : jupyterUrlLength-len(path.Base(url))]
  161. }
  162. return baseUrl
  163. }
  164. func getRestyClient() *resty.Client {
  165. if restyClient == nil {
  166. restyClient = resty.New()
  167. restyClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  168. }
  169. return restyClient
  170. }