-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #262 from guusdk/improved-stats
Fix download stats, restore community activity
- Loading branch information
Showing
21 changed files
with
339 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package org.jivesoftware.site; | ||
|
||
import org.jivesoftware.webservices.RestClient; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.servlet.ServletConfig; | ||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServlet; | ||
import java.util.HashMap; | ||
import java.util.Hashtable; | ||
import java.util.Map; | ||
|
||
public class DiscourseAPI extends HttpServlet | ||
{ | ||
private static final Logger Log = LoggerFactory.getLogger(DiscourseAPI.class); | ||
|
||
private static long CACHE_PERIOD = 30 * 60 * 1000; // 30 minutes | ||
|
||
private static long lastUpdate = 0; | ||
|
||
private static Map<Integer, Long> counts = new Hashtable<>(); | ||
|
||
private static String baseUrl; | ||
private static String apiKey; | ||
private static RestClient restClient; | ||
|
||
public void init(ServletConfig servletConfig) throws ServletException | ||
{ | ||
super.init(servletConfig); | ||
|
||
baseUrl = servletConfig.getServletContext().getInitParameter("discourse_baseurl"); | ||
if ( baseUrl == null || baseUrl.isEmpty() ) | ||
{ | ||
baseUrl = "https://discourse.igniterealtime.org/"; | ||
} | ||
|
||
apiKey = servletConfig.getServletContext().getInitParameter("discourse-api-key"); | ||
|
||
restClient = new RestClient(); | ||
} | ||
|
||
public static Long getActiveMembersLast7Days() | ||
{ | ||
collectTotals(); | ||
if (counts.containsKey(3)) { | ||
return counts.get(3); | ||
} | ||
return null; | ||
} | ||
|
||
public static Long getNewPostsLast7Days() | ||
{ | ||
collectTotals(); | ||
if (counts.containsKey(4)) { | ||
return counts.get(4); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Executes a query that's defined in Discourse's Data Explorer. The query is assumed to have a singular, numeric | ||
* return value. | ||
* | ||
* @param queryId Discourse Data Explorer Query identifier | ||
* @param lastNumberOfDays The value for the 'duration_days' parameter | ||
* @return the query result, or null if an exception occurred. | ||
*/ | ||
private static Long doSimpleQuery(final int queryId, final int lastNumberOfDays) { | ||
final Map<String, String> headers = new HashMap<>(); | ||
headers.put("Api-Key", apiKey); | ||
headers.put("Api-Username", "system"); | ||
final Map<String, String> parameters = new HashMap<>(); | ||
parameters.put("params", "{\"duration_days\":\""+lastNumberOfDays+"\"}"); | ||
parameters.put("explain", "false"); | ||
parameters.put("download", "true"); | ||
|
||
try { | ||
return restClient.post(baseUrl + "/admin/plugins/explorer/queries/"+queryId+"/run", headers, parameters).getJSONArray("rows").getJSONArray(0).getLong(0); | ||
} catch (Throwable t) { | ||
Log.warn("Unable to interact with Discourse's API.", t); | ||
return null; | ||
} | ||
} | ||
|
||
/** | ||
* Collects all of the totals from the API. Has a rudimentary caching mechanism | ||
* so that the queries are only run every CACHE_PERIOD milliseconds. | ||
*/ | ||
private synchronized static void collectTotals() { | ||
// See if we need to update the totals | ||
if ((lastUpdate + CACHE_PERIOD) > System.currentTimeMillis()) { | ||
return; | ||
} | ||
lastUpdate = System.currentTimeMillis(); | ||
|
||
// Collect the new totals on a background thread since they could take a while | ||
Thread collectorThread = new Thread(new DiscourseAPI.DownloadStatsRunnable(counts)); | ||
collectorThread.start(); | ||
if (counts.isEmpty()) { | ||
// Need to wait for the collectorThread to finish since the counts are not initialized yet | ||
try { | ||
collectorThread.join(); | ||
} | ||
catch (Exception e) { Log.debug( "An exception occurred that can probably be ignored.", e); } | ||
} | ||
} | ||
|
||
private static class DownloadStatsRunnable implements Runnable { | ||
private Map<Integer, Long> counts; | ||
|
||
public DownloadStatsRunnable(Map<Integer, Long> counts) { | ||
this.counts = counts; | ||
} | ||
|
||
public void run() { | ||
final Map<Integer, Long> results = new HashMap<>(); | ||
results.put(3, doSimpleQuery(3, 7)); | ||
results.put(4, doSimpleQuery(4, 7)); | ||
|
||
// Replace all values in the object used by the website in one go. | ||
counts.clear(); | ||
counts.putAll(results); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.