vibes-react-native 5.0.0 → 5.0.1-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/Vibes.swift +2 -3
- package/ios/VibesClient.swift +3 -4
- package/ios/VibesPluginLogger.swift +2 -5
- package/package.json +3 -2
- package/vendor/VibesPush/LICENSE +13 -0
- package/vendor/VibesPush/Sources/APIDefinition.swift +502 -0
- package/vendor/VibesPush/Sources/Actions.swift +24 -0
- package/vendor/VibesPush/Sources/AppObserver.swift +137 -0
- package/vendor/VibesPush/Sources/AuthTokenBehavior.swift +17 -0
- package/vendor/VibesPush/Sources/CombinedLogger.swift +53 -0
- package/vendor/VibesPush/Sources/ConsoleLogger.swift +97 -0
- package/vendor/VibesPush/Sources/Credential.swift +41 -0
- package/vendor/VibesPush/Sources/CredentialManager.swift +24 -0
- package/vendor/VibesPush/Sources/Date+iso8601.swift +34 -0
- package/vendor/VibesPush/Sources/Date+logPrefix.swift +20 -0
- package/vendor/VibesPush/Sources/DeviceToken.swift +15 -0
- package/vendor/VibesPush/Sources/DeviceType.swift +143 -0
- package/vendor/VibesPush/Sources/Dictionary+merged.swift +11 -0
- package/vendor/VibesPush/Sources/Event.swift +83 -0
- package/vendor/VibesPush/Sources/EventCollection.swift +36 -0
- package/vendor/VibesPush/Sources/EventTracker.swift +39 -0
- package/vendor/VibesPush/Sources/FoundationExtensions.swift +16 -0
- package/vendor/VibesPush/Sources/GitTag.swift +27 -0
- package/vendor/VibesPush/Sources/HTTP/HTTPBehavior.swift +19 -0
- package/vendor/VibesPush/Sources/HTTP/HTTPMethod.swift +20 -0
- package/vendor/VibesPush/Sources/HTTP/HTTPResource.swift +69 -0
- package/vendor/VibesPush/Sources/HTTP/HTTPResourceClient.swift +190 -0
- package/vendor/VibesPush/Sources/HTTP/JSONParser.swift +91 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/AssociatePersonOperation.swift +56 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/BaseOperation.swift +153 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/EventOperation.swift +73 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/GetGitTagsOperation.swift +61 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/GetInboxMessageOperation.swift +59 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/GetInboxMessagesOperation.swift +57 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/GetPersonOperation.swift +53 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/GetVibesAppInfoOperation.swift +45 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/MigrationCallbackOperation.swift +45 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/RegisterDeviceOperation.swift +66 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/RegisterPushOperation.swift +73 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/TrackProductActionOperation.swift +75 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/TrackPurchaseActionOperation.swift +81 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/UnregisterDeviceOperation.swift +64 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/UnregisterPushOperation.swift +72 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/UpdateDeviceOperationPatch.swift +57 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/UpdateDeviceOperationPut.swift +59 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/UpdateMessageOperation.swift +50 -0
- package/vendor/VibesPush/Sources/HTTP/Operations/VibesQueueOperation.swift +76 -0
- package/vendor/VibesPush/Sources/HTTP/ResourceResult.swift +38 -0
- package/vendor/VibesPush/Sources/HTTPURLResponse+cURL.swift +16 -0
- package/vendor/VibesPush/Sources/InboxMessage.swift +219 -0
- package/vendor/VibesPush/Sources/Info.plist +26 -0
- package/vendor/VibesPush/Sources/InputStream+readToString.swift +19 -0
- package/vendor/VibesPush/Sources/KeychainStorage.swift +64 -0
- package/vendor/VibesPush/Sources/LocalObject.swift +25 -0
- package/vendor/VibesPush/Sources/LocalStorageKeys.swift +19 -0
- package/vendor/VibesPush/Sources/LocalStorageType.swift +47 -0
- package/vendor/VibesPush/Sources/LocalValue.swift +67 -0
- package/vendor/VibesPush/Sources/PersistentEventStorage.swift +81 -0
- package/vendor/VibesPush/Sources/Person.swift +98 -0
- package/vendor/VibesPush/Sources/Product.swift +103 -0
- package/vendor/VibesPush/Sources/Purchase.swift +108 -0
- package/vendor/VibesPush/Sources/TrackedEventType.swift +48 -0
- package/vendor/VibesPush/Sources/URLRequest+cURL.swift +36 -0
- package/vendor/VibesPush/Sources/UserDefaultsStorage.swift +32 -0
- package/vendor/VibesPush/Sources/Vibes.swift +1069 -0
- package/vendor/VibesPush/Sources/VibesAPI.swift +81 -0
- package/vendor/VibesPush/Sources/VibesAPIDelegate.swift +41 -0
- package/vendor/VibesPush/Sources/VibesAppInfo.swift +77 -0
- package/vendor/VibesPush/Sources/VibesConfiguration.swift +108 -0
- package/vendor/VibesPush/Sources/VibesLogger.swift +65 -0
- package/vendor/VibesPush/Sources/VibesResult.swift +78 -0
- package/vibes-react-native.podspec +6 -2
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
//
|
|
2
|
+
// InboxMessage.swift
|
|
3
|
+
// VibesPush
|
|
4
|
+
//
|
|
5
|
+
// Created by Moin' Victor on 12/07/2019.
|
|
6
|
+
// Copyright © 2019 Vibes. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
/// Inbox Message Model
|
|
12
|
+
@objcMembers
|
|
13
|
+
public class InboxMessage: NSObject, JSONDecodable, LocalObjectType, JSONEncodable {
|
|
14
|
+
|
|
15
|
+
static let kActivityTypeKey = "activityType"
|
|
16
|
+
static let kActivityUidKey = "activityUid"
|
|
17
|
+
|
|
18
|
+
static let eActivityTypeKey = "activity_type"
|
|
19
|
+
static let eActivityUidKey = "activity_uid"
|
|
20
|
+
static let eMessageUidKey = "message_uid"
|
|
21
|
+
|
|
22
|
+
/// Local Atrributes
|
|
23
|
+
public var attributes: [String: Any] {
|
|
24
|
+
return [
|
|
25
|
+
"message_uid": messageUID ?? "",
|
|
26
|
+
"subject": subject ?? "",
|
|
27
|
+
"content": content ?? "",
|
|
28
|
+
"detail": detail ?? "",
|
|
29
|
+
"expires_at": expiresAt ?? Date(),
|
|
30
|
+
"created_at": createdAt,
|
|
31
|
+
"collapse_key": collapseKey ?? "",
|
|
32
|
+
"images": images,
|
|
33
|
+
"read": read,
|
|
34
|
+
"inbox_custom_data": inboxCustomData,
|
|
35
|
+
"client_app_data": clientAppData,
|
|
36
|
+
"apprefdata": apprefData,
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public func encodeJSON() -> VibesJSONDictionary {
|
|
41
|
+
return [
|
|
42
|
+
"message_uid": messageUID as AnyObject,
|
|
43
|
+
"subject": subject as AnyObject,
|
|
44
|
+
"content": content as AnyObject,
|
|
45
|
+
"detail": detail as AnyObject,
|
|
46
|
+
"expires_at": expiresAt?.iso8601 as AnyObject,
|
|
47
|
+
"created_at": createdAt.iso8601 as AnyObject,
|
|
48
|
+
"collapse_key": collapseKey as AnyObject,
|
|
49
|
+
"images": images as AnyObject,
|
|
50
|
+
"read": read as AnyObject,
|
|
51
|
+
"inbox_custom_data": inboxCustomData as AnyObject,
|
|
52
|
+
"client_app_data": clientAppData as AnyObject,
|
|
53
|
+
"apprefdata": apprefData as AnyObject,
|
|
54
|
+
] as VibesJSONDictionary
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public var jsonString: String? {
|
|
58
|
+
let jsonData = try? JSONSerialization.data(withJSONObject: encodeJSON(), options: .prettyPrinted)
|
|
59
|
+
return String(data: jsonData!, encoding: .utf8)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// Main Image for this inbox message
|
|
63
|
+
public var mainImage: String? {
|
|
64
|
+
return images["main"]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Icon image for this push message
|
|
68
|
+
public var iconImage: String? {
|
|
69
|
+
return images["icon"]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Inbox message uid
|
|
73
|
+
public var inboxMessageUID: String? {
|
|
74
|
+
return clientAppData["inbox_message_uid"] as? String
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// An uniqie identifier assosiated with the message
|
|
78
|
+
public internal(set) var messageUID: String!
|
|
79
|
+
/// The collapse key
|
|
80
|
+
public internal(set) var collapseKey: String?
|
|
81
|
+
/// The subject of the message
|
|
82
|
+
public var subject: String?
|
|
83
|
+
/// A message content
|
|
84
|
+
public var content: String!
|
|
85
|
+
/// Some details for this message, Currently this is the media URL
|
|
86
|
+
public internal(set) var detail: String?
|
|
87
|
+
/// If the message is read
|
|
88
|
+
public var read: Bool = false
|
|
89
|
+
/// images details for this message
|
|
90
|
+
public internal(set) var images = [String: String]()
|
|
91
|
+
/// inbox custom data details for this message
|
|
92
|
+
public internal(set) var inboxCustomData = VibesJSONDictionary()
|
|
93
|
+
/// client app data details for this message
|
|
94
|
+
public internal(set) var clientAppData = VibesJSONDictionary()
|
|
95
|
+
/// Appref data details for this message
|
|
96
|
+
public internal(set) var apprefData = VibesJSONDictionary()
|
|
97
|
+
/// When the message expires
|
|
98
|
+
public var expiresAt: Date?
|
|
99
|
+
/// When the message was created
|
|
100
|
+
public internal(set) var createdAt: Date = Date()
|
|
101
|
+
|
|
102
|
+
override init() {
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// Initialize new InboxMessage using properties
|
|
106
|
+
///
|
|
107
|
+
/// - Parameters:
|
|
108
|
+
/// - messageUID: The message id
|
|
109
|
+
/// - subject: The subject of the message
|
|
110
|
+
/// - content: The content of the message
|
|
111
|
+
/// - detail: The message details
|
|
112
|
+
/// - readStatus: The read status of the message in bool
|
|
113
|
+
/// - expiresAt: Date when the message expires
|
|
114
|
+
init(messageUID: String, subject: String?, content: String, detail: String?, read: Bool, expiresAt: Date? = nil) {
|
|
115
|
+
self.messageUID = messageUID
|
|
116
|
+
self.subject = subject
|
|
117
|
+
self.content = content
|
|
118
|
+
self.detail = detail
|
|
119
|
+
self.read = read
|
|
120
|
+
self.expiresAt = expiresAt
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Initialize new InboxMessage from JSONObject
|
|
124
|
+
///
|
|
125
|
+
/// - Parameter json: The JSON object
|
|
126
|
+
required convenience init?(json: VibesJSONDictionary) {
|
|
127
|
+
self.init()
|
|
128
|
+
guard let messageUID = json["message_uid"] as? String,
|
|
129
|
+
let content = json["content"] as? String else { return nil }
|
|
130
|
+
|
|
131
|
+
self.subject = json["subject"] as? String
|
|
132
|
+
detail = json["detail"] as? String
|
|
133
|
+
collapseKey = json["collapse_key"] as? String
|
|
134
|
+
if let readStatusValue = json["read"] as? Bool {
|
|
135
|
+
read = readStatusValue
|
|
136
|
+
}
|
|
137
|
+
if let expireDateString = json["expires_at"] as? String,
|
|
138
|
+
let expireDateTime = expireDateString.iso8601 {
|
|
139
|
+
expiresAt = expireDateTime
|
|
140
|
+
}
|
|
141
|
+
if let createdDateString = json["created_at"] as? String,
|
|
142
|
+
let createdDateTime = createdDateString.iso8601 {
|
|
143
|
+
createdAt = createdDateTime
|
|
144
|
+
}
|
|
145
|
+
if let images = json["images"] as? [String: String] {
|
|
146
|
+
self.images = images
|
|
147
|
+
}
|
|
148
|
+
if let inboxCustomData = json["inbox_custom_data"] as? VibesJSONDictionary {
|
|
149
|
+
self.inboxCustomData = inboxCustomData
|
|
150
|
+
}
|
|
151
|
+
if let clientAppData = json["client_app_data"] as? VibesJSONDictionary {
|
|
152
|
+
self.clientAppData = clientAppData
|
|
153
|
+
}
|
|
154
|
+
if let apprefData = json["apprefdata"] as? VibesJSONDictionary {
|
|
155
|
+
self.apprefData = apprefData
|
|
156
|
+
}
|
|
157
|
+
self.messageUID = messageUID
|
|
158
|
+
self.content = content
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// Initialize this object using Attributes
|
|
162
|
+
///
|
|
163
|
+
/// - Parameter attributes: - The dictionary with attributes
|
|
164
|
+
public required convenience init?(attributes: [String: Any]) {
|
|
165
|
+
self.init()
|
|
166
|
+
|
|
167
|
+
guard let messageUID = attributes["message_uid"] as? String, !messageUID.isEmpty,
|
|
168
|
+
let content = attributes["content"] as? String else { return nil }
|
|
169
|
+
|
|
170
|
+
self.subject = attributes["subject"] as? String
|
|
171
|
+
detail = attributes["detail"] as? String
|
|
172
|
+
collapseKey = attributes["collapse_key"] as? String
|
|
173
|
+
if let readStatusValue = attributes["read"] as? Bool {
|
|
174
|
+
read = readStatusValue
|
|
175
|
+
}
|
|
176
|
+
if let expireDate = attributes["expires_at"] as? Date {
|
|
177
|
+
expiresAt = expireDate
|
|
178
|
+
}
|
|
179
|
+
if let createdDateTime = attributes["created_at"] as? Date {
|
|
180
|
+
createdAt = createdDateTime
|
|
181
|
+
}
|
|
182
|
+
if let images = attributes["images"] as? [String: String] {
|
|
183
|
+
self.images = images
|
|
184
|
+
}
|
|
185
|
+
if let inboxCustomData = attributes["inbox_custom_data"] as? VibesJSONDictionary {
|
|
186
|
+
self.inboxCustomData = inboxCustomData
|
|
187
|
+
}
|
|
188
|
+
if let clientAppData = attributes["client_app_data"] as? VibesJSONDictionary {
|
|
189
|
+
self.clientAppData = clientAppData
|
|
190
|
+
}
|
|
191
|
+
if let apprefData = attributes["apprefdata"] as? VibesJSONDictionary {
|
|
192
|
+
self.apprefData = apprefData
|
|
193
|
+
}
|
|
194
|
+
self.messageUID = messageUID
|
|
195
|
+
self.content = content
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/// Equals Comparison operator for InboxMessage
|
|
200
|
+
///
|
|
201
|
+
/// - Parameters:
|
|
202
|
+
/// - lhs: The left hand side InboxMessage
|
|
203
|
+
/// - rhs: The right hand side InboxMessage
|
|
204
|
+
/// - Returns: `True` if `lhs` is equal to `rhs`, else returns `False`
|
|
205
|
+
public func == (lhs: InboxMessage, rhs: InboxMessage) -> Bool {
|
|
206
|
+
return lhs.messageUID == rhs.messageUID
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
extension InboxMessage {
|
|
210
|
+
|
|
211
|
+
/// The vent map for this inbox message
|
|
212
|
+
internal func eventMap() -> [String: String] {
|
|
213
|
+
var evMap = [String: String]()
|
|
214
|
+
evMap[InboxMessage.eMessageUidKey] = messageUID
|
|
215
|
+
evMap[InboxMessage.eActivityTypeKey] = apprefData[InboxMessage.kActivityTypeKey] as? String
|
|
216
|
+
evMap[InboxMessage.eActivityUidKey] = apprefData[InboxMessage.kActivityUidKey] as? String
|
|
217
|
+
return evMap
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>en</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>FMWK</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>5.0.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
+
<key>LSApplicationCategoryType</key>
|
|
22
|
+
<string></string>
|
|
23
|
+
<key>NSPrincipalClass</key>
|
|
24
|
+
<string></string>
|
|
25
|
+
</dict>
|
|
26
|
+
</plist>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
extension InputStream {
|
|
4
|
+
/// Read input stream to a String
|
|
5
|
+
func readToString() -> String? {
|
|
6
|
+
var data = Data()
|
|
7
|
+
self.open()
|
|
8
|
+
|
|
9
|
+
let bufferSize = 1024
|
|
10
|
+
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
|
|
11
|
+
while self.hasBytesAvailable {
|
|
12
|
+
let read = self.read(buffer, maxLength: bufferSize)
|
|
13
|
+
data.append(buffer, count: read)
|
|
14
|
+
}
|
|
15
|
+
buffer.deallocate()
|
|
16
|
+
self.close()
|
|
17
|
+
return String(data: data, encoding: String.Encoding.utf8)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
/// A storage adapter that uses the Keychain as a local storage mechanism.
|
|
3
|
+
struct KeychainStorage {
|
|
4
|
+
/// The "service" name to use
|
|
5
|
+
fileprivate let service: String
|
|
6
|
+
|
|
7
|
+
/// Initialize this object.
|
|
8
|
+
///
|
|
9
|
+
/// - parameters:
|
|
10
|
+
/// - service: the "service" name to use
|
|
11
|
+
init(service: String) {
|
|
12
|
+
self.service = service
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
extension KeychainStorage: LocalStorageType {
|
|
17
|
+
/// Retrieves the value in the keychain for the provided item.
|
|
18
|
+
///
|
|
19
|
+
/// - parameters:
|
|
20
|
+
/// - item: the local storage item to retreive
|
|
21
|
+
/// - returns: the previously-stored value, or nil
|
|
22
|
+
func get<T>(_ item: LocalValue<T>) -> T? {
|
|
23
|
+
let attributes = [
|
|
24
|
+
String(kSecClass): kSecClassGenericPassword,
|
|
25
|
+
String(kSecAttrService): service,
|
|
26
|
+
String(kSecMatchLimit): kSecMatchLimitOne,
|
|
27
|
+
String(kSecAttrAccount): item.key,
|
|
28
|
+
String(kSecReturnData): true,
|
|
29
|
+
] as [String: Any]
|
|
30
|
+
|
|
31
|
+
var result: AnyObject?
|
|
32
|
+
let status = SecItemCopyMatching(attributes as CFDictionary, &result)
|
|
33
|
+
|
|
34
|
+
guard status == noErr else { return nil }
|
|
35
|
+
guard let data = result as? Data else { return nil }
|
|
36
|
+
|
|
37
|
+
return T.unarchive(data: data)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Stores a value in the keychain with the key provided.
|
|
41
|
+
///
|
|
42
|
+
/// - parameters:
|
|
43
|
+
/// - value: the value to store
|
|
44
|
+
/// - item: the local storage item to use for storage
|
|
45
|
+
/// - returns: a boolean indicating whether storing the value was successful
|
|
46
|
+
func set<T>(_ value: T?, for item: LocalValue<T>) -> Bool {
|
|
47
|
+
var attributes = [
|
|
48
|
+
String(kSecClass): kSecClassGenericPassword,
|
|
49
|
+
String(kSecAttrService): service,
|
|
50
|
+
String(kSecAttrAccount): item.key,
|
|
51
|
+
] as [String: Any]
|
|
52
|
+
|
|
53
|
+
if let value = value {
|
|
54
|
+
attributes[String(kSecValueData)] = T.archive(value: value)
|
|
55
|
+
SecItemDelete(attributes as CFDictionary)
|
|
56
|
+
|
|
57
|
+
let status = SecItemAdd(attributes as CFDictionary, nil)
|
|
58
|
+
return status == noErr
|
|
59
|
+
} else {
|
|
60
|
+
let status = SecItemDelete(attributes as CFDictionary)
|
|
61
|
+
return status == noErr
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// A protocol for anything that can be stored as an object.
|
|
2
|
+
public protocol LocalObjectType {
|
|
3
|
+
/// Attributes that should be used to store this object in local storage.
|
|
4
|
+
var attributes: [String: Any] { get }
|
|
5
|
+
|
|
6
|
+
/// Creates an object from a set of previously-stored attributes.
|
|
7
|
+
///
|
|
8
|
+
/// - parameters:
|
|
9
|
+
/// - attributes: a dictionary of attributes to use to create this object
|
|
10
|
+
init?(attributes: [String: Any])
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// A simple struct for identifying an object that is held in local storage.
|
|
14
|
+
public struct LocalObject<T: LocalObjectType> {
|
|
15
|
+
/// The identifier to use to store this object.
|
|
16
|
+
let key: String
|
|
17
|
+
|
|
18
|
+
/// Initialize this object
|
|
19
|
+
///
|
|
20
|
+
/// - paremeters:
|
|
21
|
+
/// - key: the identifier to use to store this object
|
|
22
|
+
init(_ key: String) {
|
|
23
|
+
self.key = key
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// Type-safe local storage used by Vibes; these static instances encapsulate
|
|
2
|
+
/// the key used to store some data in local storage, along with encoding the
|
|
3
|
+
/// expected type information that should be returned.
|
|
4
|
+
enum LocalStorageKeys {
|
|
5
|
+
/// The current device's push token
|
|
6
|
+
static let pushToken = LocalValue<String>("VIBES_PUSH_TOKEN")
|
|
7
|
+
|
|
8
|
+
/// The current Credential
|
|
9
|
+
static let currentCredential = LocalObject<VibesCredential>("VIBES_CURRENT_CREDENTIAL")
|
|
10
|
+
|
|
11
|
+
/// The set of all known Credentials
|
|
12
|
+
static let allCredentials = LocalValue<[String: String]>("VIBES_ALL_CREDENTIALS")
|
|
13
|
+
|
|
14
|
+
/// All events that have been stored locally
|
|
15
|
+
static let events = LocalObject<EventCollection>("VIBES_EVENTS")
|
|
16
|
+
|
|
17
|
+
/// The current Vibes Person
|
|
18
|
+
static let currentPerson = LocalObject<Person>("VIBES_CURRENT_PERSON")
|
|
19
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/// A protocol that defines an adapter for allowing the storage of values in
|
|
2
|
+
/// some sort of local storage mechanism (e.g. UserDefaults, Keychain, etc.).
|
|
3
|
+
///
|
|
4
|
+
/// Adopters of this protocol get the ability to get and set custom objects as
|
|
5
|
+
/// well.
|
|
6
|
+
public protocol LocalStorageType {
|
|
7
|
+
/// Retrieves the value for the given item.
|
|
8
|
+
///
|
|
9
|
+
/// - parameters:
|
|
10
|
+
/// - item: a local value that identifies this item
|
|
11
|
+
/// - returns: an instance of T, if it was found; nil otherwise
|
|
12
|
+
func get<T>(_ item: LocalValue<T>) -> T?
|
|
13
|
+
|
|
14
|
+
/// Stores a value for the item provided.
|
|
15
|
+
///
|
|
16
|
+
/// - parameters:
|
|
17
|
+
/// - value: the value to store at the given key
|
|
18
|
+
/// - item: a local value to identify this item
|
|
19
|
+
/// - returns: true if storing was successful; nil otherwise
|
|
20
|
+
@discardableResult
|
|
21
|
+
func set<T>(_ value: T?, for item: LocalValue<T>) -> Bool
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
extension LocalStorageType {
|
|
25
|
+
/// Retrieves the object stored for the given item.
|
|
26
|
+
///
|
|
27
|
+
/// - parameters:
|
|
28
|
+
/// - item: the local storage item to retreive
|
|
29
|
+
/// - returns: the previously-stored object, or nil
|
|
30
|
+
func get<T>(_ item: LocalObject<T>) -> T? {
|
|
31
|
+
let localValue = LocalValue<[String: Any]>(item.key)
|
|
32
|
+
guard let attributes = get(localValue) else { return nil }
|
|
33
|
+
return T.init(attributes: attributes)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Stores an object for the item provided.
|
|
37
|
+
///
|
|
38
|
+
/// - parameters:
|
|
39
|
+
/// - value: the object to store
|
|
40
|
+
/// - item: the local storage item to use for storage
|
|
41
|
+
/// - returns: a boolean indicating whether storing the object was successful
|
|
42
|
+
@discardableResult
|
|
43
|
+
func set<T>(_ value: T?, for item: LocalObject<T>) -> Bool {
|
|
44
|
+
let localValue = LocalValue<[String: Any]>(item.key)
|
|
45
|
+
return set(value?.attributes, for: localValue)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/// A protocol for anything that can be stored as a value. This protocol
|
|
2
|
+
/// inherits default implementations, so new values can be added just be
|
|
3
|
+
/// adopting the bare protocol, e.g. `extension Date: LocalValueType {}`
|
|
4
|
+
import Foundation
|
|
5
|
+
|
|
6
|
+
public protocol VibesLocalValueType {
|
|
7
|
+
/// Archives this value to Data that can be stored.
|
|
8
|
+
///
|
|
9
|
+
/// - paremeters:
|
|
10
|
+
/// - value: an instance of self, e.g. String
|
|
11
|
+
/// - returns: the encoded value, as data
|
|
12
|
+
static func archive(value: Self) -> Data
|
|
13
|
+
|
|
14
|
+
/// Unarchives this value from Data
|
|
15
|
+
///
|
|
16
|
+
/// - paremeters:
|
|
17
|
+
/// - data: the data to convert into a value
|
|
18
|
+
/// - returns: the value that was decoded
|
|
19
|
+
static func unarchive(data: Data) -> Self?
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
extension VibesLocalValueType {
|
|
23
|
+
public static func archive(value: Self) -> Data {
|
|
24
|
+
return NSKeyedArchiver.archivedData(withRootObject: value)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static func unarchive(data: Data) -> Self? {
|
|
28
|
+
let object = NSKeyedUnarchiver.unarchiveObject(with: data)
|
|
29
|
+
return object as? Self
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
extension String: VibesLocalValueType {
|
|
34
|
+
public static func archive(value: String) -> Data {
|
|
35
|
+
return NSKeyedArchiver.archivedData(withRootObject: value)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static func unarchive(data: Data) -> String? {
|
|
39
|
+
let object = NSKeyedUnarchiver.unarchiveObject(with: data)
|
|
40
|
+
return object as? String
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
extension Dictionary: VibesLocalValueType {
|
|
45
|
+
public static func archive(value: Dictionary) -> Data {
|
|
46
|
+
return NSKeyedArchiver.archivedData(withRootObject: value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static func unarchive(data: Data) -> Dictionary? {
|
|
50
|
+
let object = NSKeyedUnarchiver.unarchiveObject(with: data)
|
|
51
|
+
return object as? Dictionary
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// A simple struct for identifying a value that is held in local storage.
|
|
56
|
+
public struct LocalValue<T: VibesLocalValueType> {
|
|
57
|
+
/// The identifier to use to store this value.
|
|
58
|
+
let key: String
|
|
59
|
+
|
|
60
|
+
/// Initialize this object.
|
|
61
|
+
///
|
|
62
|
+
/// - paremeters:
|
|
63
|
+
/// - key: the identifier to use to store this value.
|
|
64
|
+
init(_ key: String) {
|
|
65
|
+
self.key = key
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
/// An object to take care of persisting incoming events when they are received
|
|
3
|
+
/// and removing them once they have been successfully sent to Vibes.
|
|
4
|
+
class PersistentEventStorage {
|
|
5
|
+
/// A serial dispatch queue for changing local storage
|
|
6
|
+
private let internalQueue: DispatchQueue
|
|
7
|
+
|
|
8
|
+
/// The local storage mechanism we are using for storing events
|
|
9
|
+
private let storage: LocalStorageType
|
|
10
|
+
|
|
11
|
+
/// A property for the events currently stored locally.
|
|
12
|
+
var storedEvents: [Event] {
|
|
13
|
+
get {
|
|
14
|
+
return storage.get(LocalStorageKeys.events)?.events ?? []
|
|
15
|
+
}
|
|
16
|
+
set(newEvents) {
|
|
17
|
+
storage.set(EventCollection(events: newEvents), for: LocalStorageKeys.events)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// Initialize this object.
|
|
22
|
+
///
|
|
23
|
+
/// - parameters:
|
|
24
|
+
/// - storage: a local storage mechanism for storing events
|
|
25
|
+
init(storage: LocalStorageType) {
|
|
26
|
+
self.storage = storage
|
|
27
|
+
self.internalQueue = DispatchQueue(label: "Vibes")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// A convenience typelias for the completion of sending events to be tracked
|
|
31
|
+
/// over the API.
|
|
32
|
+
typealias TrackCompletion = (VibesResult<Void>) -> Void
|
|
33
|
+
|
|
34
|
+
/// A wrapper around sending events to Vibes; this is what handles
|
|
35
|
+
/// persisting/removing events from local storage.
|
|
36
|
+
///
|
|
37
|
+
/// - parameters:
|
|
38
|
+
/// - events: an Array of events to track.
|
|
39
|
+
/// - callback: a callback for when events have been tracked via the API.
|
|
40
|
+
/// It receives the events to store (which may be a superset of the
|
|
41
|
+
/// events passed in) and a completion to call with the result of sending
|
|
42
|
+
/// the events over the API.
|
|
43
|
+
func tracking(events incomingEvents: [Event], callback: ([Event], @escaping TrackCompletion) -> Void) {
|
|
44
|
+
guard let event = incomingEvents.first else {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let uniqueEvents = incomingEvents.firstUniqueElements
|
|
49
|
+
persistEvents(uniqueEvents)
|
|
50
|
+
|
|
51
|
+
let outgoingEvents = storedEvents.filter { $0.type == event.type }
|
|
52
|
+
callback(outgoingEvents, { result in
|
|
53
|
+
switch result {
|
|
54
|
+
case .success:
|
|
55
|
+
self.removeEvents(outgoingEvents)
|
|
56
|
+
default:
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// Persist events in local storage.
|
|
63
|
+
///
|
|
64
|
+
/// - parameters:
|
|
65
|
+
/// - events: an Array of events to persist.
|
|
66
|
+
private func persistEvents(_ events: [Event]) {
|
|
67
|
+
internalQueue.sync {
|
|
68
|
+
storedEvents.append(contentsOf: events)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Removes events from local storage.
|
|
73
|
+
///
|
|
74
|
+
/// - parameters:
|
|
75
|
+
/// - events: an Array of events to remove.
|
|
76
|
+
private func removeEvents(_ events: [Event]) {
|
|
77
|
+
internalQueue.sync {
|
|
78
|
+
storedEvents = storedEvents.filter { !events.contains($0) }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Person.swift
|
|
3
|
+
// VibesPush
|
|
4
|
+
//
|
|
5
|
+
// Created by clemwek on 12/07/2019.
|
|
6
|
+
// Copyright © 2019 Vibes. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
@objcMembers
|
|
11
|
+
public class Person: NSObject, JSONDecodable, LocalObjectType {
|
|
12
|
+
public var attributes: [String: Any] {
|
|
13
|
+
return [
|
|
14
|
+
"person_key": personKey ?? "",
|
|
15
|
+
"external_person_id": externalPersonId ?? "",
|
|
16
|
+
"mobile_phone": mobilePhone,
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// An external identifier assosiated with the device or person if available
|
|
21
|
+
public var externalPersonId: String?
|
|
22
|
+
/// The phone number of the assosiated person if available
|
|
23
|
+
public var mdn: String?
|
|
24
|
+
/// A unique identifier for the person, provided by Vibes when assosiated.
|
|
25
|
+
public var personKey: String?
|
|
26
|
+
|
|
27
|
+
private var mobilePhone: [String: String] = [:]
|
|
28
|
+
|
|
29
|
+
override init() {
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Initialize for testing
|
|
33
|
+
///
|
|
34
|
+
/// - Parameters:
|
|
35
|
+
/// - externalPersonId: external person id
|
|
36
|
+
/// - mdn: phone number
|
|
37
|
+
/// - personKey: person key
|
|
38
|
+
init(externalPersonId: String, mdn: String, personKey: String) {
|
|
39
|
+
self.externalPersonId = externalPersonId
|
|
40
|
+
self.mdn = mdn
|
|
41
|
+
self.personKey = personKey
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Initialize this object using JSONObject
|
|
45
|
+
///
|
|
46
|
+
/// - Parameter json: The JSONObject
|
|
47
|
+
required convenience init?(json: VibesJSONDictionary) {
|
|
48
|
+
self.init()
|
|
49
|
+
|
|
50
|
+
let mdn: String?
|
|
51
|
+
|
|
52
|
+
guard let personKey = json["person_key"] as? String else { return nil }
|
|
53
|
+
|
|
54
|
+
if let mobilePhone = json["mobile_phone"] as? [String: String] {
|
|
55
|
+
mdn = mobilePhone["mdn"]
|
|
56
|
+
} else {
|
|
57
|
+
mdn = nil
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
self.personKey = personKey
|
|
61
|
+
externalPersonId = json["external_person_id"] as? String
|
|
62
|
+
self.mdn = mdn
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Initialize this object using Attributes
|
|
66
|
+
///
|
|
67
|
+
/// - Parameter attributes: - The dictionary with attributes
|
|
68
|
+
public required convenience init?(attributes: [String: Any]) {
|
|
69
|
+
self.init()
|
|
70
|
+
|
|
71
|
+
let mdn: String?
|
|
72
|
+
|
|
73
|
+
guard let personKey = attributes["person_key"] as? String,
|
|
74
|
+
!personKey.isEmpty else { return nil }
|
|
75
|
+
|
|
76
|
+
if let mobilePhone = attributes["mobile_phone"] as? [String: String] {
|
|
77
|
+
mdn = mobilePhone["mdn"]
|
|
78
|
+
} else {
|
|
79
|
+
mdn = nil
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
externalPersonId = attributes["external_person_id"] as? String
|
|
83
|
+
self.mdn = mdn
|
|
84
|
+
self.personKey = personKey
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Equals Comparison operator for Person
|
|
89
|
+
///
|
|
90
|
+
/// - Parameters:
|
|
91
|
+
/// - lhs: The left hand side Person
|
|
92
|
+
/// - rhs: The right hand side Person
|
|
93
|
+
/// - Returns: `True` if `lhs` is equal to `rhs`, else returns `False`
|
|
94
|
+
public func == (lhs: Person, rhs: Person) -> Bool {
|
|
95
|
+
return lhs.personKey == rhs.personKey &&
|
|
96
|
+
lhs.externalPersonId == rhs.externalPersonId &&
|
|
97
|
+
lhs.mdn == rhs.mdn
|
|
98
|
+
}
|