168 lines
5.9 KiB
Java
168 lines
5.9 KiB
Java
package ch.dissem.bitmessage.repository;
|
|
|
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
|
import ch.dissem.bitmessage.exception.ApplicationException;
|
|
import ch.dissem.bitmessage.ports.NodeRegistry;
|
|
import ch.dissem.bitmessage.utils.Collections;
|
|
import ch.dissem.bitmessage.utils.SqlStrings;
|
|
import ch.dissem.bitmessage.utils.Strings;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import java.sql.*;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import static ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes;
|
|
import static ch.dissem.bitmessage.utils.UnixTime.*;
|
|
|
|
public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
|
|
private static final Logger LOG = LoggerFactory.getLogger(JdbcNodeRegistry.class);
|
|
private Map<Long, Set<NetworkAddress>> stableNodes;
|
|
|
|
public JdbcNodeRegistry(JdbcConfig config) {
|
|
super(config);
|
|
cleanUp();
|
|
}
|
|
|
|
private void cleanUp() {
|
|
try (
|
|
Connection connection = config.getConnection();
|
|
PreparedStatement ps = connection.prepareStatement(
|
|
"DELETE FROM Node WHERE time<?")
|
|
) {
|
|
ps.setLong(1, now(-28 * DAY));
|
|
ps.executeUpdate();
|
|
} catch (SQLException e) {
|
|
LOG.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
private NetworkAddress loadExisting(NetworkAddress node) {
|
|
String query =
|
|
"SELECT stream, address, port, services, time" +
|
|
" FROM Node" +
|
|
" WHERE stream = " + node.getStream() +
|
|
" AND address = X'" + Strings.hex(node.getIPv6()) + "'" +
|
|
" AND port = " + node.getPort();
|
|
try (
|
|
Connection connection = config.getConnection();
|
|
Statement stmt = connection.createStatement();
|
|
ResultSet rs = stmt.executeQuery(query)
|
|
) {
|
|
if (rs.next()) {
|
|
return new NetworkAddress.Builder()
|
|
.stream(rs.getLong("stream"))
|
|
.ipv6(rs.getBytes("address"))
|
|
.port(rs.getInt("port"))
|
|
.services(rs.getLong("services"))
|
|
.time(rs.getLong("time"))
|
|
.build();
|
|
} else {
|
|
return null;
|
|
}
|
|
} catch (Exception e) {
|
|
LOG.error(e.getMessage(), e);
|
|
throw new ApplicationException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
|
List<NetworkAddress> result = new LinkedList<>();
|
|
String query =
|
|
"SELECT stream, address, port, services, time" +
|
|
" FROM Node WHERE stream IN (" + SqlStrings.join(streams) + ")" +
|
|
" ORDER BY TIME DESC" +
|
|
" LIMIT " + limit;
|
|
try (
|
|
Connection connection = config.getConnection();
|
|
Statement stmt = connection.createStatement();
|
|
ResultSet rs = stmt.executeQuery(query)
|
|
) {
|
|
while (rs.next()) {
|
|
result.add(
|
|
new NetworkAddress.Builder()
|
|
.stream(rs.getLong("stream"))
|
|
.ipv6(rs.getBytes("address"))
|
|
.port(rs.getInt("port"))
|
|
.services(rs.getLong("services"))
|
|
.time(rs.getLong("time"))
|
|
.build()
|
|
);
|
|
}
|
|
} catch (Exception e) {
|
|
LOG.error(e.getMessage(), e);
|
|
throw new ApplicationException(e);
|
|
}
|
|
if (result.isEmpty()) {
|
|
synchronized (this) {
|
|
if (stableNodes == null) {
|
|
stableNodes = loadStableNodes();
|
|
}
|
|
}
|
|
for (long stream : streams) {
|
|
Set<NetworkAddress> nodes = stableNodes.get(stream);
|
|
if (nodes != null) {
|
|
result.add(Collections.selectRandom(nodes));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void offerAddresses(List<NetworkAddress> nodes) {
|
|
cleanUp();
|
|
nodes.stream()
|
|
.filter(node -> node.getTime() < now(+24 * HOUR) && node.getTime() > now(-28 * DAY))
|
|
.forEach(node -> {
|
|
synchronized (this) {
|
|
NetworkAddress existing = loadExisting(node);
|
|
if (existing == null) {
|
|
insert(node);
|
|
} else if (node.getTime() > existing.getTime()) {
|
|
update(node);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void insert(NetworkAddress node) {
|
|
try (
|
|
Connection connection = config.getConnection();
|
|
PreparedStatement ps = connection.prepareStatement(
|
|
"INSERT INTO Node (stream, address, port, services, time) " +
|
|
"VALUES (?, ?, ?, ?, ?)")
|
|
) {
|
|
ps.setLong(1, node.getStream());
|
|
ps.setBytes(2, node.getIPv6());
|
|
ps.setInt(3, node.getPort());
|
|
ps.setLong(4, node.getServices());
|
|
ps.setLong(5, node.getTime());
|
|
ps.executeUpdate();
|
|
} catch (SQLException e) {
|
|
LOG.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
private void update(NetworkAddress node) {
|
|
try (
|
|
Connection connection = config.getConnection();
|
|
PreparedStatement ps = connection.prepareStatement(
|
|
"UPDATE Node SET services=?, time=? WHERE stream=? AND address=? AND port=?")
|
|
) {
|
|
ps.setLong(1, node.getServices());
|
|
ps.setLong(2, node.getTime());
|
|
ps.setLong(3, node.getStream());
|
|
ps.setBytes(4, node.getIPv6());
|
|
ps.setInt(5, node.getPort());
|
|
ps.executeUpdate();
|
|
} catch (SQLException e) {
|
|
LOG.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|