/*
* Copyright 2014 The Skfiy Open Association.
*
* 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.
*/
package org.skfiy.typhon.spi;
import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.skfiy.typhon.Typhons;
import org.skfiy.typhon.domain.Player;
import org.skfiy.typhon.domain.RoleData;
import org.skfiy.typhon.repository.RoleRepository;
import org.skfiy.typhon.session.Session;
import org.skfiy.typhon.session.SessionConstants;
import org.skfiy.typhon.session.SessionListener;
import org.skfiy.typhon.spi.role.RoleDatable;
import org.skfiy.util.CustomizableThreadCreator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Kevin Zou <kevinz@skfiy.org>
*/
@Singleton
public class ScheduledPlayerSessionListener implements SessionListener {
private static final Logger LOG = LoggerFactory.getLogger(ScheduledPlayerSessionListener.class);
private final ScheduledExecutorService PLAYER_SL_SEC = Executors.newScheduledThreadPool(1,
new ThreadFactory() {
CustomizableThreadCreator threadCreator = new CustomizableThreadCreator("player-sl-");
{
threadCreator.setDaemon(true);
}
@Override
public Thread newThread(Runnable r) {
return threadCreator.createThread(r);
}
});
@Inject
private RoleRepository roleReposy;
@Resource
private Set<RoleDatable> roleDatables;
@Override
public void sessionCreated(Session session) {
cancelFuture(session);
SimpleTimerTask task = new SimpleTimerTask(session);
int period = Typhons.getInteger("typhon.spi.scheduledPlayerSL.millis", 1000 * 60 * 10);
ScheduledFuture<?> future = PLAYER_SL_SEC.scheduleAtFixedRate(task, period, period, TimeUnit.MILLISECONDS);
session.setAttribute(SessionConstants.ATTR_PLAYER_SL_KEY, future);
if (LOG.isDebugEnabled()) {
LOG.debug("sessionId:{}, sessionCreated: [{}]", session.getId(), session);
}
}
@Override
public void sessionDestroyed(Session session) {
cancelFuture(session);
updateData(session);
if (LOG.isDebugEnabled()) {
LOG.debug("sessionId:{}, sessionDestroyed: [{}]", session.getId(), session);
}
}
private void cancelFuture(Session session) {
ScheduledFuture<?> future = (ScheduledFuture<?>) session.getAttribute(SessionConstants.ATTR_PLAYER_SL_KEY);
if (future != null) {
future.cancel(true);
}
}
private void updateData(Session session) {
Player player = (Player) session.getAttribute(SessionConstants.ATTR_PLAYER);
if (player == null) {
LOG.error("player is null. [{}]", session);
return;
}
try {
String cons = player.getRole().getRid() + "__updateData__";
synchronized (cons) {
player.getNormal().setLastLogoutTime(System.currentTimeMillis());
// 更新钻石
roleReposy.update(player.getRole());
LOG.debug("sessionId:{}, username:{}\n{}", session.getId(), player.getRole().getName(), player.getRole());
RoleData roleData = new RoleData();
for (RoleDatable roleDatable : roleDatables) {
roleDatable.serialize(player, roleData);
}
// FIXME 这里只更新了RoleData数据
// 后期还需要更新Role的数据信息
roleData.setRid(player.getRole().getRid());
roleReposy.update(roleData);
LOG.debug("sessionId:{}, username:{}\n{}", session.getId(), player.getRole().getName(), roleData);
}
} catch (Exception e) {
LOG.error("sessionId:{}, saveDataError: {}", session.getId(), player.getRole().getName(), e);
}
}
private class SimpleTimerTask implements Runnable {
final Session session;
SimpleTimerTask(Session session) {
this.session = session;
}
@Override
public void run() {
updateData(session);
}
}
}