Mercurial Hosting > nabble
diff src/nabble/view/web/user/OnlineStatus.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 18cf4872fd7f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/view/web/user/OnlineStatus.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,173 @@ +package nabble.view.web.user; + +import fschmidt.util.servlet.ServletUtils; +import nabble.model.Executors; +import nabble.model.ModelHome; +import nabble.model.Person; +import nabble.model.Site; +import nabble.model.User; +import nabble.view.lib.Jtp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class OnlineStatus { + + private static final Logger logger = LoggerFactory.getLogger(OnlineStatus.class); + + private static final long TIMEOUT = 3 * 60 * 1000L; // 3 minutes + private static final String INVISIBLE = "invisible:"; + + /** Maps a site ID to a map (Person-Source-ID > last time) */ + private static final Map<Long, Map<String, Long>> sitesMap = new HashMap<Long, Map<String, Long>>(); + + public static void setOnline(HttpServletRequest request, Person visitor, Site site) { + setOnline(request,visitor.getSearchId(),site); + } + + private static void setOnline(HttpServletRequest request, String sourceId, Site site) { + synchronized(sitesMap) { + Map<String, Long> map = sitesMap.get(site.getId()); + if (map == null) { + map = new HashMap<String, Long>(); + sitesMap.put(site.getId(), map); + logger.debug("New map for site ID = " + site.getId()); + } + boolean isVisible = ServletUtils.getCookieValue(request, "visible") == null || !Jtp.isInteger(sourceId); + map.put(isVisible? sourceId : INVISIBLE+sourceId, System.currentTimeMillis()); + } + } + + public static boolean isOnline(Person visitor, Site site) { + return isOnline(visitor.getSearchId(),site); + } + + public static boolean isOnline(String sourceId, Site site) { + synchronized(sitesMap) { + Map<String, Long> map = sitesMap.get(site.getId()); + return map != null && map.get(sourceId) != null; + } + } + + private static void runGC() { + final long start = System.currentTimeMillis(); + synchronized(sitesMap) { + for( Iterator<Map<String, Long>> iter = sitesMap.values().iterator(); iter.hasNext(); ) { + Map<String, Long> map = iter.next(); + for( Iterator<Long> subIter = map.values().iterator(); subIter.hasNext(); ) { + long time = subIter.next(); + if (start - time > TIMEOUT) { + subIter.remove(); + logger.debug("Removed user"); + } + } + if( map.isEmpty() ) { + iter.remove(); + logger.debug("Removed map"); + } + } + } + logger.info("OnlineStatus GC took " + (System.currentTimeMillis()-start) + " ms"); + } + + public static String getOnlineStats() { + int count = 0; + int sites; + float ratio = 0f; + synchronized(sitesMap) { + Collection<Map<String, Long>> entries = sitesMap.values(); + for (Map<String, Long> entry : entries) { + count += entry.keySet().size(); + } + sites = sitesMap.size(); + if (sites > 0) + ratio = count / (float) sitesMap.size(); + } + return "Users = " + count + " | Sites = " + sites + " | Ratio = " + String.format("%.2f", ratio); + } + + public static Map<String, Integer> getOnlineSites() { + Map<String, Integer> sites = new HashMap<String, Integer>(); + + synchronized(sitesMap) { + for (Map.Entry<Long, Map<String, Long>> entry : sitesMap.entrySet()) { + String url = ModelHome.getSite(entry.getKey()).getBaseUrl(); + sites.put(url, entry.getValue().size()); + } + } + return sites; + } + + public static List<User> getOnlineUsers(Site site, boolean includeInvisibleUsers) { + String[] visitorIDs = getVisitorIds(site); + List<User> users = new ArrayList<User>(); + for (String id : visitorIDs) { + long userId = 0; + if (Jtp.isInteger(id)) { + userId = Long.valueOf(id); + } else if (includeInvisibleUsers && isInvisible(id)) { + userId = Long.valueOf(id.substring(INVISIBLE.length())); + } + if (userId > 0) { + User u = site.getUser(userId); + if (u != null) + users.add(u); + } + } + return users; + } + + public static int getOnlineAnonymousUsersCount(Site site) { + String[] visitorIDs = getVisitorIds(site); + int c = 0; + for (String id : visitorIDs) + if (!Jtp.isInteger(id) && !isInvisible(id)) { + c++; + } + return c; + } + + public static int getOnlineInvisibleUsersCount(Site site) { + String[] visitorIDs = getVisitorIds(site); + int c = 0; + for (String id : visitorIDs) { + if (isInvisible(id)) + c++; + } + return c; + } + + private static String[] getVisitorIds(Site site) { + synchronized(sitesMap) { + Map<String, Long> map = sitesMap.get(site.getId()); + if (map == null) + return new String[0]; + Set<String> set = map.keySet(); + String[] visitorIds = new String[set.size()]; + set.toArray(visitorIds); + return visitorIds; + } + } + + private static boolean isInvisible(String id) { + return id.startsWith(INVISIBLE); + } + + static { + Executors.scheduleWithFixedDelay(new Runnable(){ + public void run(){ + runGC(); + } + }, 2*60, 2*60, TimeUnit.SECONDS); // Every 2 minutes + } + +}