server.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package main
  2. // 与平台的通信(docs/design/21-knowledge-sources.md §4.5):Unix socket,一行一个 JSON 请求和响应,每个请求都要带密钥。
  3. import (
  4. "bufio"
  5. "context"
  6. "crypto/rand"
  7. "crypto/subtle"
  8. "encoding/hex"
  9. "encoding/json"
  10. "errors"
  11. "log"
  12. "net"
  13. "os"
  14. "time"
  15. )
  16. type request struct {
  17. Token string `json:"token"`
  18. Op string `json:"op"`
  19. Path string `json:"path,omitempty"`
  20. Mounts []mountSpec `json:"mounts,omitempty"`
  21. Remote *remoteSpec `json:"remote,omitempty"`
  22. }
  23. type server struct {
  24. token string
  25. mgr *manager
  26. version string
  27. }
  28. func newToken() string {
  29. b := make([]byte, 32)
  30. if _, err := rand.Read(b); err != nil {
  31. panic(err)
  32. }
  33. return hex.EncodeToString(b)
  34. }
  35. // writeGroupFile 写入文件并设为目录的组(平台以 agentsvc 组身份读取)
  36. func writeGroupFile(path string, data []byte, mode os.FileMode, gid int) error {
  37. tmp := path + ".tmp"
  38. if err := os.WriteFile(tmp, data, mode); err != nil {
  39. return err
  40. }
  41. if err := os.Chown(tmp, -1, gid); err != nil {
  42. os.Remove(tmp)
  43. return err
  44. }
  45. if err := os.Chmod(tmp, mode); err != nil {
  46. return err
  47. }
  48. return os.Rename(tmp, path)
  49. }
  50. func (s *server) handle(req request) map[string]any {
  51. fail := func(err error) map[string]any {
  52. var ce *checkError
  53. if errors.As(err, &ce) {
  54. return map[string]any{"ok": false, "error": ce.Message, "state": ce.State}
  55. }
  56. return map[string]any{"ok": false, "error": err.Error()}
  57. }
  58. switch req.Op {
  59. case "ping":
  60. return map[string]any{"ok": true, "version": s.version}
  61. case "status":
  62. // 顺便重新检查:路径被删除、改名不会引起挂载表变化
  63. s.mgr.refreshAll()
  64. s.mgr.checkRemotes()
  65. return map[string]any{"ok": true, "version": s.version, "mounts": s.mgr.status()}
  66. case "list":
  67. res, cerr := browse(req.Path, s.mgr.roots)
  68. if cerr != nil {
  69. return fail(cerr)
  70. }
  71. return map[string]any{"ok": true, "result": res}
  72. case "check":
  73. real, cerr := checkSource(req.Path, s.mgr.roots)
  74. if cerr != nil {
  75. return fail(cerr)
  76. }
  77. return map[string]any{"ok": true, "result": identify(s.mgr.sys, real)}
  78. case "test":
  79. if req.Remote == nil {
  80. return map[string]any{"ok": false, "error": "缺少远程存储配置"}
  81. }
  82. if s.mgr.runner == nil {
  83. return map[string]any{"ok": false, "error": "挂载服务没有配置 rclone"}
  84. }
  85. env, err := buildRemote(*req.Remote, s.mgr.runner.bin)
  86. if err != nil {
  87. return map[string]any{"ok": false, "error": err.Error(), "state": "mount_failed"}
  88. }
  89. return map[string]any{"ok": true, "result": s.mgr.runner.probe(context.Background(), env, 20*time.Second)}
  90. case "sync":
  91. st, err := s.mgr.sync(req.Mounts, true)
  92. if err != nil {
  93. return fail(err)
  94. }
  95. return map[string]any{"ok": true, "mounts": st}
  96. default:
  97. return map[string]any{"ok": false, "error": "未知请求:" + req.Op}
  98. }
  99. }
  100. func (s *server) serveConn(c net.Conn) {
  101. defer c.Close()
  102. r := bufio.NewReader(c)
  103. enc := json.NewEncoder(c)
  104. for {
  105. _ = c.SetReadDeadline(time.Now().Add(60 * time.Second))
  106. line, err := r.ReadBytes('\n')
  107. if len(line) > 4<<20 {
  108. _ = enc.Encode(map[string]any{"ok": false, "error": "请求过大"})
  109. return
  110. }
  111. if len(line) == 0 && err != nil {
  112. return
  113. }
  114. var req request
  115. if jerr := json.Unmarshal(line, &req); jerr != nil {
  116. _ = enc.Encode(map[string]any{"ok": false, "error": "请求格式不正确"})
  117. return
  118. }
  119. if subtle.ConstantTimeCompare([]byte(req.Token), []byte(s.token)) != 1 {
  120. _ = enc.Encode(map[string]any{"ok": false, "error": "密钥不正确"})
  121. return
  122. }
  123. _ = c.SetWriteDeadline(time.Now().Add(30 * time.Second))
  124. if err := enc.Encode(s.handle(req)); err != nil {
  125. return
  126. }
  127. if err != nil {
  128. return
  129. }
  130. }
  131. }
  132. func (s *server) serve(l net.Listener) {
  133. for {
  134. c, err := l.Accept()
  135. if err != nil {
  136. if errors.Is(err, net.ErrClosed) {
  137. return
  138. }
  139. log.Printf("accept:%v", err)
  140. time.Sleep(100 * time.Millisecond)
  141. continue
  142. }
  143. go s.serveConn(c)
  144. }
  145. }