229 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Swift
		
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Swift
		
	
	
| //
 | ||
| //  DBEntities.swift
 | ||
| //  Alamofire
 | ||
| //
 | ||
| //  Created by mayue on 2022/11/4.
 | ||
| //
 | ||
| 
 | ||
| import Foundation
 | ||
| import CryptoSwift
 | ||
| 
 | ||
| internal enum Entity {
 | ||
|     
 | ||
| }
 | ||
| 
 | ||
| extension Entity {
 | ||
|     struct EventRecord: Codable {
 | ||
|         
 | ||
|         enum Priority: Int, Codable {
 | ||
|             case EMERGENCE = 0
 | ||
|             case HIGH = 5
 | ||
|             case DEFAULT = 10
 | ||
|             case LOW = 15
 | ||
|         }
 | ||
|         
 | ||
|         enum TransitionStatus: Int, Codable {
 | ||
|             case idle = 0
 | ||
|             case instransition = 1
 | ||
|         }
 | ||
|         
 | ||
|         let recordId: String
 | ||
|         let eventName: String
 | ||
|         let eventJson: String
 | ||
|         ///单位毫秒
 | ||
|         let timestamp: Int64
 | ||
|         let priority: Priority
 | ||
|         let transitionStatus: TransitionStatus
 | ||
|         
 | ||
|         init(eventName: String, event: Entity.Event, priority: Priority = .DEFAULT, transitionStatus: TransitionStatus = .idle) {
 | ||
|             let now = Date()
 | ||
|             let eventJson = event.asString ?? ""
 | ||
|             if eventJson.isEmpty {
 | ||
|                 cdPrint("[WARNING] error for convert event to json")
 | ||
|             }
 | ||
|             self.recordId = "\(eventName)\(eventJson)\(now.timeIntervalSince1970)\(Int.random(in: Int.min...Int.max))".md5()
 | ||
|             self.eventName = eventName
 | ||
|             self.eventJson = eventJson
 | ||
|             self.timestamp = event.timestamp
 | ||
|             self.priority = priority
 | ||
|             self.transitionStatus = transitionStatus
 | ||
|         }
 | ||
|         
 | ||
|         init(recordId: String, eventName: String, eventJson: String, timestamp: Int64, priority: Int, transitionStatus: Int) {
 | ||
|             self.recordId = recordId
 | ||
|             self.eventName = eventName
 | ||
|             self.eventJson = eventJson
 | ||
|             self.timestamp = timestamp
 | ||
|             self.priority = .init(rawValue: priority) ?? .DEFAULT
 | ||
|             self.transitionStatus = .init(rawValue: transitionStatus) ?? .idle
 | ||
|         }
 | ||
|         
 | ||
|         enum CodingKeys: String, CodingKey {
 | ||
|             case recordId
 | ||
|             case eventName
 | ||
|             case eventJson
 | ||
|             case timestamp
 | ||
|             case priority
 | ||
|             case transitionStatus
 | ||
|         }
 | ||
|         
 | ||
|         static func createTableSql(with name: String) -> String {
 | ||
|             return """
 | ||
|                 CREATE TABLE IF NOT EXISTS \(name)(
 | ||
|                 \(CodingKeys.recordId.rawValue) TEXT UNIQUE NOT NULL PRIMARY KEY,
 | ||
|                 \(CodingKeys.eventName.rawValue) TEXT NOT NULL,
 | ||
|                 \(CodingKeys.eventJson.rawValue) TEXT NOT NULL,
 | ||
|                 \(CodingKeys.timestamp.rawValue) INTEGER,
 | ||
|                 \(CodingKeys.priority.rawValue) INTEGER,
 | ||
|                 \(CodingKeys.transitionStatus.rawValue) INTEGER);
 | ||
|                 """
 | ||
|         }
 | ||
|         
 | ||
|         func insertSql(to tableName: String) -> String {
 | ||
|             return "INSERT INTO \(tableName) VALUES ('\(recordId)', '\(eventName)', '\(eventJson)', '\(timestamp)', '\(priority.rawValue)', '\(transitionStatus.rawValue)')"
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
| }
 | ||
| 
 | ||
| extension Entity {
 | ||
|     struct Event: Codable {
 | ||
|         ///客户端中记录此事件的时间(采用世界协调时间,毫秒为单位)
 | ||
|         let timestamp: Int64
 | ||
|         let event: String
 | ||
|         let userInfo: UserInfo
 | ||
|         let param: [String: EventValue]
 | ||
|         let properties: [String: String]
 | ||
|         let eventId: String
 | ||
|         
 | ||
|         enum CodingKeys: String, CodingKey {
 | ||
|             case timestamp
 | ||
|             case userInfo = "info"
 | ||
|             case event, param, properties
 | ||
|             case eventId
 | ||
|         }
 | ||
|         
 | ||
|         init(timestamp: Int64, event: String, userInfo: UserInfo, parameters: [String : Any], properties: [String : String]) throws {
 | ||
|             guard let normalizedEvent = Self.normalizeKey(event),
 | ||
|                   normalizedEvent == event else {
 | ||
|                 cdPrint("drop event because of illegal event name: \(event)")
 | ||
|                 cdPrint("standard: https://developers.google.com/android/reference/com/google/firebase/analytics/FirebaseAnalytics.Event")
 | ||
|                 throw NSError(domain: "cunstrcting event error", code: 0, userInfo: [NSLocalizedDescriptionKey : "illegal event name: \(event)"])
 | ||
|             }
 | ||
|             self.eventId = UUID().uuidString.lowercased()
 | ||
|             self.timestamp = timestamp
 | ||
|             self.event = normalizedEvent
 | ||
|             self.userInfo = userInfo
 | ||
|             self.param = Self.normalizeParameters(parameters)
 | ||
|             self.properties = properties
 | ||
|         }
 | ||
|         
 | ||
|         static let maxParametersCount = 25
 | ||
|         static let maxKeyLength = 40
 | ||
|         static let maxParameterStringValueLength = 128
 | ||
|         
 | ||
|         static func normalizeParameters(_ parameters: [String : Any]) -> [String : EventValue] {
 | ||
|             var params = [String : EventValue]()
 | ||
|             var count = 0
 | ||
|             parameters.sorted(by: { $0.key < $1.key }).forEach({ key, value in
 | ||
|                 
 | ||
|                 guard count < maxParametersCount else {
 | ||
|                     cdPrint("too many parameters")
 | ||
|                     cdPrint("standard: https://developers.google.com/android/reference/com/google/firebase/analytics/FirebaseAnalytics.Event")
 | ||
|                     return
 | ||
|                 }
 | ||
|                 
 | ||
|                 guard let normalizedKey = normalizeKey(key),
 | ||
|                       normalizedKey == key else {
 | ||
|                     cdPrint("drop event parameter because of illegal key: \(key)")
 | ||
|                     cdPrint("standard: https://developers.google.com/android/reference/com/google/firebase/analytics/FirebaseAnalytics.Event")
 | ||
|                     return
 | ||
|                 }
 | ||
|                 
 | ||
|                 if let value = value as? String {
 | ||
|                     params[normalizedKey] = Entity.EventValue(stringValue: String(value.prefix(maxParameterStringValueLength)))
 | ||
|                 } else if let value = value as? Int {
 | ||
|                     params[normalizedKey] = Entity.EventValue(longValue: Int64(value))
 | ||
|                 } else if let value = value as? Int64 {
 | ||
|                     params[normalizedKey] = Entity.EventValue(longValue: value)
 | ||
|                 } else if let value = value as? Double {
 | ||
|                     params[normalizedKey] = Entity.EventValue(doubleValue: value)
 | ||
|                 } else {
 | ||
|                     params[normalizedKey] = Entity.EventValue(stringValue: String("\(value)".prefix(maxParameterStringValueLength)))
 | ||
|                 }
 | ||
|                 
 | ||
|                 count += 1
 | ||
|             })
 | ||
|             
 | ||
|             return params
 | ||
|         }
 | ||
|         
 | ||
|         static func normalizeKey(_ key: String) -> String? {
 | ||
|             var mutableKey = key
 | ||
|             
 | ||
|             while let first = mutableKey.first,
 | ||
|                     !first.isLetter {
 | ||
|                 _ = mutableKey.removeFirst()
 | ||
|             }
 | ||
|             
 | ||
|             var normalizedKey = ""
 | ||
|             var count = 0
 | ||
|             mutableKey.forEach { c in
 | ||
|                 guard count < maxKeyLength,
 | ||
|                       c.isAlphabetic || c.isDigit || c == "_" else { return }
 | ||
|                 normalizedKey.append(c)
 | ||
|                 count += 1
 | ||
|             }
 | ||
|             
 | ||
|             return normalizedKey.isEmpty ? nil : normalizedKey
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
|     ///用户信息
 | ||
|     struct UserInfo: Codable {
 | ||
|         ///中台ID。只在未获取到uid时可以为空
 | ||
|         let uid: String?
 | ||
|         ///设备ID(用户的设备ID,iOS取用户的IDFV或UUID,Android取androidID)
 | ||
|         let deviceId: String?
 | ||
|         ///adjust_id。只在未获取到adjust时可以为空
 | ||
|         let adjustId: String?
 | ||
|         ///广告 ID/广告标识符 (IDFA)
 | ||
|         let adId: String?
 | ||
|         ///用户的pseudo_id
 | ||
|         let firebaseId: String?
 | ||
|         
 | ||
|         enum CodingKeys: String, CodingKey {
 | ||
|             case deviceId
 | ||
|             case uid
 | ||
|             case adjustId
 | ||
|             case adId
 | ||
|             case firebaseId
 | ||
|         }
 | ||
|     }
 | ||
|     
 | ||
|     // 参数对应的值
 | ||
|     struct EventValue: Codable {
 | ||
|         let stringValue: String?    // 事件参数的字符串值
 | ||
|         let longValue: Int64?         // 事件参数的整数值
 | ||
|         let doubleValue: Double?    // 事件参数的小数值。注意:APP序列化成JSON时,注意不要序列化成科学计数法
 | ||
|         
 | ||
|         init(stringValue: String? = nil, longValue: Int64? = nil, doubleValue: Double? = nil) {
 | ||
|             self.stringValue = stringValue
 | ||
|             self.longValue = longValue
 | ||
|             self.doubleValue = doubleValue
 | ||
|         }
 | ||
|         
 | ||
|         enum CodingKeys: String, CodingKey {
 | ||
|             case stringValue = "s"
 | ||
|             case longValue = "i"
 | ||
|             case doubleValue = "d"
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| extension Entity {
 | ||
|     struct SystemTimeResult: Codable {
 | ||
|         let data: Int64
 | ||
|     }
 | ||
| }
 |