Revision control

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
import Sync
6
import Shared
7
import Storage
8
9
public enum SyncDisplayState {
10
case inProgress
11
case good
12
case bad(message: String?)
13
case warning(message: String)
14
15
func asObject() -> [String: String]? {
16
switch self {
17
case .bad(let msg):
18
guard let message = msg else {
19
return ["state": "Error"]
20
}
21
return ["state": "Error",
22
"message": message]
23
case .warning(let message):
24
return ["state": "Warning",
25
"message": message]
26
default:
27
break
28
}
29
return nil
30
}
31
}
32
33
public func ==(a: SyncDisplayState, b: SyncDisplayState) -> Bool {
34
switch (a, b) {
35
case (.inProgress, .inProgress):
36
return true
37
case (.good, .good):
38
return true
39
case (.bad(let a), .bad(let b)) where a == b:
40
return true
41
case (.warning(let a), .warning(let b)) where a == b:
42
return true
43
default:
44
return false
45
}
46
}
47
48
/*
49
* Translates the fine-grained SyncStatuses of each sync engine into a more coarse-grained
50
* display-oriented state for displaying warnings/errors to the user.
51
*/
52
public struct SyncStatusResolver {
53
54
let engineResults: Maybe<EngineResults>
55
56
public func resolveResults() -> SyncDisplayState {
57
guard let results = engineResults.successValue else {
58
return SyncDisplayState.bad(message: nil)
59
}
60
61
// Run through the engine results and produce a relevant display status for each one
62
let displayStates: [SyncDisplayState] = results.map { (engineIdentifier, syncStatus) in
63
print("Sync status for \(engineIdentifier): \(syncStatus)")
64
65
// Explicitly call out each of the enum cases to let us lean on the compiler when
66
// we add new error states
67
switch syncStatus {
68
case .notStarted(let reason):
69
switch reason {
70
case .offline:
71
return .bad(message: Strings.FirefoxSyncOfflineTitle)
72
case .noAccount:
73
return .warning(message: Strings.FirefoxSyncOfflineTitle)
74
case .backoff(_):
75
return .good
76
case .engineRemotelyNotEnabled(_):
77
return .good
78
case .engineFormatOutdated(_):
79
return .good
80
case .engineFormatTooNew(_):
81
return .good
82
case .storageFormatOutdated(_):
83
return .good
84
case .storageFormatTooNew(_):
85
return .good
86
case .stateMachineNotReady:
87
return .good
88
case .redLight:
89
return .good
90
case .unknown:
91
return .good
92
}
93
case .completed:
94
return .good
95
case .partial:
96
return .good
97
}
98
}
99
100
// TODO: Instead of finding the worst offender in a list of statuses, we should better surface
101
// what might have happened with a particular engine when syncing.
102
let aggregate: SyncDisplayState = displayStates.reduce(.good) { carried, displayState in
103
switch displayState {
104
105
case .bad(_):
106
return displayState
107
108
case .warning(_):
109
// If the state we're carrying is worse than the stale one, keep passing
110
// along the worst one
111
switch carried {
112
case .bad(_):
113
return carried
114
default:
115
return displayState
116
}
117
default:
118
// This one is good so just pass on what was being carried
119
return carried
120
}
121
}
122
123
print("Resolved sync display state: \(aggregate)")
124
return aggregate
125
}
126
}