diff --git a/notes.txt b/notes.txt
index b48c38b..e5a9943 100644
--- a/notes.txt
+++ b/notes.txt
@@ -48,7 +48,7 @@ Server architecture 1:
Server architecture 2:
There is some other entity like Application class that handles running threads, making Tracker responsible for only one thing
- abd that thing is tracking peers of torrents. This is preferred design choice since we can then export tracking and scraping
+ and that thing is tracking peers of torrents. This is preferred design choice since we can then export tracking and scraping
functionality in separate interfaces, since UDP announce protocol has scrape method, whilst HTTP doesn't. As for now, current Tracker
class implementation doesn't provide any other information for Torrent besides its InfoHash and PeerSet, which is built from local announces
and announces to destination trackers.
diff --git a/pom.xml b/pom.xml
index b567876..8ea6540 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,7 +124,7 @@
exec-maven-plugin
3.4.1
- com.mykola2312.retracker.App
+ com.mykola2312.retracker.Main
diff --git a/src/main/java/com/mykola2312/retracker/Application.java b/src/main/java/com/mykola2312/retracker/Application.java
new file mode 100644
index 0000000..4543a7c
--- /dev/null
+++ b/src/main/java/com/mykola2312/retracker/Application.java
@@ -0,0 +1,19 @@
+package com.mykola2312.retracker;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mykola2312.retracker.config.Config;
+
+/* Class responsible for managing running server threads
+ * and repeating timer-based tasks
+ */
+public class Application {
+ private static final Logger logger = LoggerFactory.getLogger(Application.class);
+
+ private Config config;
+
+ public Application(Config config) {
+ this.config = config;
+ }
+}
diff --git a/src/main/java/com/mykola2312/retracker/App.java b/src/main/java/com/mykola2312/retracker/Main.java
similarity index 95%
rename from src/main/java/com/mykola2312/retracker/App.java
rename to src/main/java/com/mykola2312/retracker/Main.java
index 69c5ac1..e976def 100644
--- a/src/main/java/com/mykola2312/retracker/App.java
+++ b/src/main/java/com/mykola2312/retracker/Main.java
@@ -20,8 +20,8 @@ import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
-public class App {
- private static final Logger log = LoggerFactory.getLogger(App.class);
+public class Main {
+ private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
final Option configFileOpt = new Option("c", "config", true, "config.json path");
@@ -84,6 +84,8 @@ public class App {
logbackLogger.setAdditive(false);
}
+ Application app = new Application(config);
+
log.info("retracker started!");
}
}
diff --git a/src/main/java/com/mykola2312/retracker/tracker/TrackerEndpoint.java b/src/main/java/com/mykola2312/retracker/tracker/TrackerEndpoint.java
new file mode 100644
index 0000000..66ee4e9
--- /dev/null
+++ b/src/main/java/com/mykola2312/retracker/tracker/TrackerEndpoint.java
@@ -0,0 +1,80 @@
+package com.mykola2312.retracker.tracker;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+
+public class TrackerEndpoint {
+ private TrackerProtocol protocol;
+ private InetSocketAddress address;
+
+ private TrackerEndpoint(TrackerProtocol protocol, InetSocketAddress address) {
+ this.protocol = protocol;
+ this.address = address;
+ }
+
+ public TrackerProtocol getProtocol() {
+ return protocol;
+ }
+
+ public InetSocketAddress getAddress() {
+ return address;
+ }
+
+ static class TrackerEndpointException extends Exception {
+ private static final long serialVersionUID = 284186934690560946L;
+
+ public TrackerEndpointException(String url, String message) {
+ super(String.format("malformed tracker url %s, error: %s", url, message));
+ }
+ }
+
+ public static TrackerEndpoint parseEndpoint(String url) throws TrackerEndpointException {
+ int hostnameIdx = 0;
+ TrackerProtocol protocol;
+ if (url.startsWith("http://")) {
+ hostnameIdx = 7;
+ protocol = TrackerProtocol.HTTP;
+ } else if (url.startsWith("udp://")) {
+ hostnameIdx = 6;
+ protocol = TrackerProtocol.UDP;
+ } else {
+ throw new TrackerEndpointException(url, "unknown tracker protocol");
+ }
+
+ String part1 = url.substring(hostnameIdx);
+ if (part1.isEmpty() || part1.isBlank()) {
+ throw new TrackerEndpointException(url, "no hostname after protocol");
+ }
+
+ String[] hostnameAndUri = part1.split("/");
+ String hostname = (hostnameAndUri != null && hostnameAndUri.length > 0)
+ ? hostnameAndUri[0] : part1;
+
+ if (hostname.isEmpty() || hostname.isBlank()) {
+ throw new TrackerEndpointException(url, "no hostname");
+ }
+
+ String[] hostnameAndPort = hostname.split(":");
+ try {
+ int port;
+ InetSocketAddress address;
+
+ if (hostnameAndPort != null && hostnameAndPort.length > 1) {
+ // parse port from url
+ port = Integer.parseInt(hostnameAndPort[1]);
+ address = new InetSocketAddress(InetAddress.getByName(hostnameAndPort[0]), port);
+ } else {
+ // use default port for protocol
+ port = protocol.getDefaultPort();
+ address = new InetSocketAddress(InetAddress.getByName(hostname), port);
+ }
+
+ return new TrackerEndpoint(protocol, address);
+ } catch (NumberFormatException e) {
+ throw new TrackerEndpointException(url, "failed to parse port");
+ } catch (UnknownHostException e) {
+ throw new TrackerEndpointException(url, e.toString());
+ }
+ }
+}
diff --git a/src/main/java/com/mykola2312/retracker/tracker/TrackerProtocol.java b/src/main/java/com/mykola2312/retracker/tracker/TrackerProtocol.java
new file mode 100644
index 0000000..6a3d0ff
--- /dev/null
+++ b/src/main/java/com/mykola2312/retracker/tracker/TrackerProtocol.java
@@ -0,0 +1,14 @@
+package com.mykola2312.retracker.tracker;
+
+public enum TrackerProtocol {
+ HTTP,
+ UDP;
+
+ public int getDefaultPort() {
+ switch (this) {
+ case HTTP: return 80;
+ case UDP: return 2710;
+ default: return 0;
+ }
+ }
+}
diff --git a/src/test/java/com/mykola2312/retracker/tracker/TrackerEndpointTest.java b/src/test/java/com/mykola2312/retracker/tracker/TrackerEndpointTest.java
new file mode 100644
index 0000000..71a9bdb
--- /dev/null
+++ b/src/test/java/com/mykola2312/retracker/tracker/TrackerEndpointTest.java
@@ -0,0 +1,53 @@
+package com.mykola2312.retracker.tracker;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class TrackerEndpointTest {
+ @Test
+ public void parseTrackerUrlTest() {
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("http://example.com");
+ assertEquals(TrackerProtocol.HTTP, endpoint.getProtocol());
+ assertEquals("example.com", endpoint.getAddress().getHostName());
+ assertEquals(80, endpoint.getAddress().getPort());
+ });
+
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("http://example.com/");
+ assertEquals(TrackerProtocol.HTTP, endpoint.getProtocol());
+ assertEquals("example.com", endpoint.getAddress().getHostName());
+ assertEquals(80, endpoint.getAddress().getPort());
+ });
+
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("http://example.com:80");
+ assertEquals(TrackerProtocol.HTTP, endpoint.getProtocol());
+ assertEquals("example.com", endpoint.getAddress().getHostName());
+ assertEquals(80, endpoint.getAddress().getPort());
+ });
+
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("http://example.com:80/");
+ assertEquals(TrackerProtocol.HTTP, endpoint.getProtocol());
+ assertEquals("example.com", endpoint.getAddress().getHostName());
+ assertEquals(80, endpoint.getAddress().getPort());
+ });
+
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("udp://example.com");
+ assertEquals(TrackerProtocol.UDP, endpoint.getProtocol());
+ assertEquals("example.com", endpoint.getAddress().getHostName());
+ assertEquals(TrackerProtocol.UDP.getDefaultPort(), endpoint.getAddress().getPort());
+ });
+
+ assertDoesNotThrow(() -> {
+ TrackerEndpoint endpoint = TrackerEndpoint.parseEndpoint("udp://127.0.0.1:1337");
+ assertEquals(TrackerProtocol.UDP, endpoint.getProtocol());
+ assertEquals("localhost", endpoint.getAddress().getHostName());
+ assertEquals(1337, endpoint.getAddress().getPort());
+ });
+ }
+}