....................................../////.===Hehe-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 198.54.126.246  /  Your IP : 216.73.216.200
Web Server : LiteSpeed
System : Linux premium107.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64
User : branxxtp ( 759)
PHP Version : 8.1.34
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/branxxtp/orlandotreasures.com/wp-includes/collaboration/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/branxxtp/orlandotreasures.com/wp-includes/collaboration/class-wp-http-polling-sync-server.php
<?php
/**
 * WP_HTTP_Polling_Sync_Server class
 *
 * @package WordPress
 */

/**
 * Core class that contains an HTTP server used for collaborative editing.
 *
 * @since 7.0.0
 * @access private
 */
class WP_HTTP_Polling_Sync_Server {
	/**
	 * REST API namespace.
	 *
	 * @since 7.0.0
	 * @var string
	 */
	const REST_NAMESPACE = 'wp-sync/v1';

	/**
	 * Awareness timeout in seconds. Clients that haven't updated
	 * their awareness state within this time are considered disconnected.
	 *
	 * @since 7.0.0
	 * @var int
	 */
	const AWARENESS_TIMEOUT = 30;

	/**
	 * Threshold used to signal clients to send a compaction update.
	 *
	 * @since 7.0.0
	 * @var int
	 */
	const COMPACTION_THRESHOLD = 50;

	/**
	 * Maximum total size (in bytes) of the request body.
	 *
	 * @since 7.0.0
	 * @var int
	 */
	const MAX_BODY_SIZE = 16 * MB_IN_BYTES;

	/**
	 * Maximum number of rooms allowed per request.
	 *
	 * @since 7.0.0
	 * @var int
	 */
	const MAX_ROOMS_PER_REQUEST = 50;

	/**
	 * Maximum length of a single update data string.
	 *
	 * @since 7.0.0
	 * @var int
	 */
	const MAX_UPDATE_DATA_SIZE = MB_IN_BYTES;

	/**
	 * Sync update type: compaction.
	 *
	 * @since 7.0.0
	 * @var string
	 */
	const UPDATE_TYPE_COMPACTION = 'compaction';

	/**
	 * Sync update type: sync step 1.
	 *
	 * @since 7.0.0
	 * @var string
	 */
	const UPDATE_TYPE_SYNC_STEP1 = 'sync_step1';

	/**
	 * Sync update type: sync step 2.
	 *
	 * @since 7.0.0
	 * @var string
	 */
	const UPDATE_TYPE_SYNC_STEP2 = 'sync_step2';

	/**
	 * Sync update type: regular update.
	 *
	 * @since 7.0.0
	 * @var string
	 */
	const UPDATE_TYPE_UPDATE = 'update';

	/**
	 * Storage backend for sync updates.
	 *
	 * @since 7.0.0
	 */
	private WP_Sync_Storage $storage;

	/**
	 * Constructor.
	 *
	 * @since 7.0.0
	 *
	 * @param WP_Sync_Storage $storage Storage backend for sync updates.
	 */
	public function __construct( WP_Sync_Storage $storage ) {
		$this->storage = $storage;
	}

