Keep run logs opaque and streamline transfers

This commit is contained in:
npc0-hue
2026-09-03 16:40:05 +08:00
parent 48dd540253
commit 330b1c0130
27 changed files with 429 additions and 673 deletions
+65 -1
View File
@@ -31,6 +31,16 @@ type PlatformClient struct {
serverClockOffsetActive *atomic.Bool
}
const (
runSessionTokenHeader = "X-Run-Session-Token"
artifactTransferIDHeader = "X-Artifact-Transfer-Id"
artifactIDHeader = "X-Artifact-Id"
artifactChunkIndexHeader = "X-Artifact-Chunk-Index"
artifactChunkOffsetHeader = "X-Artifact-Offset"
artifactChunkSizeHeader = "X-Artifact-Size"
artifactChunkHashHeader = "X-Artifact-Checksum"
)
type PlatformRequestError struct {
Status int
Path string
@@ -326,7 +336,7 @@ func (c PlatformClient) OpenArtifactTransfer(ctx context.Context, request protoc
}
func (c PlatformClient) UploadArtifactChunk(ctx context.Context, request protocol.ArtifactChunkUploadRequest) (protocol.ArtifactChunkUploadResponse, error) {
return postPlatformJSON[protocol.ArtifactChunkUploadRequest, protocol.ArtifactChunkUploadResponse](ctx, c, "/api/v1/run/artifacts/chunks", request)
return postPlatformArtifactChunk(ctx, c, "/api/v1/run/artifacts/chunks", request)
}
func (c PlatformClient) QueryArtifactTransferStatus(ctx context.Context, request protocol.ArtifactTransferStatusRequest) (protocol.ArtifactTransferStatusResponse, error) {
@@ -337,6 +347,56 @@ func (c PlatformClient) CompleteArtifactTransfer(ctx context.Context, request pr
return postPlatformJSON[protocol.ArtifactTransferCompleteRequest, protocol.ArtifactTransferCompleteResponse](ctx, c, "/api/v1/run/artifacts/complete", request)
}
func postPlatformArtifactChunk(ctx context.Context, client PlatformClient, path string, request protocol.ArtifactChunkUploadRequest) (protocol.ArtifactChunkUploadResponse, error) {
var response protocol.ArtifactChunkUploadResponse
startedAt := time.Now()
log.Printf("RUN platform request status=starting method=POST base=%s path=%s", diagnosticLogValue(client.baseURL), path)
body := request.Payload
httpRequest, err := http.NewRequestWithContext(ctx, http.MethodPost, client.baseURL+path, bytes.NewReader(body))
if err != nil {
log.Printf("RUN platform request status=build_error method=POST base=%s path=%s durationMs=%d error=%s", diagnosticLogValue(client.baseURL), path, time.Since(startedAt).Milliseconds(), err)
return response, fmt.Errorf("build platform request: %w", err)
}
httpRequest.Header.Set("Content-Type", "application/octet-stream")
httpRequest.Header.Set("Accept", "application/json")
httpRequest.Header.Set(runSessionTokenHeader, request.SessionToken)
httpRequest.Header.Set(artifactTransferIDHeader, request.TransferID)
httpRequest.Header.Set(artifactIDHeader, request.ArtifactID)
httpRequest.Header.Set(artifactChunkIndexHeader, strconv.Itoa(request.ChunkIndex))
httpRequest.Header.Set(artifactChunkOffsetHeader, strconv.FormatInt(request.Offset, 10))
httpRequest.Header.Set(artifactChunkSizeHeader, strconv.Itoa(request.SizeBytes))
httpRequest.Header.Set(artifactChunkHashHeader, request.Checksum)
signatureSummary, err := signRunRequestWithEnvelope(httpRequest, body, runRequestEnvelope{RunEndpointID: request.RunEndpointID, SessionToken: request.SessionToken}, client.signatureTime())
if err != nil {
log.Printf("RUN platform request status=sign_error method=POST base=%s path=%s durationMs=%d error=%s", diagnosticLogValue(client.baseURL), path, time.Since(startedAt).Milliseconds(), err)
return response, err
}
log.Printf("RUN platform request status=signed method=POST base=%s path=%s endpoint=%s timestamp=%s nonce=%s bodyHash=%s signature=%s", diagnosticLogValue(client.baseURL), path, diagnosticLogValue(signatureSummary.RunEndpointID), signatureSummary.Timestamp, shortDiagnosticValue(signatureSummary.Nonce), shortDiagnosticValue(signatureSummary.BodyHash), shortDiagnosticValue(signatureSummary.Signature))
httpResponse, err := client.httpClient.Do(httpRequest)
if err != nil {
log.Printf("RUN platform request status=send_error method=POST base=%s path=%s durationMs=%d error=%s", diagnosticLogValue(client.baseURL), path, time.Since(startedAt).Milliseconds(), err)
return response, fmt.Errorf("send platform request: %w", err)
}
defer httpResponse.Body.Close()
log.Printf("RUN platform request status=response method=POST base=%s path=%s httpStatus=%d durationMs=%d", diagnosticLogValue(client.baseURL), path, httpResponse.StatusCode, time.Since(startedAt).Milliseconds())
if httpResponse.StatusCode < http.StatusOK || httpResponse.StatusCode >= http.StatusMultipleChoices {
var failure struct {
Code string `json:"code"`
Details []string `json:"details"`
}
_ = json.NewDecoder(io.LimitReader(httpResponse.Body, 64<<10)).Decode(&failure)
return response, PlatformRequestError{Status: httpResponse.StatusCode, Path: path, Code: failure.Code, Details: failure.Details}
}
if err := json.NewDecoder(httpResponse.Body).Decode(&response); err != nil {
return response, fmt.Errorf("decode platform response: %w", err)
}
client.observeResponseServerTime(response)
return response, nil
}
func postPlatformJSON[Request any, Response any](ctx context.Context, client PlatformClient, path string, request Request) (Response, error) {
var response Response
startedAt := time.Now()
@@ -405,6 +465,10 @@ func signRunRequest(request *http.Request, body []byte, stamp time.Time) (runReq
if err := json.Unmarshal(body, &envelope); err != nil {
return runRequestSignatureSummary{}, fmt.Errorf("decode Run signing envelope: %w", err)
}
return signRunRequestWithEnvelope(request, body, envelope, stamp)
}
func signRunRequestWithEnvelope(request *http.Request, body []byte, envelope runRequestEnvelope, stamp time.Time) (runRequestSignatureSummary, error) {
if strings.TrimSpace(envelope.RunEndpointID) == "" || strings.TrimSpace(envelope.SessionToken) == "" {
return runRequestSignatureSummary{}, fmt.Errorf("Run signing envelope requires endpoint and session token")
}