tdlib-session-container/src/main/java/it/tdlight/reactiveapi/Entrypoint.java

200 lines
7.3 KiB
Java
Raw Normal View History

2021-12-05 15:15:28 +01:00
package it.tdlight.reactiveapi;
2022-01-09 18:27:14 +01:00
import static java.util.Collections.unmodifiableSet;
2021-12-05 15:15:28 +01:00
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.atomix.cluster.Node;
import io.atomix.cluster.discovery.BootstrapDiscoveryProvider;
import io.atomix.core.Atomix;
import io.atomix.core.AtomixBuilder;
2021-12-05 23:47:54 +01:00
import io.atomix.core.profile.ConsensusProfileConfig;
2021-12-05 15:15:28 +01:00
import io.atomix.core.profile.Profile;
import io.atomix.protocols.raft.partition.RaftPartitionGroup;
import java.io.IOException;
2022-01-09 18:27:14 +01:00
import java.lang.reflect.InvocationTargetException;
2021-12-05 15:15:28 +01:00
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
2022-01-09 18:27:14 +01:00
import java.util.HashSet;
2021-12-05 15:15:28 +01:00
import java.util.List;
2022-01-09 18:27:14 +01:00
import java.util.Set;
2022-01-13 16:19:10 +01:00
import java.util.concurrent.ThreadLocalRandom;
2022-01-07 23:54:18 +01:00
import org.jetbrains.annotations.Nullable;
2021-12-05 15:15:28 +01:00
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Entrypoint {
private static final Logger LOG = LoggerFactory.getLogger(Entrypoint.class);
2022-01-13 01:59:26 +01:00
public record ValidEntrypointArgs(String clusterPath, String instancePath, String diskSessionsPath) {}
2021-12-05 15:15:28 +01:00
public static ValidEntrypointArgs parseArguments(String[] args) {
// Check arguments validity
if (args.length != 3
|| args[0].isBlank()
|| args[1].isBlank()
|| args[2].isBlank()
|| !Files.isRegularFile(Paths.get(args[0]))
|| !Files.isRegularFile(Paths.get(args[1]))
|| !Files.isRegularFile(Paths.get(args[2]))) {
System.err.println("Syntax: executable <path/to/cluster.yaml> <path/to/instance.yaml> <path/to/disk-sessions.yaml");
System.exit(1);
}
return new ValidEntrypointArgs(args[0], args[1], args[2]);
}
public static ReactiveApi start(ValidEntrypointArgs args, AtomixBuilder atomixBuilder) throws IOException {
// Read settings
ClusterSettings clusterSettings;
InstanceSettings instanceSettings;
DiskSessionsManager diskSessions;
{
var mapper = new ObjectMapper(new YAMLFactory());
mapper.findAndRegisterModules();
String clusterConfigPath = args.clusterPath;
String instanceConfigPath = args.instancePath;
String diskSessionsConfigPath = args.diskSessionsPath;
clusterSettings = mapper.readValue(Paths.get(clusterConfigPath).toFile(), ClusterSettings.class);
instanceSettings = mapper.readValue(Paths.get(instanceConfigPath).toFile(), InstanceSettings.class);
2022-01-07 23:54:18 +01:00
if (instanceSettings.client) {
diskSessions = null;
} else {
diskSessions = new DiskSessionsManager(mapper, diskSessionsConfigPath);
}
2021-12-05 15:15:28 +01:00
}
2022-01-07 23:54:18 +01:00
return start(clusterSettings, instanceSettings, diskSessions, atomixBuilder);
}
public static ReactiveApi start(ClusterSettings clusterSettings,
InstanceSettings instanceSettings,
@Nullable DiskSessionsManager diskSessions,
AtomixBuilder atomixBuilder) {
atomixBuilder.withCompatibleSerialization(false);
2021-12-05 15:15:28 +01:00
atomixBuilder.withClusterId(clusterSettings.id);
2022-01-09 18:27:14 +01:00
Set<ResultingEventTransformer> resultingEventTransformerSet;
2021-12-05 23:47:54 +01:00
String nodeId;
2021-12-05 15:15:28 +01:00
if (instanceSettings.client) {
2022-01-07 23:54:18 +01:00
if (diskSessions != null) {
throw new IllegalArgumentException("A client instance can't have a session manager!");
}
2022-01-09 18:27:14 +01:00
if (instanceSettings.clientAddress == null) {
throw new IllegalArgumentException("A client instance must have an address (host:port)");
}
2022-01-13 16:19:10 +01:00
var randomizedClientId = instanceSettings.id + "-" + ThreadLocalRandom.current().nextLong(0, Long.MAX_VALUE);
2022-01-09 18:27:14 +01:00
var address = Address.fromString(instanceSettings.clientAddress);
2022-01-13 16:19:10 +01:00
atomixBuilder.withMemberId(randomizedClientId).withHost(address.host()).withPort(address.port());
2021-12-05 23:47:54 +01:00
nodeId = null;
2022-01-09 18:27:14 +01:00
resultingEventTransformerSet = Set.of();
2021-12-05 15:15:28 +01:00
} else {
2022-01-07 23:54:18 +01:00
if (diskSessions == null) {
throw new IllegalArgumentException("A full instance must have a session manager!");
}
2021-12-05 15:15:28 +01:00
// Find node settings
var nodeSettingsOptional = clusterSettings.nodes
.stream()
.filter(node -> node.id.equals(instanceSettings.id))
.findAny();
// Check node settings presence
if (nodeSettingsOptional.isEmpty()) {
System.err.printf("Node id \"%s\" has not been described in cluster.yaml nodes list%n", instanceSettings.id);
System.exit(2);
}
var nodeSettings = nodeSettingsOptional.get();
2022-01-09 18:27:14 +01:00
var address = Address.fromString(nodeSettings.address);
atomixBuilder.withMemberId(instanceSettings.id).withHost(address.host()).withPort(address.port());
resultingEventTransformerSet = new HashSet<>();
if (instanceSettings.resultingEventTransformers != null) {
for (var resultingEventTransformer: instanceSettings.resultingEventTransformers) {
try {
var instance = resultingEventTransformer.getConstructor().newInstance();
resultingEventTransformerSet.add(instance);
LOG.info("Loaded and applied resulting event transformer: " + resultingEventTransformer.getName());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException("Failed to load resulting event transformer: "
+ resultingEventTransformer.getName());
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("The client transformer must declare an empty constructor: "
+ resultingEventTransformer.getName());
}
}
}
2021-12-05 23:47:54 +01:00
nodeId = nodeSettings.id;
2022-01-09 18:27:14 +01:00
resultingEventTransformerSet = unmodifiableSet(resultingEventTransformerSet);
2021-12-05 15:15:28 +01:00
}
var bootstrapDiscoveryProviderNodes = new ArrayList<Node>();
List<String> systemPartitionGroupMembers = new ArrayList<>();
for (NodeSettings node : clusterSettings.nodes) {
2022-01-11 00:21:26 +01:00
var address = Address.fromString(node.address);
bootstrapDiscoveryProviderNodes.add(Node
.builder()
.withId(node.id)
.withHost(address.host())
.withPort(address.port())
.build());
2021-12-05 15:15:28 +01:00
systemPartitionGroupMembers.add(node.id);
}
var bootstrapDiscoveryProviderBuilder = BootstrapDiscoveryProvider.builder();
bootstrapDiscoveryProviderBuilder.withNodes(bootstrapDiscoveryProviderNodes).build();
atomixBuilder.withMembershipProvider(bootstrapDiscoveryProviderBuilder.build());
atomixBuilder.withManagementGroup(RaftPartitionGroup
.builder("system")
.withNumPartitions(1)
.withMembers(systemPartitionGroupMembers)
2021-12-05 23:47:54 +01:00
.withDataDirectory(Paths.get(".data-" + instanceSettings.id).toFile())
2021-12-05 15:15:28 +01:00
.build());
atomixBuilder.withShutdownHook(false);
atomixBuilder.withTypeRegistrationRequired();
if (instanceSettings.client) {
atomixBuilder.addProfile(Profile.client());
2021-12-05 23:47:54 +01:00
} else {
var prof = Profile.consensus(systemPartitionGroupMembers);
var profCfg = (ConsensusProfileConfig) prof.config();
//profCfg.setDataGroup("raft");
profCfg.setDataPath(".data-" + instanceSettings.id);
2021-12-07 02:25:01 +01:00
profCfg.setPartitions(3);
2021-12-05 23:47:54 +01:00
atomixBuilder.addProfile(prof);
//atomixBuilder.addProfile(Profile.dataGrid(32));
2021-12-05 15:15:28 +01:00
}
var atomix = atomixBuilder.build();
TdSerializer.register(atomix.getSerializationService());
atomix.start().join();
2022-01-13 01:59:26 +01:00
var kafkaParameters = new KafkaParameters(clusterSettings, instanceSettings.id);
var api = new AtomixReactiveApi(nodeId, atomix, kafkaParameters, diskSessions, resultingEventTransformerSet);
2021-12-05 15:15:28 +01:00
LOG.info("Starting ReactiveApi...");
2021-12-05 23:47:54 +01:00
api.start().block();
LOG.info("Started ReactiveApi");
2021-12-05 15:15:28 +01:00
return api;
}
public static void main(String[] args) throws IOException {
var validArgs = parseArguments(args);
var atomixBuilder = Atomix.builder().withShutdownHookEnabled();
start(validArgs, atomixBuilder);
}
}