implement tracker url parsing, begin working on application thread

running
This commit is contained in:
mykola2312 2024-11-02 22:54:40 +02:00
parent fa7e340ad7
commit 067f10ff69
7 changed files with 172 additions and 4 deletions

View file

@ -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.

View file

@ -124,7 +124,7 @@
<artifactId>exec-maven-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<mainClass>com.mykola2312.retracker.App</mainClass>
<mainClass>com.mykola2312.retracker.Main</mainClass>
</configuration>
</plugin>
</plugins>

View file

@ -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;
}
}

View file

@ -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!");
}
}

View file

@ -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());
}
}
}

View file

@ -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;
}
}
}

View file

@ -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());
});
}
}