-
Notifications
You must be signed in to change notification settings - Fork 0
feat(daemon): send session-project path mapping to server #224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -51,6 +51,25 @@ func SendLocalDataToSocket( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // SendSessionProject sends a session-to-project mapping to the daemon (fire-and-forget) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func SendSessionProject(socketPath string, sessionID, projectPath string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conn, err := net.DialTimeout("unix", socketPath, 10*time.Millisecond) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defer conn.Close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| msg := SocketMessage{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Type: SocketMessageTypeSessionProject, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Payload: SessionProjectRequest{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SessionID: sessionID, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProjectPath: projectPath, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| json.NewEncoder(conn).Encode(msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Missing write deadline on socket connection in SendSessionProject can block the statusline indefinitely
Root Cause and ImpactCompare with This function is called synchronously in the statusline command ( Impact: Under load or unusual daemon conditions, the statusline could hang or time out, degrading the user experience.
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // RequestCCInfo requests CC info (cost data and git info) from the daemon | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func RequestCCInfo(socketPath string, timeRange CCInfoTimeRange, workingDir string, timeout time.Duration) (*CCInfoResponse, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conn, err := net.DialTimeout("unix", socketPath, timeout) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package daemon | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "log/slog" | ||
|
|
@@ -17,12 +18,18 @@ import ( | |
| type SocketMessageType string | ||
|
|
||
| const ( | ||
| SocketMessageTypeSync SocketMessageType = "sync" | ||
| SocketMessageTypeHeartbeat SocketMessageType = "heartbeat" | ||
| SocketMessageTypeStatus SocketMessageType = "status" | ||
| SocketMessageTypeCCInfo SocketMessageType = "cc_info" | ||
| SocketMessageTypeSync SocketMessageType = "sync" | ||
| SocketMessageTypeHeartbeat SocketMessageType = "heartbeat" | ||
| SocketMessageTypeStatus SocketMessageType = "status" | ||
| SocketMessageTypeCCInfo SocketMessageType = "cc_info" | ||
| SocketMessageTypeSessionProject SocketMessageType = "session_project" | ||
| ) | ||
|
|
||
| type SessionProjectRequest struct { | ||
| SessionID string `json:"sessionId"` | ||
| ProjectPath string `json:"projectPath"` | ||
| } | ||
|
|
||
| type CCInfoTimeRange string | ||
|
|
||
| const ( | ||
|
|
@@ -179,6 +186,15 @@ func (p *SocketHandler) handleConnection(conn net.Conn) { | |
| encoder.Encode(map[string]string{"status": "ok"}) | ||
| case SocketMessageTypeCCInfo: | ||
| p.handleCCInfo(conn, msg) | ||
| case SocketMessageTypeSessionProject: | ||
| if payload, ok := msg.Payload.(map[string]interface{}); ok { | ||
| sessionID, _ := payload["sessionId"].(string) | ||
| projectPath, _ := payload["projectPath"].(string) | ||
| if sessionID != "" && projectPath != "" { | ||
| go model.SendSessionProjectUpdate(context.Background(), *p.config, sessionID, projectPath) | ||
| slog.Debug("session_project update dispatched", slog.String("sessionId", sessionID)) | ||
| } | ||
|
Comment on lines
+191
to
+196
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block has a couple of issues that should be addressed for robustness:
The suggested change below addresses both points by checking the type assertion results and handling the error from the API call by logging it. sessionID, ok1 := payload["sessionId"].(string)
projectPath, ok2 := payload["projectPath"].(string)
if ok1 && ok2 && sessionID != "" && projectPath != "" {
go func() {
if err := model.SendSessionProjectUpdate(context.Background(), *p.config, sessionID, projectPath); err != nil {
slog.Warn("Failed to send session-project update", slog.Any("err", err), slog.String("sessionId", sessionID))
}
}()
slog.Debug("session_project update dispatched", slog.String("sessionId", sessionID))
} else {
slog.Warn("Received invalid or incomplete session_project payload", "payload", payload)
} |
||
| } | ||
| default: | ||
| slog.Error("Unknown message type:", slog.String("messageType", string(msg.Type))) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package model | ||
|
|
||
| import ( | ||
| "context" | ||
| "net/http" | ||
| "time" | ||
| ) | ||
|
|
||
| type sessionProjectRequest struct { | ||
| SessionID string `json:"session_id"` | ||
| ProjectPath string `json:"project_path"` | ||
| } | ||
|
|
||
| type sessionProjectResponse struct{} | ||
|
|
||
| // SendSessionProjectUpdate sends a session-to-project path mapping to the server | ||
| func SendSessionProjectUpdate(ctx context.Context, config ShellTimeConfig, sessionID, projectPath string) error { | ||
| ctx, span := modelTracer.Start(ctx, "session_project.send") | ||
| defer span.End() | ||
|
|
||
| var resp sessionProjectResponse | ||
| err := SendHTTPRequestJSON(HTTPRequestOptions[*sessionProjectRequest, sessionProjectResponse]{ | ||
| Context: ctx, | ||
| Endpoint: Endpoint{ | ||
| APIEndpoint: config.APIEndpoint, | ||
| Token: config.Token, | ||
| }, | ||
| Method: http.MethodPost, | ||
| Path: "/api/v1/cc/session-project", | ||
| Payload: &sessionProjectRequest{ | ||
| SessionID: sessionID, | ||
| ProjectPath: projectPath, | ||
| }, | ||
| Response: &resp, | ||
| Timeout: 5 * time.Second, | ||
| }) | ||
|
|
||
| return err | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error returned by
json.NewEncoder(conn).Encode(msg)is not handled. Even for a fire-and-forget function, it's good practice to log such errors for debugging purposes. You could use theslogpackage for this, which is used elsewhere in thedaemonpackage (you would need to add thelog/slogimport).