11package chat .rocket .reactnative .notification ;
22
33import android .os .Bundle ;
4+ import android .util .Log ;
45
56import com .facebook .react .bridge .ReactApplicationContext ;
67import com .google .gson .Gson ;
8+ import com .google .gson .JsonSyntaxException ;
9+
10+ import java .io .IOException ;
11+ import java .util .concurrent .TimeUnit ;
712
813import okhttp3 .HttpUrl ;
914import okhttp3 .OkHttpClient ;
1015import okhttp3 .Request ;
1116import okhttp3 .Response ;
17+ import okhttp3 .ResponseBody ;
1218
1319class JsonResponse {
1420 Data data ;
@@ -31,54 +37,163 @@ class Payload {
3137 String notificationType ;
3238 String name ;
3339 String messageType ;
40+ String senderName ;
41+ String msg ;
42+ String tmid ;
43+ Content content ;
3444
3545 class Sender {
3646 String _id ;
3747 String username ;
3848 String name ;
3949 }
50+
51+ class Content {
52+ String algorithm ;
53+ String ciphertext ;
54+ String kid ;
55+ String iv ;
56+ }
4057 }
4158 }
4259 }
4360}
4461
4562public class LoadNotification {
63+ private static final String TAG = "RocketChat.LoadNotif" ;
4664 private int RETRY_COUNT = 0 ;
4765 private int [] TIMEOUT = new int []{0 , 1 , 3 , 5 , 10 };
4866 private String TOKEN_KEY = "reactnativemeteor_usertoken-" ;
4967
5068 public void load (ReactApplicationContext reactApplicationContext , final Ejson ejson , Callback callback ) {
51- final OkHttpClient client = new OkHttpClient ();
52- HttpUrl .Builder url = HttpUrl .parse (ejson .serverURL ().concat ("/api/v1/push.get" )).newBuilder ();
69+ Log .i (TAG , "Starting notification load for message-id-only notification" );
70+
71+ // Validate ejson object
72+ if (ejson == null ) {
73+ Log .e (TAG , "Failed to load notification: ejson is null" );
74+ callback .call (null );
75+ return ;
76+ }
77+
78+ final String serverURL = ejson .serverURL ();
79+ final String messageId = ejson .messageId ;
80+
81+ Log .d (TAG , "Notification payload - serverURL: " + NotificationHelper .sanitizeUrl (serverURL ) + ", messageId: " + (messageId != null ? "[present]" : "[null]" ));
82+
83+ // Validate required fields
84+ if (serverURL == null || serverURL .isEmpty ()) {
85+ Log .e (TAG , "Failed to load notification: serverURL is null or empty" );
86+ callback .call (null );
87+ return ;
88+ }
89+
90+ if (messageId == null || messageId .isEmpty ()) {
91+ Log .e (TAG , "Failed to load notification: messageId is null or empty" );
92+ callback .call (null );
93+ return ;
94+ }
5395
5496 final String userId = ejson .userId ();
5597 final String userToken = ejson .token ();
5698
57- if (userId == null || userToken == null ) {
99+ if (userId == null || userId .isEmpty ()) {
100+ Log .w (TAG , "Failed to load notification: userId is null or empty (user may not be logged in)" );
101+ callback .call (null );
102+ return ;
103+ }
104+
105+ if (userToken == null || userToken .isEmpty ()) {
106+ Log .w (TAG , "Failed to load notification: userToken is null or empty (user may not be logged in)" );
107+ callback .call (null );
108+ return ;
109+ }
110+
111+ // Configure OkHttpClient with proper timeouts
112+ final OkHttpClient client = new OkHttpClient .Builder ()
113+ .connectTimeout (10 , TimeUnit .SECONDS )
114+ .readTimeout (30 , TimeUnit .SECONDS )
115+ .writeTimeout (30 , TimeUnit .SECONDS )
116+ .build ();
117+
118+ HttpUrl .Builder urlBuilder ;
119+ try {
120+ urlBuilder = HttpUrl .parse (serverURL .concat ("/api/v1/push.get" )).newBuilder ();
121+ } catch (Exception e ) {
122+ Log .e (TAG , "Failed to parse server URL: " + NotificationHelper .sanitizeUrl (serverURL ), e );
123+ callback .call (null );
58124 return ;
59125 }
60126
61127 Request request = new Request .Builder ()
62128 .header ("x-user-id" , userId )
63129 .header ("x-auth-token" , userToken )
64- .url (url .addQueryParameter ("id" , ejson . messageId ).build ())
130+ .url (urlBuilder .addQueryParameter ("id" , messageId ).build ())
65131 .build ();
132+
133+ String sanitizedEndpoint = NotificationHelper .sanitizeUrl (serverURL ) + "/api/v1/push.get" ;
134+ Log .d (TAG , "Built request to endpoint: " + sanitizedEndpoint );
66135
67- runRequest (client , request , callback );
136+ runRequest (client , request , callback , sanitizedEndpoint );
68137 }
69138
70- private void runRequest (OkHttpClient client , Request request , Callback callback ) {
139+ private void runRequest (OkHttpClient client , Request request , Callback callback , String sanitizedEndpoint ) {
71140 try {
72- Thread .sleep (TIMEOUT [RETRY_COUNT ] * 1000 );
141+ int delay = TIMEOUT [RETRY_COUNT ];
142+ if (delay > 0 ) {
143+ Log .d (TAG , "Retry attempt " + RETRY_COUNT + ", waiting " + delay + " seconds before request" );
144+ } else {
145+ Log .d (TAG , "Attempt " + (RETRY_COUNT + 1 ) + ", executing request to " + sanitizedEndpoint );
146+ }
147+
148+ Thread .sleep (delay * 1000 );
73149
74150 Response response = client .newCall (request ).execute ();
75- String body = response .body ().string ();
151+ int statusCode = response .code ();
152+
153+ ResponseBody responseBody = response .body ();
154+ if (responseBody == null ) {
155+ Log .e (TAG , "Request failed: response body is null (status: " + statusCode + ")" );
156+ throw new IOException ("Response body is null" );
157+ }
158+
159+ String body = responseBody .string ();
160+
76161 if (!response .isSuccessful ()) {
77- throw new Exception ("Error" );
162+ if (statusCode == 401 || statusCode == 403 ) {
163+ Log .w (TAG , "Authentication failed: HTTP " + statusCode + " - user may need to re-login" );
164+ } else if (statusCode >= 500 ) {
165+ Log .e (TAG , "Server error: HTTP " + statusCode + " - server may be experiencing issues" );
166+ } else {
167+ Log .w (TAG , "Request failed with HTTP " + statusCode );
168+ }
169+ throw new IOException ("HTTP " + statusCode );
78170 }
171+
172+ Log .i (TAG , "Successfully received response (HTTP " + statusCode + "), parsing notification data" );
79173
80174 Gson gson = new Gson ();
81- JsonResponse json = gson .fromJson (body , JsonResponse .class );
175+ JsonResponse json ;
176+ try {
177+ json = gson .fromJson (body , JsonResponse .class );
178+ } catch (JsonSyntaxException e ) {
179+ Log .e (TAG , "Failed to parse JSON response" , e );
180+ throw e ;
181+ }
182+
183+ // Validate parsed response structure
184+ if (json == null || json .data == null || json .data .notification == null ) {
185+ Log .e (TAG , "Invalid response structure: missing required fields" );
186+ throw new IllegalStateException ("Invalid response structure" );
187+ }
188+
189+ // Log encryption fields if present
190+ if (json .data .notification .payload != null ) {
191+ boolean hasEncryption = json .data .notification .payload .msg != null || json .data .notification .payload .content != null ;
192+ if (hasEncryption ) {
193+ Log .d (TAG , "Notification contains encrypted content: msg=" + (json .data .notification .payload .msg != null ) +
194+ ", content=" + (json .data .notification .payload .content != null ));
195+ }
196+ }
82197
83198 Bundle bundle = new Bundle ();
84199 bundle .putString ("notId" , json .data .notification .notId );
@@ -87,15 +202,33 @@ private void runRequest(OkHttpClient client, Request request, Callback callback)
87202 bundle .putString ("ejson" , gson .toJson (json .data .notification .payload ));
88203 bundle .putBoolean ("notificationLoaded" , true );
89204
205+ Log .i (TAG , "Successfully loaded and parsed notification data" );
90206 callback .call (bundle );
91207
208+ } catch (IOException e ) {
209+ Log .e (TAG , "Network error on attempt " + (RETRY_COUNT + 1 ) + ": " + e .getClass ().getSimpleName () + " - " + e .getMessage ());
210+ handleRetryOrFailure (client , request , callback , sanitizedEndpoint );
211+ } catch (JsonSyntaxException e ) {
212+ Log .e (TAG , "JSON parsing error: " + e .getMessage ());
213+ handleRetryOrFailure (client , request , callback , sanitizedEndpoint );
214+ } catch (InterruptedException e ) {
215+ Log .e (TAG , "Request interrupted: " + e .getMessage ());
216+ Thread .currentThread ().interrupt (); // Restore interrupt status
217+ callback .call (null );
92218 } catch (Exception e ) {
93- if (RETRY_COUNT <= TIMEOUT .length ) {
94- RETRY_COUNT ++;
95- runRequest (client , request , callback );
96- } else {
97- callback .call (null );
98- }
219+ Log .e (TAG , "Unexpected error on attempt " + (RETRY_COUNT + 1 ) + ": " + e .getClass ().getSimpleName () + " - " + e .getMessage ());
220+ handleRetryOrFailure (client , request , callback , sanitizedEndpoint );
221+ }
222+ }
223+
224+ private void handleRetryOrFailure (OkHttpClient client , Request request , Callback callback , String sanitizedEndpoint ) {
225+ if (RETRY_COUNT < TIMEOUT .length - 1 ) {
226+ RETRY_COUNT ++;
227+ Log .d (TAG , "Will retry request (attempt " + (RETRY_COUNT + 1 ) + " of " + TIMEOUT .length + ")" );
228+ runRequest (client , request , callback , sanitizedEndpoint );
229+ } else {
230+ Log .e (TAG , "All retry attempts exhausted (" + TIMEOUT .length + " attempts). Notification load failed." );
231+ callback .call (null );
99232 }
100233 }
101234}
0 commit comments