/*
* Created by Andrey Cherkashin (acherkashin)
* http://acherkashin.me
*
* License
* Copyright (c) 2015 Andrey Cherkashin
* The project released under the MIT license: http://opensource.org/licenses/MIT
*/
package ragefist.core.network;
import com.juniform.IJUniformPacker;
import com.juniform.JUniform;
import com.juniform.JUniformObject;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author acherkashin
*/
public class Client extends SocketClient
{
private final SocketChannel _socketChannel;
private boolean _isConnected;
private IJUniformPacker _packer;
private ISocketStrategy _socketStrategy;
// ---------------------------------------------------------------------- //
// STATIC
// ---------------------------------------------------------------------- //
public static Client newInstance() {
try {
return new Client();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
// ---------------------------------------------------------------------- //
// PUBLIC
// ---------------------------------------------------------------------- //
@Override
public int getPacketBufferSize() {
return 4096;
}
public final void setPacketPacker(IJUniformPacker packer) {
_packer = packer;
}
public boolean connect(InetSocketAddress address) {
_isConnected = false;
try {
_socketChannel.connect(address);
while(!_socketChannel.finishConnect()) {
Thread.sleep(1);
}
_isConnected = true;
} catch (IOException | InterruptedException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, "Failed to connect to" + address, ex);
}
return _isConnected;
}
@Override
public void sendPacket(byte[] bytes) {
try {
_socketStrategy.writePacket(this, bytes);
} catch(IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.WARNING, "Failed to write request into client socket", ex);
}
}
@Override
public void sendPacket(JUniformObject packet) {
byte[] bytes = _packer.fromUniformObjectToByteArray(packet);
sendPacket(bytes);
}
/**
* Returns an array of new packets or NULL if there are no new packets
* @param readBuffer
* @return array | null
* @throws IOException
*/
@Override
public JUniformObject[] readPackets(ByteBuffer readBuffer) throws IOException {
byte[][] packets = _socketStrategy.readPackets(this, readBuffer);
if (packets.length == 0) {
return null;
}
JUniformObject[] objects = new JUniformObject[packets.length];
for(int i = 0; i < packets.length; i++) {
objects[i] = _packer.toUniformObjectFromBytes(packets[i]);
}
return objects;
}
@Override
public int write(ByteBuffer buffer) {
int bytesWritten = 0;
try {
while(buffer.hasRemaining()) {
bytesWritten += _socketChannel.write(buffer);
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, "Failed to write into buffer. Closing connection...", ex);
close();
}
return bytesWritten;
}
@Override
public int read(ByteBuffer buffer) {
int bytesSumRead = 0;
try {
int bytesRead = 0;
while((bytesRead = _socketChannel.read(buffer)) > 0) {
bytesSumRead += bytesRead;
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, "Failed to read from client socket. Closing connection...", ex);
close();
}
return bytesSumRead;
}
public void close() {
_isConnected = false;
try {
_socketChannel.close();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, "Failed to close client socket correctly", ex);
}
}
// ---------------------------------------------------------------------- //
// PRIVATE
// ---------------------------------------------------------------------- //
private Client() throws IOException {
_socketChannel = SocketChannel.open();
_socketChannel.configureBlocking(false);
_packer = JUniform.getPackerInstance(JUniform.PACKER_TYPE_JSON);
_socketStrategy = SocketStrategyDefault.getInstance();
}
}