Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9a2026d

Browse files
committed
chore: add mutagen session state conversions
1 parent64c54d6 commit9a2026d

File tree

4 files changed

+254
-26
lines changed

4 files changed

+254
-26
lines changed

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,17 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
1111
varbody:someView{
1212
Group{
1313
Table(items, selection: $selection){
14-
TableColumn("Local Path"){ rowin
15-
Text(row.localPath.path())
14+
TableColumn("Local Path"){
15+
Text($0.localPath).help($0.localPath)
1616
}.width(min:200, ideal:240)
17-
TableColumn("Workspace", value: \.workspace)
17+
TableColumn("Workspace", value: \.agentHost)
1818
.width(min:100, ideal:120)
19-
TableColumn("Remote Path", value: \.remotePath)
19+
TableColumn("Remote Path"){Text($0.remotePath).help($0.remotePath)}
2020
.width(min:100, ideal:120)
21-
TableColumn("Status"){ $0.status.body}
21+
TableColumn("Status"){ $0.status.column.help($0.statusAndErrors)}
2222
.width(min:80, ideal:100)
23-
TableColumn("Size"){ itemin
24-
Text(item.size)
25-
}
26-
.width(min:60, ideal:80)
23+
TableColumn("Size"){Text($0.maxSize.humanSizeBytes).help($0.sizeDescription)}
24+
.width(min:60, ideal:80)
2725
}
2826
.frame(minWidth:400, minHeight:200)
2927
.padding(.bottom,25)

‎Coder-Desktop/VPNLib/FileSync/FileSyncSession.swift

Lines changed: 179 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,142 @@ import SwiftUI
22

33
publicstructFileSyncSession:Identifiable{
44
publicletid:String
5-
publicletlocalPath:URL
6-
publicletworkspace:String
7-
// This is a string as to be host-OS agnostic
5+
publicletname:String
6+
7+
publicletlocalPath:String
8+
publicletagentHost:String
89
publicletremotePath:String
910
publicletstatus:FileSyncStatus
10-
publicletsize:String
11+
12+
publicletmaxSize:FileSyncSessionEndpointSize
13+
publicletlocalSize:FileSyncSessionEndpointSize
14+
publicletremoteSize:FileSyncSessionEndpointSize
15+
16+
publicleterrors:[FileSyncError]
17+
18+
init(state:Synchronization_State){
19+
id= state.session.identifier
20+
name= state.session.name
21+
22+
// If the protocol isn't what we expect for alpha or beta, show unknown
23+
localPath=if state.session.alpha.protocol==Url_Protocol.local, !state.session.alpha.path.isEmpty{
24+
state.session.alpha.path
25+
}else{
26+
"Unknown"
27+
}
28+
if state.session.beta.protocol==Url_Protocol.ssh, !state.session.beta.host.isEmpty{
29+
lethost= state.session.beta.host
30+
// TOOD: We need to either:
31+
// - make this compatible with custom suffixes
32+
// - always strip the tld
33+
// - always keep the tld
34+
agentHost= host.hasSuffix(".coder")?String(host.dropLast(6)): host
35+
}else{
36+
agentHost="Unknown"
37+
}
38+
remotePath=if !state.session.beta.path.isEmpty{
39+
state.session.beta.path
40+
}else{
41+
"Unknown"
42+
}
43+
44+
varstatus:FileSyncStatus=if state.session.paused{
45+
.paused
46+
}else{
47+
convertSessionStatus(status: state.status)
48+
}
49+
if case.error= status{}else{
50+
if state.conflicts.count>0{
51+
status=.needsAttention(name:"Conflicts", desc:"The session has conflicts that need to be resolved")
52+
}
53+
}
54+
self.status= status
55+
56+
localSize=.init(
57+
sizeBytes: state.alphaState.totalFileSize,
58+
fileCount: state.alphaState.files,
59+
dirCount: state.alphaState.directories,
60+
symLinkCount: state.alphaState.symbolicLinks
61+
)
62+
remoteSize=.init(
63+
sizeBytes: state.betaState.totalFileSize,
64+
fileCount: state.betaState.files,
65+
dirCount: state.betaState.directories,
66+
symLinkCount: state.betaState.symbolicLinks
67+
)
68+
maxSize= localSize.maxOf(other: remoteSize)
69+
70+
errors=accumulateErrors(from: state)
71+
}
72+
73+
publicvarstatusAndErrors:String{
74+
varout="\(status.type)\n\n\(status.description)"
75+
errors.forEach{ out+="\n\t\($0)"}
76+
return out
77+
}
78+
79+
publicvarsizeDescription:String{
80+
varout=""
81+
if localSize!= remoteSize{
82+
out+="Maximum:\n\(maxSize.description(linePrefix:""))\n\n"
83+
}
84+
out+="Local:\n\(localSize.description(linePrefix:""))\n\n"
85+
out+="Remote:\n\(remoteSize.description(linePrefix:""))"
86+
return out
87+
}
88+
}
89+
90+
publicstructFileSyncSessionEndpointSize:Equatable{
91+
publicletsizeBytes:UInt64
92+
publicletfileCount:UInt64
93+
publicletdirCount:UInt64
94+
publicletsymLinkCount:UInt64
95+
96+
publicinit(sizeBytes:UInt64, fileCount:UInt64, dirCount:UInt64, symLinkCount:UInt64){
97+
self.sizeBytes= sizeBytes
98+
self.fileCount= fileCount
99+
self.dirCount= dirCount
100+
self.symLinkCount= symLinkCount
101+
}
102+
103+
func maxOf(other:FileSyncSessionEndpointSize)->FileSyncSessionEndpointSize{
104+
FileSyncSessionEndpointSize(
105+
sizeBytes:max(sizeBytes, other.sizeBytes),
106+
fileCount:max(fileCount, other.fileCount),
107+
dirCount:max(dirCount, other.dirCount),
108+
symLinkCount:max(symLinkCount, other.symLinkCount)
109+
)
110+
}
111+
112+
publicvarhumanSizeBytes:String{
113+
humanReadableBytes(sizeBytes)
114+
}
115+
116+
publicfunc description(linePrefix:String="")->String{
117+
varresult=""
118+
result+= linePrefix+ humanReadableBytes(sizeBytes)+"\n"
119+
letnumberFormatter=NumberFormatter()
120+
numberFormatter.numberStyle=.decimal
121+
iflet formattedFileCount= numberFormatter.string(from:NSNumber(value: fileCount)){
122+
result+="\(linePrefix)\(formattedFileCount) file\(fileCount==1?"":"s")\n"
123+
}
124+
iflet formattedDirCount= numberFormatter.string(from:NSNumber(value: dirCount)){
125+
result+="\(linePrefix)\(formattedDirCount) director\(dirCount==1?"y":"ies")"
126+
}
127+
if symLinkCount>0,let formattedSymLinkCount= numberFormatter.string(from:NSNumber(value: symLinkCount)){
128+
result+="\n\(linePrefix)\(formattedSymLinkCount) symlink\(symLinkCount==1?"":"s")"
129+
}
130+
return result
131+
}
11132
}
12133

13134
publicenumFileSyncStatus{
14135
case unknown
15-
case error(String)
136+
case error(name:String, desc:String)
16137
case ok
17138
case paused
18-
case needsAttention(String)
19-
case working(String)
139+
case needsAttention(name:String, desc:String)
140+
case working(name:String, desc:String)
20141

21142
publicvarcolor:Color{
22143
switchself{
@@ -31,28 +152,69 @@ public enum FileSyncStatus {
31152
case.needsAttention:
32153
.orange
33154
case.working:
34-
.white
155+
.purple
35156
}
36157
}
37158

38-
publicvardescription:String{
159+
publicvartype:String{
39160
switchself{
40161
case.unknown:
41162
"Unknown"
42-
caselet.error(msg):
43-
msg
163+
caselet.error(name, _):
164+
"\(name)"
44165
case.ok:
45166
"Watching"
46167
case.paused:
47168
"Paused"
48-
caselet.needsAttention(msg):
49-
msg
50-
caselet.working(msg):
51-
msg
169+
caselet.needsAttention(name, _):
170+
name
171+
caselet.working(name, _):
172+
name
52173
}
53174
}
54175

55-
publicvarbody:someView{
56-
Text(description).foregroundColor(color)
176+
publicvardescription:String{
177+
switchself{
178+
case.unknown:
179+
"Unknown status message."
180+
caselet.error(_, desc):
181+
desc
182+
case.ok:
183+
"The session is watching for filesystem changes."
184+
case.paused:
185+
"The session is paused."
186+
caselet.needsAttention(_, desc):
187+
desc
188+
caselet.working(_, desc):
189+
desc
190+
}
191+
}
192+
193+
publicvarcolumn:someView{
194+
Text(type).foregroundColor(color)
195+
}
196+
}
197+
198+
publicenumFileSyncEndpoint{
199+
case local
200+
case remote
201+
}
202+
203+
publicenumFileSyncProblemType{
204+
case scan
205+
case transition
206+
}
207+
208+
publicenumFileSyncError{
209+
case generic(String)
210+
case problem(FileSyncEndpoint,FileSyncProblemType, path:String, error:String)
211+
212+
vardescription:String{
213+
switchself{
214+
caselet.generic(error):
215+
error
216+
caselet.problem(endpoint, type, path, error):
217+
"\(endpoint)\(type) error at\(path):\(error)"
218+
}
57219
}
58220
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// swiftlint:disable:next cyclomatic_complexity
2+
func convertSessionStatus(status:Synchronization_Status)->FileSyncStatus{
3+
switch status{
4+
case.disconnected:
5+
.error(name:"Disconnected",
6+
desc:"The session is unpaused but not currently connected or connecting to either endpoint.")
7+
case.haltedOnRootEmptied:
8+
.error(name:"Halted on root emptied", desc:"The session is halted due to the root emptying safety check.")
9+
case.haltedOnRootDeletion:
10+
.error(name:"Halted on root deletion", desc:"The session is halted due to the root deletion safety check.")
11+
case.haltedOnRootTypeChange:
12+
.error(
13+
name:"Halted on root type change",
14+
desc:"The session is halted due to the root type change safety check."
15+
)
16+
case.waitingForRescan:
17+
.error(name:"Waiting for rescan",
18+
desc:"The session is waiting to retry scanning after an error during the previous scan.")
19+
case.connectingAlpha:
20+
// Alpha -> Local
21+
.working(name:"Connecting (local)", desc:"The session is attempting to connect to the local endpoint.")
22+
case.connectingBeta:
23+
// Beta -> Remote
24+
.working(name:"Connecting (remote)", desc:"The session is attempting to connect to the remote endpoint.")
25+
case.scanning:
26+
.working(name:"Scanning", desc:"The session is scanning the filesystem on each endpoint.")
27+
case.reconciling:
28+
.working(name:"Reconciling", desc:"The session is performing reconciliation.")
29+
case.stagingAlpha:
30+
// Alpha -> Local
31+
.working(name:"Staging (local)", desc:"The session is staging files locally")
32+
case.stagingBeta:
33+
// Beta -> Remote
34+
.working(name:"Staging (remote)", desc:"The session is staging files on the remote")
35+
case.transitioning:
36+
.working(name:"Transitioning", desc:"The session is performing transition operations on each endpoint.")
37+
case.saving:
38+
.working(name:"Saving", desc:"The session is recording synchronization history to disk.")
39+
case.watching:
40+
.ok
41+
case.UNRECOGNIZED:
42+
.unknown
43+
}
44+
}
45+
46+
func accumulateErrors(from state:Synchronization_State)->[FileSyncError]{
47+
varerrors:[FileSyncError]=[]
48+
if !state.lastError.isEmpty{
49+
errors.append(.generic(state.lastError))
50+
}
51+
forproblemin state.alphaState.scanProblems{
52+
errors.append(.problem(.local,.scan, path: problem.path, error: problem.error))
53+
}
54+
forproblemin state.alphaState.transitionProblems{
55+
errors.append(.problem(.local,.transition, path: problem.path, error: problem.error))
56+
}
57+
forproblemin state.betaState.scanProblems{
58+
errors.append(.problem(.remote,.scan, path: problem.path, error: problem.error))
59+
}
60+
forproblemin state.betaState.transitionProblems{
61+
errors.append(.problem(.remote,.transition, path: problem.path, error: problem.error))
62+
}
63+
return errors
64+
}
65+
66+
func humanReadableBytes(_ bytes:UInt64)->String{
67+
ByteCountFormatter().string(fromByteCount:Int64(bytes))
68+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp