sdm.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os/exec"
  6. tea "github.com/charmbracelet/bubbletea"
  7. )
  8. // Constants for SDM command exit codes
  9. const (
  10. exitCodeAuthRequired = 9
  11. )
  12. // connection represents a SDM connection from the status command.
  13. type connection struct {
  14. Name string `json:"name"`
  15. Type string `json:"type"`
  16. Address string `json:"address"`
  17. Connected bool `json:"connected"`
  18. WebURL *string `json:"web_url"`
  19. }
  20. // statusMsg is sent when the status fetch operation completes.
  21. type statusMsg struct {
  22. connections []connection
  23. err error
  24. }
  25. // authRequiredMsg is sent when authentication is required.
  26. type authRequiredMsg struct{}
  27. // loginMsg is sent when the login operation completes.
  28. type loginMsg struct {
  29. err error
  30. }
  31. // connectMsg is sent when a connect operation completes.
  32. type connectMsg struct {
  33. name string
  34. address string
  35. err error
  36. }
  37. // disconnectMsg is sent when a disconnect operation completes.
  38. type disconnectMsg struct {
  39. name string
  40. err error
  41. }
  42. // checkSDMBinary verifies that the sdm binary is available in PATH.
  43. func checkSDMBinary() error {
  44. _, err := exec.LookPath("sdm")
  45. if err != nil {
  46. return fmt.Errorf("sdm binary not found in PATH. Please install sdm and try again")
  47. }
  48. return nil
  49. }
  50. // fetchStatus executes the SDM status command and returns the result as a message.
  51. // If authentication is required (exit code 9), it returns authRequiredMsg.
  52. func fetchStatus() tea.Msg {
  53. cmd := exec.Command("sdm", "status", "-j")
  54. output, err := cmd.CombinedOutput()
  55. if err != nil {
  56. if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == exitCodeAuthRequired {
  57. return authRequiredMsg{}
  58. }
  59. return statusMsg{err: fmt.Errorf("%v: %s", err, string(output))}
  60. }
  61. var connections []connection
  62. if err := json.Unmarshal(output, &connections); err != nil {
  63. return statusMsg{err: err}
  64. }
  65. return statusMsg{connections: connections}
  66. }
  67. // loginSDM executes the SDM login command with the provided email.
  68. func loginSDM(email string) tea.Msg {
  69. cmd := exec.Command("sdm", "login", "--email", email)
  70. output, err := cmd.CombinedOutput()
  71. if err != nil {
  72. return loginMsg{err: fmt.Errorf("%v: %s", err, string(output))}
  73. }
  74. return loginMsg{}
  75. }
  76. // connectSDM executes the SDM connect command and waits for it to complete.
  77. func connectSDM(name, address string) tea.Msg {
  78. cmd := exec.Command("sdm", "connect", name)
  79. output, err := cmd.CombinedOutput()
  80. if err != nil {
  81. return connectMsg{name: name, address: address, err: fmt.Errorf("%v: %s", err, string(output))}
  82. }
  83. return connectMsg{name: name, address: address}
  84. }
  85. // disconnectSDM executes the SDM disconnect command for a specific connection.
  86. func disconnectSDM(name string) tea.Msg {
  87. cmd := exec.Command("sdm", "disconnect", name)
  88. output, err := cmd.CombinedOutput()
  89. if err != nil {
  90. return disconnectMsg{name: name, err: fmt.Errorf("%v: %s", err, string(output))}
  91. }
  92. return disconnectMsg{name: name}
  93. }
  94. // getAddress returns the appropriate address for a connection, preferring WebURL over Address.
  95. func getAddress(conn connection) string {
  96. if conn.WebURL != nil {
  97. return *conn.WebURL
  98. }
  99. return conn.Address
  100. }
  101. // sendNotification sends a desktop notification using notify-send.
  102. func sendNotification(title, message string) {
  103. cmd := exec.Command("notify-send", title, message)
  104. cmd.Run() // Ignore errors - notification is non-critical
  105. }