1+ package com .foxdebug .acode .rk .auth ;
2+
3+ import android .util .Log ;
4+ import org .apache .cordova .CallbackContext ;
5+ import org .json .JSONArray ;
6+ import org .json .JSONException ;
7+ import org .json .JSONObject ;
8+ import java .net .HttpURLConnection ;
9+ import java .net .URL ;
10+ import java .util .Scanner ;
11+
12+ public class PluginRetriever {
13+ private static final String TAG = "AcodePluginRetriever" ;
14+ private static final int LIMIT = 20 ;
15+ private static final String API_BASE = "https://acode.app/api" ;
16+
17+ public static void retrieveFilteredPlugins (String token ,JSONObject filterState , CallbackContext callbackContext ) throws Exception {
18+ JSONObject result = new JSONObject ();
19+
20+ if (filterState == null ) {
21+ result .put ("items" , new JSONArray ());
22+ result .put ("hasMore" , false );
23+ callbackContext .success (result );
24+ return ;
25+ }
26+
27+ String type = filterState .optString ("type" , "" );
28+
29+ if ("orderBy" .equals (type )) {
30+ int page = filterState .optInt ("nextPage" , 1 );
31+ String value = filterState .optString ("value" , "" );
32+ String url ;
33+
34+ if ("top_rated" .equals (value )) {
35+ url = API_BASE + "/plugins?explore=random&page=" + page + "&limit=" + LIMIT ;
36+ } else {
37+ url = API_BASE + "/plugin?orderBy=" + value + "&page=" + page + "&limit=" + LIMIT ;
38+ }
39+
40+ JSONArray items = fetchJsonArray (token ,url );
41+ if (items == null ) items = new JSONArray ();
42+
43+ filterState .put ("nextPage" , page + 1 );
44+ result .put ("items" , items );
45+ result .put ("hasMore" , items .length () == LIMIT );
46+ callbackContext .success (result );
47+ return ;
48+ }
49+
50+ JSONArray buffer = filterState .optJSONArray ("buffer" );
51+ if (buffer == null ) {
52+ buffer = new JSONArray ();
53+ filterState .put ("buffer" , buffer );
54+ }
55+
56+ boolean hasMoreSource = !filterState .has ("hasMoreSource" ) || filterState .getBoolean ("hasMoreSource" );
57+ int nextPage = filterState .optInt ("nextPage" , 1 );
58+ if (!filterState .has ("nextPage" )) {
59+ filterState .put ("nextPage" , 1 );
60+ }
61+
62+ JSONArray items = new JSONArray ();
63+
64+ while (items .length () < LIMIT ) {
65+ if (buffer .length () > 0 ) {
66+ items .put (buffer .get (0 ));
67+ JSONArray newBuffer = new JSONArray ();
68+ for (int i = 1 ; i < buffer .length (); i ++) newBuffer .put (buffer .get (i ));
69+ buffer = newBuffer ;
70+ filterState .put ("buffer" , buffer );
71+ continue ;
72+ }
73+
74+ if (!hasMoreSource ) break ;
75+
76+ String url = API_BASE + "/plugins?page=" + nextPage + "&limit=" + LIMIT ;
77+ JSONArray data = fetchJsonArray (token ,url );
78+ nextPage ++;
79+ filterState .put ("nextPage" , nextPage );
80+
81+ if (data == null || data .length () == 0 ) {
82+ hasMoreSource = false ;
83+ filterState .put ("hasMoreSource" , false );
84+ break ;
85+ }
86+
87+ if (data .length () < LIMIT ) {
88+ hasMoreSource = false ;
89+ filterState .put ("hasMoreSource" , false );
90+ }
91+
92+ for (int i = 0 ; i < data .length (); i ++) {
93+ JSONObject plugin = data .getJSONObject (i );
94+ if (matchesFilter (plugin , filterState )) {
95+ buffer .put (plugin );
96+ }
97+ }
98+ filterState .put ("buffer" , buffer );
99+ }
100+
101+ while (items .length () < LIMIT && buffer .length () > 0 ) {
102+ items .put (buffer .get (0 ));
103+ JSONArray newBuffer = new JSONArray ();
104+ for (int i = 1 ; i < buffer .length (); i ++) newBuffer .put (buffer .get (i ));
105+ buffer = newBuffer ;
106+ filterState .put ("buffer" , buffer );
107+ }
108+
109+ boolean hasMore = (hasMoreSource && filterState .has ("nextPage" )) || buffer .length () > 0 ;
110+
111+ result .put ("items" , items );
112+ result .put ("hasMore" , hasMore );
113+ callbackContext .success (result );
114+ }
115+
116+ // Change fetchJsonArray signature to accept token
117+ private static JSONArray fetchJsonArray (String urlString , String token ) {
118+ HttpURLConnection conn = null ;
119+ try {
120+ Log .d (TAG , "Fetching: " + urlString );
121+ URL url = new URL (urlString );
122+ conn = (HttpURLConnection ) url .openConnection ();
123+ conn .setRequestMethod ("GET" );
124+ conn .setConnectTimeout (5000 );
125+ conn .setReadTimeout (5000 );
126+
127+ // Add auth header if token is present
128+ if (token != null && !token .isEmpty ()) {
129+ conn .setRequestProperty ("x-auth-token" , token );
130+ }
131+
132+ int code = conn .getResponseCode ();
133+ if (code != 200 ) {
134+ Log .w (TAG , "Non-200 response (" + code + ") for: " + urlString );
135+ return null ;
136+ }
137+
138+ Scanner s = new Scanner (conn .getInputStream (), "UTF-8" ).useDelimiter ("\\ A" );
139+ String body = s .hasNext () ? s .next () : "[]" ;
140+ return new JSONArray (body );
141+ } catch (Exception e ) {
142+ Log .e (TAG , "fetchJsonArray error: " + e .getMessage (), e );
143+ return null ;
144+ } finally {
145+ if (conn != null ) conn .disconnect ();
146+ }
147+ }
148+
149+ private static boolean matchesFilter (JSONObject plugin , JSONObject filterState ) {
150+ try {
151+ String type = filterState .optString ("type" , "" );
152+ String value = filterState .optString ("value" , "" ).toLowerCase ();
153+
154+ if (value .isEmpty ()) return true ;
155+
156+ switch (type ) {
157+ case "search" :
158+ String name = plugin .optString ("name" , "" ).toLowerCase ();
159+ String desc = plugin .optString ("description" , "" ).toLowerCase ();
160+ return name .contains (value ) || desc .contains (value );
161+ case "author" :
162+ String author = plugin .optString ("author" , "" ).toLowerCase ();
163+ return author .contains (value );
164+ default :
165+ return true ;
166+ }
167+ } catch (Exception e ) {
168+ Log .e (TAG , "matchesFilter error: " + e .getMessage (), e );
169+ return false ;
170+ }
171+ }
172+ }
0 commit comments