промежуточный коммит

This commit is contained in:
kirillius 2025-09-12 21:01:26 +03:00
parent 47bd3ef9d6
commit 830ea4d9fa
17 changed files with 414 additions and 86 deletions

View File

@ -23,6 +23,15 @@
<version>0.1.0.0</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>7.3.0.202506031305-r</version>
</dependency>
</dependencies>
</project>

View File

@ -1,62 +1,31 @@
package ru.kirillius.pf.sdn;
import lombok.Getter;
import org.eclipse.jetty.server.Server;
import ru.kirillius.pf.sdn.External.API.HENetBGPInfoProvider;
import ru.kirillius.pf.sdn.core.Auth.AuthManager;
import ru.kirillius.pf.sdn.core.Config;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInformationService;
import ru.kirillius.pf.sdn.core.Networking.NetworkManager;
import ru.kirillius.utils.logging.SystemLogger;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.logging.Level;
public class App implements Context {
public static void main(String[] args) {
new App();
}
public class App extends AppContext {
private final static File configFile = new File("config.json");
public App() {
try {
config = Config.load(configFile);
} catch (IOException e) {
config = new Config();
try {
Config.store(config, configFile);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
authManager = new AuthManager(this);
server = new Server();
autonomousSystemInformationService = new AutonomousSystemInformationService();
autonomousSystemInformationService.setProvider(new HENetBGPInfoProvider());
networkManager = new NetworkManager(this);
var inputResources = networkManager.getInputResources();
inputResources.add(config.getCustomResources());
networkManager.triggerUpdate();
while (networkManager.isUpdatingNow()) {
Thread.yield();
}
return;
public App(File configFile) {
super(configFile);
}
@Getter
private final NetworkManager networkManager;
@Getter
private Config config;
@Getter
private final AuthManager authManager;
@Getter
private final Server server;
@Getter
private final AutonomousSystemInformationService autonomousSystemInformationService;
static {
SystemLogger.initializeLogging(Level.INFO, Collections.emptyList());
}
public static void main(String[] args) {
try (App app = new App(configFile)) {
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,66 @@
package ru.kirillius.pf.sdn;
import lombok.Getter;
import org.eclipse.jetty.server.Server;
import ru.kirillius.pf.sdn.External.API.HEInfoProvider;
import ru.kirillius.pf.sdn.core.Auth.AuthManager;
import ru.kirillius.pf.sdn.core.Config;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.ContextEventsHandler;
import ru.kirillius.pf.sdn.core.Networking.ASInfoService;
import ru.kirillius.pf.sdn.core.Networking.NetworkManager;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
public class AppContext implements Context, Closeable {
public AppContext(File configFile) {
try {
config = Config.load(configFile);
} catch (IOException e) {
config = new Config();
try {
Config.store(config, configFile);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
authManager = new AuthManager(this);
server = new Server();
ASInfoService = new ASInfoService();
ASInfoService.setProvider(new HEInfoProvider(this));
networkManager = new NetworkManager(this);
networkManager.getInputResources().add(config.getCustomResources());
}
@Getter
private final NetworkManager networkManager;
@Getter
private Config config;
@Getter
private final AuthManager authManager;
@Getter
private final Server server;
@Getter
private final ASInfoService ASInfoService;
@Override
public void close() throws IOException {
ASInfoService.close();
networkManager.close();
try {
server.stop();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Getter
private final ContextEventsHandler EventsHandler = new ContextEventsHandler();
}

View File

@ -0,0 +1,119 @@
package ru.kirillius.pf.sdn.External.API;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
import ru.kirillius.pf.sdn.core.Subscription.RepositoryConfig;
import ru.kirillius.pf.sdn.core.Subscription.SubscriptionProvider;
import ru.kirillius.pf.sdn.core.Util.HashUtil;
import ru.kirillius.utils.logging.SystemLogger;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class GitSubscription implements SubscriptionProvider {
private final Context context;
public GitSubscription(Context context) {
this.context = context;
}
@Override
public Map<String, NetworkResourceBundle> getResources(RepositoryConfig config) {
try {
var repoDir = new File(context.getConfig().getCacheDirectory(), "git/" + HashUtil.md5(config.getName()));
if (!repoDir.exists()) {
if (!repoDir.mkdirs()) {
throw new IOException("Unable to create directory: " + repoDir.getAbsolutePath());
}
}
var repository = isGitRepository(repoDir) ? openRepository(repoDir) : cloneRepository(config.getSource(), repoDir);
SystemLogger.message("Fetching git repository " + config.getName(), CTX);
checkAndPullUpdates(repository);
repository.close();
return Map.of();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void checkAndPullUpdates(Git git) throws GitAPIException {
var fetchResult = git.fetch()
.setCheckFetchedObjects(true)
.call();
if (fetchResult.getTrackingRefUpdates() != null && !fetchResult.getTrackingRefUpdates().isEmpty()) {
SystemLogger.message("Downloading updates...", CTX);
// Выполняем pull чтобы получить изменения
var pullResult = git.pull().call();
if (pullResult.isSuccessful()) {
System.out.println("✅ Обновление успешно завершено!");
// Проверяем были ли обновлены файлы
if (pullResult.getFetchResult() != null &&
!pullResult.getFetchResult().getTrackingRefUpdates().isEmpty()) {
System.out.println("📁 Были обновлены файлы:");
pullResult.getFetchResult().getTrackingRefUpdates().forEach(refUpdate -> {
System.out.println(" - " + refUpdate.getLocalName() +
" : " + refUpdate.getOldObjectId().abbreviate(7).name() +
" -> " + refUpdate.getNewObjectId().abbreviate(7).name());
});
}
} else {
System.out.println("❌ Ошибка при обновлении репозитория");
}
} else {
System.out.println("✅ Репозиторий уже актуален, обновлений нет");
}
}
private final static String CTX = GitSubscription.class.getSimpleName();
private static Git cloneRepository(String REPO_URL, File path) throws GitAPIException {
SystemLogger.message("Cloning repository " + REPO_URL, CTX);
return Git.cloneRepository()
.setURI(REPO_URL)
.setDirectory(path)
.setCloneAllBranches(true)
.call();
}
private static Git openRepository(File repoDir) throws IOException {
var builder = new FileRepositoryBuilder();
var repository = builder.setGitDir(new File(repoDir, ".git"))
.readEnvironment()
.findGitDir()
.build();
return new Git(repository);
}
private static boolean isGitRepository(File directory) {
if (!directory.exists() || !directory.isDirectory()) {
return false;
}
var gitDir = new File(directory, ".git");
return gitDir.exists() && gitDir.isDirectory();
}
}

View File

@ -4,7 +4,8 @@ import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import org.json.JSONTokener;
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInfoProvider;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.Networking.ASInfoProvider;
import ru.kirillius.pf.sdn.core.Networking.IPv4Subnet;
import ru.kirillius.utils.logging.SystemLogger;
@ -17,7 +18,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HENetBGPInfoProvider implements AutonomousSystemInfoProvider {
public class HEInfoProvider implements ASInfoProvider {
private final Context context;
public HEInfoProvider(Context context) {
this.context = context;
}
@Override
@SneakyThrows
public List<IPv4Subnet> getPrefixes(int as) {
@ -52,5 +60,5 @@ public class HENetBGPInfoProvider implements AutonomousSystemInfoProvider {
return list;
}
private final static String CTX = HENetBGPInfoProvider.class.getSimpleName();
private final static String CTX = HEInfoProvider.class.getSimpleName();
}

View File

@ -11,6 +11,7 @@ import ru.kirillius.json.JSONSerializable;
import ru.kirillius.json.JSONUtility;
import ru.kirillius.pf.sdn.core.Auth.AuthToken;
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
import ru.kirillius.pf.sdn.core.Subscription.RepositoryConfig;
import java.io.*;
import java.util.Collections;
@ -27,11 +28,21 @@ public class Config {
@JSONProperty
private String host = "0.0.0.0";
@Setter
@Getter
@JSONProperty
private File cacheDirectory = new File("./.cache");
@Setter
@Getter
@JSONArrayProperty(type = AuthToken.class)
private List<AuthToken> tokens = Collections.emptyList();
@Setter
@Getter
@JSONArrayProperty(type = RepositoryConfig.class)
private List<RepositoryConfig> subscriptions = Collections.emptyList();
@Setter
@Getter
@JSONProperty

View File

@ -2,7 +2,7 @@ package ru.kirillius.pf.sdn.core;
import org.eclipse.jetty.server.Server;
import ru.kirillius.pf.sdn.core.Auth.AuthManager;
import ru.kirillius.pf.sdn.core.Networking.AutonomousSystemInformationService;
import ru.kirillius.pf.sdn.core.Networking.ASInfoService;
import ru.kirillius.pf.sdn.core.Networking.NetworkManager;
public interface Context {
@ -12,8 +12,8 @@ public interface Context {
Server getServer();
AutonomousSystemInformationService getAutonomousSystemInformationService();
ASInfoService getASInfoService();
NetworkManager getNetworkManager();
ContextEventsHandler getEventsHandler();
}

View File

@ -0,0 +1,13 @@
package ru.kirillius.pf.sdn.core;
import lombok.Getter;
import ru.kirillius.java.utils.events.ConcurrentEventHandler;
import ru.kirillius.java.utils.events.EventHandler;
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
public final class ContextEventsHandler {
@Getter
private final EventHandler<NetworkResourceBundle> networkManagerUpdateEvent = new ConcurrentEventHandler<>();
@Getter
private final EventHandler<NetworkResourceBundle> subscriptionsUpdateEvent = new ConcurrentEventHandler<>();
}

View File

@ -0,0 +1,20 @@
package ru.kirillius.pf.sdn.core.Networking;
import ru.kirillius.pf.sdn.core.Context;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public interface ASInfoProvider {
List<IPv4Subnet> getPrefixes(int as);
static ASInfoProvider instantiate(Class<? extends ASInfoProvider> providerClass, Context context) {
try {
var constructor = providerClass.getConstructor(Context.class);
return constructor.newInstance(context);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -12,13 +12,13 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@NoArgsConstructor
public class AutonomousSystemInformationService implements Closeable {
public class ASInfoService implements Closeable {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@Getter
@Setter
private AutonomousSystemInfoProvider provider = null;
private ASInfoProvider provider = null;
public Future<List<IPv4Subnet>> getPrefixes(int as) {

View File

@ -1,7 +0,0 @@
package ru.kirillius.pf.sdn.core.Networking;
import java.util.List;
public interface AutonomousSystemInfoProvider {
List<IPv4Subnet> getPrefixes(int as);
}

View File

@ -72,6 +72,11 @@ public class NetworkManager implements Closeable {
outputResources.setSubnets(subnets.stream().toList());
outputResources.setDomains(domains.stream().toList());
try {
context.getEventsHandler().getNetworkManagerUpdateEvent().invoke(outputResources);
} catch (Exception e) {
throw new RuntimeException(e);
}
}));
}
@ -81,7 +86,7 @@ public class NetworkManager implements Closeable {
private void fetchPrefixes(List<Integer> systems) {
systems.forEach(as -> {
var service = context.getAutonomousSystemInformationService();
var service = context.getASInfoService();
var future = service.getPrefixes(as);
while (!future.isDone() && !future.isCancelled()) {

View File

@ -0,0 +1,26 @@
package ru.kirillius.pf.sdn.core.Subscription;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import ru.kirillius.json.JSONProperty;
import ru.kirillius.json.JSONSerializable;
@NoArgsConstructor
@JSONSerializable
public class RepositoryConfig {
@Setter
@Getter
@JSONProperty
private String name;
@Setter
@Getter
@JSONProperty
private Class<?> type;
@Setter
@Getter
@JSONProperty
private String source;
}

View File

@ -0,0 +1,57 @@
package ru.kirillius.pf.sdn.core.Subscription;
import lombok.Getter;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
public class SubscriptionManager implements Closeable {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Context context;
public SubscriptionManager(Context context) {
this.context = context;
}
private final AtomicReference<Future<?>> updateProcess = new AtomicReference<>();
@Getter
private final NetworkResourceBundle outputResources = new NetworkResourceBundle();
public boolean isUpdatingNow() {
var future = updateProcess.get();
return future != null && !future.isDone() && !future.isCancelled();
}
public synchronized void triggerUpdate() {
if (isUpdatingNow()) {
return;
}
updateProcess.set(executor.submit(() -> {
var bundle = new NetworkResourceBundle();
outputResources.clear();
outputResources.add(bundle);
try {
context.getEventsHandler().getSubscriptionsUpdateEvent().invoke(outputResources);
} catch (Exception e) {
throw new RuntimeException(e);
}
}));
}
@Override
public void close() throws IOException {
executor.shutdown();
}
}

View File

@ -0,0 +1,21 @@
package ru.kirillius.pf.sdn.core.Subscription;
import ru.kirillius.pf.sdn.core.Context;
import ru.kirillius.pf.sdn.core.Networking.NetworkResourceBundle;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public interface SubscriptionProvider {
Map<String, NetworkResourceBundle> getResources(RepositoryConfig config);
static SubscriptionProvider instantiate(Class<? extends SubscriptionProvider> providerClass, Context context) {
try {
var constructor = providerClass.getConstructor(Context.class);
return constructor.newInstance(context);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -8,6 +8,26 @@ public final class HashUtil {
private HashUtil() {
}
public static String md5(String input) {
try {
var md = MessageDigest.getInstance("MD5");
var hash = md.digest(input.getBytes());
var hexString = new StringBuilder();
for (var b : hash) {
var hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 algorithm not found", e);
}
}
public static String hash(String data, String salt) {
String generatedPassword = null;

33
pom.xml
View File

@ -63,22 +63,8 @@
<artifactId>cron-utils</artifactId>
<version>9.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.snmp4j/snmp4j -->
<dependency>
<groupId>org.snmp4j</groupId>
<artifactId>snmp4j</artifactId>
<version>3.7.7</version>
</dependency>
<dependency>
<groupId>ru.kirillius</groupId>
<artifactId>icmp4j</artifactId>
<version>1.0.0.0</version>
</dependency>
<dependency>
<groupId>ru.kirillius.util</groupId>
<artifactId>dynamic-types</artifactId>
<version>2.0.0.0</version>
</dependency>
<dependency>
<groupId>ru.kirillius</groupId>
<artifactId>json-rpc-servlet</artifactId>
@ -89,12 +75,17 @@
<artifactId>common-logging</artifactId>
<version>1.3.0.0</version>
</dependency>
<dependency>
<groupId>ru.kirillius</groupId>
<artifactId>hibernate-commons</artifactId>
<version>2.2.0.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-server -->
<dependency>