Fix server file browse flow
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -19,6 +20,7 @@ const (
|
||||
serverFileTransferChannel = "run-file-transfer"
|
||||
serverFileMaxInlineEditBytes = 64 * 1024
|
||||
serverFileDefaultDirectoryKey = "server-root"
|
||||
serverFileBrowseWait = 4 * time.Second
|
||||
)
|
||||
|
||||
type serverFileContext struct {
|
||||
@@ -188,6 +190,82 @@ func (svc *CoreService) RefreshServerFileListForSession(sessionID string, reques
|
||||
return domain.CopyServerFileListResult(domain.ServerFileListResult{ServerInstanceID: ctx.Instance.ID, PluginID: ctx.Plugin.ID, DirectoryKey: request.DirectoryKey, Path: request.Path, State: "pending", Entries: entries, Job: job, Reason: "目录刷新任务已派发到 Run。"}), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) BrowseServerFilesForSession(ctx context.Context, sessionID string, request domain.ServerFileListRequest) (domain.ServerFileListResult, error) {
|
||||
request = normalizeServerFileListRequest(request)
|
||||
if request.IdempotencyKey == "" {
|
||||
idempotencyKey, err := svc.serverFileBrowseIdempotencyKey(request)
|
||||
if err != nil {
|
||||
return domain.ServerFileListResult{}, err
|
||||
}
|
||||
request.IdempotencyKey = idempotencyKey
|
||||
}
|
||||
result, err := svc.RefreshServerFileListForSession(sessionID, request)
|
||||
if err != nil || result.State != "pending" || result.Job.ID == "" {
|
||||
return result, err
|
||||
}
|
||||
timer := time.NewTimer(serverFileBrowseWait)
|
||||
defer timer.Stop()
|
||||
for {
|
||||
current, ready, err := svc.serverFileListResultFromJob(request, result, result.Job.ID)
|
||||
if err != nil || ready {
|
||||
return current, err
|
||||
}
|
||||
waiter := svc.registerRunJobWaiter(result.Job.RunEndpointID)
|
||||
current, ready, err = svc.serverFileListResultFromJob(request, result, result.Job.ID)
|
||||
if err != nil || ready {
|
||||
svc.unregisterRunJobWaiter(result.Job.RunEndpointID, waiter)
|
||||
return current, err
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
svc.unregisterRunJobWaiter(result.Job.RunEndpointID, waiter)
|
||||
return domain.ServerFileListResult{}, ctx.Err()
|
||||
case <-waiter:
|
||||
case <-timer.C:
|
||||
svc.unregisterRunJobWaiter(result.Job.RunEndpointID, waiter)
|
||||
current.Reason = "正在读取目录。"
|
||||
return current, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *CoreService) serverFileListResultFromJob(request domain.ServerFileListRequest, fallback domain.ServerFileListResult, jobID string) (domain.ServerFileListResult, bool, error) {
|
||||
job, err := svc.store.Jobs().Get(jobID)
|
||||
if err != nil {
|
||||
return domain.ServerFileListResult{}, true, err
|
||||
}
|
||||
result := domain.CopyServerFileListResult(fallback)
|
||||
result.Job = job
|
||||
if !isTerminalJobState(job.State) {
|
||||
return result, false, nil
|
||||
}
|
||||
result.RefreshedAt = job.TerminalAt
|
||||
if job.State != domain.JobStateSucceeded || job.ExecutionResult.Kind != "file.list" {
|
||||
result.State = "failed"
|
||||
result.Reason = serverFileListJobFailureReason(job)
|
||||
return result, true, nil
|
||||
}
|
||||
entries, err := serverFileEntriesFromRunList(job.ExecutionResult.Content, request.DirectoryKey, request.Path)
|
||||
if err != nil {
|
||||
result.State = "failed"
|
||||
result.Reason = "Run 返回的文件列表无法解析。"
|
||||
return result, true, nil
|
||||
}
|
||||
result.State = "ready"
|
||||
result.Entries = filterServerFileEntries(entries, request.Query)
|
||||
result.Reason = "目录读取完成。"
|
||||
return result, true, nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) serverFileBrowseIdempotencyKey(request domain.ServerFileListRequest) (string, error) {
|
||||
token, err := randomToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
raw := strings.Join([]string{request.ServerInstanceID, request.DirectoryKey, request.Path, request.Query, strconv.FormatBool(request.Recursive), token}, ":")
|
||||
return fmt.Sprintf("file-browse:%d", stableStringNumber(raw)), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) ReadServerFileForSession(sessionID string, request domain.ServerFileReadRequest) (domain.FileOperationDispatchResult, error) {
|
||||
if err := validator.ValidateServerFileReadRequest(request); err != nil {
|
||||
return domain.FileOperationDispatchResult{}, err
|
||||
@@ -545,7 +623,7 @@ func (svc *CoreService) putBrowserFileArtifact(artifact domain.Artifact, payload
|
||||
if err := svc.artifactStore.PutPayload(artifact.ID, payload); err != nil {
|
||||
return err
|
||||
}
|
||||
svc.artifactPayloads[artifact.ID] = domain.CopyBytes(payload)
|
||||
svc.cacheArtifactPayload(artifact.ID, payload)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user