astra.debugger.DebuggerServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of astra-interpreter Show documentation
Show all versions of astra-interpreter Show documentation
Core interpreter artifact for the ASTRA Language
package astra.debugger;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DebuggerServer implements Runnable {
private ServerSocketChannel serverChannel;
private List changeRequests = new LinkedList();
private Map> pendingData = new HashMap>();
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
private InetAddress host = null;
private int port;
private DebuggerWorker worker;
public DebuggerServer(int port, DebuggerWorker worker) throws IOException {
this.port = port;
this.worker = worker;
selector = initSelector();
}
private Selector initSelector() throws IOException {
Selector socketSelector = SelectorProvider.provider().openSelector();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(host, this.port);
serverChannel.socket().bind(isa);
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
System.out.println("DebugServer listening on port: "+ port);
return socketSelector;
}
public void run() {
while (true) {
try {
synchronized (this.changeRequests) {
Iterator changes = this.changeRequests.iterator();
while (changes.hasNext()) {
ChangeRequest change = changes.next();
switch (change.type) {
case ChangeRequest.CHANGEOPS:
SelectionKey key = change.socket.keyFor(this.selector);
try {
key.interestOps(change.ops);
} catch (Throwable e) {
e.printStackTrace();
System.exit(1);
}
}
}
this.changeRequests.clear();
}
selector.select();
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = selectedKeys.next();
selectedKeys.remove();
if (!key.isValid())
continue;
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
this.write(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void accept(SelectionKey key) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(this.selector, SelectionKey.OP_READ);
}
private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
readBuffer.clear();
int bytesRead;
try {
bytesRead = socketChannel.read(readBuffer);
} catch (IOException e) {
key.cancel();
socketChannel.close();
return;
}
if (bytesRead == -1) {
key.channel().close();
key.cancel();
return;
}
this.worker.processData(this, socketChannel, this.readBuffer.array(), bytesRead);
}
private void write(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
synchronized (this.pendingData) {
List queue = this.pendingData.get(socketChannel);
while (!queue.isEmpty()) {
ByteBuffer buf = (ByteBuffer) queue.get(0);
socketChannel.write(buf);
if (buf.remaining() > 0) {
// ... or the socket's buffer fills up
break;
}
queue.remove(0);
}
if (queue.isEmpty()) {
key.interestOps(SelectionKey.OP_READ);
}
}
}
public void send(SocketChannel socket, byte[] data) {
synchronized (this.changeRequests) {
this.changeRequests.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));
synchronized (this.pendingData) {
List queue = this.pendingData.get(socket);
if (queue == null) {
queue = new ArrayList();
this.pendingData.put(socket, queue);
}
queue.add(ByteBuffer.wrap(data));
}
}
this.selector.wakeup();
}
}