view src/nabble/view/web/user/OnlineStatus.java @ 19:18cf4872fd7f

remove anonymous posting
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 29 May 2020 22:58:25 -0600
parents 7ecd1a4ef557
children
line wrap: on
line source

package nabble.view.web.user;

import fschmidt.util.servlet.ServletUtils;
import nabble.model.Executors;
import nabble.model.ModelHome;
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, User user, Site site) {
		if( user==null )
			return;
		String sourceId = user.getSearchId();
		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(User 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
	}

}