Skip to content

Commit

Permalink
split into two modules, document the differences
Browse files Browse the repository at this point in the history
  • Loading branch information
maxdeliso committed Mar 4, 2019
1 parent 71dc38c commit b3f5a65
Showing 31 changed files with 619 additions and 350 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
target/
.idea/
*.iml
*.iml
.mvn/
logs/
14 changes: 9 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -2,26 +2,30 @@

Teflon is a simple, configurable peer to peer chat application implemented in Java. It uses IPV6 multicast over UDP to transmit, Swing for a user interface, and JSON serialization.

### Building ###
### Modules ###

mvn compile
There are two Maven modules, one implementing the core network event loop, and the other providing a simple Swing wrapper around the former, which is packaged as a runnable Jar.

### Generating Binaries ###

mvn install

_note: the resulting runnable Jar will appear at the following path: swing\target\swing-{version}-....jar_

### Configuring ###

You need a configuration in the working directory of the program, of name "teflon.json".
You need a configuration file in the working directory of the program, of name "teflon.json".

Here is the documentation on each of the fields:

* udpPort - the port to send and receive on
* inputBufferLength - the largest message buffer you want to receive
* bufferLength - the largest message buffer you want to receive
* backlogLength - how many messages to store in memory before dropping
* multicastGroup - the IPv6 multicast group address to join
* hostAddress - a host address, probably the IPv6 multicast group address to join
* interfaceName - the network interface name to join a multicast group with

_note: see the provided teflon.json reference in the swing module._

#### Network Interfaces ####

If you run the program with a command line argument -L, it will list the names of all available interfaces.
27 changes: 27 additions & 0 deletions core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/

.mvn
34 changes: 34 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>name.maxdeliso</groupId>
<artifactId>teflon</artifactId>
<version>1.0.5-SNAPSHOT</version>
</parent>
<groupId>name.maxdeliso.teflon</groupId>
<artifactId>core</artifactId>
<version>1.0.5-SNAPSHOT</version>
<name>core</name>
<description>core Teflon classes</description>

