From 297be2bc9ccc1a7fa715afce72b14558999a6f0f Mon Sep 17 00:00:00 2001 From: Delirium Date: Fri, 24 May 2024 16:49:48 +0200 Subject: [PATCH] feat ui/tracker: add compression to assist plugin (#2186) * feat ui/tracker: add compression to assist plugin * fix: changelog, package.json changes etc * feat tracker: split big batches in addition to compression --- frontend/app/player/web/MessageManager.ts | 1 - .../app/player/web/assist/AssistManager.ts | 14 +++++++- frontend/app/player/web/assist/Call.ts | 7 ++++ tracker/tracker-assist/CHANGELOG.md | 4 +++ tracker/tracker-assist/bun.lockb | Bin 250563 -> 250587 bytes tracker/tracker-assist/package.json | 3 +- tracker/tracker-assist/src/Assist.ts | 32 +++++++++++++++--- tracker/tracker-assist/src/version.ts | 2 +- tracker/tracker/package.json | 2 +- 9 files changed, 56 insertions(+), 9 deletions(-) diff --git a/frontend/app/player/web/MessageManager.ts b/frontend/app/player/web/MessageManager.ts index ce38d93cf..d8f5625f9 100644 --- a/frontend/app/player/web/MessageManager.ts +++ b/frontend/app/player/web/MessageManager.ts @@ -258,7 +258,6 @@ export default class MessageManager { ); } }); - if ( this.waitingForFiles || (this.lastMessageTime <= t && diff --git a/frontend/app/player/web/assist/AssistManager.ts b/frontend/app/player/web/assist/AssistManager.ts index 69ca39383..1ba2b567a 100644 --- a/frontend/app/player/web/assist/AssistManager.ts +++ b/frontend/app/player/web/assist/AssistManager.ts @@ -1,5 +1,6 @@ import MessageManager from 'Player/web/MessageManager'; import type { Socket } from 'socket.io-client'; +import { Message } from "../messages"; import type Screen from '../Screen/Screen'; import type { PlayerMsg, Store } from 'App/player'; import MStreamReader from '../messages/MStreamReader'; @@ -8,6 +9,7 @@ import Call, { CallingState } from './Call'; import RemoteControl, { RemoteControlStatus } from './RemoteControl'; import ScreenRecording, { SessionRecordingStatus } from './ScreenRecording'; import CanvasReceiver from 'Player/web/assist/CanvasReceiver'; +import { gunzipSync } from 'fflate'; export { RemoteControlStatus, SessionRecordingStatus, CallingState }; @@ -196,7 +198,7 @@ export default class AssistManager { this.setStatus(ConnectionStatus.WaitingMessages); }); - socket.on('messages', (messages) => { + const processMessages = (messages: { meta: { version: number, tabId: string }, data: Message[] }) => { const isOldVersion = messages.meta.version === 1; this.assistVersion = isOldVersion ? 1 : 2; @@ -217,7 +219,17 @@ export default class AssistManager { for (let msg = reader.readNext(); msg !== null; msg = reader.readNext()) { this.handleMessage(msg, msg._index); } + } + + socket.on('messages', (messages) => { + processMessages(messages) }); + socket.on('messages_gz', (gzBuf) => { + const unpackData = gunzipSync(new Uint8Array(gzBuf.data)); + const str = new TextDecoder().decode(unpackData); + const messages = JSON.parse(str); + processMessages({ ...gzBuf, data: messages }) + }) socket.on('SESSION_RECONNECTED', () => { this.clearDisconnectTimeout(); diff --git a/frontend/app/player/web/assist/Call.ts b/frontend/app/player/web/assist/Call.ts index e3f0b26c1..6c71c3ed8 100644 --- a/frontend/app/player/web/assist/Call.ts +++ b/frontend/app/player/web/assist/Call.ts @@ -55,6 +55,13 @@ export default class Call { this.store.update({ calling: CallingState.NoCall }); } }); + socket.on('messages_gz', () => { + if (reconnecting) { + // 'messages' come frequently, so it is better to have Reconnecting + this._callSessionPeer(); + reconnecting = false; + } + }) socket.on('messages', () => { if (reconnecting) { // 'messages' come frequently, so it is better to have Reconnecting diff --git a/tracker/tracker-assist/CHANGELOG.md b/tracker/tracker-assist/CHANGELOG.md index 7ab25ece5..43f2f3d70 100644 --- a/tracker/tracker-assist/CHANGELOG.md +++ b/tracker/tracker-assist/CHANGELOG.md @@ -1,3 +1,7 @@ +## 9.0.0 + +- support for message compression inside plugin + ## 8.0.4 - fix for multiple canvas streaming diff --git a/tracker/tracker-assist/bun.lockb b/tracker/tracker-assist/bun.lockb index 6dea11a765d7559ba081b8c9ed8b3048bf343076..08169f8c3e0e2bd91cc88005f1028df872940c8d 100755 GIT binary patch delta 42252 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

NX^gd=KwF>&bCnnB1 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 z zSJCu(+DK3vR05SjDWG#m42S|ccm%;A@*D(jf`5Y-!7iX(QzwhDK&OcgpgUL%f0w3T z0r(ftnP3VTrh@4p3(NpI5Xi_;pj}DtJeC8|AOtFc2zPTE>xRwlxES^b*v}s2&6pt$&Ui+tfk@R}ITy_;7;fl!`ZY>m99L=<&@Ojh3 zTpwtVpaHINtAn-btMU0F_!m&O-j38b(|Bv)H)F03+?ta}_$A^xgPTBe^k(2X!ZpD> z&=&m0M>Z}7nhWB}AgkLraoSJBYx}$iy*yBwZs@X~0BQi)YJ_a4aovDGeNY?J0xDFy zz$Ks#s0$RQaATm;U_`%^u#SK#)IG-`wSTt+I$i77r@g%y(B7`RI`8UytGG^Dc*6wR zgA|~e>%`FkbOfD%j4NJoUBP9b3z!FD{9gP8$Vj{v?!7kMZ^&POD)ki5sy_@wyfK9G z-2<6w+XHk5DoifYYOa-Cr!sBHY2Zqr6<&MV<)9zXYJUY72y{YIyiRXd0af&Ba19s= zrhp%Sy6Op#Q@nLLtEhG7fNK3T_!&$Es=2lu)qE@%4Mu|DARUYVqkt-}G+G@pfLyJ@ zBIRfUm#0(~>2lotOb4YpK!+05P>DN%$u=yb%A|_OxI88AD4h-`ic`fk>ze|_PXpQ` z)!HAy_uyL)X}MP+{IAU402Q_u$dFpD!oCJi0k!^G5Gi~H;dx*w_zZjsZUyR2xmCt< zfo#tOvUvk&1!jXtL#|g%Rbx%JnP3)BrbuGNNuL9hS-J}Ov!Pbzk-32;IrkH_38-!x zft;i|-UU{Hm0%%Q0`h?Bd<%#IH-nqNjbJ{|P`V97Y}`(GF~|ptfb1y0@-FbgIW8gN zicrQ#BIzrD1MUFJ!7^a16kohjDr_~l6R0p%MvamkVFS1i+zkqVD!oRYxtG8_U_Dq1 z8iI8|2_qHQOjySL$EA8kh6N1)wd!S{9+aD30vZY$UK&;!P8zd2fJVZTU_00bl>bGb zvA-KU2b4FGZ!}@$-3gunyFkvfd_50d0RIAAfDEXm?|?VKTVRh3YrGeNSHQo)tKbdr zIye9nw-3Aq_S>+e8mO+7y|;nfe^ev$eF8_oA#f193l4+#z=z-i@DcbJd;ZBRVKOqJ0N2}fYU%O{TgUSUJHH%;*>|c z!e^{L)pD|R7W@P>>6!xB`*U8U`&IoPDQptqi1F5hOZdHWeE{hPv*A=oHc(|`U?flh zx&}~7rvceeeig1Xir4P&1hN$AG`>nAl_p26RmOQB8Zy_0mmoE5ltC913P+~qh3KU% zAK?_Q21L3-Hp`JlSGwv}b#tU*+U1q5oBCfhtN>97R0LDd8z5y&HI8^>0%6s-D~K4V zN;-@bExu0?R=-w(ABHUMDUFG-Kr=udQ3dO$|K%EGluPvots-u%L%24m1!{sZ#8*eg z0Zq4yk<~yAi+aeq;1WI7tts4RLw<bq0^`Y`tBb+P2>u19 zo10o(S|iosR!D^h0bOQY4*G*Ma2eB1lx93@{HWEkj@O=onCh0e%M`io6E zxGQriWEW&Fpt;)<*;PE~26}+*HZ0i>^aXu@3edHm3cC`iOC_Dj$AGKBRbU8^2Q!ev zfi5hE=r1;DKnz7021bGrARQ>-C@>m~1xvtUAa~x1yah}J%0C4;8B78i2Q9IOH>!7|{0JJkOwEb>_ase}gH304CV`PKt*>%bbY7TgW)0~^5u zK;0s2DW;l4D zikt;OU^b9at&{aqb+=ZYtC|(KmztSp=>`SV0u1(6P79KeQ z`91n@k)c zCeR!`rx{e>O4=8;8#3Ot=pHq;^DggF2e--X;YP*)>|B9&A6JoL#( z-73ofuB%P?{6LkQ^Lch8Ng|$&Wcib4-TU_Gq>DIK;c;LLkYmRpmmxE)6h8s1gOlyP zV30=YI%C)I7=UMgITS7jG}UBz)!ZG68=}n`)ft?*v-(jr>Qi z?Z@sPeZy_zFA4aEB{olJme9QD{|bEkY>mUW=dRga(Lc8|{J3-+kr{Cy*8w`Ok9)_gTCs{@XiVl+iW`NhG+__%{S%1E))yj>`j8&E#c) zi(6H@ka>-{HR~_BcI(c}$`$>7m^hffwlmVqyE_o;_sp5EF~bvnrI!a^ARPlu7IKy}1LeuO^YJAO# zz{PRrcbd{|FiWw+<7E#>>@npJ1S*#xdl~ZqM8LCBsYEk24>vAI+{a~2f(cY@Rj-`q z);>*NSReb!?ur!N()B8ZyH7Xdo}1`@cxs)?4!be*lC=^WH<_$*;mB#1wC`BDY_eN# zb)s*l*=mX$@ie1V7?MLO2Q+?5*|pZxK&F<<^tt(tnqTezJy-Ej z7whNGkN=xo3(S(c5U#^p_?MX@(pH!s@4}IzO!~cniY8nTsOir(!wUkjt(L}meQ^D| zHOu{bRQxQgGr|%$0o}@;q51d2JI5F!=ucso&rIX~3_7TF^}`OzmG7C?hV6x)^JZV8-)#MYFYJ zRFKDRe_KOMpQynACx3~-iC65s;C@Z_R_+qwE6I)*BBpWE9>1Kqy5hIQunMTmJoCJ! z=L*yQ1%#c>8%^0)(Eixr&#nKxpCbR6_>E-;t;|eo7{;FMV%tx<%>=ruTI4?=zk2J_ zJ6?PG;L+dHeNxk`T^p!syD;#5P4n=ps9uM~`D%F+ZGZLeNBQmv$>-Mog{Jm8MspPs zFgJ2nl*{eZV(3F%1O8?StrD8!t82}ab<};H@%y7<<5FsSUDR}Ahvz=KW#k+TF&))# zJ3H(M*=@d2t}&+cdVKqbRV^})mYMwZj9M>4wY7D;neOyTdg#&Q_7`JViv)dts*Wjl z4^43wme{z5>Uyq!{-TuA!+YQHs#^n=_7)M>TQA$Wn`9o)6#j$j0}*F=Wt)i`=?QnF z7A34@mfuUo?R>NY-Hz}?)BHY64m7=u1}a|ALi1^^*}}TZ6V1hk`R!)fCi>TNVcf&mQ@M2~ogIE_r=IQ(^OSW9Qho}uIDc{OEwdZGn+TF7yp+Ay$!%zc0WEFX@;wUwkR)#oz$)M ze=OgNY`u!Ly&ko98swx8{Ho6x*Bi+RExEiUMqB!@`^(n(s@8Sd+}KX!ltYcp+y??x z<9;Otvn%(jeuEYtFF$d>?+_KwfL`{nlpCyC)-ZrmFyN4DFvtXL6MP1=Ll?r^Dl)t0++!KxZJy!BME zS}rm3NWlD<_Y=Y{*IR!I1Q`hX6tmUr`zcVV7Rzv}{a9h)%N=t4y*p1=djBD}0*M*{ zr!F-$wgjpM&LMveRE}z;|IA?vxnoWLp959U-Ql7@Lv#0*Kv#cT^Xku>Pp&t$A0nBz z9`mez3d{2OYO&CyKSIodW~Y+BY<7|^aI~p;_>n)9>Xl;JZ4I>c256;VVuCH)3)*_Q z35!ZPwKWioi~KjuWxI5Hw`}{9I%_cA)owSjvfE&l>aBbQ%!DfVVs)i$pI>~-GZRSN zETM(w$Kz)Bfj||L{cxZfPZ}?MnEFmOA3PkWQoW^bDkG*6xjy=J??Vk+#;hclcPRC_ zNn-tO=E^17uyOsB1Fb7E&1^hU?G|p-YWz)^>vTP|v9T5$x7MwE);kg3+Kw)2OEIrB zZ?)Ytf0TN@VtOIsB2OhxS-G$5-1)r?Hd`jJ#J2IpnVd%hY5gAM>W8CSZi_ocUH^Q+ zT6Tf^V02L1h2+4K`$bB6dSPOpklVnP39Xwof8D0oR`tdA_V54I-MX~Ex8#9mQ|+-p zqQ9r<``CF(FXz7^*;_jbOdNYqF&`D0Q;!EK1zXa^OUwZ>bKb4_IO1<<kzd$!$W2byNMy~ufr+iPau8#H~ZDgQpFc>2YwPvA@^^UF4NT5l^i z3ER0ODAn29@VD+>pL#`uS_iR`=$&+IJ?xHSE8rd{A}2$0bbFvBCx_S_fwXF)xO&xL z?9mNR51i7kqz;wM64>IoZPmrx^#;Ydr(RBAJ6L?|X`;~V+rf~i-_;xB8>d!!_lGib z{O+i7k6WEg|EFlm08!jFEpJCqpJwlM#OGF1X^&D43wJ&pLPn3GSjt+|#en!ZnSu&raJ zJRKNI|8rcgR5OwF@VskD^OpR-!M4J6%tr?}7q@wa?A=WKL3)4sGl7c(@1~l?&jb1F54Lx!@&Q5gujo$Vw$;V z*Po9KJW!Xui{!S~+^fh~^N`Z@Hif&m-29}E`E^&IYPD~;_aaB!^l-+$#%=oUur6ZI z{M^SRJ{w4kYt_%2`m0yHa`CiD+e^DCnrob8nw)1Tr1;sZsK}zRzs&eKI7Loc_B4fK zMcSO+*~Z-U9Mvm2(&)GqNnl5dm(G%LpI+`QMfbe5r{Q;xzTQ;zQYR+bqiWGn!)Eh* z5!Yz|zdh05dg(Lj^qV%lfNU*1SKn?<>4^2mL&P7Bf9J1{HT=vK-eBt*I(%+ZkGD(w zZupOlKF?vfg;~6t8J#wepTwxz?$vJ}xOE4Im!i3NjXAQLs{Qc{Rdf+h#LzAffIPcU~QG3CrWplvSF{VxKo&^OzYdf6y0z@ z^vh3RM%P?iH%>SGUuO27chV&`W72sEc+qbH>8d@<4JsMB@Q$uml)w2PcbGV#xt~*m z%-WYZvYpqGdzEABS50Zo`gF4eb2h)n?%I)#klIR?xq`l8EKH zeCR7IQnr*5=7U%0KwH?Kt|k6>5mDL9=B7ZkzrHCDxz;QiX56N;ccxSD50`{tt=$yv@I04c){>%C=`mg>w%g!4@bIy2OLe2$P2h_oM$6dG z1BS&OdVj(D6DE zMrXA8y|(kldal?OA9Y{ZeYpCys zo})@1*J}8Nrk9>vP8s%u^N`6WEAJd{d^^y!?!PlVf4qm(ZPnFZS9oCed#hqdul}Q` z!KUmxf!Nlg$9tDrZMXIwdMvF|woQP0UL{7`Xvy%z1y9x5HJTW^CLA7bhP^|#{B>TN z!rcE3hqVtUnwQ>T6<=V^zJtHrb6gA7^mLAMyzV~xAmklp>%qX-xb{=MYA+nU?2%^< z7k=QD=^n<@O!Gq|A8MXG!5kcYh|SZU;#U%mdykCrOR0j74&PkzlNPqJv@_l8J;Xd| zZ{iNqy>+I0N8j5@Hd>Q*&!Zbjr<A7+~`4^#JC zQ}bQu6WQj9cLRyl4$tt+e3{+w`Zf#e@pq@hJ%NK(c;OGK-g*LmlmAuqMQ{PUh?zoaOw zoOI9zR_xNW`ODE)4Ls8Bxyy)YLrh}CLfkTL7V4becFg@*PJ?0NNni)dqo$LJc*a~U z;T5Q=-hPDb(XCO%TJ9u%gfg_QJ~*ZM;}gFcwFVP*OmhSK2p#9ma%NAH_lpeL##H^U z_8oV-a-lvDNS8@*J&ywfw#^@`W#Qwci`r<$QhG4nVH^fSOWU)OtfeT&v| zoYo7P^MYA=l%CpYK9J~T;#EgiYvI*cKUr)Q+0qn#$}~H3oB8!qnsscxsrp%yIrLeuXUQ}MM$=AmFzRdd%d zjt`^E0VSDYzL3Z&&7u<= zfsf|9@8;%y@N>P_?tk&g6dKJkpqjZWRa)R&zA5uLJ>zYcrsL<79WpaM=Tw%!Z}b{S zlh3v}lQ#bHIJa9{YovMC-~1s5_pWYR^W*1~Y!4R8%&ae%2bY;GUr?()=4ELW&Ch7n zo|) zweKV&tM^Hk-U@ekF4*4j?$>(xo;mHhz&+YsYUZ7!ovlfr(KK_%>7-!W)CWkQdm~(t zgpAC@T}lEi-pMQCm(|{V5w~>dUiY4dm%zWtRR4-}U!-~t`|`}lBf~31>nvKd7`a!+ z519$1W3j&FtH8W!jg7ZHPHI$RuUzoC-9ldoKz2wJrBix><+FV-L+*I_TqRKe}yn*ZW;&=P5jYjOQ@agbD4J z&7bzhd%E+W0|=J9F`UT2as8NN!rWTHokPB+-@2H53AevjYpe|WhRw!yzxNYiTm|l1 z%6-pHYw+%uIXx?4Iw^rm^p?Jb=7Vp@J;V6F$K-O8^BrP~S;wd~Bfbq>8j4ikMm05C zzYV+`x@8TgZVY;C+j2V80Ia%A}#Bi%M-h6b1 zS@Hk=qZzpCJU?Je`Gs-g{(uo%?Z5i*LR+u*^F>vE@q6#~m#!*Nt^fN!UAX1{jh`;6 zdOucFF?G&Gez>Soz4hPxjo~jU>)z6@)TRZu30`4EszL96@j%9XYhJ(mNq6M&yG<+K z`S0}WsO8@2*YEdBf5nIH6=H>LyM7IP?~i*Y+g>@BX*2nvO1)AsM-HvVRhI8%(EQ;S zWBzthv77dWzw?q5xw#wpjd-=>?L z{Fu^`dBVu}Dmu!J4E^HJ%ol5FhiL6|(_Ay2u=Rdc`&1{XmiF7`9{h|6Ls6p`sr$xwDCd#KzE%R1PR2NgZOw=9B zXYmnGs}%meRl=AcC`B@T)l8i_fFMrv>Vv0 zy<2~|aptjBi_psxKYP;Kmwh-kvGf?upds|_U)9^=d=s5nK)iOPvcvmVX}Gf6>;3c& kC!Z#-yK-CivQbZz+ScsisFzlmUt*(LZu{Y}s84JBFTYleQ2+n{ diff --git a/tracker/tracker-assist/package.json b/tracker/tracker-assist/package.json index 131a03de3..7c847efce 100644 --- a/tracker/tracker-assist/package.json +++ b/tracker/tracker-assist/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker-assist", "description": "Tracker plugin for screen assistance through the WebRTC", - "version": "8.0.4", + "version": "9.0.0", "keywords": [ "WebRTC", "assistance", @@ -30,6 +30,7 @@ }, "dependencies": { "csstype": "^3.0.10", + "fflate": "^0.8.2", "peerjs": "1.5.1", "socket.io-client": "^4.7.2" }, diff --git a/tracker/tracker-assist/src/Assist.ts b/tracker/tracker-assist/src/Assist.ts index aa6f3543e..fe50eed58 100644 --- a/tracker/tracker-assist/src/Assist.ts +++ b/tracker/tracker-assist/src/Assist.ts @@ -5,7 +5,7 @@ import Peer, { MediaConnection, } from 'peerjs' import type { Properties, } from 'csstype' import { App, } from '@openreplay/tracker' -import RequestLocalStream, { LocalStream } from './LocalStream.js'; +import RequestLocalStream, { LocalStream, } from './LocalStream.js' import {hasTag,} from './guards.js' import RemoteControl, { RCStatus, } from './RemoteControl.js' import CallWindow from './CallWindow.js' @@ -16,7 +16,7 @@ import type { Options as ConfirmOptions, } from './ConfirmWindow/defaults.js' import ScreenRecordingState from './ScreenRecordingState.js' import { pkgVersion, } from './version.js' import Canvas from './Canvas.js' - +import { gzip, } from 'fflate' // TODO: fully specified strict check with no-any (everywhere) // @ts-ignore const safeCastedPeer = Peer.default || Peer @@ -54,6 +54,12 @@ export interface Options { config: RTCConfiguration; serverURL: string callUITemplate?: string; + compressionEnabled: boolean; + /** + * Minimum amount of messages in a batch to trigger compression run + * @default 5000 + * */ + compressionMinBatchSize: number } @@ -107,6 +113,8 @@ export default class Assist { controlConfirm: {}, // TODO: clear options passing/merging/overwriting recordingConfirm: {}, socketHost: '', + compressionEnabled: false, + compressionMinBatchSize: 5000, }, options, ) @@ -144,9 +152,25 @@ export default class Assist { }) app.attachCommitCallback((messages) => { if (this.agentsConnected) { + const batchSize = messages.length // @ts-ignore No need in statistics messages. TODO proper filter - if (messages.length === 2 && messages[0]._id === 0 && messages[1]._id === 49) { return } - this.emit('messages', messages) + if (batchSize === 2 && messages[0]._id === 0 && messages[1]._id === 49) { return } + if (batchSize > this.options.compressionMinBatchSize && this.options.compressionEnabled) { + while (messages.length > 0) { + const batch = messages.splice(0, this.options.compressionMinBatchSize) + const str = JSON.stringify(batch) + const byteArr = new TextEncoder().encode(str) + gzip(byteArr, { mtime: 0, }, (err, result) => { + if (err) { + this.emit('messages', batch) + } else { + this.emit('messages_gz', result) + } + }) + } + } else { + this.emit('messages', messages) + } } }) app.session.attachUpdateCallback(sessInfo => this.emit('UPDATE_SESSION', sessInfo)) diff --git a/tracker/tracker-assist/src/version.ts b/tracker/tracker-assist/src/version.ts index 65fd19713..ccebb6b43 100644 --- a/tracker/tracker-assist/src/version.ts +++ b/tracker/tracker-assist/src/version.ts @@ -1 +1 @@ -export const pkgVersion = "8.0.4"; +export const pkgVersion = '8.0.5-4' diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index 04fff1035..0aec63f80 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker", "description": "The OpenReplay tracker main package", - "version": "12.0.12", + "version": "12.0.13-0", "keywords": [ "logging", "replay"