package com.planet_ink.coffee_mud.Libraries; import java.util.*; import java.util.concurrent.TimeUnit; import com.planet_ink.coffee_mud.Areas.interfaces.Area; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.CatalogLibrary.CataData; import com.planet_ink.coffee_mud.MOBS.interfaces.MOB; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.CMSecurity.DbgFlag; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.core.interfaces.*; /* Copyright 2001-2016 Bo Zimmerman Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ public class Sessions extends StdLibrary implements SessionsList { @Override public String ID(){return "Sessions";} private volatile long nextSweepTime = System.currentTimeMillis(); public final SLinkedList<Session> all=new SLinkedList<Session>(); private final static Filterer<Session> localOnlineFilter=new Filterer<Session>() { @Override public boolean passesFilter(Session obj) { if((obj!=null) && (!obj.isStopped()) && (((obj.getStatus())==Session.SessionStatus.MAINLOOP))) { final MOB M=obj.mob(); return ((M!=null)&&M.amActive()&&(CMLib.flags().isInTheGame(M,true))); } return false; } }; @Override public Iterator<Session> all(){return all.iterator();} @Override public Iterable<Session> allIterable(){return all;} @Override public Iterator<Session> localOnline() { return new FilteredIterator<Session>(all.iterator(),localOnlineFilter); } @Override public Iterable<Session> localOnlineIterable() { return new FilteredIterable<Session>(all,localOnlineFilter); } @Override public int getCountAll() { return getCount(all()); } @Override public int getCountLocalOnline() { return getCount(localOnline()); } protected int getCount(Iterator<Session> i) { int xt=0; for(;i.hasNext();) { i.next(); xt++; } return xt; } @Override public Session getAllSessionAt(int index) { return getAllSessionAt(all(),index); } protected Session getAllSessionAt(Iterator<Session> i, int index) { int xt=0; Session S; for(;i.hasNext();) { S=i.next(); if(xt==index) return S; xt++; } return null; } @Override public synchronized void add(Session s) { if(!all.contains(s)) all.add(s); } @Override public synchronized void remove(Session s) { all.remove(s); } @Override public void stopSessionAtAllCosts(Session S) { if(S==null) return; S.stopSession(true,true,false); CMLib.s_sleep(100); if(all.contains(S)) { CMLib.s_sleep(100); S.run(); CMLib.s_sleep(100); S.stopSession(true,true,false); CMLib.s_sleep(100); if(all.contains(S)) { S.stopSession(true,true,true); remove(S); } } } protected void sessionCheck() { setThreadStatus(serviceClient,"checking player sessions."); for(final Session S : all) { final long time=System.currentTimeMillis()-S.getInputLoopTime(); if(time>0) { if((S.mob()!=null)||((S.getStatus())==Session.SessionStatus.ACCOUNT_MENU)||((S.getStatus())==Session.SessionStatus.CHARCREATE)) { long check=60000; if((S.getPreviousCMD()!=null) &&(S.getPreviousCMD().size()>0) &&(S.getPreviousCMD().get(0).equalsIgnoreCase("IMPORT") ||S.getPreviousCMD().get(0).equalsIgnoreCase("EXPORT") ||S.getPreviousCMD().get(0).equalsIgnoreCase("CHARGEN") ||S.getPreviousCMD().get(0).equalsIgnoreCase("MERGE"))) check=check*600; else if((S.mob()!=null)&&(CMSecurity.isAllowed(S.mob(),S.mob().location(),CMSecurity.SecFlag.CMDROOMS))) check=check*15; else if((S.getStatus())==Session.SessionStatus.LOGIN) check=check*5; if(time>(check*10)) { final String roomID=S.mob()!=null?CMLib.map().getExtendedRoomID(S.mob().location()):""; if((S.getPreviousCMD()==null)||(S.getPreviousCMD().size()==0) ||((S.getStatus())==Session.SessionStatus.LOGIN) ||((S.getStatus())==Session.SessionStatus.ACCOUNT_MENU) ||((S.getStatus())==Session.SessionStatus.CHARCREATE)) Log.sysOut(serviceClient.getName(),"Kicking out: "+((S.mob()==null)?"Unknown":S.mob().Name())+" who has spent "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)+" out-game."); else { Log.errOut(serviceClient.getName(),"KILLING DEAD Session: "+((S.mob()==null)?"Unknown":S.mob().Name())+" ("+roomID+"), out for "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)); Log.errOut(serviceClient.getName(),"STATUS was :"+S.getStatus()+", LASTCMD was :"+((S.getPreviousCMD()!=null)?S.getPreviousCMD().toString():"")); if(S instanceof Thread) CMLib.threads().debugDumpStack("Sessions",(Thread)S); } setThreadStatus(serviceClient,"killing session "); stopSessionAtAllCosts(S); setThreadStatus(serviceClient,"checking player sessions."); } else if(time>check) { if((S.mob()==null)||(S.mob().Name()==null)||(S.mob().Name().length()==0)) stopSessionAtAllCosts(S); else if((S.getPreviousCMD()!=null)&&(S.getPreviousCMD().size()>0)) { final String roomID=S.mob()!=null?CMLib.map().getExtendedRoomID(S.mob().location()):""; if((S.isLockedUpWriting()) &&(CMLib.flags().isInTheGame(S.mob(),true))) { Log.errOut(serviceClient.getName(),"LOGGED OFF Session: "+((S.mob()==null)?"Unknown":S.mob().Name())+" ("+roomID+"), out for "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)+": "+S.isLockedUpWriting()); stopSessionAtAllCosts(S); } else Log.errOut(serviceClient.getName(),"Suspect Session: "+((S.mob()==null)?"Unknown":S.mob().Name())+" ("+roomID+"), out for "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)); if(((S.getStatus())!=Session.SessionStatus.LOGIN) ||((S.getPreviousCMD()!=null)&&(S.getPreviousCMD().size()>0))) Log.errOut(serviceClient.getName(),"STATUS is :"+S.getStatus()+", LASTCMD was :"+((S.getPreviousCMD()!=null)?S.getPreviousCMD().toString():"")); else Log.errOut(serviceClient.getName(),"STATUS is :"+S.getStatus()+", no last command available."); } } } else if(time>(300000)) { final String roomID=S.mob()!=null?CMLib.map().getExtendedRoomID(S.mob().location()):""; if((S.getStatus())==Session.SessionStatus.LOGIN) Log.sysOut(serviceClient.getName(),"Kicking out login session after "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)+"."); else { Log.errOut(serviceClient.getName(),"KILLING DEAD Session: "+((S.mob()==null)?"Unknown":S.mob().Name())+" ("+roomID+"), out for "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)); if(S instanceof Thread) CMLib.threads().debugDumpStack("Sessions",(Thread)S); } if(((S.getStatus())!=Session.SessionStatus.LOGIN) ||((S.getPreviousCMD()!=null)&&(S.getPreviousCMD().size()>0))) Log.errOut(serviceClient.getName(),"STATUS was :"+S.getStatus()+", LASTCMD was :"+((S.getPreviousCMD()!=null)?S.getPreviousCMD().toString():"")); setThreadStatus(serviceClient,"killing session "); stopSessionAtAllCosts(S); setThreadStatus(serviceClient,"checking player sessions"); } } } } @Override public boolean activate() { nextSweepTime = System.currentTimeMillis()+MudHost.TIME_UTILTHREAD_SLEEP; if(serviceClient==null) { name="THSessions"+Thread.currentThread().getThreadGroup().getName().charAt(0); serviceClient=CMLib.threads().startTickDown(this, Tickable.TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK, 100, 1); } return true; } @Override public boolean tick(Tickable ticking, int tickID) { tickStatus=Tickable.STATUS_ALIVE; try { final double numThreads=all.size(); if(numThreads>0.0) { for(final Session S : all) { if(!S.isRunning()) { CMLib.threads().executeRunnable(S.getGroupName(), S); } } } if(System.currentTimeMillis() >= nextSweepTime) { nextSweepTime = System.currentTimeMillis()+MudHost.TIME_UTILTHREAD_SLEEP; if((!CMSecurity.isDisabled(CMSecurity.DisFlag.UTILITHREAD)) &&(!CMSecurity.isDisabled(CMSecurity.DisFlag.SESSIONTHREAD))) { isDebugging=CMSecurity.isDebugging(DbgFlag.UTILITHREAD); sessionCheck(); } } } finally { tickStatus=Tickable.STATUS_NOT; setThreadStatus(serviceClient,"sleeping"); } return true; } @Override public boolean shutdown() { if(CMLib.threads().isTicking(this, TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK)) { CMLib.threads().deleteTick(this, TICKID_SUPPORT|Tickable.TICKID_SOLITARYMASK); serviceClient=null; } return true; } @Override public MOB findPlayerOnline(String srchStr, boolean exactOnly) { final Session S=findPlayerSessionOnline(srchStr, exactOnly); if(S==null) return null; return S.mob(); } @Override public Session findPlayerSessionOnline(String srchStr, boolean exactOnly) { // then look for players for(final Session S : localOnlineIterable()) if(S.mob().Name().equalsIgnoreCase(srchStr)) return S; for(final Session S : localOnlineIterable()) if(S.mob().name().equalsIgnoreCase(srchStr)) return S; // keep looking for players if(!exactOnly) { for(final Session S : localOnlineIterable()) if(CMLib.english().containsString(S.mob().Name(),srchStr)) return S; for(final Session S : localOnlineIterable()) if(CMLib.english().containsString(S.mob().name(),srchStr)) return S; } return null; } @Override public void moveSessionToCorrectThreadGroup(final Session session, int theme) { final int themeDex=CMath.firstBitSetIndex(theme); if((themeDex>=0)&&(themeDex<Area.THEME_BIT_NAMES.length)) { final ThreadGroup privateGroup=CMProps.getPrivateOwner(Area.THEME_BIT_NAMES[themeDex]+"PLAYERS"); if((privateGroup!=null) &&(privateGroup.getName().length()>0) &&(!privateGroup.getName().equals(session.getGroupName()))) { if(session.getGroupName().length()>0) { if(CMLib.library(session.getGroupName().charAt(0), CMLib.Library.SESSIONS) != CMLib.library(privateGroup.getName().charAt(0), CMLib.Library.SESSIONS)) { ((Sessions)CMLib.library(session.getGroupName().charAt(0), CMLib.Library.SESSIONS)).remove(session); ((Sessions)CMLib.library(privateGroup.getName().charAt(0), CMLib.Library.SESSIONS)).add(session); } } session.setGroupName(privateGroup.getName()); } } } }