Server/Management-Server/src/main/java/ms/net/IoSession.java
2021-07-22 11:08:19 -05:00

351 lines
No EOL
6.6 KiB
Java

package ms.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import ms.ServerConstants;
import ms.net.producer.HSEventProducer;
import ms.world.GameServer;
/**
* Represents a connected I/O session.
* @author Emperor
*
*/
public class IoSession {
/**
* The handshake event producer.
*/
private static final EventProducer HANDSHAKE_PRODUCER = new HSEventProducer();
/**
* The selection key.
*/
private final SelectionKey key;
/**
* The executor service.
*/
private final ExecutorService service;
/**
* The event producer.
*/
private EventProducer producer = HANDSHAKE_PRODUCER;
/**
* The currently queued writing data.
*/
private List<ByteBuffer> writingQueue = new ArrayList<>(20);
/**
* The currently queued reading data.
*/
private ByteBuffer readingQueue;
/**
* The writing lock.
*/
private final Lock writingLock = new ReentrantLock();
/**
* The name hash.
*/
private int nameHash;
/**
* The server key.
*/
private long serverKey;
/**
* The JS-5 encryption value.
*/
private int js5Encryption;
/**
* If the session is active.
*/
private boolean active = true;
/**
* The last ping time stamp.
*/
private long lastPing;
/**
* The address.
*/
private final String address;
/**
* The game server object for this session.
*/
private GameServer gameServer;
/**
* Constructs a new {@code IoSession}.
* @param key The selection key.
* @param service The executor service.
*/
public IoSession(SelectionKey key, ExecutorService service) {
this.key = key;
this.service = service;
String address = getRemoteAddress().replaceAll("/", "").split(":")[0];
if (address.equals("127.0.0.1")) {
address = ServerConstants.HOST_ADDRESS;
}
this.address = address;
}
/**
* Fires a write event created using the current event producer.
* @param context The event context.
*/
public void write(Object context) {
write(context, false);
}
/**
* Fires a write event created using the current event producer.
* @param context The event context.
* @param instant If the event should be instantly executed on this thread.
*/
public void write(Object context, boolean instant) {
if (context == null) {
throw new IllegalStateException("Invalid writing context!");
}
if (instant) {
producer.produceWriter(this, context).run();
return;
}
service.execute(producer.produceWriter(this, context));
}
/**
* Sends the packet data (without write event encoding).
* @param buffer The buffer.
*/
public void queue(ByteBuffer buffer) {
try {
writingLock.tryLock(1000L, TimeUnit.MILLISECONDS);
} catch (Exception e){
e.printStackTrace();
writingLock.unlock();
return;
}
writingQueue.add(buffer);
writingLock.unlock();
write();
}
/**
* Handles the writing of all buffers in the queue.
*/
public void write() {
if (!key.isValid()) {
disconnect();
return;
}
writingLock.lock();
SocketChannel channel = (SocketChannel) key.channel();
try {
while (!writingQueue.isEmpty()) {
ByteBuffer buffer = writingQueue.get(0);
channel.write(buffer);
if (buffer.hasRemaining()) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
writingQueue.remove(0);
}
} catch (IOException e) {
disconnect();
}
writingLock.unlock();
}
/**
* Disconnects the session.
*/
public void disconnect() {
try {
if (!active) {
return;
}
active = false;
key.cancel();
SocketChannel channel = (SocketChannel) key.channel();
channel.socket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Gets the IP-address (without the port).
* @return The address.
*/
public String getAddress() {
return address;
}
/**
* Gets the remote address of this session.
* @return The remote address, as a String.
*/
public String getRemoteAddress() {
try {
return ((SocketChannel) key.channel()).getRemoteAddress().toString();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Gets the current event producer.
* @return The producer.
*/
public EventProducer getProducer() {
return producer;
}
/**
* Sets the event producer.
* @param producer The producer to set.
*/
public void setProducer(EventProducer producer) {
this.producer = producer;
}
/**
* Gets the queued reading data.
* @return The readingQueue.
*/
public ByteBuffer getReadingQueue() {
synchronized (this) {
return readingQueue;
}
}
/**
* Queues reading data.
* @param readingQueue The readingQueue to set.
*/
public void setReadingQueue(ByteBuffer readingQueue) {
synchronized (this) {
this.readingQueue = readingQueue;
}
}
/**
* Gets the writing lock.
* @return The writing lock.
*/
public Lock getWritingLock() {
return writingLock;
}
/**
* Gets the selection key.
* @return The selection key.
*/
public SelectionKey getKey() {
return key;
}
/**
* @return The active.
*/
public boolean isActive() {
return active;
}
/**
* @return The js5Encryption.
*/
public int getJs5Encryption() {
return js5Encryption;
}
/**
* @param js5Encryption The js5Encryption to set.
*/
public void setJs5Encryption(int js5Encryption) {
this.js5Encryption = js5Encryption;
}
/**
* Gets the lastPing.
* @return The lastPing.
*/
public long getLastPing() {
return lastPing;
}
/**
* Sets the lastPing.
* @param lastPing The lastPing to set.
*/
public void setLastPing(long lastPing) {
this.lastPing = lastPing;
}
/**
* Gets the nameHash.
* @return The nameHash.
*/
public int getNameHash() {
return nameHash;
}
/**
* Sets the nameHash.
* @param nameHash The nameHash to set.
*/
public void setNameHash(int nameHash) {
this.nameHash = nameHash;
}
/**
* Gets the serverKey.
* @return The serverKey.
*/
public long getServerKey() {
return serverKey;
}
/**
* Sets the serverKey.
* @param serverKey The serverKey to set.
*/
public void setServerKey(long serverKey) {
this.serverKey = serverKey;
}
/**
* Gets the gameServer value.
* @return The gameServer.
*/
public GameServer getGameServer() {
return gameServer;
}
/**
* Sets the gameServer value.
* @param gameServer The gameServer to set.
*/
public void setGameServer(GameServer gameServer) {
this.gameServer = gameServer;
}
}