memos_service.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // ============================================================================
  2. // memos_service.go — Memos 速记
  3. //
  4. // 通过 Memos 的 REST API 新建备忘:POST {地址}/api/memos,请求头带
  5. // Authorization: Bearer <访问令牌>,body 为 {"content": "...", "visibility": "..."}。
  6. // 地址、访问令牌与默认可见性保存在「设置 → 工具」中。
  7. // ============================================================================
  8. package main
  9. import (
  10. "bytes"
  11. "encoding/json"
  12. "errors"
  13. "fmt"
  14. "io"
  15. "net/http"
  16. "strings"
  17. "time"
  18. )
  19. // MemosConfig 保存 Memos 速记所需的配置。
  20. type MemosConfig struct {
  21. URL string `json:"url"` // 实例地址,如 https://m.scwy.net
  22. Token string `json:"token"` // 个人访问令牌(PAT),只存本地
  23. }
  24. // MemosService 提供 Memos 速记的配置读取与新建备忘接口。
  25. type MemosService struct{}
  26. // NewMemosService 创建 Memos 服务实例。
  27. func NewMemosService() *MemosService { return &MemosService{} }
  28. // GetConfig 返回当前 Memos 配置(供前端回填设置表单)。
  29. func (s *MemosService) GetConfig() MemosConfig {
  30. return loadSettings().Memos
  31. }
  32. // CreateMemo 调用 Memos REST API 新建一条私有备忘,返回备忘名称(形如 memos/xxxx)。
  33. func (s *MemosService) CreateMemo(content string) (string, error) {
  34. content = strings.TrimSpace(content)
  35. if content == "" {
  36. return "", errors.New("内容不能为空")
  37. }
  38. cfg := loadSettings().Memos
  39. base := strings.TrimRight(strings.TrimSpace(cfg.URL), "/")
  40. if base == "" {
  41. return "", errors.New("未配置 Memos 地址,请到「设置 → 工具」中填写")
  42. }
  43. token := strings.TrimSpace(cfg.Token)
  44. if token == "" {
  45. return "", errors.New("未配置访问令牌,请到「设置 → 工具」中填写")
  46. }
  47. // 固定创建私有备忘
  48. payload, err := json.Marshal(map[string]string{
  49. "content": content,
  50. "visibility": "PRIVATE",
  51. })
  52. if err != nil {
  53. return "", err
  54. }
  55. req, err := http.NewRequest(http.MethodPost, base+"/api/memos", bytes.NewReader(payload))
  56. if err != nil {
  57. return "", fmt.Errorf("地址无效:%w", err)
  58. }
  59. req.Header.Set("Authorization", "Bearer "+token)
  60. req.Header.Set("Content-Type", "application/json")
  61. client := &http.Client{Timeout: 20 * time.Second}
  62. resp, err := client.Do(req)
  63. if err != nil {
  64. return "", fmt.Errorf("请求失败:%w", err)
  65. }
  66. defer resp.Body.Close()
  67. body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
  68. if resp.StatusCode < 200 || resp.StatusCode >= 300 {
  69. return "", fmt.Errorf("创建失败(HTTP %d):%s", resp.StatusCode, strings.TrimSpace(string(body)))
  70. }
  71. var out struct {
  72. Name string `json:"name"`
  73. }
  74. if json.Unmarshal(body, &out) == nil && out.Name != "" {
  75. return out.Name, nil
  76. }
  77. return "已创建", nil
  78. }