2 // EventSerializer.swift
5 // Created by Cornelius Horstmann on 11.01.18.
6 // Copyright © 2018 PIWIK. All rights reserved.
11 final class EventSerializer {
12 internal func jsonData(for events: [Event]) throws -> Data {
13 let eventsAsQueryItems = events.map({ $0.queryItems })
14 let serializedEvents = eventsAsQueryItems.map({ items in
15 items.flatMap({ item in
16 guard let value = item.value,
17 let encodedValue = value.addingPercentEncoding(withAllowedCharacters: .urlQueryParameterAllowed) else { return nil }
18 return "\(item.name)=\(encodedValue)"
19 }).joined(separator: "&")
21 let body = ["requests": serializedEvents.map({ "?\($0)" })]
22 return try JSONSerialization.data(withJSONObject: body, options: [])
26 fileprivate extension Event {
28 private func customVariableParameterValue() -> String {
29 let customVariableParameterValue: [String] = customVariables.map { "\"\($0.index)\":[\"\($0.name)\",\"\($0.value)\"]" }
30 return "{\(customVariableParameterValue.joined(separator: ","))}"
33 var queryItems: [URLQueryItem] {
36 URLQueryItem(name: "idsite", value: siteId),
37 URLQueryItem(name: "rec", value: "1"),
39 URLQueryItem(name: "_id", value: visitor.id),
40 URLQueryItem(name: "uid", value: visitor.userId),
43 URLQueryItem(name: "_idvc", value: "\(session.sessionsCount)"),
44 URLQueryItem(name: "_viewts", value: "\(Int(session.lastVisit.timeIntervalSince1970))"),
45 URLQueryItem(name: "_idts", value: "\(Int(session.firstVisit.timeIntervalSince1970))"),
47 URLQueryItem(name: "url", value:url?.absoluteString),
48 URLQueryItem(name: "action_name", value: actionName.joined(separator: "/")),
49 URLQueryItem(name: "lang", value: language),
50 URLQueryItem(name: "urlref", value: referer?.absoluteString),
51 URLQueryItem(name: "new_visit", value: isNewSession ? "1" : nil),
53 URLQueryItem(name: "h", value: DateFormatter.hourDateFormatter.string(from: date)),
54 URLQueryItem(name: "m", value: DateFormatter.minuteDateFormatter.string(from: date)),
55 URLQueryItem(name: "s", value: DateFormatter.secondsDateFormatter.string(from: date)),
58 URLQueryItem(name: "res", value:String(format: "%1.0fx%1.0f", screenResolution.width, screenResolution.height)),
60 URLQueryItem(name: "e_c", value: eventCategory),
61 URLQueryItem(name: "e_a", value: eventAction),
62 URLQueryItem(name: "e_n", value: eventName),
63 URLQueryItem(name: "e_v", value: eventValue != nil ? "\(eventValue!)" : nil),
65 URLQueryItem(name: "_rcn", value: campaignName),
66 URLQueryItem(name: "_rck", value: campaignKeyword),
68 URLQueryItem(name: "search", value: searchQuery),
69 URLQueryItem(name: "search_cat", value: searchCategory),
70 URLQueryItem(name: "search_count", value: searchResultsCount != nil ? "\(searchResultsCount!)" : nil),
72 URLQueryItem(name: "c_n", value: contentName),
73 URLQueryItem(name: "c_p", value: contentPiece),
74 URLQueryItem(name: "c_t", value: contentTarget),
75 URLQueryItem(name: "c_i", value: contentInteraction),
76 ].filter { $0.value != nil }
78 let dimensionItems = dimensions.map { URLQueryItem(name: "dimension\($0.index)", value: $0.value) }
79 let customItems = customTrackingParameters.map { return URLQueryItem(name: $0.key, value: $0.value) }
80 let customVariableItems = customVariables.count > 0 ? [URLQueryItem(name: "_cvar", value: customVariableParameterValue())] : []
82 return items + dimensionItems + customItems + customVariableItems
87 fileprivate extension DateFormatter {
88 static let hourDateFormatter: DateFormatter = {
89 let dateFormatter = DateFormatter()
90 dateFormatter.dateFormat = "HH"
93 static let minuteDateFormatter: DateFormatter = {
94 let dateFormatter = DateFormatter()
95 dateFormatter.dateFormat = "mm"
98 static let secondsDateFormatter: DateFormatter = {
99 let dateFormatter = DateFormatter()
100 dateFormatter.dateFormat = "ss"
105 fileprivate extension CharacterSet {
107 /// Returns the character set for characters allowed in a query parameter URL component.
108 fileprivate static var urlQueryParameterAllowed: CharacterSet {
109 return CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "&/?"))