transport.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package lsp
  2. import (
  3. "bufio"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "strings"
  9. "github.com/opencode-ai/opencode/internal/config"
  10. "github.com/opencode-ai/opencode/internal/logging"
  11. )
  12. // Write writes an LSP message to the given writer
  13. func WriteMessage(w io.Writer, msg *Message) error {
  14. data, err := json.Marshal(msg)
  15. if err != nil {
  16. return fmt.Errorf("failed to marshal message: %w", err)
  17. }
  18. cnf := config.Get()
  19. if cnf.DebugLSP {
  20. logging.Debug("Sending message to server", "method", msg.Method, "id", msg.ID)
  21. }
  22. _, err = fmt.Fprintf(w, "Content-Length: %d\r\n\r\n", len(data))
  23. if err != nil {
  24. return fmt.Errorf("failed to write header: %w", err)
  25. }
  26. _, err = w.Write(data)
  27. if err != nil {
  28. return fmt.Errorf("failed to write message: %w", err)
  29. }
  30. return nil
  31. }
  32. // ReadMessage reads a single LSP message from the given reader
  33. func ReadMessage(r *bufio.Reader) (*Message, error) {
  34. cnf := config.Get()
  35. // Read headers
  36. var contentLength int
  37. for {
  38. line, err := r.ReadString('\n')
  39. if err != nil {
  40. return nil, fmt.Errorf("failed to read header: %w", err)
  41. }
  42. line = strings.TrimSpace(line)
  43. if cnf.DebugLSP {
  44. logging.Debug("Received header", "line", line)
  45. }
  46. if line == "" {
  47. break // End of headers
  48. }
  49. if strings.HasPrefix(line, "Content-Length: ") {
  50. _, err := fmt.Sscanf(line, "Content-Length: %d", &contentLength)
  51. if err != nil {
  52. return nil, fmt.Errorf("invalid Content-Length: %w", err)
  53. }
  54. }
  55. }
  56. if cnf.DebugLSP {
  57. logging.Debug("Content-Length", "length", contentLength)
  58. }
  59. // Read content
  60. content := make([]byte, contentLength)
  61. _, err := io.ReadFull(r, content)
  62. if err != nil {
  63. return nil, fmt.Errorf("failed to read content: %w", err)
  64. }
  65. if cnf.DebugLSP {
  66. logging.Debug("Received content", "content", string(content))
  67. }
  68. // Parse message
  69. var msg Message
  70. if err := json.Unmarshal(content, &msg); err != nil {
  71. return nil, fmt.Errorf("failed to unmarshal message: %w", err)
  72. }
  73. return &msg, nil
  74. }
  75. // handleMessages reads and dispatches messages in a loop
  76. func (c *Client) handleMessages() {
  77. cnf := config.Get()
  78. for {
  79. msg, err := ReadMessage(c.stdout)
  80. if err != nil {
  81. if cnf.DebugLSP {
  82. logging.Error("Error reading message", "error", err)
  83. }
  84. return
  85. }
  86. // Handle server->client request (has both Method and ID)
  87. if msg.Method != "" && msg.ID != 0 {
  88. if cnf.DebugLSP {
  89. logging.Debug("Received request from server", "method", msg.Method, "id", msg.ID)
  90. }
  91. response := &Message{
  92. JSONRPC: "2.0",
  93. ID: msg.ID,
  94. }
  95. // Look up handler for this method
  96. c.serverHandlersMu.RLock()
  97. handler, ok := c.serverRequestHandlers[msg.Method]
  98. c.serverHandlersMu.RUnlock()
  99. if ok {
  100. result, err := handler(msg.Params)
  101. if err != nil {
  102. response.Error = &ResponseError{
  103. Code: -32603,
  104. Message: err.Error(),
  105. }
  106. } else {
  107. rawJSON, err := json.Marshal(result)
  108. if err != nil {
  109. response.Error = &ResponseError{
  110. Code: -32603,
  111. Message: fmt.Sprintf("failed to marshal response: %v", err),
  112. }
  113. } else {
  114. response.Result = rawJSON
  115. }
  116. }
  117. } else {
  118. response.Error = &ResponseError{
  119. Code: -32601,
  120. Message: fmt.Sprintf("method not found: %s", msg.Method),
  121. }
  122. }
  123. // Send response back to server
  124. if err := WriteMessage(c.stdin, response); err != nil {
  125. logging.Error("Error sending response to server", "error", err)
  126. }
  127. continue
  128. }
  129. // Handle notification (has Method but no ID)
  130. if msg.Method != "" && msg.ID == 0 {
  131. c.notificationMu.RLock()
  132. handler, ok := c.notificationHandlers[msg.Method]
  133. c.notificationMu.RUnlock()
  134. if ok {
  135. if cnf.DebugLSP {
  136. logging.Debug("Handling notification", "method", msg.Method)
  137. }
  138. go handler(msg.Params)
  139. } else if cnf.DebugLSP {
  140. logging.Debug("No handler for notification", "method", msg.Method)
  141. }
  142. continue
  143. }
  144. // Handle response to our request (has ID but no Method)
  145. if msg.ID != 0 && msg.Method == "" {
  146. c.handlersMu.RLock()
  147. ch, ok := c.handlers[msg.ID]
  148. c.handlersMu.RUnlock()
  149. if ok {
  150. if cnf.DebugLSP {
  151. logging.Debug("Received response for request", "id", msg.ID)
  152. }
  153. ch <- msg
  154. close(ch)
  155. } else if cnf.DebugLSP {
  156. logging.Debug("No handler for response", "id", msg.ID)
  157. }
  158. }
  159. }
  160. }
  161. // Call makes a request and waits for the response
  162. func (c *Client) Call(ctx context.Context, method string, params any, result any) error {
  163. cnf := config.Get()
  164. id := c.nextID.Add(1)
  165. if cnf.DebugLSP {
  166. logging.Debug("Making call", "method", method, "id", id)
  167. }
  168. msg, err := NewRequest(id, method, params)
  169. if err != nil {
  170. return fmt.Errorf("failed to create request: %w", err)
  171. }
  172. // Create response channel
  173. ch := make(chan *Message, 1)
  174. c.handlersMu.Lock()
  175. c.handlers[id] = ch
  176. c.handlersMu.Unlock()
  177. defer func() {
  178. c.handlersMu.Lock()
  179. delete(c.handlers, id)
  180. c.handlersMu.Unlock()
  181. }()
  182. // Send request
  183. if err := WriteMessage(c.stdin, msg); err != nil {
  184. return fmt.Errorf("failed to send request: %w", err)
  185. }
  186. if cnf.DebugLSP {
  187. logging.Debug("Request sent", "method", method, "id", id)
  188. }
  189. // Wait for response
  190. resp := <-ch
  191. if cnf.DebugLSP {
  192. logging.Debug("Received response", "id", id)
  193. }
  194. if resp.Error != nil {
  195. return fmt.Errorf("request failed: %s (code: %d)", resp.Error.Message, resp.Error.Code)
  196. }
  197. if result != nil {
  198. // If result is a json.RawMessage, just copy the raw bytes
  199. if rawMsg, ok := result.(*json.RawMessage); ok {
  200. *rawMsg = resp.Result
  201. return nil
  202. }
  203. // Otherwise unmarshal into the provided type
  204. if err := json.Unmarshal(resp.Result, result); err != nil {
  205. return fmt.Errorf("failed to unmarshal result: %w", err)
  206. }
  207. }
  208. return nil
  209. }
  210. // Notify sends a notification (a request without an ID that doesn't expect a response)
  211. func (c *Client) Notify(ctx context.Context, method string, params any) error {
  212. cnf := config.Get()
  213. if cnf.DebugLSP {
  214. logging.Debug("Sending notification", "method", method)
  215. }
  216. msg, err := NewNotification(method, params)
  217. if err != nil {
  218. return fmt.Errorf("failed to create notification: %w", err)
  219. }
  220. if err := WriteMessage(c.stdin, msg); err != nil {
  221. return fmt.Errorf("failed to send notification: %w", err)
  222. }
  223. return nil
  224. }
  225. type (
  226. NotificationHandler func(params json.RawMessage)
  227. ServerRequestHandler func(params json.RawMessage) (any, error)
  228. )