81: Control Nenjim process construction and ordered startup through NenjimHub.conf
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
package com.r35157.nenjim.hubd.impl.ref;
|
||||
|
||||
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/** Immutable, validated process-start plan for one Hub startup attempt. */
|
||||
record NenjimHubConfiguration(
|
||||
List<NenjimComponentId> autoStartProcessIds) {
|
||||
|
||||
NenjimHubConfiguration {
|
||||
Objects.requireNonNull(
|
||||
autoStartProcessIds,
|
||||
"autoStartProcessIds");
|
||||
autoStartProcessIds.forEach(componentId ->
|
||||
Objects.requireNonNull(componentId, "autoStartProcessId"));
|
||||
autoStartProcessIds = List.copyOf(autoStartProcessIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
package com.r35157.nenjim.hubd.impl.ref;
|
||||
|
||||
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Strict parser for the implementation-only Nenjim Hub configuration. */
|
||||
final class NenjimHubConfigurationParser {
|
||||
|
||||
static NenjimHubConfiguration parse(
|
||||
Path path,
|
||||
Set<NenjimComponentId> knownProcessIds,
|
||||
NenjimComponentId registryProcessId,
|
||||
NenjimComponentId journalProcessId) throws IOException {
|
||||
Objects.requireNonNull(path, "path");
|
||||
Objects.requireNonNull(knownProcessIds, "knownProcessIds");
|
||||
Objects.requireNonNull(registryProcessId, "registryProcessId");
|
||||
Objects.requireNonNull(journalProcessId, "journalProcessId");
|
||||
|
||||
List<String> lines = readConfiguration(path);
|
||||
List<ParsedProcess> parsedProcesses = parseLines(path, lines);
|
||||
validateProcessPlan(
|
||||
path,
|
||||
parsedProcesses,
|
||||
Set.copyOf(knownProcessIds),
|
||||
registryProcessId,
|
||||
journalProcessId);
|
||||
|
||||
return new NenjimHubConfiguration(
|
||||
parsedProcesses.stream()
|
||||
.map(ParsedProcess::componentId)
|
||||
.toList());
|
||||
}
|
||||
|
||||
private static List<String> readConfiguration(Path path)
|
||||
throws IOException {
|
||||
if (!Files.exists(path)) {
|
||||
throw new IOException(
|
||||
path + ": Nenjim Hub runtime configuration is missing");
|
||||
}
|
||||
if (!Files.isRegularFile(path)) {
|
||||
throw new IOException(
|
||||
path + ": Nenjim Hub runtime configuration is not a "
|
||||
+ "regular file");
|
||||
}
|
||||
if (!Files.isReadable(path)) {
|
||||
throw new IOException(
|
||||
path + ": Nenjim Hub runtime configuration is not "
|
||||
+ "readable");
|
||||
}
|
||||
|
||||
try {
|
||||
return Files.readAllLines(path, StandardCharsets.UTF_8);
|
||||
} catch (IOException exception) {
|
||||
throw new IOException(
|
||||
path + ": Failed to read Nenjim Hub runtime "
|
||||
+ "configuration",
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ParsedProcess> parseLines(
|
||||
Path path,
|
||||
List<String> lines) {
|
||||
ParserState state = ParserState.EXPECT_FORMAT_VERSION;
|
||||
List<ParsedProcess> parsedProcesses = new ArrayList<>();
|
||||
|
||||
for (int lineIndex = 0; lineIndex < lines.size(); lineIndex++) {
|
||||
String sourceLine = lines.get(lineIndex);
|
||||
String trimmedSourceLine = sourceLine.strip();
|
||||
boolean blankLine = trimmedSourceLine.isEmpty();
|
||||
boolean commentOnlyLine = trimmedSourceLine.startsWith("#");
|
||||
String content = stripTrailingComment(sourceLine).strip();
|
||||
int lineNumber = lineIndex + 1;
|
||||
|
||||
switch (state) {
|
||||
case EXPECT_FORMAT_VERSION -> {
|
||||
if (blankLine || commentOnlyLine) {
|
||||
continue;
|
||||
}
|
||||
parseFormatVersion(path, lineNumber, content);
|
||||
state = ParserState.EXPECT_AUTO_START;
|
||||
}
|
||||
case EXPECT_AUTO_START -> {
|
||||
if (blankLine || commentOnlyLine) {
|
||||
continue;
|
||||
}
|
||||
rejectAdditionalFormatVersion(
|
||||
path,
|
||||
lineNumber,
|
||||
content);
|
||||
if (!AUTO_START_HEADER.equals(content)) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Expected " + AUTO_START_HEADER
|
||||
+ " as the first actual entry after "
|
||||
+ FORMAT_VERSION_DECLARATION);
|
||||
}
|
||||
state = ParserState.IN_AUTO_START;
|
||||
}
|
||||
case IN_AUTO_START -> {
|
||||
if (blankLine) {
|
||||
state = ParserState.AFTER_AUTO_START;
|
||||
continue;
|
||||
}
|
||||
if (commentOnlyLine) {
|
||||
continue;
|
||||
}
|
||||
rejectAdditionalFormatVersion(
|
||||
path,
|
||||
lineNumber,
|
||||
content);
|
||||
rejectSectionHeader(path, lineNumber, content);
|
||||
parsedProcesses.add(parseProcessId(
|
||||
path,
|
||||
lineNumber,
|
||||
content));
|
||||
}
|
||||
case AFTER_AUTO_START -> {
|
||||
if (blankLine || commentOnlyLine) {
|
||||
continue;
|
||||
}
|
||||
rejectAdditionalFormatVersion(
|
||||
path,
|
||||
lineNumber,
|
||||
content);
|
||||
rejectSectionHeader(path, lineNumber, content);
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Unexpected content after "
|
||||
+ AUTO_START_HEADER + " terminated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state == ParserState.EXPECT_FORMAT_VERSION) {
|
||||
throw new IllegalArgumentException(
|
||||
path + ": Missing " + FORMAT_VERSION_DECLARATION
|
||||
+ " as the first actual configuration entry");
|
||||
}
|
||||
if (state == ParserState.EXPECT_AUTO_START) {
|
||||
throw new IllegalArgumentException(
|
||||
path + ": Missing required " + AUTO_START_HEADER
|
||||
+ " section");
|
||||
}
|
||||
|
||||
return parsedProcesses;
|
||||
}
|
||||
|
||||
private static void parseFormatVersion(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String content) {
|
||||
Matcher matcher = FORMAT_VERSION_PATTERN.matcher(content);
|
||||
if (!matcher.matches()) {
|
||||
String reason = content.startsWith(FORMAT_VERSION_KEY)
|
||||
? "Malformed FORMAT_VERSION; expected exactly "
|
||||
+ FORMAT_VERSION_DECLARATION
|
||||
: FORMAT_VERSION_DECLARATION
|
||||
+ " must be the first actual configuration entry";
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
reason);
|
||||
}
|
||||
|
||||
int version;
|
||||
try {
|
||||
version = Integer.parseInt(matcher.group(1));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Malformed FORMAT_VERSION; expected "
|
||||
+ FORMAT_VERSION_DECLARATION,
|
||||
exception);
|
||||
}
|
||||
|
||||
if (version != SUPPORTED_FORMAT_VERSION) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Unsupported FORMAT_VERSION '" + version
|
||||
+ "'; only version "
|
||||
+ SUPPORTED_FORMAT_VERSION + " is supported");
|
||||
}
|
||||
if (!FORMAT_VERSION_DECLARATION.equals(content)) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Malformed FORMAT_VERSION; expected exactly "
|
||||
+ FORMAT_VERSION_DECLARATION);
|
||||
}
|
||||
}
|
||||
|
||||
private static void rejectAdditionalFormatVersion(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String content) {
|
||||
if (content.startsWith(FORMAT_VERSION_KEY)) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Duplicate or misplaced FORMAT_VERSION declaration");
|
||||
}
|
||||
}
|
||||
|
||||
private static void rejectSectionHeader(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String content) {
|
||||
if (AUTO_START_HEADER.equals(content)) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Duplicate " + AUTO_START_HEADER + " section");
|
||||
}
|
||||
if (content.startsWith("[") || content.endsWith("]")) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Unknown or malformed section; only "
|
||||
+ AUTO_START_HEADER + " is supported");
|
||||
}
|
||||
}
|
||||
|
||||
private static ParsedProcess parseProcessId(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String content) {
|
||||
try {
|
||||
return new ParsedProcess(
|
||||
new NenjimComponentId(content),
|
||||
lineNumber);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
lineNumber,
|
||||
content,
|
||||
"Invalid Nenjim process ID: "
|
||||
+ exception.getMessage(),
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateProcessPlan(
|
||||
Path path,
|
||||
List<ParsedProcess> parsedProcesses,
|
||||
Set<NenjimComponentId> knownProcessIds,
|
||||
NenjimComponentId registryProcessId,
|
||||
NenjimComponentId journalProcessId) {
|
||||
Map<NenjimComponentId, Integer> firstLineById = new HashMap<>();
|
||||
|
||||
for (ParsedProcess parsedProcess : parsedProcesses) {
|
||||
NenjimComponentId componentId = parsedProcess.componentId();
|
||||
Integer firstLine = firstLineById.putIfAbsent(
|
||||
componentId,
|
||||
parsedProcess.lineNumber());
|
||||
if (firstLine != null) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
parsedProcess.lineNumber(),
|
||||
componentId.value(),
|
||||
"Duplicate process ID; first declared on line "
|
||||
+ firstLine);
|
||||
}
|
||||
if (!knownProcessIds.contains(componentId)) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
parsedProcess.lineNumber(),
|
||||
componentId.value(),
|
||||
"ID does not identify a modern Nenjim process "
|
||||
+ "constructible by this Hub");
|
||||
}
|
||||
}
|
||||
|
||||
requireProcessAtPosition(
|
||||
path,
|
||||
parsedProcesses,
|
||||
registryProcessId,
|
||||
0,
|
||||
"Registry must be the first AUTO_START process");
|
||||
requireProcessAtPosition(
|
||||
path,
|
||||
parsedProcesses,
|
||||
journalProcessId,
|
||||
1,
|
||||
"Journal must be the second AUTO_START process");
|
||||
}
|
||||
|
||||
private static void requireProcessAtPosition(
|
||||
Path path,
|
||||
List<ParsedProcess> parsedProcesses,
|
||||
NenjimComponentId requiredId,
|
||||
int requiredIndex,
|
||||
String reason) {
|
||||
if (parsedProcesses.size() <= requiredIndex) {
|
||||
throw new IllegalArgumentException(
|
||||
path + ": Missing required process ID '"
|
||||
+ requiredId.value() + "'; " + reason);
|
||||
}
|
||||
|
||||
ParsedProcess actual = parsedProcesses.get(requiredIndex);
|
||||
if (!requiredId.equals(actual.componentId())) {
|
||||
throw invalidLine(
|
||||
path,
|
||||
actual.lineNumber(),
|
||||
actual.componentId().value(),
|
||||
reason + "; found '"
|
||||
+ actual.componentId().value() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private static String stripTrailingComment(String line) {
|
||||
int commentStart = line.indexOf('#');
|
||||
return commentStart < 0 ? line : line.substring(0, commentStart);
|
||||
}
|
||||
|
||||
private static IllegalArgumentException invalidLine(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String value,
|
||||
String reason) {
|
||||
return invalidLine(path, lineNumber, value, reason, null);
|
||||
}
|
||||
|
||||
private static IllegalArgumentException invalidLine(
|
||||
Path path,
|
||||
int lineNumber,
|
||||
String value,
|
||||
String reason,
|
||||
Exception cause) {
|
||||
return new IllegalArgumentException(
|
||||
path + ":" + lineNumber + ": Invalid Nenjim Hub "
|
||||
+ "configuration value '" + value + "': " + reason,
|
||||
cause);
|
||||
}
|
||||
|
||||
private record ParsedProcess(
|
||||
NenjimComponentId componentId,
|
||||
int lineNumber) {
|
||||
}
|
||||
|
||||
private enum ParserState {
|
||||
EXPECT_FORMAT_VERSION,
|
||||
EXPECT_AUTO_START,
|
||||
IN_AUTO_START,
|
||||
AFTER_AUTO_START
|
||||
}
|
||||
|
||||
private static final int SUPPORTED_FORMAT_VERSION = 1;
|
||||
private static final String FORMAT_VERSION_KEY = "FORMAT_VERSION";
|
||||
private static final String FORMAT_VERSION_DECLARATION =
|
||||
FORMAT_VERSION_KEY + "=" + SUPPORTED_FORMAT_VERSION;
|
||||
private static final String AUTO_START_HEADER = "[AUTO_START]";
|
||||
private static final Pattern FORMAT_VERSION_PATTERN =
|
||||
Pattern.compile(FORMAT_VERSION_KEY + "=(\\d+)");
|
||||
|
||||
private NenjimHubConfigurationParser() {
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import com.r35157.nenjim.hubd.NenjimHub;
|
||||
import com.r35157.nenjim.npm.NenjimProcessManager;
|
||||
import com.r35157.nenjim.npm.impl.ref.NenjimProcessManagerImpl;
|
||||
import com.r35157.nenjim.process.NenjimProcess;
|
||||
import com.r35157.nenjim.service.journal.JournalService;
|
||||
import com.r35157.nenjim.service.journal.JournalServiceManager;
|
||||
import com.r35157.nenjim.service.journal.impl.ref.JournalServiceAssembly;
|
||||
import com.r35157.nenjim.service.registry.NenjimRegistryService;
|
||||
@@ -58,7 +57,10 @@ import java.nio.file.Path;
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -74,10 +76,19 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
"NenjimHub start has already been attempted");
|
||||
}
|
||||
|
||||
log.info("Initializing Nenjim Registry and components...");
|
||||
Map<NenjimComponentId, ProcessConstructor> processConstructors =
|
||||
createProcessConstructorCatalogue();
|
||||
NenjimHubConfiguration configuration =
|
||||
NenjimHubConfigurationParser.parse(
|
||||
HUB_CONFIGURATION_PATH,
|
||||
selectableProcessIds(processConstructors),
|
||||
REGISTRY_SERVICE_ID,
|
||||
JOURNAL_SERVICE_ID);
|
||||
|
||||
log.info("Initializing Nenjim Registry...");
|
||||
NenjimRegistryAssembly registryAssembly =
|
||||
NenjimRegistryAssembly.create();
|
||||
NenjimRegistryService registryService =
|
||||
registryService =
|
||||
registryAssembly.registryService();
|
||||
NenjimProcess registryProcess = registryAssembly.registryProcess();
|
||||
registryServiceManager = registryAssembly.registryServiceManager();
|
||||
@@ -87,19 +98,19 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
REGISTRY_SERVICE_ID,
|
||||
registryService);
|
||||
recordStartedProcess(REGISTRY_SERVICE_ID);
|
||||
initializeAndStartJournal(registryServiceManager);
|
||||
initializeAndRegisterComponents(
|
||||
registryService,
|
||||
registryServiceManager);
|
||||
|
||||
log.info("Starting explicitly enabled Nenjim processes...");
|
||||
startProcess(registryService, TICKER_SERVICE_ID);
|
||||
startProcess(registryService, EVELYN_SERVICE_PROD_ID);
|
||||
startProcess(registryService, EVELYN_SERVICE_TEST_ID);
|
||||
startProcess(registryService, EVELYN_IOU_BURNER_PROD_ID);
|
||||
startProcess(registryService, JAVAFX_RUNTIME_SERVICE_ID);
|
||||
startProcess(registryService, EVELYN_MISSION_CONTROL_ID);
|
||||
startProcess(registryService, PROCESS_MANAGER_ID);
|
||||
log.info("Initializing passive Nenjim components...");
|
||||
initializeAndRegisterPassiveComponents(registryServiceManager);
|
||||
|
||||
log.info("Constructing and starting configured Nenjim processes...");
|
||||
for (NenjimComponentId componentId
|
||||
: configuration.autoStartProcessIds().subList(
|
||||
1,
|
||||
configuration.autoStartProcessIds().size())) {
|
||||
constructRegisterAndStartProcess(
|
||||
componentId,
|
||||
processConstructors);
|
||||
}
|
||||
|
||||
System.out.println("Done - Now online!");
|
||||
|
||||
@@ -112,29 +123,18 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
return List.copyOf(startedProcessIds);
|
||||
}
|
||||
|
||||
private void initializeAndStartJournal(
|
||||
NenjimRegistryServiceManager registryServiceManager)
|
||||
throws Exception {
|
||||
private NenjimProcess constructJournalProcess() {
|
||||
JournalServiceAssembly journalAssembly =
|
||||
JournalServiceAssembly.create(JOURNAL_ROOT);
|
||||
JournalService journalService = journalAssembly.journalService();
|
||||
NenjimProcess journalProcess = journalAssembly.journalProcess();
|
||||
journalServiceManager = journalAssembly.journalServiceManager();
|
||||
|
||||
registryServiceManager.registerComponent(
|
||||
JOURNAL_SERVICE_ID,
|
||||
journalService);
|
||||
journalProcess.start();
|
||||
recordStartedProcess(JOURNAL_SERVICE_ID);
|
||||
return journalAssembly.journalProcess();
|
||||
}
|
||||
|
||||
private void initializeAndRegisterComponents(
|
||||
NenjimRegistryService registryService,
|
||||
private void initializeAndRegisterPassiveComponents(
|
||||
NenjimRegistryServiceManager registryServiceManager) {
|
||||
initializeBuildingBlocks(registryServiceManager);
|
||||
initializePriceSources(registryServiceManager);
|
||||
initializeServices(registryService, registryServiceManager);
|
||||
initializeApplications(registryServiceManager);
|
||||
initializePassiveServices(registryServiceManager);
|
||||
}
|
||||
|
||||
private void initializeBuildingBlocks(
|
||||
@@ -199,15 +199,8 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
raydiumPoolPriceSource);
|
||||
}
|
||||
|
||||
private void initializeServices(
|
||||
NenjimRegistryService registryService,
|
||||
private void initializePassiveServices(
|
||||
NenjimRegistryServiceManager registryServiceManager) {
|
||||
tickerService = new TickerServiceImpl(
|
||||
registryService,
|
||||
RAYDIUM_POOL_PRICE_SOURCE_ID
|
||||
);
|
||||
registryServiceManager.registerComponent(TICKER_SERVICE_ID, tickerService);
|
||||
|
||||
jupiterServicePerpsProd = new AnchorIdlJupiterPerpsServiceImpl(
|
||||
cachedSolanaBlockChain,
|
||||
solanaWalletEvelynPerpsProd,
|
||||
@@ -226,21 +219,6 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
JUPITER_PERPS_EVELYN_TEST_ID,
|
||||
jupiterServicePerpsTest);
|
||||
|
||||
jupiterPerpsAlarm = new JupiterPerpsAlarmImpl(
|
||||
solanaWalletEvelynPerpsTest,
|
||||
jupiterServicePerpsTest,
|
||||
"--config=conf/alarms.conf"
|
||||
);
|
||||
registryServiceManager.registerComponent(
|
||||
JUPITER_PERPS_ALARM_ID,
|
||||
jupiterPerpsAlarm);
|
||||
|
||||
evelynServiceProd = new EvelynImpl("Production", tickerService, eveUSDT, clockUTC);
|
||||
registryServiceManager.registerComponent(EVELYN_SERVICE_PROD_ID, evelynServiceProd);
|
||||
|
||||
evelynServiceTest = new EvelynImpl("Test", tickerService, eveUSDT, clockUTC);
|
||||
registryServiceManager.registerComponent(EVELYN_SERVICE_TEST_ID, evelynServiceTest);
|
||||
|
||||
jupiterSwapService = new JupiterSwapServiceImpl(solanaBlockChain, solanaWalletEvelynBurnerProd);
|
||||
registryServiceManager.registerComponent(
|
||||
JUPITER_SWAP_EVELYN_BURNER_PROD_ID,
|
||||
@@ -254,16 +232,64 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
registryServiceManager.registerComponent(
|
||||
DISCORD_ASSETAZ_TOKEN_NOTIFICATION_ID,
|
||||
discordAssetAZTokenNotificationService);
|
||||
}
|
||||
|
||||
private NenjimProcess constructTickerProcess() {
|
||||
TickerServiceImpl process = new TickerServiceImpl(
|
||||
registryService,
|
||||
RAYDIUM_POOL_PRICE_SOURCE_ID);
|
||||
tickerService = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private NenjimProcess constructJupiterPerpsAlarmProcess() {
|
||||
JupiterPerpsAlarmImpl process = new JupiterPerpsAlarmImpl(
|
||||
solanaWalletEvelynPerpsTest,
|
||||
jupiterServicePerpsTest,
|
||||
"--config=conf/alarms.conf");
|
||||
jupiterPerpsAlarm = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private NenjimProcess constructEvelynProdProcess() {
|
||||
EvelynImpl process = new EvelynImpl(
|
||||
"Production",
|
||||
requireProcessDependency(
|
||||
tickerService,
|
||||
EVELYN_SERVICE_PROD_ID,
|
||||
TICKER_SERVICE_ID),
|
||||
eveUSDT,
|
||||
clockUTC);
|
||||
evelynServiceProd = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private NenjimProcess constructEvelynTestProcess() {
|
||||
EvelynImpl process = new EvelynImpl(
|
||||
"Test",
|
||||
requireProcessDependency(
|
||||
tickerService,
|
||||
EVELYN_SERVICE_TEST_ID,
|
||||
TICKER_SERVICE_ID),
|
||||
eveUSDT,
|
||||
clockUTC);
|
||||
evelynServiceTest = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private NenjimProcess constructEvelynIOUBurnerProdProcess() {
|
||||
List<MoneyAmount> burnTokenCandidates = List.of(new MoneyAmount(new ΩAmountΩ("0.1"), cis.resolve(CurrencyTypeIds.USDT_ID)));
|
||||
|
||||
ΩUSDCAmountΩ maximumSwapAmountPerIterationInUSD = new ΩUSDCAmountΩ("0.25");
|
||||
|
||||
evelynIOUBurnerServiceProd = new EvelynIOUBurnerServiceImpl(
|
||||
EvelynIOUBurnerServiceImpl process = new EvelynIOUBurnerServiceImpl(
|
||||
solanaWalletEvelynBurnerProd,
|
||||
jupiterSwapService,
|
||||
solanaBlockChain,
|
||||
tickerService,
|
||||
requireProcessDependency(
|
||||
tickerService,
|
||||
EVELYN_IOU_BURNER_PROD_ID,
|
||||
TICKER_SERVICE_ID),
|
||||
cis,
|
||||
discordAssetAZTokenNotificationService,
|
||||
burnTokenCandidates,
|
||||
@@ -273,32 +299,109 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
Duration.ofSeconds(10),
|
||||
Duration.ofHours(1)
|
||||
);
|
||||
registryServiceManager.registerComponent(
|
||||
EVELYN_IOU_BURNER_PROD_ID,
|
||||
evelynIOUBurnerServiceProd);
|
||||
evelynIOUBurnerServiceProd = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private void initializeApplications(
|
||||
NenjimRegistryServiceManager registryServiceManager) {
|
||||
javaFxRuntimeService = new JavaFxRuntimeServiceImpl();
|
||||
registryServiceManager.registerComponent(
|
||||
JAVAFX_RUNTIME_SERVICE_ID,
|
||||
javaFxRuntimeService);
|
||||
private NenjimProcess constructJavaFxRuntimeProcess() {
|
||||
JavaFxRuntimeServiceImpl process = new JavaFxRuntimeServiceImpl();
|
||||
javaFxRuntimeService = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
missionControl = new EvelynMissionControlImpl(
|
||||
evelynServiceProd,
|
||||
evelynServiceTest,
|
||||
javaFxRuntimeService);
|
||||
registryServiceManager.registerComponent(
|
||||
EVELYN_MISSION_CONTROL_ID,
|
||||
missionControl);
|
||||
private NenjimProcess constructMissionControlProcess() {
|
||||
EvelynMissionControlImpl process = new EvelynMissionControlImpl(
|
||||
requireProcessDependency(
|
||||
evelynServiceProd,
|
||||
EVELYN_MISSION_CONTROL_ID,
|
||||
EVELYN_SERVICE_PROD_ID),
|
||||
requireProcessDependency(
|
||||
evelynServiceTest,
|
||||
EVELYN_MISSION_CONTROL_ID,
|
||||
EVELYN_SERVICE_TEST_ID),
|
||||
requireProcessDependency(
|
||||
javaFxRuntimeService,
|
||||
EVELYN_MISSION_CONTROL_ID,
|
||||
JAVAFX_RUNTIME_SERVICE_ID));
|
||||
missionControl = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
processManager = new NenjimProcessManagerImpl(
|
||||
private NenjimProcess constructProcessManagerProcess() {
|
||||
NenjimProcessManagerImpl process = new NenjimProcessManagerImpl(
|
||||
this,
|
||||
javaFxRuntimeService);
|
||||
registryServiceManager.registerComponent(
|
||||
PROCESS_MANAGER_ID,
|
||||
processManager);
|
||||
requireProcessDependency(
|
||||
javaFxRuntimeService,
|
||||
PROCESS_MANAGER_ID,
|
||||
JAVAFX_RUNTIME_SERVICE_ID));
|
||||
processManager = process;
|
||||
return process;
|
||||
}
|
||||
|
||||
private void constructRegisterAndStartProcess(
|
||||
NenjimComponentId componentId,
|
||||
Map<NenjimComponentId, ProcessConstructor> processConstructors)
|
||||
throws Exception {
|
||||
ProcessConstructor constructor = processConstructors.get(componentId);
|
||||
if (constructor == null) {
|
||||
throw new IllegalStateException(
|
||||
"Validated Nenjim process '" + componentId.value()
|
||||
+ "' has no constructor");
|
||||
}
|
||||
|
||||
NenjimProcess process = constructor.construct();
|
||||
registryServiceManager.registerComponent(componentId, process);
|
||||
startProcess(registryService, componentId);
|
||||
}
|
||||
|
||||
private Map<NenjimComponentId, ProcessConstructor>
|
||||
createProcessConstructorCatalogue() {
|
||||
return Map.ofEntries(
|
||||
Map.entry(JOURNAL_SERVICE_ID, this::constructJournalProcess),
|
||||
Map.entry(TICKER_SERVICE_ID, this::constructTickerProcess),
|
||||
Map.entry(
|
||||
JUPITER_PERPS_ALARM_ID,
|
||||
this::constructJupiterPerpsAlarmProcess),
|
||||
Map.entry(
|
||||
EVELYN_SERVICE_PROD_ID,
|
||||
this::constructEvelynProdProcess),
|
||||
Map.entry(
|
||||
EVELYN_SERVICE_TEST_ID,
|
||||
this::constructEvelynTestProcess),
|
||||
Map.entry(
|
||||
EVELYN_IOU_BURNER_PROD_ID,
|
||||
this::constructEvelynIOUBurnerProdProcess),
|
||||
Map.entry(
|
||||
JAVAFX_RUNTIME_SERVICE_ID,
|
||||
this::constructJavaFxRuntimeProcess),
|
||||
Map.entry(
|
||||
EVELYN_MISSION_CONTROL_ID,
|
||||
this::constructMissionControlProcess),
|
||||
Map.entry(
|
||||
PROCESS_MANAGER_ID,
|
||||
this::constructProcessManagerProcess));
|
||||
}
|
||||
|
||||
private static Set<NenjimComponentId> selectableProcessIds(
|
||||
Map<NenjimComponentId, ProcessConstructor> processConstructors) {
|
||||
Set<NenjimComponentId> processIds =
|
||||
new HashSet<>(processConstructors.keySet());
|
||||
processIds.add(REGISTRY_SERVICE_ID);
|
||||
return Set.copyOf(processIds);
|
||||
}
|
||||
|
||||
private static <T> T requireProcessDependency(
|
||||
T dependency,
|
||||
NenjimComponentId processId,
|
||||
NenjimComponentId dependencyId) {
|
||||
if (dependency == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot construct configured Nenjim process '"
|
||||
+ processId.value() + "': required predecessor '"
|
||||
+ dependencyId.value()
|
||||
+ "' has not been constructed");
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
private void startProcess(
|
||||
@@ -328,8 +431,15 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
System.out.println("Nenjim is now shut down!");
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ProcessConstructor {
|
||||
NenjimProcess construct() throws Exception;
|
||||
}
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(
|
||||
NenjimHubImpl.class);
|
||||
private static final Path HUB_CONFIGURATION_PATH =
|
||||
Path.of("conf/NenjimHub.conf");
|
||||
private static final NenjimComponentId REGISTRY_SERVICE_ID =
|
||||
new NenjimComponentId("nenjim.registry.service");
|
||||
private static final NenjimComponentId JOURNAL_SERVICE_ID =
|
||||
@@ -386,6 +496,7 @@ public final class NenjimHubImpl implements NenjimHub {
|
||||
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||
private final AtomicBoolean startAttempted = new AtomicBoolean();
|
||||
private final List<NenjimComponentId> startedProcessIds = new ArrayList<>();
|
||||
private NenjimRegistryService registryService;
|
||||
private NenjimRegistryServiceManager registryServiceManager;
|
||||
private JournalServiceManager journalServiceManager;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user