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.CMLib.Library;
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-2019 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(final 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> sessions()
{
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 numSessions()
{
return all.size();
}
@Override
public Iterable<Session> allIterableAllHosts()
{
final MultiIterable<Session> allIterable=new MultiIterable<Session>();
final WorldMap map=CMLib.map();
//allIterable.add(CMLib.sessions().allIterable(), CMLib.sessions().numSessions());
for(final Enumeration<CMLibrary> pl=CMLib.libraries(CMLib.Library.SESSIONS); pl.hasMoreElements(); )
{
final SessionsList list=(SessionsList)pl.nextElement();
if(map == CMLib.library(CMLib.getLibraryThreadID(Library.SESSIONS, list), Library.MAP))
allIterable.add(list.allIterable(),list.numSessions());
}
return allIterable;
}
@Override
public int numLocalOnline()
{
return getCount(localOnline());
}
protected int getCount(final Iterator<Session> i)
{
int xt=0;
for(;i.hasNext();)
{
i.next();
xt++;
}
return xt;
}
protected Session getAllSessionAt(final Iterator<Session> i, final 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(final Session s)
{
if(!all.contains(s))
all.add(s);
}
@Override
public synchronized void remove(final Session s)
{
all.remove(s);
}
@Override
public synchronized boolean isSession(final Session s)
{
return all.contains(s);
}
@Override
public void stopSessionAtAllCosts(final 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.HANDSHAKE_MCCP)
||(S.getStatus()==Session.SessionStatus.HANDSHAKE_OPEN)
||(S.getStatus()==Session.SessionStatus.CHARCREATE))
Log.sysOut(serviceClient.getName(),"Kicking out: "+((S.mob()==null)?"Unknown":S.mob().Name())+", idle: "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)+", status: "+S.getStatus());
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()):"";
final String statusMsg;
if(((S.getStatus())!=Session.SessionStatus.LOGIN)
||((S.getPreviousCMD()!=null)&&(S.getPreviousCMD().size()>0)))
statusMsg = "STATUS is :"+S.getStatus()+", LASTCMD was :"+((S.getPreviousCMD()!=null)?S.getPreviousCMD().toString():"");
else
statusMsg = "STATUS is :"+S.getStatus()+", no last command available.";
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()+"\r\n"+statusMsg);
stopSessionAtAllCosts(S);
}
else
Log.warnOut(serviceClient.getName(),"Suspect Session: "+((S.mob()==null)?"Unknown":S.mob().Name())+" ("+roomID+"), out for "+CMLib.time().date2EllapsedTime(time, TimeUnit.MILLISECONDS, true)+"\r\n"+statusMsg);
}
}
}
else
if(time>(300000))
{
final String roomID=S.mob()!=null?CMLib.map().getExtendedRoomID(S.mob().location()):"";
if((S.getStatus()==Session.SessionStatus.LOGIN)
||(S.getStatus()==Session.SessionStatus.HANDSHAKE_MCCP)
||(S.getStatus()==Session.SessionStatus.HANDSHAKE_OPEN))
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.HANDSHAKE_MCCP)
{
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(final Tickable ticking, final 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(final String srchStr, final boolean exactOnly)
{
final Session S=findPlayerSessionOnline(srchStr, exactOnly);
if(S==null)
return null;
return S.mob();
}
@Override
public Session findPlayerSessionOnline(final String srchStr, final 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, final 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());
}
}
}
}