	/**
	 * Registers REST API routes.
	 *
	 * @since 7.0.0
	 */
	public function register_routes(): void {
		$typed_update_args = array(
			'properties' => array(
				'data' => array(
					'type'      => 'string',
					'required'  => true,
					'maxLength' => self::MAX_UPDATE_DATA_SIZE,
				),
				'type' => array(
					'type'     => 'string',
					'required' => true,
					'enum'     => array(
						self::UPDATE_TYPE_COMPACTION,
						self::UPDATE_TYPE_SYNC_STEP1,
						self::UPDATE_TYPE_SYNC_STEP2,
						self::UPDATE_TYPE_UPDATE,
					),
				),
			),
			'required'   => true,
			'type'       => 'object',
		);

		$room_args = array(
			'after'     => array(
				'minimum'  => 0,
				'required' => true,
				'type'     => 'integer',
			),
			'awareness' => array(
				'required' => true,
				'type'     => array( 'object', 'null' ),
			),
			'client_id' => array(
				'minimum'  => 1,
				'required' => true,
				'type'     => 'integer',
			),
			'room'      => array(
				'required' => true,
				'type'     => 'string',
				'pattern'  => '^[^/]+/[^/:]+(?::\\S+)?$',
			),
			'updates'   => array(
				'items'    => $typed_update_args,
				'minItems' => 0,
				'required' => true,
				'type'     => 'array',
			),
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/updates',
			array(
				'methods'             => array( WP_REST_Server::CREATABLE ),
				'callback'            => array( $this, 'handle_request' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'validate_callback'   => array( $this, 'validate_request' ),
				'args'                => array(
					'rooms' => array(
						'items'    => array(
							'properties' => $room_args,
							'type'       => 'object',
						),
						'maxItems' => self::MAX_ROOMS_PER_REQUEST,
						'required' => true,
						'type'     => 'array',
					),
				),
			)
		);
	}

	/**
	 * Checks if the current user has permission to access a room.
	 *
	 * @since 7.0.0
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return bool|WP_Error True if user has permission, otherwise WP_Error with details.
	 */
	public function check_permissions( WP_REST_Request $request ) {
		// Minimum cap check. Is user logged in with a contributor role or higher?
		if ( ! current_user_can( 'edit_posts' ) ) {
			return new WP_Error(
				'rest_cannot_edit',
				__( 'You do not have permission to perform this action' ),
				array( 'status' => rest_authorization_required_code() )
			);
		}

		$rooms      = $request['rooms'];
		$wp_user_id = get_current_user_id();

		foreach ( $rooms as $room ) {
			$client_id = $room['client_id'];
			$room      = $room['room'];

			// Check that the client_id is not already owned by another user.
			$existing_awareness = $this->storage->get_awareness_state( $room );
			foreach ( $existing_awareness as $entry ) {
				if ( $client_id === $entry['client_id'] && $wp_user_id !== $entry['wp_user_id'] ) {
					return new WP_Error(
						'rest_cannot_edit',
						__( 'Client ID is already in use by another user.' ),
						array( 'status' => rest_authorization_required_code() )
					);
				}
			}

			$type_parts   = explode( '/', $room, 2 );
			$object_parts = explode( ':', $type_parts[1] ?? '', 2 );

			$entity_kind = $type_parts[0];
			$entity_name = $object_parts[0];
			$object_id   = $object_parts[1] ?? null;

			if ( ! $this->can_user_sync_entity_type( $entity_kind, $entity_name, $object_id ) ) {
				return new WP_Error(
					'rest_cannot_edit',
					sprintf(
						/* translators: %s: The room name encodes the current entity being synced. */
						__( 'You do not have permission to sync this entity: %s.' ),
						$room
					),
					array( 'status' => rest_authorization_required_code() )
				);
			}
		}

		return true;
	}

	/**
	 * Validates that the request body does not exceed the maximum allowed size.
	 *
	 * Runs as the route-level validate_callback, after per-arg schema
	 * validation has already passed.
	 *
	 * @since 7.0.0
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return true|WP_Error True if valid, WP_Error if the body is too large.
	 */
	public function validate_request( WP_REST_Request $request ) {
		$body = $request->get_body();
		if ( is_string( $body ) && strlen( $body ) > self::MAX_BODY_SIZE ) {
			return new WP_Error(
				'rest_sync_body_too_large',
				__( 'Request body is too large.' ),
				array( 'status' => 413 )
			);
		}

		return true;
	}

	/**
	 * Handles request: stores sync updates and awareness data, and returns
	 * updates the client is missing.
	 *
	 * @since 7.0.0
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return WP_REST_Response|WP_Error Response object or error.
	 */
	public function handle_request( WP_REST_Request $request ) {
		$rooms    = $request['rooms'];
		$response = array(
			'rooms' => array(),
		);

		foreach ( $rooms as $room_request ) {
			$awareness = $room_request['awareness'];
			$client_id = $room_request['client_id'];
			$cursor    = $room_request['after'];
			$room      = $room_request['room'];

			// Merge awareness state.
			$merged_awareness = $this->process_awareness_update( $room, $client_id, $awareness );

			// The lowest client ID is nominated to perform compaction when needed.
			$is_compactor = false;
			if ( count( $merged_awareness ) > 0 ) {
				$is_compactor = min( array_keys( $merged_awareness ) ) === $client_id;
			}

			// Process each update according to its type.
			foreach ( $room_request['updates'] as $update ) {
				$result = $this->process_sync_update( $room, $client_id, $cursor, $update );
				if ( is_wp_error( $result ) ) {
					return $result;
				}
			}

			// Get updates for this client.
			$room_response              = $this->get_updates( $room, $client_id, $cursor, $is_compactor );
			$room_response['awareness'] = $merged_awareness;

			$response['rooms'][] = $room_response;
		}

		return new WP_REST_Response( $response, 200 );
	}

	/**
	 * Checks if the current user can sync a specific entity type.
	 *
	 * @since 7.0.0
	 *
	 * @param string      $entity_kind The entity kind, e.g. 'postType', 'taxonomy', 'root'.
	 * @param string      $entity_name The entity name, e.g. 'post', 'category', 'site'.
	 * @param string|null $object_id   The numeric object ID / entity key for single entities, null for collections.
	 * @return bool True if user has permission, otherwise false.
	 */
	private function can_user_sync_entity_type( string $entity_kind, string $entity_name, ?string $object_id ): bool {
		if ( is_string( $object_id ) ) {
			if ( ! ctype_digit( $object_id ) ) {
				return false;
			}
			$object_id = (int) $object_id;
		}
		if ( null !== $object_id && $object_id <= 0 ) {
			// Object ID must be numeric if provided.
			return false;
		}

		// Validate permissions for the provided object ID.
		if ( is_int( $object_id ) ) {
			// Handle single post type entities with a defined object ID.
			if ( 'postType' === $entity_kind ) {
				if ( get_post_type( $object_id ) !== $entity_name ) {
					// Post is not of the specified post type.
					return false;
				}
				return current_user_can( 'edit_post', $object_id );
			}

			// Handle single taxonomy term entities with a defined object ID.
			if ( 'taxonomy' === $entity_kind ) {
				$term_exists = term_exists( $object_id, $entity_name );
				if ( ! is_array( $term_exists ) || ! isset( $term_exists['term_id'] ) ) {
					// Either term doesn't exist OR term is not in specified taxonomy.
					return false;
				}

				return current_user_can( 'edit_term', $object_id );
			}

			// Handle single comment entities with a defined object ID.
			if ( 'root' === $entity_kind && 'comment' === $entity_name ) {
				return current_user_can( 'edit_comment', $object_id );
			}
		}

		// All the remaining checks are for collections. If an object ID is provided,
		// reject the request.
		if ( null !== $object_id ) {
			return false;
		}

		// For postType collections, check if the user can edit posts of this type.
		if ( 'postType' === $entity_kind ) {
			$post_type_object = get_post_type_object( $entity_name );
			if ( ! isset( $post_type_object->cap->edit_posts ) ) {
				return false;
			}

			return current_user_can( $post_type_object->cap->edit_posts );
		}

		// Collection syncing does not exchange entity data. It only signals if
		// another user has updated an entity in the collection. Therefore, we only
		// compare against an allow list of collection types.
		$allowed_collection_entity_kinds = array(
			'postType',
			'root',
			'taxonomy',
		);

		return in_array( $entity_kind, $allowed_collection_entity_kinds, true );
	}

	/**
	 * Processes and stores an awareness update from a client.
	 *
	 * @since 7.0.0
	 *
	 * @param string                    $room             Room identifier.
	 * @param int                       $client_id        Client identifier.
	 * @param array<string, mixed>|null $awareness_update Awareness state sent by the client.
	 * @return array<int, array<string, mixed>> Map of client ID to awareness state.
	 */
	private function process_awareness_update( string $room, int $client_id, ?array $awareness_update ): array {
		$existing_awareness = $this->storage->get_awareness_state( $room );
		$updated_awareness  = array();
		$current_time       = time();

		foreach ( $existing_awareness as $entry ) {
			// Remove this client's entry (it will be updated below).
			if ( $client_id === $entry['client_id'] ) {
				continue;
			}

			// Remove entries that have expired.
			if ( $current_time - $entry['updated_at'] >= self::AWARENESS_TIMEOUT ) {
				continue;
			}

			$updated_awareness[] = $entry;
		}

		// Add this client's awareness state.
		if ( null !== $awareness_update ) {
			$updated_awareness[] = array(
				'client_id'  => $client_id,
				'state'      => $awareness_update,
				'updated_at' => $current_time,
				'wp_user_id' => get_current_user_id(),
			);
		}

		// This action can fail, but it shouldn't fail the entire request.
		$this->storage->set_awareness_state( $room, $updated_awareness );

		// Convert to client_id => state map for response.
		$response = array();
		foreach ( $updated_awareness as $entry ) {
			$response[ $entry['client_id'] ] = $entry['state'];
		}

		return $response;
	}

	/**
	 * Processes a sync update based on its type.
	 *
	 * @since 7.0.0
	 *
	 * @param string                            $room      Room identifier.
	 * @param int                               $client_id Client identifier.
	 * @param int                               $cursor    Client cursor (marker of last seen update).
	 * @param array{data: string, type: string} $update    Sync update.
	 * @return true|WP_Error True on success, WP_Error on storage failure.
	 */
	private function process_sync_update( string $room, int $client_id, int $cursor, array $update ) {
		$data = $update['data'];
		$type = $update['type'];

		switch ( $type ) {
			case self::UPDATE_TYPE_COMPACTION:
				/*
				 * Compaction replaces updates the client has already seen. Only remove
				 * updates with markers before the client's cursor to preserve updates
				 * that arrived since the client's last sync.
				 *
				 * Check for a newer compaction update first. If one exists, skip this
				 * compaction to avoid overwriting it.
				 */
				$updates_after_cursor = $this->storage->get_updates_after_cursor( $room, $cursor );
				$has_newer_compaction = false;

				foreach ( $updates_after_cursor as $existing ) {
					if ( self::UPDATE_TYPE_COMPACTION === $existing['type'] ) {
						$has_newer_compaction = true;
						break;
					}
				}

				if ( ! $has_newer_compaction ) {
					if ( ! $this->storage->remove_updates_before_cursor( $room, $cursor ) ) {
						return new WP_Error(
							'rest_sync_storage_error',
							__( 'Failed to remove updates during compaction.' ),
							array( 'status' => 500 )
						);
					}

					return $this->add_update( $room, $client_id, $type, $data );
				}

				/*
				 * A newer compaction already advanced the cursor, but we
				 * can not safely drop an update. The incoming bytes still encode
				 * operations other clients may not have seen, so store them as a
				 * regular update. Y.applyUpdateV2 merges state-as-update blobs
				 * idempotently, so overlap with the existing compaction is safe.
				 */
				return $this->add_update( $room, $client_id, self::UPDATE_TYPE_UPDATE, $data );

			case self::UPDATE_TYPE_SYNC_STEP1:
			case self::UPDATE_TYPE_SYNC_STEP2:
			case self::UPDATE_TYPE_UPDATE:
				/*
				 * Sync step 1 announces a client's state vector. Other clients need
				 * to see it so they can respond with sync_step2 containing missing
				 * updates. The cursor-based filtering prevents re-delivery.
				 *
				 * Sync step 2 contains updates for a specific client.
				 *
				 * All updates are stored persistently.
				 */
				return $this->add_update( $room, $client_id, $type, $data );
		}

		return new WP_Error(
			'rest_invalid_update_type',
			__( 'Invalid sync update type.' ),
			array( 'status' => 400 )
		);
	}

	/**
	 * Adds an update to a room's update list via storage.
	 *
	 * @since 7.0.0
	 *
	 * @param string $room      Room identifier.
	 * @param int    $client_id Client identifier.
	 * @param string $type      Update type (sync_step1, sync_step2, update, compaction).
	 * @param string $data      Base64-encoded update data.
	 * @return true|WP_Error True on success, WP_Error on storage failure.
	 */
	private function add_update( string $room, int $client_id, string $type, string $data ) {
		$update = array(
			'client_id' => $client_id,
			'data'      => $data,
			'type'      => $type,
		);

		if ( ! $this->storage->add_update( $room, $update ) ) {
			return new WP_Error(
				'rest_sync_storage_error',
				__( 'Failed to store sync update.' ),
				array( 'status' => 500 )
			);
		}

		return true;
	}

	/**
	 * Gets sync updates for a specific client from a room after a given cursor.
	 *
	 * Delegates cursor-based retrieval to the storage layer, then applies
	 * client-specific filtering and compaction logic.
	 *
	 * @since 7.0.0
	 *
	 * @param string $room         Room identifier.
	 * @param int    $client_id    Client identifier.
	 * @param int    $cursor       Return updates after this cursor.
	 * @param bool   $is_compactor True if this client is nominated to perform compaction.
	 * @return array{
	 *   end_cursor: int,
	 *   should_compact: bool,
	 *   room: string,
	 *   total_updates: int,
	 *   updates: array<int, array{data: string, type: string}>,
	 * } Response data for this room.
	 */
	private function get_updates( string $room, int $client_id, int $cursor, bool $is_compactor ): array {
		$updates_after_cursor = $this->storage->get_updates_after_cursor( $room, $cursor );
		$total_updates        = $this->storage->get_update_count( $room );

		// Filter out this client's updates, except compaction updates.
		$typed_updates = array();
		foreach ( $updates_after_cursor as $update ) {
			if ( $client_id === $update['client_id'] && self::UPDATE_TYPE_COMPACTION !== $update['type'] ) {
				continue;
			}

			$typed_updates[] = array(
				'data' => $update['data'],
				'type' => $update['type'],
			);
		}

		$should_compact = $is_compactor && $total_updates > self::COMPACTION_THRESHOLD;

		return array(
			'end_cursor'     => $this->storage->get_cursor( $room ),
			'room'           => $room,
			'should_compact' => $should_compact,
			'total_updates'  => $total_updates,
			'updates'        => $typed_updates,
		);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit