package cc.blynk.server.core.stats.model; import cc.blynk.server.core.BlockingIOProcessor; import cc.blynk.server.core.dao.SessionDao; import cc.blynk.server.core.dao.UserDao; import cc.blynk.server.core.dao.UserKey; import cc.blynk.server.core.model.DashBoard; import cc.blynk.server.core.model.auth.Session; import cc.blynk.server.core.model.auth.User; import cc.blynk.server.core.protocol.enums.Command; import cc.blynk.server.core.stats.GlobalStats; import cc.blynk.utils.JsonParser; import java.util.Map; import java.util.concurrent.atomic.LongAdder; /** * The Blynk Project. * Created by Dmitriy Dumanskiy. * Created on 19.07.15. */ public class Stat { private final static long ONE_DAY = 24 * 60 * 60 * 1000; private final static long ONE_WEEK = 7 * ONE_DAY; private final static long ONE_MONTH = 30 * ONE_DAY; public final CommandStat commands = new CommandStat(); public final HttpStat http = new HttpStat(); public final BlockingIOStat ioStat; public final int oneMinRate; public final int registrations; public final int active; public final int activeWeek; public final int activeMonth; public final int connected; public final int onlineApps; public final int totalOnlineApps; public final int onlineHards; public final int totalOnlineHards; public final transient long ts; public Stat(SessionDao sessionDao, UserDao userDao, BlockingIOProcessor blockingIOProcessor, GlobalStats globalStats, boolean reset) { //yeap, some stats updates may be lost (because of sumThenReset()), //but we don't care, cause this is just for general monitoring for (Short command : Command.valuesName.keySet()) { LongAdder longAdder = globalStats.specificCounters[command]; int val = (int) (reset ? longAdder.sumThenReset() : longAdder.sum()); this.http.assign(command, val); this.commands.assign(command, val); } this.commands.appTotal = (int) globalStats.getTotalAppCounter(reset); this.commands.mqttTotal = (int) globalStats.getTotalMqttCounter(reset); this.oneMinRate = (int) globalStats.totalMessages.getOneMinuteRate(); int connectedSessions = 0; int hardActive = 0; int totalOnlineHards = 0; int appActive = 0; int totalOnlineApps = 0; int active = 0; int activeWeek = 0; int activeMonth = 0; this.ts = System.currentTimeMillis(); for (Map.Entry<UserKey, Session> entry: sessionDao.userSession.entrySet()) { Session session = entry.getValue(); if (session.isHardwareConnected() && session.isAppConnected()) { connectedSessions++; } if (session.isHardwareConnected()) { hardActive++; totalOnlineHards += session.hardwareChannels.size(); } if (session.isAppConnected()) { appActive++; totalOnlineApps += session.appChannels.size(); } UserKey userKey = entry.getKey(); User user = userDao.users.get(userKey); if (user != null) { if (this.ts - user.lastModifiedTs < ONE_DAY || dashUpdated(user, this.ts, ONE_DAY)) { active++; activeWeek++; activeMonth++; continue; } if (this.ts - user.lastModifiedTs < ONE_WEEK || dashUpdated(user, this.ts, ONE_WEEK)) { activeWeek++; activeMonth++; continue; } if (this.ts - user.lastModifiedTs < ONE_MONTH || dashUpdated(user, this.ts, ONE_MONTH)) { activeMonth++; } } } this.connected = connectedSessions; this.onlineApps = appActive; this.totalOnlineApps = totalOnlineApps; this.onlineHards = hardActive; this.totalOnlineHards = totalOnlineHards; this.active = active; this.activeWeek = activeWeek; this.activeMonth = activeMonth; this.registrations = userDao.users.size(); this.ioStat = new BlockingIOStat(blockingIOProcessor); } private boolean dashUpdated(User user, long now, long period) { for (DashBoard dash : user.profile.dashBoards) { if (now - dash.updatedAt < period) { return true; } } return false; } @Override public String toString() { return JsonParser.toJson(this); } }