github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/transferfiles/state/runstatus.go (about) 1 package state 2 3 import ( 4 "encoding/json" 5 "os" 6 "sync" 7 "time" 8 9 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 10 "github.com/jfrog/jfrog-client-go/utils/errorutils" 11 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 12 ) 13 14 // The current version of the run-status.json file. 15 // Can be used to identify when the version of the CLI doesn't support the structure of the transfer directory. 16 const transferRunStatusVersion = 1 17 18 var saveRunStatusMutex sync.Mutex 19 20 type ActionOnStatusFunc func(transferRunStatus *TransferRunStatus) error 21 22 // This struct holds the run status of the current transfer. 23 // It is saved to a file in JFrog CLI's home, but gets reset every time the transfer begins. 24 // This state is used to allow showing the current run status by the 'jf rt transfer-files --status' command. 25 // It is also used for the time estimation and more. 26 type TransferRunStatus struct { 27 // Timestamp since the beginning of the current transfer execution 28 startTimestamp time.Time 29 lastSaveTimestamp time.Time 30 // This variable holds the total/transferred number of repositories (not their files). 31 OverallTransfer ProgressState `json:"overall_transfer,omitempty"` 32 TotalRepositories ProgressStateUnits `json:"total_repositories,omitempty"` 33 OverallBiFiles ProgressStateUnits `json:"overall_bi_files,omitempty"` 34 // Version of the TransferRunStatus file. 35 Version int `json:"version,omitempty"` 36 CurrentRepoKey string `json:"current_repo,omitempty"` 37 // True if currently transferring a build info repository. 38 BuildInfoRepo bool `json:"build_info_repo,omitempty"` 39 CurrentRepoPhase int `json:"current_repo_phase,omitempty"` 40 WorkingThreads int `json:"working_threads,omitempty"` 41 VisitedFolders uint64 `json:"visited_folders,omitempty"` 42 DelayedFiles uint64 `json:"delayed_files,omitempty"` 43 TransferFailures uint64 `json:"transfer_failures,omitempty"` 44 TimeEstimationManager `json:"time_estimation,omitempty"` 45 StaleChunks []StaleChunks `json:"stale_chunks,omitempty"` 46 } 47 48 // This structure contains a collection of chunks that have been undergoing processing for over 30 minutes 49 type StaleChunks struct { 50 NodeID string `json:"node_id,omitempty"` 51 Chunks []StaleChunk `json:"stale_node_chunks,omitempty"` 52 } 53 54 type StaleChunk struct { 55 ChunkID string `json:"chunk_id,omitempty"` 56 Files []string `json:"files,omitempty"` 57 Sent int64 `json:"sent,omitempty"` 58 } 59 60 func (ts *TransferRunStatus) action(action ActionOnStatusFunc) error { 61 if err := action(ts); err != nil { 62 return err 63 } 64 65 now := time.Now() 66 if now.Sub(ts.lastSaveTimestamp).Seconds() < float64(stateAndStatusSaveIntervalSecs) { 67 return nil 68 } 69 70 if !saveRunStatusMutex.TryLock() { 71 return nil 72 } 73 defer saveRunStatusMutex.Unlock() 74 75 ts.lastSaveTimestamp = now 76 return ts.persistTransferRunStatus() 77 } 78 79 func (ts *TransferRunStatus) persistTransferRunStatus() (err error) { 80 statusFilePath, err := coreutils.GetJfrogTransferRunStatusFilePath() 81 if err != nil { 82 return err 83 } 84 85 ts.Version = transferRunStatusVersion 86 content, err := json.Marshal(ts) 87 if err != nil { 88 return errorutils.CheckError(err) 89 } 90 91 err = os.WriteFile(statusFilePath, content, 0600) 92 if err != nil { 93 return errorutils.CheckError(err) 94 } 95 return nil 96 } 97 98 func loadTransferRunStatus() (transferRunStatus TransferRunStatus, exists bool, err error) { 99 statusFilePath, err := coreutils.GetJfrogTransferRunStatusFilePath() 100 if err != nil { 101 return 102 } 103 exists, err = fileutils.IsFileExists(statusFilePath, false) 104 if err != nil || !exists { 105 return 106 } 107 108 content, err := fileutils.ReadFile(statusFilePath) 109 if err != nil { 110 return 111 } 112 113 err = errorutils.CheckError(json.Unmarshal(content, &transferRunStatus)) 114 return 115 } 116 117 func VerifyTransferRunStatusVersion() error { 118 transferRunStatus, exists, err := loadTransferRunStatus() 119 if err != nil || !exists { 120 return err 121 } 122 if transferRunStatus.Version != transferRunStatusVersion { 123 return GetOldTransferDirectoryStructureError() 124 } 125 return nil 126 }