Cameron Weinfurt 2 years ago
parent
commit
d226c1e051
  1. 16
      proto/ProtoHandler.java
  2. 22
      proto/ProtoID.java
  3. 108
      proto/ProtoIn.java
  4. 110
      proto/ProtoOut.java
  5. 102
      sample/Main.java

16
proto/ProtoHandler.java

@ -0,0 +1,16 @@
package proto;
import java.util.ArrayList;
public interface ProtoHandler
{
void handleError(String username, byte msg[]);
void handleJoin(String username);
void handlePart(String username);
void handleListing(String username, ArrayList<String> names);
void handleListingRequest(String username);
void handleMessage(String username, String message);
void handleFile(String username, String filename, byte data[]);
void handleUnknownCommand(int length, byte id, String username);
void handleClose();
}

22
proto/ProtoID.java

@ -0,0 +1,22 @@
package proto;
// This file is more of a reference than code that will actually be used
// As agreed upon when designing the protocol
public enum ProtoID
{
ERROR((byte) 0),
JOIN((byte) 1),
PART((byte) 2),
LISTING((byte) 3),
MESSAGE((byte) 4),
FILE((byte) 5),
INFO((byte) 6);
public byte b;
ProtoID(byte b)
{
this.b = b;
}
}

108
proto/ProtoIn.java

@ -0,0 +1,108 @@
package proto;
import java.io.DataInputStream;
import java.io.EOFException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.stream.IntStream;
public class ProtoIn
{
private DataInputStream dis;
public boolean loop;
private ProtoHandler handler;
public void init()
{
this.loop = true;
new Thread(() -> mainLoop()).start();
}
public ProtoIn(DataInputStream dis, ProtoHandler handler)
{
this.dis = dis;
this.handler = handler;
}
private String readName() throws java.io.IOException
{
int length = Byte.toUnsignedInt(dis.readByte());
byte bytes[] = new byte[length];
dis.read(bytes, 0, length);
return new String(bytes, Charset.forName("UTF-8"));
}
private void mainLoop()
{
while (this.loop)
{
try {
byte id = dis.readByte();
int length = dis.readInt();
String username = readName();
switch (id)
{
case 0:
byte msg[] = new byte[length];
dis.read(msg, 0, length);
new Thread(() -> handler.handleError(username, msg));
break;
case 1:
IntStream.range(0, length).forEach((x) -> { try { dis.read(); } catch (Exception e) {} } );
new Thread(() -> handler.handleJoin(username)).start();
break;
case 2:
IntStream.range(0, length).forEach((x) -> { try { dis.read(); } catch (Exception e) {} } );
new Thread(() -> handler.handlePart(username)).start();
break;
case 3:
if (length == 0)
{
Thread t = new Thread(() -> handler.handleListingRequest(username));
t.start();
} else
{
ArrayList<String> names = new ArrayList<>();
int a = 0;
while (a < length)
{
int nLength = Byte.toUnsignedInt(dis.readByte());
byte bytes[] = new byte[nLength];
dis.read(bytes, 0, nLength);
a += nLength;
names.add(new String(bytes, "UTF-8"));
}
handler.handleListing(username, names);
}
break;
case 4:
byte[] msgb = new byte[length];
dis.read(msgb, 0, length);
String message = new String(msgb, "UTF-8");
new Thread(() -> handler.handleMessage(username, message)).start();
break;
case 5:
int fnlength = Byte.toUnsignedInt(dis.readByte());
byte fnameb[] = new byte[fnlength];
dis.read(fnameb, 0, fnlength);
String fname = new String(fnameb, "UTF-8");
int flen = length - fnlength - 1;
byte data[] = new byte[flen];
dis.read(data, 0, flen);
new Thread(() -> handler.handleFile(username, fname, data)).start();
break;
case 6:
// TODO
break;
default:
Thread t = new Thread(() -> handler.handleUnknownCommand(length, id, username));
t.start();
}
} catch (EOFException e)
{
this.loop = false;
handler.handleClose();
} catch (Exception e) { e.printStackTrace(); } // Not much we can do about this
}
}
}

110
proto/ProtoOut.java

