PUB/SUB and HELP commands.
Several GUI fixes.
This commit is contained in:
parent
ad19b4ffb3
commit
fb9436c47e
5 changed files with 255 additions and 118 deletions
|
|
@ -13,12 +13,14 @@ sp_cleanup.always_use_blocks=true
|
||||||
sp_cleanup.always_use_parentheses_in_expressions=false
|
sp_cleanup.always_use_parentheses_in_expressions=false
|
||||||
sp_cleanup.always_use_this_for_non_static_field_access=false
|
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||||
sp_cleanup.always_use_this_for_non_static_method_access=false
|
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||||
sp_cleanup.convert_to_enhanced_for_loop=false
|
sp_cleanup.convert_functional_interfaces=false
|
||||||
|
sp_cleanup.convert_to_enhanced_for_loop=true
|
||||||
sp_cleanup.correct_indentation=false
|
sp_cleanup.correct_indentation=false
|
||||||
sp_cleanup.format_source_code=true
|
sp_cleanup.format_source_code=true
|
||||||
sp_cleanup.format_source_code_changes_only=false
|
sp_cleanup.format_source_code_changes_only=false
|
||||||
sp_cleanup.make_local_variable_final=false
|
sp_cleanup.insert_inferred_type_arguments=false
|
||||||
sp_cleanup.make_parameters_final=false
|
sp_cleanup.make_local_variable_final=true
|
||||||
|
sp_cleanup.make_parameters_final=true
|
||||||
sp_cleanup.make_private_fields_final=true
|
sp_cleanup.make_private_fields_final=true
|
||||||
sp_cleanup.make_type_abstract_if_missing_method=false
|
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||||
sp_cleanup.make_variable_declarations_final=true
|
sp_cleanup.make_variable_declarations_final=true
|
||||||
|
|
@ -29,15 +31,16 @@ sp_cleanup.organize_imports=true
|
||||||
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||||
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||||
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||||
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
|
||||||
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||||
sp_cleanup.remove_private_constructors=true
|
sp_cleanup.remove_private_constructors=true
|
||||||
sp_cleanup.remove_trailing_whitespaces=false
|
sp_cleanup.remove_redundant_type_arguments=false
|
||||||
|
sp_cleanup.remove_trailing_whitespaces=true
|
||||||
sp_cleanup.remove_trailing_whitespaces_all=true
|
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||||
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||||
sp_cleanup.remove_unnecessary_casts=true
|
sp_cleanup.remove_unnecessary_casts=true
|
||||||
sp_cleanup.remove_unnecessary_nls_tags=false
|
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||||
sp_cleanup.remove_unused_imports=false
|
sp_cleanup.remove_unused_imports=true
|
||||||
sp_cleanup.remove_unused_local_variables=false
|
sp_cleanup.remove_unused_local_variables=false
|
||||||
sp_cleanup.remove_unused_private_fields=true
|
sp_cleanup.remove_unused_private_fields=true
|
||||||
sp_cleanup.remove_unused_private_members=false
|
sp_cleanup.remove_unused_private_members=false
|
||||||
|
|
@ -45,10 +48,13 @@ sp_cleanup.remove_unused_private_methods=true
|
||||||
sp_cleanup.remove_unused_private_types=true
|
sp_cleanup.remove_unused_private_types=true
|
||||||
sp_cleanup.sort_members=false
|
sp_cleanup.sort_members=false
|
||||||
sp_cleanup.sort_members_all=false
|
sp_cleanup.sort_members_all=false
|
||||||
sp_cleanup.use_blocks=false
|
sp_cleanup.use_anonymous_class_creation=false
|
||||||
|
sp_cleanup.use_blocks=true
|
||||||
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||||
|
sp_cleanup.use_lambda=false
|
||||||
sp_cleanup.use_parentheses_in_expressions=false
|
sp_cleanup.use_parentheses_in_expressions=false
|
||||||
sp_cleanup.use_this_for_non_static_field_access=false
|
sp_cleanup.use_this_for_non_static_field_access=true
|
||||||
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||||
sp_cleanup.use_this_for_non_static_method_access=false
|
sp_cleanup.use_this_for_non_static_method_access=true
|
||||||
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||||
|
sp_cleanup.use_type_arguments=false
|
||||||
|
|
|
||||||
|
|
@ -56,5 +56,10 @@
|
||||||
<artifactId>netty-all</artifactId>
|
<artifactId>netty-all</artifactId>
|
||||||
<version>4.0.18.Final</version>
|
<version>4.0.18.Final</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -8,69 +8,42 @@ import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.Transparency;
|
import java.awt.Transparency;
|
||||||
import java.awt.event.ComponentEvent;
|
import java.awt.event.ComponentEvent;
|
||||||
|
import java.awt.event.ComponentListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.KeyListener;
|
||||||
import java.awt.image.BufferStrategy;
|
import java.awt.image.BufferStrategy;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
public class NetCanvas {
|
public class NetCanvas implements ComponentListener, KeyListener {
|
||||||
private volatile BufferedImage drawBuffer;
|
private volatile BufferedImage drawBuffer;
|
||||||
private volatile BufferedImage overlayBuffer;
|
private volatile BufferedImage overlayBuffer;
|
||||||
private volatile BufferedImage paintBuffer;
|
private volatile BufferedImage paintBuffer;
|
||||||
|
|
||||||
private final BufferStrategy strategy;
|
private BufferStrategy strategy;
|
||||||
private final Thread refresher;
|
private final Thread refresher;
|
||||||
private final JFrame frame;
|
private final JFrame frame;
|
||||||
private final Canvas canvas;
|
private final Canvas canvas;
|
||||||
|
|
||||||
public NetCanvas() {
|
public NetCanvas() {
|
||||||
|
frame = new JFrame();
|
||||||
frame = new JFrame() {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processKeyEvent(KeyEvent e) {
|
|
||||||
super.processKeyEvent(e);
|
|
||||||
if (e.getKeyChar() == 'c') {
|
|
||||||
Graphics g = drawBuffer.getGraphics();
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
g.fillRect(0, 0, drawBuffer.getWidth(),
|
|
||||||
drawBuffer.getHeight());
|
|
||||||
g.dispose();
|
|
||||||
}
|
|
||||||
if (e.getKeyChar() == 'q'
|
|
||||||
|| e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processComponentEvent(ComponentEvent e) {
|
|
||||||
super.processComponentEvent(e);
|
|
||||||
if (e.getID() == ComponentEvent.COMPONENT_RESIZED) {
|
|
||||||
resizeBuffer(getWidth(), getHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
canvas = new Canvas();
|
canvas = new Canvas();
|
||||||
canvas.setSize(800, 600);
|
resizeBuffer(1024, 1024);
|
||||||
|
|
||||||
|
frame.addComponentListener(this);
|
||||||
|
canvas.addKeyListener(this);
|
||||||
|
|
||||||
|
canvas.setSize(800, 600);
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
frame.setTitle("Pixelflut");
|
frame.setTitle("Pixelflut");
|
||||||
// frame.setUndecorated(true);
|
// frame.setUndecorated(true);
|
||||||
frame.setResizable(true);
|
frame.setResizable(true);
|
||||||
// frame.setAlwaysOnTop(true);
|
// frame.setAlwaysOnTop(true);
|
||||||
|
|
||||||
frame.add(canvas);
|
frame.add(canvas);
|
||||||
frame.pack();
|
frame.pack();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
|
|
||||||
canvas.createBufferStrategy(2);
|
|
||||||
strategy = canvas.getBufferStrategy();
|
|
||||||
resizeBuffer(1024, 1024);
|
|
||||||
|
|
||||||
refresher = new Thread(new Runnable() {
|
refresher = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
@ -79,34 +52,37 @@ public class NetCanvas {
|
||||||
draw();
|
draw();
|
||||||
Thread.sleep(1000 / 30);
|
Thread.sleep(1000 / 30);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
refresher.start();
|
refresher.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void blit(BufferedImage source, BufferedImage target) {
|
private void blit(final BufferedImage source, final BufferedImage target) {
|
||||||
Graphics g = target.getGraphics();
|
final Graphics g = target.getGraphics();
|
||||||
g.drawImage(source, 0, 0, null);
|
g.drawImage(source, 0, 0, null);
|
||||||
g.dispose();
|
g.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized private void resizeBuffer(int w, int h) {
|
synchronized private void resizeBuffer(final int w, final int h) {
|
||||||
BufferedImage newBuffer;
|
BufferedImage newBuffer;
|
||||||
int mw = w, mh = h;
|
int mw = w, mh = h;
|
||||||
|
|
||||||
if (drawBuffer != null) {
|
if (drawBuffer != null) {
|
||||||
mw = Math.max(w, drawBuffer.getWidth());
|
mw = Math.max(w, drawBuffer.getWidth());
|
||||||
mh = Math.max(h, drawBuffer.getHeight());
|
mh = Math.max(h, drawBuffer.getHeight());
|
||||||
if (mw > w && mh > h)
|
if (mw > w && mh > h) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuffer = frame.getGraphicsConfiguration().createCompatibleImage(w,
|
newBuffer = frame.getGraphicsConfiguration().createCompatibleImage(w,
|
||||||
h, Transparency.OPAQUE);
|
h, Transparency.OPAQUE);
|
||||||
if (drawBuffer != null)
|
if (drawBuffer != null) {
|
||||||
blit(drawBuffer, newBuffer);
|
blit(drawBuffer, newBuffer);
|
||||||
|
}
|
||||||
drawBuffer = newBuffer;
|
drawBuffer = newBuffer;
|
||||||
|
|
||||||
overlayBuffer = frame.getGraphicsConfiguration().createCompatibleImage(
|
overlayBuffer = frame.getGraphicsConfiguration().createCompatibleImage(
|
||||||
|
|
@ -117,7 +93,7 @@ public class NetCanvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawOverlay() {
|
private void drawOverlay() {
|
||||||
Graphics2D g = overlayBuffer.createGraphics();
|
final Graphics2D g = overlayBuffer.createGraphics();
|
||||||
g.setComposite(AlphaComposite.Clear);
|
g.setComposite(AlphaComposite.Clear);
|
||||||
g.fillRect(0, 0, overlayBuffer.getWidth(), overlayBuffer.getHeight());
|
g.fillRect(0, 0, overlayBuffer.getWidth(), overlayBuffer.getHeight());
|
||||||
g.setComposite(AlphaComposite.SrcOver);
|
g.setComposite(AlphaComposite.SrcOver);
|
||||||
|
|
@ -128,34 +104,38 @@ public class NetCanvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void draw() {
|
synchronized public void draw() {
|
||||||
|
if (!frame.isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
drawOverlay();
|
drawOverlay();
|
||||||
// Prepare composite buffer
|
// Prepare composite buffer
|
||||||
Graphics2D g = paintBuffer.createGraphics();
|
final Graphics2D g = paintBuffer.createGraphics();
|
||||||
g.drawImage(drawBuffer, 0, 0, null);
|
g.drawImage(drawBuffer, 0, 0, null);
|
||||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
|
||||||
g.drawImage(overlayBuffer, 0, 0, null);
|
g.drawImage(overlayBuffer, 0, 0, null);
|
||||||
g.dispose();
|
g.dispose();
|
||||||
|
|
||||||
// Blit into double buffer
|
// Blit into double buffer
|
||||||
Graphics g2 = strategy.getDrawGraphics();
|
final Graphics g2 = strategy.getDrawGraphics();
|
||||||
g2.drawImage(paintBuffer, 0, 0, null);
|
g2.drawImage(paintBuffer, 0, 0, null);
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
strategy.show();
|
strategy.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPixel(int x, int y, int argb) {
|
public void setPixel(final int x, final int y, final int argb) {
|
||||||
// Below this values 8bit color channels are nulled.
|
// Below this values 8bit color channels are nulled.
|
||||||
BufferedImage img = drawBuffer;
|
final BufferedImage img = drawBuffer;
|
||||||
|
|
||||||
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
||||||
int alpha = (argb >>> 24) % 256;
|
final int alpha = (argb >>> 24) % 256;
|
||||||
int rgb = argb & 0xffffff;
|
int rgb = argb & 0xffffff;
|
||||||
|
|
||||||
if (alpha < 1)
|
if (alpha < 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (alpha < 255) {
|
if (alpha < 255) {
|
||||||
int target = img.getRGB(x, y);
|
final int target = img.getRGB(x, y);
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
|
|
||||||
r = ((target >>> 16) & 0xff) * (255 - alpha);
|
r = ((target >>> 16) & 0xff) * (255 - alpha);
|
||||||
|
|
@ -176,10 +156,11 @@ public class NetCanvas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPixel(int x, int y) {
|
public int getPixel(final int x, final int y) {
|
||||||
BufferedImage img = drawBuffer;
|
final BufferedImage img = drawBuffer;
|
||||||
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight())
|
if (x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight()) {
|
||||||
return img.getRGB(x, y) & 0x00ffffff;
|
return img.getRGB(x, y) & 0x00ffffff;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,4 +172,44 @@ public class NetCanvas {
|
||||||
return drawBuffer.getHeight();
|
return drawBuffer.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(final KeyEvent e) {
|
||||||
|
if (e.getKeyChar() == 'c') {
|
||||||
|
final Graphics g = drawBuffer.getGraphics();
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.fillRect(0, 0, drawBuffer.getWidth(), drawBuffer.getHeight());
|
||||||
|
g.dispose();
|
||||||
|
} else if (e.getKeyChar() == 'q'
|
||||||
|
|| e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(final KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(final KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentResized(final ComponentEvent e) {
|
||||||
|
resizeBuffer(canvas.getWidth(), canvas.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentMoved(final ComponentEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentShown(final ComponentEvent e) {
|
||||||
|
canvas.createBufferStrategy(2);
|
||||||
|
strategy = canvas.getBufferStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentHidden(final ComponentEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,90 +2,195 @@ package de.paws.pixelwar;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.traffic.TrafficCounter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
public class PixelClientHandler extends SimpleChannelInboundHandler<String> {
|
||||||
|
|
||||||
|
public interface CommandHandler {
|
||||||
|
public void handle(PixelClientHandler client, String[] args);
|
||||||
|
}
|
||||||
|
|
||||||
private static Set<PixelClientHandler> clients = new HashSet<>();
|
private static Set<PixelClientHandler> clients = new HashSet<>();
|
||||||
|
|
||||||
private final NetCanvas canvas;
|
private final NetCanvas canvas;
|
||||||
private long connected;
|
private ChannelHandlerContext channelContext;
|
||||||
private long c = 0;
|
private final Set<String> subscriptions = new HashSet<>();
|
||||||
private ChannelHandlerContext channel;
|
private final Map<String, CommandHandler> handlers = new HashMap<>();
|
||||||
|
|
||||||
public PixelClientHandler(NetCanvas canvas) {
|
private long connectedTime;
|
||||||
|
private long pixelCount = 0;
|
||||||
|
private long missedMessages = 0;
|
||||||
|
|
||||||
|
public PixelClientHandler(final NetCanvas canvas) {
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
final TrafficCounter tc = new TrafficCounter(null, null, null,
|
||||||
|
connectedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void installHandler(final String command,
|
||||||
|
final CommandHandler handler) {
|
||||||
|
handlers.put(command.toUpperCase(), handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
this.connected = System.currentTimeMillis();
|
connectedTime = System.currentTimeMillis();
|
||||||
channel = ctx;
|
channelContext = ctx;
|
||||||
synchronized (clients) {
|
synchronized (clients) {
|
||||||
clients.add(this);
|
clients.add(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(final ChannelHandlerContext ctx)
|
||||||
|
throws Exception {
|
||||||
super.channelActive(ctx);
|
super.channelActive(ctx);
|
||||||
long passed = System.currentTimeMillis() - connected;
|
final long passed = System.currentTimeMillis() - connectedTime;
|
||||||
System.out.print(c * 1000 / passed);
|
|
||||||
synchronized (clients) {
|
synchronized (clients) {
|
||||||
clients.remove(this);
|
clients.remove(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeIfPossible(String str) {
|
public void writeIfPossible(final String str) {
|
||||||
if (channel.channel().isWritable()) {
|
if (channelContext.channel().isWritable()) {
|
||||||
channel.writeAndFlush(str.trim() + "\n");
|
channelContext.write(str + "\n");
|
||||||
|
} else {
|
||||||
|
missedMessages++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeChannel(final String channel, final String message) {
|
||||||
|
if (subscriptions.contains(channel) || subscriptions.contains("*")) {
|
||||||
|
writeIfPossible(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(final String str) {
|
||||||
|
channelContext.writeAndFlush(str + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(final String msg) {
|
||||||
|
write("ERR " + msg + "\n");
|
||||||
|
channelContext.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, String msg)
|
protected void channelRead0(final ChannelHandlerContext ctx,
|
||||||
throws Exception {
|
final String msg) throws Exception {
|
||||||
String[] parts = msg.split(" ");
|
final int split = msg.indexOf(" ");
|
||||||
if (parts.length < 1)
|
String command;
|
||||||
|
String data;
|
||||||
|
if (split == -1) {
|
||||||
|
command = msg.toUpperCase();
|
||||||
|
data = "";
|
||||||
|
} else {
|
||||||
|
command = msg.substring(0, split).toUpperCase();
|
||||||
|
data = msg.substring(split + 1).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case ("PX"):
|
||||||
|
handle_PX(ctx, data);
|
||||||
|
break;
|
||||||
|
case ("SIZE"):
|
||||||
|
handle_SIZE(ctx, data);
|
||||||
|
break;
|
||||||
|
case ("PUB"):
|
||||||
|
handle_PUB(ctx, data);
|
||||||
|
break;
|
||||||
|
case ("SUB"):
|
||||||
|
handle_SUB(ctx, data);
|
||||||
|
break;
|
||||||
|
case ("HELP"):
|
||||||
|
handle_HELP(ctx, data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handle_HELP(final ChannelHandlerContext ctx, final String data) {
|
||||||
|
writeIfPossible("HELP Commands:\n" + "HELP SIZE\n"
|
||||||
|
+ "HELP PX <x> <y>\n" + "HELP PX <x> <y> <rrggbb[aa]>\n"
|
||||||
|
+ "HELP SUB\n" + "HELP SUB [-]<channel>\n"
|
||||||
|
+ "HELP PUB <channel> <message>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handle_SUB(final ChannelHandlerContext ctx, final String data) {
|
||||||
|
if (data.startsWith("-")) {
|
||||||
|
final String channel = data.substring(1);
|
||||||
|
if (!subscriptions.remove(channel.toLowerCase())) {
|
||||||
|
error("Not subscribed to this channel.");
|
||||||
|
}
|
||||||
|
} else if (data.length() > 0) {
|
||||||
|
final String channel = data.toLowerCase();
|
||||||
|
if (!channel.matches("^[a-zA-Z0-9_]+$")) {
|
||||||
|
error("Invalid channel name");
|
||||||
|
} else if (subscriptions.size() >= 16) {
|
||||||
|
error("Too many subscriptions");
|
||||||
|
} else {
|
||||||
|
subscriptions.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write("SUB " + StringUtils.join(subscriptions, " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handle_PUB(final ChannelHandlerContext ctx, final String data) {
|
||||||
|
final String[] parts = data.split(" ", 1);
|
||||||
|
if (parts.length != 2) {
|
||||||
|
error("Usage: PUB <channel> <message>");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String command = parts[0].toUpperCase();
|
final String channel = parts[0].toLowerCase();
|
||||||
|
final String message = "PUB " + channel + " " + parts[1].trim();
|
||||||
|
|
||||||
if (command.equals("PX")) {
|
for (final PixelClientHandler c : clients) {
|
||||||
c++;
|
if (c != this) {
|
||||||
if (parts.length == 3) {
|
c.writeChannel(channel, message);
|
||||||
int x = Integer.parseInt(parts[1]);
|
}
|
||||||
int y = Integer.parseInt(parts[2]);
|
}
|
||||||
int c = canvas.getPixel(x, y);
|
}
|
||||||
ctx.write(String.format("PX %d %d %06x\n", x, y, c));
|
|
||||||
ctx.flush();
|
private void handle_SIZE(final ChannelHandlerContext ctx, final String data) {
|
||||||
} else if (parts.length == 4) {
|
if (data.length() > 0) {
|
||||||
int x = Integer.parseInt(parts[1]);
|
error("SIZE");
|
||||||
int y = Integer.parseInt(parts[2]);
|
}
|
||||||
int color = (int) Long.parseLong(parts[3], 16);
|
write(String
|
||||||
if (parts[3].length() == 6)
|
.format("SIZE %d %d", canvas.getWidth(), canvas.getHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handle_PX(final ChannelHandlerContext ctx, final String data) {
|
||||||
|
final String[] args = data.split(" ");
|
||||||
|
try {
|
||||||
|
pixelCount++;
|
||||||
|
if (args.length == 2) {
|
||||||
|
final int x = Integer.parseInt(args[0]);
|
||||||
|
final int y = Integer.parseInt(args[1]);
|
||||||
|
final int c = canvas.getPixel(x, y);
|
||||||
|
write(String.format("PX %d %d %06x", x, y, c));
|
||||||
|
} else if (args.length == 3) {
|
||||||
|
final int x = Integer.parseInt(args[0]);
|
||||||
|
final int y = Integer.parseInt(args[1]);
|
||||||
|
int color = (int) Long.parseLong(args[2], 16);
|
||||||
|
if (args[2].length() == 6) {
|
||||||
color += 0xff000000;
|
color += 0xff000000;
|
||||||
|
}
|
||||||
canvas.setPixel(x, y, color);
|
canvas.setPixel(x, y, color);
|
||||||
} else {
|
} else {
|
||||||
ctx.writeAndFlush("ERR\n");
|
error("Usage: PX x y [rrggbb[aa]]");
|
||||||
ctx.close();
|
|
||||||
}
|
}
|
||||||
} else if (command.equals("SIZE")) {
|
} catch (final NumberFormatException e) {
|
||||||
ctx.writeAndFlush(String.format("SIZE %d %d\n", canvas.getWidth(),
|
error("Usage: PX x y [rrggbb[aa]]");
|
||||||
canvas.getHeight()));
|
|
||||||
} else if (command.equals("MSG")) {
|
|
||||||
String text = command + " "
|
|
||||||
+ msg.substring(command.length()).trim();
|
|
||||||
for (PixelClientHandler c : clients) {
|
|
||||||
if (c != this)
|
|
||||||
c.writeIfPossible(text);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx.writeAndFlush("ERR\n");
|
|
||||||
ctx.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,25 +22,25 @@ public class PixelServer extends ChannelHandlerAdapter {
|
||||||
private final NetCanvas canvas;
|
private final NetCanvas canvas;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
public PixelServer(int port) {
|
public PixelServer(final int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.canvas = new NetCanvas();
|
canvas = new NetCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() throws InterruptedException {
|
public void run() throws InterruptedException {
|
||||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
try {
|
try {
|
||||||
ServerBootstrap b = new ServerBootstrap();
|
final ServerBootstrap b = new ServerBootstrap();
|
||||||
b.group(bossGroup, workerGroup)
|
b.group(bossGroup, workerGroup)
|
||||||
.channel(NioServerSocketChannel.class)
|
.channel(NioServerSocketChannel.class)
|
||||||
.option(ChannelOption.SO_BACKLOG, 100)
|
.option(ChannelOption.SO_BACKLOG, 100)
|
||||||
.handler(new LoggingHandler(LogLevel.INFO))
|
.handler(new LoggingHandler(LogLevel.INFO))
|
||||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch)
|
public void initChannel(final SocketChannel ch)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
ChannelPipeline p = ch.pipeline();
|
final ChannelPipeline p = ch.pipeline();
|
||||||
|
|
||||||
// p.addLast("logger", new LoggingHandler(
|
// p.addLast("logger", new LoggingHandler(
|
||||||
// LogLevel.DEBUG));
|
// LogLevel.DEBUG));
|
||||||
|
|
@ -55,7 +55,7 @@ public class PixelServer extends ChannelHandlerAdapter {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start the server.
|
// Start the server.
|
||||||
ChannelFuture f = b.bind(port).sync();
|
final ChannelFuture f = b.bind(port).sync();
|
||||||
|
|
||||||
// Wait until the server socket is closed.
|
// Wait until the server socket is closed.
|
||||||
f.channel().closeFuture().sync();
|
f.channel().closeFuture().sync();
|
||||||
|
|
@ -66,7 +66,7 @@ public class PixelServer extends ChannelHandlerAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws InterruptedException {
|
public static void main(final String[] args) throws InterruptedException {
|
||||||
new PixelServer(8080).run();
|
new PixelServer(8080).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue