@@ -8,25 +8,36 @@ import OSLog
88 import Common
99#endif
1010
11+ enum RRWebPlayerConstants {
12+ // padding requiered by used html dom structure
13+ static let padding = CGSize ( width: 11 , height: 11 )
14+ // size limit of accumulated continues canvas operations on the RRWeb player
15+ static let canvasBufferLimit = 10_000_000 // ~10mb
16+
17+ static let canvasDrawEntourage = 300 // bytes
18+ }
19+
1120actor SessionReplayEventGenerator {
1221 private var title : String
13- let padding = CGSize ( width : 11 , height : 11 )
14- var sid = 0
15- var nextSid : Int {
22+ private let padding = RRWebPlayerConstants . padding
23+ private var sid = 0
24+ private var nextSid : Int {
1625 sid += 1
1726 return sid
1827 }
1928
20- var id = 16
21- var nextId : Int {
29+ private var id = 16
30+ private var nextId : Int {
2231 id += 1
2332 return id
2433 }
34+ private var pushedCanvasSize : Int = 0
35+ private var generatingCanvasSize : Int = 0
2536
26- var imageId : Int ?
27- var lastExportImage : ExportImage ?
28- var stats : SessionReplayStats ?
29- let isDebug = false
37+ private var imageId : Int ?
38+ private var lastExportImage : ExportImage ?
39+ private var stats : SessionReplayStats ?
40+ private let isDebug = false
3041
3142 init ( log: OSLog , title: String ) {
3243 if isDebug {
@@ -37,6 +48,7 @@ actor SessionReplayEventGenerator {
3748
3849 func generateEvents( items: [ EventQueueItem ] ) -> [ Event ] {
3950 var events = [ Event] ( )
51+ self . generatingCanvasSize = pushedCanvasSize
4052 for item in items {
4153 appendEvents ( item: item, events: & events)
4254 }
@@ -56,15 +68,15 @@ actor SessionReplayEventGenerator {
5668 fileprivate func wakeUpPlayerEvents( _ events: inout [ Event ] , _ imageId: Int , _ timestamp: TimeInterval ) {
5769 // artificial mouse movement to wake up session replay player
5870 events. append ( Event ( type: . IncrementalSnapshot,
59- data: AnyEventData ( EventData ( source: . mouseInteraction,
71+ data: AnyEventData ( MouseInteractionData ( source: . mouseInteraction,
6072 type: . mouseDown,
6173 id: imageId,
6274 x: padding. width,
6375 y: padding. height) ) ,
6476 timestamp: timestamp,
6577 _sid: nextSid) )
6678 events. append ( Event ( type: . IncrementalSnapshot,
67- data: AnyEventData ( EventData ( source: . mouseInteraction,
79+ data: AnyEventData ( MouseInteractionData ( source: . mouseInteraction,
6880 type: . mouseUp,
6981 id: imageId,
7082 x: padding. width,
@@ -91,7 +103,8 @@ actor SessionReplayEventGenerator {
91103 if let imageId,
92104 let lastExportImage,
93105 lastExportImage. originalWidth == exportImage. originalWidth,
94- lastExportImage. originalHeight == exportImage. originalHeight {
106+ lastExportImage. originalHeight == exportImage. originalHeight,
107+ generatingCanvasSize < RRWebPlayerConstants . canvasBufferLimit {
95108 events. append ( drawImageEvent ( exportImage: exportImage, timestamp: timestamp, imageId: imageId) )
96109 } else {
97110 // if screen changed size we send fullSnapshot as canvas resizing might take to many hours on the server
@@ -122,14 +135,14 @@ actor SessionReplayEventGenerator {
122135 fileprivate func appendTouchInteraction( interaction: TouchInteraction , events: inout [ Event ] ) {
123136 if let touchEventData: EventDataProtocol = switch interaction. kind {
124137 case . touchDown( let point) :
125- EventData ( source: . mouseInteraction,
138+ MouseInteractionData ( source: . mouseInteraction,
126139 type: . touchStart,
127140 id: imageId,
128141 x: point. x + padding. width,
129142 y: point. y + padding. height)
130143
131144 case . touchUp( let point) :
132- EventData ( source: . mouseInteraction,
145+ MouseInteractionData ( source: . mouseInteraction,
133146 type: . touchEnd,
134147 id: imageId,
135148 x: point. x + padding. width,
@@ -145,7 +158,7 @@ actor SessionReplayEventGenerator {
145158 timeOffset: p. timestamp - interaction. timestamp) } )
146159
147160 default :
148- Optional< EventData > . none
161+ Optional< MouseInteractionData > . none
149162 } {
150163 let event = Event ( type: . IncrementalSnapshot,
151164 data: AnyEventData ( touchEventData) ,
@@ -162,7 +175,6 @@ actor SessionReplayEventGenerator {
162175 func clickEvent( interaction: TouchInteraction ) -> Event ? {
163176 guard case . touchDown = interaction. kind else { return nil }
164177
165- let viewName = interaction. target? . className
166178 let eventData = CustomEventData ( tag: . click, payload: ClickPayload (
167179 clickTarget: interaction. target? . className ?? " " ,
168180 clickTextContent: interaction. target? . accessibilityIdentifier ?? " " ,
@@ -174,10 +186,8 @@ actor SessionReplayEventGenerator {
174186 return event
175187 }
176188
177-
178-
179189 func windowEvent( href: String , width: Int , height: Int , timestamp: TimeInterval ) -> Event {
180- let eventData = EventData ( href: href, width: width, height: height)
190+ let eventData = WindowData ( href: href, width: width, height: height)
181191 let event = Event ( type: . Meta,
182192 data: AnyEventData ( eventData) ,
183193 timestamp: timestamp,
@@ -210,18 +220,13 @@ actor SessionReplayEventGenerator {
210220 }
211221
212222 func viewPortEvent( exportImage: ExportImage , timestamp: TimeInterval ) -> Event {
213- #if os(iOS)
214- let currentOrientation = UIDevice . current. orientation. isLandscape ? 1 : 0
215- #else
216- let currentOrientation = 0
217- #endif
218223 let payload = ViewportPayload ( width: exportImage. originalWidth,
219224 height: exportImage. originalHeight,
220225 availWidth: exportImage. originalWidth,
221226 availHeight: exportImage. originalHeight,
222227 colorDepth: 30 ,
223228 pixelDepth: 30 ,
224- orientation: currentOrientation )
229+ orientation: exportImage . orientation )
225230 let eventData = CustomEventData ( tag: . viewport, payload: payload)
226231 let event = Event ( type: . Custom,
227232 data: AnyEventData ( eventData) ,
@@ -232,7 +237,8 @@ actor SessionReplayEventGenerator {
232237
233238 func drawImageEvent( exportImage: ExportImage , timestamp: TimeInterval , imageId: Int ) -> Event {
234239 let clearRectCommand = ClearRect ( x: 0 , y: 0 , width: exportImage. originalWidth, height: exportImage. originalHeight)
235- let arrayBuffer = RRArrayBuffer ( base64: exportImage. data. base64EncodedString ( ) )
240+ let base64String = exportImage. data. base64EncodedString ( )
241+ let arrayBuffer = RRArrayBuffer ( base64: base64String)
236242 let blob = AnyRRNode ( RRBlob ( data: [ AnyRRNode ( arrayBuffer) ] , type: exportImage. mimeType) )
237243 let drawImageCommand = DrawImage ( image: AnyRRNode ( RRImageBitmap ( args: [ blob] ) ) ,
238244 dx: 0 ,
@@ -244,10 +250,13 @@ actor SessionReplayEventGenerator {
244250 id: imageId,
245251 type: . mouseUp,
246252 commands: [
247- AnyCommand ( clearRectCommand) ,
248- AnyCommand ( drawImageCommand)
253+ AnyCommand ( clearRectCommand, canvasSize : 80 ) ,
254+ AnyCommand ( drawImageCommand, canvasSize : base64String . count )
249255 ] )
250- let event = Event ( type: . IncrementalSnapshot, data: AnyEventData ( eventData) , timestamp: timestamp, _sid: nextSid)
256+ let event = Event ( type: . IncrementalSnapshot,
257+ data: AnyEventData ( eventData) ,
258+ timestamp: timestamp, _sid: nextSid)
259+ generatingCanvasSize += eventData. canvasSize + RRWebPlayerConstants. canvasDrawEntourage
251260 return event
252261 }
253262
@@ -264,32 +273,38 @@ actor SessionReplayEventGenerator {
264273
265274 func fullSnapshotEvent( exportImage: ExportImage , timestamp: TimeInterval ) -> Event {
266275 id = 0
267- let rootNode = fullSnapshotNode ( exportImage: exportImage)
268- let eventData = EventData ( node: rootNode)
276+ let eventData = fullSnapshotData ( exportImage: exportImage)
269277 let event = Event ( type: . FullSnapshot, data: AnyEventData ( eventData) , timestamp: timestamp, _sid: nextSid)
278+ // start again counting canvasSize
279+ generatingCanvasSize = eventData. canvasSize + RRWebPlayerConstants. canvasDrawEntourage
270280 return event
271281 }
272282
273- func fullSnapshotNode ( exportImage: ExportImage ) -> EventNode {
283+ func fullSnapshotData ( exportImage: ExportImage ) -> DomData {
274284 var rootNode = EventNode ( id: nextId, type: . Document)
275285 let htmlDocNode = EventNode ( id: nextId, type: . DocumentType, name: " html " )
276286 rootNode. childNodes. append ( htmlDocNode)
277-
287+ let base64String = exportImage. base64DataURL ( )
288+
278289 let htmlNode = EventNode ( id: nextId, type: . Element, tagName: " html " , attributes: [ " lang " : " en " ] , childNodes: [
279290 EventNode ( id: nextId, type: . Element, tagName: " head " , attributes: [ : ] ) ,
280291 EventNode ( id: nextId, type: . Element, tagName: " body " , attributes: [ : ] , childNodes: [
281- exportImage. eventNode ( id: nextId)
292+ exportImage. eventNode ( id: nextId, rr_dataURL : base64String )
282293 ] ) ,
283294 ] )
284295 imageId = id
285296 rootNode. childNodes. append ( htmlNode)
286297
287- return rootNode
298+ return DomData ( node : rootNode, canvasSize : base64String . count )
288299 }
289300
290301 private func appendFullSnapshotEvents( _ exportImage: ExportImage , _ timestamp: TimeInterval , _ events: inout [ Event ] ) {
291302 events. append ( windowEvent ( href: " " , width: paddedWidth ( exportImage. originalWidth) , height: paddedHeight ( exportImage. originalHeight) , timestamp: timestamp) )
292303 events. append ( fullSnapshotEvent ( exportImage: exportImage, timestamp: timestamp) )
293304 events. append ( viewPortEvent ( exportImage: exportImage, timestamp: timestamp) )
294305 }
306+
307+ func updatePushedCanvasSize( ) {
308+ pushedCanvasSize = generatingCanvasSize
309+ }
295310}
0 commit comments