@ -0,0 +1,110 @@
package proto;
import javafx.scene.chart.XYChart;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Collector;
import java.util.stream.Collectors;
public class ProtoOut
{
private DataOutputStream out;
private DataOutputStream real_out;
private ByteArrayOutputStream buffer;
public ProtoOut(DataOutputStream out)
{
this.real_out = out;
this.buffer = new ByteArrayOutputStream();
this.out = new DataOutputStream(buffer);
}
private void commit() throws java.io.IOException
{
real_out.write(buffer.toByteArray());
real_out.flush();
buffer = new ByteArrayOutputStream();
this.out = new DataOutputStream(buffer);
}
private void checkName(String name) throws IOException
{
if (name.length() > 255)
throw new IOException("Username too long");
}
private void writeUserName(String name) throws IOException
{
checkName(name);
byte nameBytes[] = name.getBytes("UTF-8");
out.writeByte(nameBytes.length);
out.write(nameBytes);
}
public void sendJoin(String username) throws IOException
{
out.writeByte(ProtoID.JOIN.b);
out.writeInt(0);
writeUserName(username);
commit();
}
public void sendPart(String username) throws IOException
{
out.writeByte(ProtoID.PART.b);
out.writeInt(0);
writeUserName(username);
commit();
}
public void requestUserList(String username) throws IOException
{
out.writeByte(ProtoID.LISTING.b); // type: listing
out.writeInt(0); // length
writeUserName(username); // username
commit(); // Make it so!
}
public void giveUserListing(String username, String names[]) throws IOException
{
out.writeByte(ProtoID.LISTING.b);
// I can recognize bad code when I write it, and this is bad code.
out.writeInt(Arrays.asList(names).stream().collect(Collectors.summingInt((s) -> s.getBytes().length)));
writeUserName(username);
for (String n : names)
{
writeUserName(n);
}
commit();
}
public void sendMessage(String username, String message) throws IOException
{
out.writeByte(ProtoID.MESSAGE.b);
byte msgb[] = message.getBytes("UTF-8");
out.writeInt(msgb.length);
writeUserName(username);
out.write(msgb);
}
public void sendFile(String username, String filename, byte data[]) throws IOException
{
out.writeByte(ProtoID.FILE.b);
byte fnb[] = filename.getBytes("UTF-8");
if (fnb.length > 255)
throw new IOException("File name too long");
out.writeInt(fnb.length + data.length + 1);
writeUserName(username);
out.writeByte(fnb.length);
out.write(fnb);
out.write(data);
}
public void sendInfo(String username) throws IOException
{
// TODO
throw new IOException("not implemented");
}
}

102
sample/Main.java

@ -0,0 +1,102 @@
package sample;
import proto.ProtoHandler;
import proto.ProtoIn;
import proto.ProtoOut;
import java.awt.desktop.OpenURIEvent;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(25519);
Socket o = new Socket("127.0.0.1", 25519);
Socket i = ss.accept();
OutputStream os = o.getOutputStream();
InputStream is = i.getInputStream();
ProtoOut po = new ProtoOut(new DataOutputStream(os));
ProtoIn pi = new ProtoIn(new DataInputStream(is), new TestHandler());
pi.init();
po.requestUserList("me");
po.sendJoin("ji");
po.sendMessage("ji", "yeet me off Snell");
po.sendFile("ji", "yeet.jpg", new byte[]{1,2,3,4,5});
po.sendPart("ji");
po.requestUserList("aaaa");
o.close();
while (true)
{
// System.out.println(is.read());
}
}
}
class TestHandler implements ProtoHandler
{
public TestHandler() {}
@Override
synchronized public void handleError(String username, byte[] msg)
{
System.out.println("error");
}
@Override
synchronized public void handleJoin(String username)
{
System.out.println("joined: " + username);
}
@Override
synchronized public void handlePart(String username)
{
System.out.println("parted: " + username);
}
@Override
synchronized public void handleListing(String username, ArrayList<String> names)
{
System.out.println("listing for " + username);
for (String n : names)
{
System.out.println(n);
}
System.out.println("end listing");
}
@Override
synchronized public void handleListingRequest(String username)
{
System.out.println("listing request from " + username);
}
@Override
synchronized public void handleMessage(String username, String message)
{
System.out.println(username + ": " + message);
}
@Override
synchronized public void handleFile(String username, String filename, byte data[])
{
System.out.println(username + " sent a file called " + filename);
}
@Override
synchronized public void handleUnknownCommand(int length, byte id, String username)
{
System.out.print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHH!!!!!!!!!!!!!!!!!!!!! ");
System.out.println("(" + id + ")");
}
@Override
synchronized public void handleClose()
{
System.out.println("closed");
}
}
Loading…
Cancel
Save