@@ -72,8 +72,24 @@ class Push {
7272 protected $ output ;
7373 /** @var array */
7474 protected $ payloadsToSend = [];
75+
76+ /** @var bool */
77+ protected $ deferPreparing = false ;
7578 /** @var bool */
7679 protected $ deferPayloads = false ;
80+ /** @var array[] */
81+ protected $ deletesToPush = [];
82+ /** @var INotification[] */
83+ protected $ notificationsToPush = [];
84+
85+ /** @var null[]|IUserStatus[] */
86+ protected $ userStatuses = [];
87+ /** @var array[] */
88+ protected $ userDevices = [];
89+ /** @var string[] */
90+ protected $ loadDevicesForUsers = [];
91+ /** @var string[] */
92+ protected $ loadStatusForUsers = [];
7793
7894 public function __construct (IDBConnection $ connection ,
7995 INotificationManager $ notificationManager ,
@@ -112,10 +128,47 @@ public function isDeferring(): bool {
112128 }
113129
114130 public function deferPayloads (): void {
131+ $ this ->deferPreparing = true ;
115132 $ this ->deferPayloads = true ;
116133 }
117134
118135 public function flushPayloads (): void {
136+ $ this ->deferPreparing = false ;
137+
138+ if (!empty ($ this ->loadDevicesForUsers )) {
139+ $ this ->loadDevicesForUsers = array_unique ($ this ->loadDevicesForUsers );
140+ $ missingDevicesFor = array_diff ($ this ->loadDevicesForUsers , array_keys ($ this ->userDevices ));
141+ $ newUserDevices = $ this ->getDevicesForUsers ($ missingDevicesFor );
142+ foreach ($ missingDevicesFor as $ userId ) {
143+ $ this ->userDevices [$ userId ] = $ newUserDevices [$ userId ] ?? [];
144+ }
145+ $ this ->loadDevicesForUsers = [];
146+ }
147+
148+ if (!empty ($ this ->loadStatusForUsers )) {
149+ $ this ->loadStatusForUsers = array_unique ($ this ->loadStatusForUsers );
150+ $ missingStatusFor = array_diff ($ this ->loadStatusForUsers , array_keys ($ this ->userStatuses ));
151+ $ newUserStatuses = $ this ->userStatusManager ->getUserStatuses ($ missingStatusFor );
152+ foreach ($ missingStatusFor as $ userId ) {
153+ $ this ->userStatuses [$ userId ] = $ newUserStatuses [$ userId ] ?? null ;
154+ }
155+ $ this ->loadStatusForUsers = [];
156+ }
157+
158+ if (!empty ($ this ->notificationsToPush )) {
159+ foreach ($ this ->notificationsToPush as $ id => $ notification ) {
160+ $ this ->pushToDevice ($ id , $ notification );
161+ }
162+ $ this ->notificationsToPush = [];
163+ }
164+
165+ if (!empty ($ this ->deletesToPush )) {
166+ foreach ($ this ->deletesToPush as $ id => $ data ) {
167+ $ this ->pushDeleteToDevice ($ data ['userId ' ], $ id , $ data ['app ' ]);
168+ }
169+ $ this ->deletesToPush = [];
170+ }
171+
119172 $ this ->deferPayloads = false ;
120173 $ this ->sendNotificationsToProxies ();
121174 }
@@ -154,21 +207,38 @@ public function pushToDevice(int $id, INotification $notification, ?OutputInterf
154207 return ;
155208 }
156209
210+ if ($ this ->deferPreparing ) {
211+ $ this ->notificationsToPush [$ id ] = clone $ notification ;
212+ $ this ->loadDevicesForUsers [] = $ notification ->getUser ();
213+ $ this ->loadStatusForUsers [] = $ notification ->getUser ();
214+ return ;
215+ }
216+
157217 $ user = $ this ->createFakeUserObject ($ notification ->getUser ());
158218
159- $ userStatus = $ this ->userStatusManager ->getUserStatuses ([
160- $ notification ->getUser (),
161- ]);
219+ if (!array_key_exists ($ notification ->getUser (), $ this ->userStatuses )) {
220+ $ userStatus = $ this ->userStatusManager ->getUserStatuses ([
221+ $ notification ->getUser (),
222+ ]);
162223
163- if (isset ($ userStatus [$ notification ->getUser ()])) {
164- $ userStatus = $ userStatus [$ notification ->getUser ()];
224+ $ this ->userStatuses [$ notification ->getUser ()] = $ userStatus [$ notification ->getUser ()] ?? null ;
225+ }
226+
227+ if (isset ($ this ->userStatuses [$ notification ->getUser ()])) {
228+ $ userStatus = $ this ->userStatuses [$ notification ->getUser ()];
165229 if ($ userStatus ->getStatus () === IUserStatus::DND ) {
166230 $ this ->printInfo ('<error>User status is set to DND - no push notifications will be sent</error> ' );
167231 return ;
168232 }
169233 }
170234
171- $ devices = $ this ->getDevicesForUser ($ notification ->getUser ());
235+ if (!array_key_exists ($ notification ->getUser (), $ this ->userDevices )) {
236+ $ devices = $ this ->getDevicesForUser ($ notification ->getUser ());
237+ $ this ->userDevices [$ notification ->getUser ()] = $ devices ;
238+ } else {
239+ $ devices = $ this ->userDevices [$ notification ->getUser ()];
240+ }
241+
172242 if (empty ($ devices )) {
173243 $ this ->printInfo ('No devices found for user ' );
174244 return ;
@@ -237,9 +307,21 @@ public function pushDeleteToDevice(string $userId, int $notificationId, string $
237307 return ;
238308 }
239309
310+ if ($ this ->deferPreparing ) {
311+ $ this ->deletesToPush [$ notificationId ] = ['userId ' => $ userId , 'app ' => $ app ];
312+ $ this ->loadDevicesForUsers [] = $ userId ;
313+ return ;
314+ }
315+
240316 $ user = $ this ->createFakeUserObject ($ userId );
241317
242- $ devices = $ this ->getDevicesForUser ($ userId );
318+ if (!array_key_exists ($ userId , $ this ->userDevices )) {
319+ $ devices = $ this ->getDevicesForUser ($ userId );
320+ $ this ->userDevices [$ userId ] = $ devices ;
321+ } else {
322+ $ devices = $ this ->userDevices [$ userId ];
323+ }
324+
243325 if ($ notificationId !== 0 && $ app !== '' ) {
244326 // Only filter when it's not a single delete
245327 $ devices = $ this ->filterDeviceList ($ devices , $ app );
@@ -516,6 +598,30 @@ protected function getDevicesForUser(string $uid): array {
516598 return $ devices ;
517599 }
518600
601+ /**
602+ * @param string[] $userIds
603+ * @return array[]
604+ */
605+ protected function getDevicesForUsers (array $ userIds ): array {
606+ $ query = $ this ->db ->getQueryBuilder ();
607+ $ query ->select ('* ' )
608+ ->from ('notifications_pushhash ' )
609+ ->where ($ query ->expr ()->in ('uid ' , $ query ->createNamedParameter ($ userIds , IQueryBuilder::PARAM_STR_ARRAY )));
610+
611+ $ devices = [];
612+ $ result = $ query ->executeQuery ();
613+ while ($ row = $ result ->fetch ()) {
614+ if (!isset ($ devices [$ row ['uid ' ]])) {
615+ $ devices [$ row ['uid ' ]] = [];
616+ }
617+ $ devices [$ row ['uid ' ]][] = $ row ;
618+ }
619+
620+ $ result ->closeCursor ();
621+
622+ return $ devices ;
623+ }
624+
519625 /**
520626 * @param int $tokenId
521627 * @return bool
0 commit comments