<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>
10 changes: 10 additions & 0 deletions core/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module name.maxdeliso.teflon.core {
requires slf4j.api;
requires gson;
requires dagger;
requires javax.inject;

exports name.maxdeliso.teflon.core.data;
exports name.maxdeliso.teflon.core.net;
exports name.maxdeliso.teflon.core.di;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package name.maxdeliso.teflon.data;
package name.maxdeliso.teflon.core.data;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package name.maxdeliso.teflon.data;
package name.maxdeliso.teflon.core.data;

/**
* A simple message class with a sender id and a string body.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package name.maxdeliso.teflon.data;
package name.maxdeliso.teflon.core.data;

import java.nio.ByteBuffer;
import java.util.Optional;

public interface MessageMarshaller {
Optional<Message> bufferToMessage(final byte[] buffer);

ByteBuffer messageToBuffer(final Message message);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package name.maxdeliso.teflon.core.di;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import dagger.Module;
import dagger.Provides;
import name.maxdeliso.teflon.core.data.JsonMessageMarshaller;
import name.maxdeliso.teflon.core.data.Message;
import name.maxdeliso.teflon.core.net.NetSelector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Named;
import javax.inject.Singleton;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

@Module
public class TeflonCoreModule {
private static final Logger LOG = LoggerFactory.getLogger(TeflonCoreModule.class);

@Provides
@Singleton
BlockingQueue<Message> provideMessageQueue(@Named("teflon.backlogLength") final int backlogLength) {
return new LinkedBlockingQueue<>(backlogLength);
}

@Provides
@Singleton
InetAddress provideInetAddress(@Named("teflon.host.address") final String hostAddress) {
try {
// NOTE: this causes a DNS Query to run
return InetAddress.getByName(hostAddress);
} catch (UnknownHostException uhe) {
LOG.error("failed to process multicast group from config", uhe);
throw new RuntimeException(uhe);
}
}

@Provides
@Singleton
NetworkInterface provideNetworkInterface(@Named("teflon.host.interface") final String hostInterface) {
try {
// NOTE: this invokes some platform specific code
return NetworkInterface.getByName(hostInterface);
} catch (final SocketException se) {
LOG.error("failed to process interface name from config", se);
throw new RuntimeException(se);
}
}

@Provides
@Singleton
NetSelector provideNetSelector(@Named("teflon.udp.port") final int udpPort,
@Named("teflon.udp.bufferLength") final int bufferLength,
final BiConsumer<SocketAddress, byte[]> incomingConsumer,
final InetAddress multicastGroupAddress,
final NetworkInterface multicastInterface,
final Supplier<ByteBuffer> outgoingDataSupplier) {
return new NetSelector(
udpPort,
bufferLength,
incomingConsumer,
multicastGroupAddress,
multicastInterface,
outgoingDataSupplier);

}

@Provides
@Singleton
Gson provideGSON() {
return new GsonBuilder().create();
}

@Provides
@Singleton
JsonMessageMarshaller provideJsonMessageMarshaller(final Gson gson) {
return new JsonMessageMarshaller(gson);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package name.maxdeliso.teflon.net;
package name.maxdeliso.teflon.core.net;

import name.maxdeliso.teflon.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@@ -26,7 +25,6 @@
public class NetSelector {
private static final Logger LOG = LoggerFactory.getLogger(NetSelector.class);

private final AtomicBoolean alive;
private final ByteBuffer incomingBuffer;
private final InetSocketAddress multicastSendSocketAddress;
private final InetSocketAddress multicastListenSocketAddress;
@@ -35,19 +33,20 @@ public class NetSelector {
private final NetworkInterface multicastInterface;
private final Supplier<ByteBuffer> outgoingMessageSupplier;

public NetSelector(final AtomicBoolean alive,
private final AtomicBoolean alive = new AtomicBoolean(true);

public NetSelector(final int udpPort,
final int bufferLength,
final BiConsumer<SocketAddress, byte[]> incomingByteBufferConsumer,
final InetAddress multicastGroupAddress,
final NetworkInterface multicastInterface,
final Supplier<ByteBuffer> outgoingDataSupplier,
final Config config) {
this.alive = alive;
final Supplier<ByteBuffer> outgoingDataSupplier) {
this.incomingByteBufferConsumer = incomingByteBufferConsumer;
this.multicastGroupAddress = multicastGroupAddress;
this.multicastInterface = multicastInterface;
this.incomingBuffer = ByteBuffer.allocate(config.getInputBufferLength());
this.multicastSendSocketAddress = new InetSocketAddress(multicastGroupAddress, config.getUdpPort());
this.multicastListenSocketAddress = new InetSocketAddress(config.getUdpPort());
this.incomingBuffer = ByteBuffer.allocate(bufferLength);
this.multicastSendSocketAddress = new InetSocketAddress(multicastGroupAddress, udpPort);
this.multicastListenSocketAddress = new InetSocketAddress(udpPort);
this.outgoingMessageSupplier = outgoingDataSupplier;
}

@@ -82,8 +81,7 @@ public void selectLoop() {
.map(bufferToSend -> {
try {
final var bufferLength = bufferToSend.array().length;
final var sentBytes = datagramChannel
.send(bufferToSend, multicastSendSocketAddress);
final var sentBytes = datagramChannel.send(bufferToSend, multicastSendSocketAddress);
LOG.debug("sent {} of {} bytes over the wire", sentBytes, bufferLength);
return bufferLength == sentBytes;
} catch (IOException exc) {
@@ -117,4 +115,8 @@ private DatagramChannel setupDatagramChannel() throws IOException {
channel.join(multicastGroupAddress, multicastInterface);
return channel;
}

public void signalExit() {
this.alive.set(false);
}
}
Loading

0 comments on commit b3f5a65

Please sign in to comment.