76: Introduce the Nenjim component registry and move runtime composition into its manager

This commit is contained in:
2026-08-29 17:20:19 +02:00
parent b230e15ece
commit 8fa9ce3dec
52 changed files with 1240 additions and 454 deletions
@@ -1,5 +1,6 @@
package com.fanitas.evelyn.core;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -7,7 +8,7 @@ import java.util.List;
/**
* Collects and exposes the status-index history for one named Evelyn instance.
*/
public interface Evelyn extends AutoCloseable {
public interface Evelyn extends NenjimComponent, AutoCloseable {
/**
* Executes the legacy Evelyn service operation.
*
@@ -15,6 +15,7 @@ import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.assetaz.services.ticker.PriceObservation;
import com.r35157.assetaz.services.ticker.TickerService;
import com.r35157.nenjim.component.NenjimApplication;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,7 +46,7 @@ import java.util.concurrent.ConcurrentHashMap;
import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.SPL_TOKEN_PROGRAM;
import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.TOKEN_2022_PROGRAM;
public class EvelynImpl implements Evelyn {
public class EvelynImpl implements Evelyn, NenjimApplication {
public EvelynImpl(
@NotNull String instanceName,
@@ -1,6 +1,7 @@
package com.fanitas.evelyn.service.burner;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.nenjim.component.NenjimComponent;
import java.util.List;
@@ -66,7 +67,7 @@ import java.util.List;
* weaken duplicate prevention; operators should reconcile uncertain on-chain
* activity before deliberately restarting a suspended or pending service.</p>
*/
public interface EvelynIOUBurnerService {
public interface EvelynIOUBurnerService extends NenjimComponent {
/**
* Starts the dedicated worker and begins the first iteration immediately.
*
@@ -18,6 +18,7 @@ import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.nenjim.component.NenjimApplication;
import com.r35157.service.notification.BoundNotificationService;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
@@ -48,7 +49,7 @@ import static com.r35157.assetaz.services.cis.ExternalCurrencyReference.SOLANA_M
* Reference implementation of the Evelyn IOU buyback-and-burn lifecycle.
*/
public final class EvelynIOUBurnerServiceImpl
implements EvelynIOUBurnerService {
implements EvelynIOUBurnerService, NenjimApplication {
/**
* Creates an Evelyn IOU burner with all runtime dependencies and current
* operating policy.
@@ -1,6 +1,7 @@
package com.r35157.assetaz.services.cis;
import com.r35157.assetaz.valuetypes.CurrencyType;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
@@ -20,7 +21,7 @@ import java.util.UUID;
* {@link CurrencyType} instances, but callers must compare currency values with
* {@link Object#equals(Object)} rather than reference identity.</p>
*/
public interface CurrencyIdentityService {
public interface CurrencyIdentityService extends NenjimComponent {
/**
* Resolves an AssetAZ currency UUID to its current currency metadata.
*
@@ -1,12 +1,13 @@
package com.r35157.assetaz.services.ticker;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
/**
* Provides price observations for trading pairs.
*/
public interface TickerService {
public interface TickerService extends NenjimComponent {
/**
* Starts the ticker service.
@@ -1,11 +1,14 @@
package com.r35157.assetaz.services.ticker.impl.ref;
import com.r35157.assetaz.services.ticker.PriceObservation;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.TickerService;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.nenjim.component.NenjimApplication;
import com.r35157.nenjim.service.registry.NenjimRegistryService;
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,11 +39,28 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public final class TickerServiceImpl implements TickerService, PriceSink {
public TickerServiceImpl(PriceSource... priceSources) {
public final class TickerServiceImpl implements
TickerService,
PriceSink,
NenjimApplication {
public TickerServiceImpl(
@NotNull NenjimRegistryService registryService,
@NotNull NenjimComponentId... priceSourceIds) {
this(DATA_ROOT);
for (PriceSource priceSource : priceSources) {
Objects.requireNonNull(registryService, "registryService");
Objects.requireNonNull(priceSourceIds, "priceSourceIds");
for (NenjimComponentId priceSourceId : priceSourceIds) {
Objects.requireNonNull(priceSourceId, "priceSourceId");
PriceSource priceSource = registryService.getComponent(
priceSourceId,
PriceSource.class);
if (priceSource == null) {
throw new IllegalArgumentException(
"Required Nenjim component '" + priceSourceId.value()
+ "' is not registered as "
+ PriceSource.class.getName());
}
addPriceSource(priceSource);
}
}
@@ -1,4 +1,4 @@
package com.r35157.assetaz.services.ticker.plugins.pricesource;
package com.r35157.assetaz.services.ticker.pricesource;
import org.jetbrains.annotations.NotNull;
@@ -1,12 +1,13 @@
package com.r35157.assetaz.services.ticker.plugins.pricesource;
package com.r35157.assetaz.services.ticker.pricesource;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
/**
* Obtains prices for one trading pair and announces them to a {@link PriceSink}.
*/
public interface PriceSource {
public interface PriceSource extends NenjimComponent {
@NotNull TradingPair getTradingPair();
@@ -1,7 +1,7 @@
package com.r35157.assetaz.services.ticker.plugins.pricesource.impl.hardcoded;
package com.r35157.assetaz.services.ticker.pricesource.impl.hardcoded;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.pricesource.PriceSource;
import com.r35157.assetaz.services.cis.CurrencyIdentityService;
import com.r35157.libs.valuetypes.basic.TradingPair;
import org.jetbrains.annotations.NotNull;
@@ -1,7 +1,7 @@
package com.r35157.assetaz.services.ticker.plugins.pricesource.impl.raydiumpool;
package com.r35157.assetaz.services.ticker.pricesource.impl.raydiumpool;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.pricesource.PriceSink;
import com.r35157.assetaz.services.ticker.pricesource.PriceSource;
import com.r35157.libs.raydium.Raydium;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.TradingPair;
@@ -2,6 +2,7 @@ package com.r35157.cryptowallet.solana;
import com.r35157.libs.solana.SolanaSignedTransaction;
import com.r35157.libs.solana.SolanaUnsignedTransaction;
import com.r35157.nenjim.component.NenjimComponent;
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import org.jetbrains.annotations.NotNull;
@@ -17,7 +18,7 @@ import java.math.BigDecimal;
* <p>Signing and submission can be performed separately or as one complete
* operation.</p>
*/
public interface SolanaWallet {
public interface SolanaWallet extends NenjimComponent {
/**
* Returns the public Solana address controlled by this wallet.
*
@@ -1,5 +1,7 @@
package com.r35157.evelyn.emc;
public interface EvelynMissionControl {
import com.r35157.nenjim.component.NenjimComponent;
public interface EvelynMissionControl extends NenjimComponent {
void start();
}
@@ -4,6 +4,8 @@ import com.fanitas.evelyn.core.Evelyn;
import com.fanitas.evelyn.core.EvelynStatusIndexPoint;
import com.r35157.evelyn.emc.EvelynMissionControl;
import com.r35157.libs.javafx.JavaFxRuntime;
import com.r35157.nenjim.component.NenjimApplication;
import org.jetbrains.annotations.NotNull;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
@@ -26,9 +28,14 @@ import java.util.List;
import java.util.Objects;
import java.util.function.Function;
public final class EvelynMissionControlImpl implements EvelynMissionControl {
public final class EvelynMissionControlImpl implements
EvelynMissionControl,
NenjimApplication {
public EvelynMissionControlImpl(Evelyn evelynServiceProd, Evelyn evelynServiceTest) {
public EvelynMissionControlImpl(
@NotNull Evelyn evelynServiceProd,
@NotNull Evelyn evelynServiceTest
) {
this.evelynProd = Objects.requireNonNull(evelynServiceProd, "evelynServiceProd");
this.evelynTest = Objects.requireNonNull(evelynServiceTest, "evelynServiceTest");
refreshTimeline.setCycleCount(Timeline.INDEFINITE);
@@ -1,5 +1,7 @@
package com.r35157.jupiterperpsalarm;
import com.r35157.nenjim.component.NenjimComponent;
/**
* Monitors configured Jupiter Perps prices and dispatches matching alarm
* actions.
@@ -9,7 +11,7 @@ package com.r35157.jupiterperpsalarm;
* wallet is observed and used for transaction actions; alarm action files do
* not select them.</p>
*/
public interface JupiterPerpsAlarm {
public interface JupiterPerpsAlarm extends NenjimComponent {
/**
* Starts alarm monitoring asynchronously.
*
@@ -3,6 +3,7 @@ package com.r35157.jupiterperpsalarm.impl.ref;
import com.r35157.cryptowallet.solana.SolanaWallet;
import com.r35157.jupiterperpsalarm.JupiterPerpsAlarm;
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
import com.r35157.nenjim.component.NenjimApplication;
import org.jetbrains.annotations.NotNull;
import java.net.URI;
@@ -15,7 +16,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
public final class JupiterPerpsAlarmImpl implements JupiterPerpsAlarm {
public final class JupiterPerpsAlarmImpl implements
JupiterPerpsAlarm,
NenjimApplication {
public JupiterPerpsAlarmImpl(
@NotNull SolanaWallet solanaWallet,
@@ -43,7 +46,7 @@ public final class JupiterPerpsAlarmImpl implements JupiterPerpsAlarm {
} catch (Throwable throwable) {
throwable.printStackTrace(System.err);
}
}, "Nenjim Plugin - JupiterPerpsAlarm");
}, "Nenjim Component - JupiterPerpsAlarm");
this.thread.setDaemon(false);
}
@@ -254,9 +257,10 @@ public final class JupiterPerpsAlarmImpl implements JupiterPerpsAlarm {
private void printUsage() {
System.err.println("""
JupiterPerpsAlarmImpl is constructed and started by NenjimHubImpl.
JupiterPerpsAlarmImpl is constructed and registered by the Nenjim Registry service manager.
It is intentionally excluded from the current explicit startup list.
Current Hub configuration:
Current registered configuration:
--config=conf/alarms.conf
Environment:
@@ -1,6 +1,7 @@
package com.r35157.libs.jupiter.perps;
import com.r35157.libs.jupiter.JupiterTransactionOutcomeException;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -16,7 +17,7 @@ import java.util.Set;
* configured wallet is responsible for signing them. Position operations
* return normally only after independent Solana {@code CONFIRMED} success.</p>
*/
public interface JupiterPerpsService {
public interface JupiterPerpsService extends NenjimComponent {
/**
* Reads a Jupiter Perps position from a known position account.
*
@@ -2,6 +2,7 @@ package com.r35157.libs.jupiter.swap;
import com.r35157.libs.jupiter.JupiterTransactionOutcomeException;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -24,7 +25,7 @@ import java.math.BigDecimal;
* endpoint, and independently awaits Solana confirmation. Legacy SPL-token
* and Token-2022 behavior is unchanged.</p>
*/
public interface JupiterSwapService {
public interface JupiterSwapService extends NenjimComponent {
/**
* Swaps an exact amount of a supported token or native SOL into an SPL
* token.
@@ -1,12 +1,13 @@
package com.r35157.libs.objcache;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Stores objects under structured keys for a caller-supplied time to live.
*/
public interface ObjectCache {
public interface ObjectCache extends NenjimComponent {
/**
* Stores or replaces an object.
@@ -3,12 +3,13 @@ package com.r35157.libs.raydium;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.Range;
import com.r35157.nenjim.component.NenjimComponent;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Set;
public interface Raydium {
public interface Raydium extends NenjimComponent {
/**
* Fetches the current price for a Raydium liquidity pool.
*
@@ -3,6 +3,7 @@ package com.r35157.libs.solana;
import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress;
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.nenjim.component.NenjimComponent;
import java.io.IOException;
import java.time.Duration;
@@ -21,7 +22,7 @@ import java.util.Set;
* logic. Higher-level integrations are expected to interpret Solana accounts,
* token holdings and derived addresses according to their own domain rules.</p>
*/
public interface SolanaBlockChain {
public interface SolanaBlockChain extends NenjimComponent {
/**
* Fetches the native SOL balance for a Solana address.
*
@@ -0,0 +1,6 @@
package com.r35157.nenjim.component;
/** A Nenjim component with an active start lifecycle. */
public interface NenjimApplication extends NenjimComponent {
void start() throws Exception;
}
@@ -0,0 +1,5 @@
package com.r35157.nenjim.component;
/** Marker for a constructed Nenjim component that is ready for use. */
public interface NenjimComponent {
}
@@ -0,0 +1,16 @@
package com.r35157.nenjim.hubd;
import com.r35157.nenjim.component.NenjimApplication;
import com.r35157.nenjim.service.registry.impl.ref.NenjimRegistryServiceManagerImpl;
import org.jetbrains.annotations.NotNull;
public final class Main {
private Main() {
}
public static void main(@NotNull String[] args) throws Exception {
NenjimApplication registryServiceManager =
new NenjimRegistryServiceManagerImpl();
registryServiceManager.start();
}
}
@@ -1,43 +0,0 @@
package com.r35157.nenjim.hubd;
import crypto.r35157.nenjim.NenjimProcess;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
/**
* Coordinates the lifecycle of Nenjim services and applications.
*/
public interface NenjimHub {
/**
* Starts all initialized services and applications in dependency order,
* then blocks while the Hub remains online.
*
* @throws Exception if startup or shutdown waiting fails
*/
void start() throws Exception;
/**
* Requests startup of the implementation bound to a fully qualified process
* interface name in the active context.
*
* <p>Dynamic binding through this method is not yet implemented by the
* reference Hub.</p>
*
* @param fqInterfaceName fully qualified interface name; the interface must
* extend {@link NenjimProcess}
*/
void startProcess(String fqInterfaceName);
/**
* Provides a map of all running processes managed by the NenjimHub, keyed by the processId.
*
* @return a map of {@code NenjimProcess} running processes
*/
HashMap<Integer, NenjimProcess> getRunningProcesses();
/**
* Performs no operation.
*/
void noop();
}
@@ -1,12 +0,0 @@
package com.r35157.nenjim.hubd.impl.ref;
import com.r35157.nenjim.hubd.NenjimHub;
public class Main {
// TODO: Consider if we really need a Main class or we just need to move the main method to NenjimHubImpl?
static void main() throws Exception {
NenjimHub nenjimHub = new NenjimHubImpl();
nenjimHub.start();
}
}
@@ -1,324 +0,0 @@
package com.r35157.nenjim.hubd.impl.ref;
import com.fanitas.evelyn.core.Evelyn;
import com.fanitas.evelyn.core.impl.ref.EvelynImpl;
import com.fanitas.evelyn.service.burner.EvelynIOUBurnerService;
import com.fanitas.evelyn.service.burner.impl.ref.EvelynIOUBurnerServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r35157.assetaz.services.cis.CurrencyTypeIds;
import com.r35157.assetaz.services.ticker.plugins.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.TickerService;
import com.r35157.assetaz.services.ticker.plugins.pricesource.impl.hardcoded.HardcodedPriceSource;
import com.r35157.assetaz.services.ticker.plugins.pricesource.impl.raydiumpool.RaydiumPoolPriceSource;
import com.r35157.assetaz.services.ticker.impl.ref.TickerServiceImpl;
import com.r35157.assetaz.services.cis.CurrencyIdentityService;
import com.r35157.assetaz.services.cis.impl.hc.HardcodedCurrencyIdentityService;
import com.r35157.cryptowallet.solana.SolanaWallet;
import com.r35157.cryptowallet.solana.impl.ref.SolanaWalletImpl;
import com.r35157.evelyn.emc.EvelynMissionControl;
import com.r35157.evelyn.emc.impl.ref.EvelynMissionControlImpl;
import com.r35157.jupiterperpsalarm.JupiterPerpsAlarm;
import com.r35157.jupiterperpsalarm.impl.ref.JupiterPerpsAlarmImpl;
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
import com.r35157.libs.jupiter.perps.impl.anchoridl.AnchorIdlJupiterPerpsServiceImpl;
import com.r35157.libs.jupiter.swap.JupiterSwapService;
import com.r35157.libs.jupiter.swap.impl.ref.JupiterSwapServiceImpl;
import com.r35157.libs.objcache.ObjectCache;
import com.r35157.libs.objcache.impl.ref.ObjectCacheImpl;
import com.r35157.libs.solana.impl.cached.CachedSolanaBlockChain;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.nenjim.composer.NenjimComposer;
import com.r35157.nenjim.composer.impl.ref.NenjimComposerImpl;
import com.r35157.nenjim.hubd.NenjimHub;
import com.r35157.nenjim.npm.NenjimProcessManager;
import com.r35157.nenjim.npm.impl.ref.NenjimProcessManagerImpl;
import com.r35157.nenjim.ntt.NenjimTestTool;
import com.r35157.nenjim.ntt.impl.ref.NenjimTestToolImpl;
import com.r35157.libs.raydium.Raydium;
import com.r35157.libs.raydium.impl.ref.RaydiumImpl;
import com.r35157.libs.solana.SolanaBlockChain;
import com.r35157.libs.solana.impl.ref.SolanaBlockChainImpl;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.service.notification.BoundNotificationService;
import com.r35157.service.notification.impl.discord.DiscordNotificationServiceImpl;
import com.r35157.stm.SodaTaskManager;
import com.r35157.stm.impl.ref.SodaTaskManagerImpl;
import com.r35157.suwimo.hub.client.SuwimoClient;
import com.r35157.suwimo.hub.client.impl.j2fx.SuwimoClientImpl;
import crypto.r35157.nenjim.NenjimProcess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.time.Clock;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import static com.r35157.assetaz.services.cis.CurrencyTypeIds.EVE_ID;
import static com.r35157.assetaz.services.cis.CurrencyTypeIds.USDT_ID;
public class NenjimHubImpl implements NenjimHub {
public NenjimHubImpl() {
log.info("Initializing NenjimHub...");
initializeAll();
nextProcessId = 1;
//processesScope = new StructuredTaskScope.ShutdownOnFailure();
processes = new HashMap<>();
}
@Override
public void start() throws Exception {
log.info("Starting:");
log.info(" Services...");
tickerService.start();
//jupiterPerpsAlarm.start();
evelynServiceProd.start();
evelynServiceTest.start();
evelynIOUBurnerServiceProd.start();
log.info(" Applications...");
missionControl.start();
//nenjimComposer.start();
//processManager.start();
//testTool.start();
//sodaTaskManager.start();
//suwimoClient.start();
System.out.println("Done - Now online!");
waitForAndShutdown();
}
@Override
public HashMap<Integer, NenjimProcess> getRunningProcesses() {
return processes;
}
@Override
public void noop() {
System.out.println("NenjimHub command: 'noop'");
}
@Override
public void startProcess(String className) {
ClassLoader loader = ClassLoader.getSystemClassLoader();
/*processesScope.fork(() -> {
Class<?> clazz = loader.loadClass(className);
if (!NenjimProcess.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException("'" + className + "' does NOT implement NenjimProcess");
}
NenjimProcess proc = (NenjimProcess) clazz.getDeclaredConstructor().newInstance();
processes.put(nextProcessId, proc);
nextProcessId++;
NenjimContext context = new NenjimContext() { };
proc.setNenjimProcessContext(context);
proc.setNenjimHub(this);
Thread.currentThread().setName(proc.getProcessName());
System.out.println(" Starter Nenjim process '" + proc.getProcessName() + "'");
proc.run();
return null;
});*/
}
private void initializeAll() {
log.info(" Initializing building blocks...");
initializeBuildingBlocks();
log.info(" Initializing plugins...");
initializePlugins();
log.info(" Initializing services...");
initializeServices();
log.info(" Initializing applications...");
initializeApplications();
}
private void initializeBuildingBlocks() {
objectCache = new ObjectCacheImpl();
clockUTC = Clock.systemUTC();
cis = new HardcodedCurrencyIdentityService();
httpClient = HttpClient.newHttpClient();
objectMapper = new ObjectMapper();
solanaBlockChain = new SolanaBlockChainImpl(httpClient, objectMapper, cis);
cachedSolanaBlockChain = new CachedSolanaBlockChain(solanaBlockChain, objectCache);
raydium = new RaydiumImpl(httpClient, objectMapper, cachedSolanaBlockChain, cis);
eveUSDT = new TradingPair(cis.resolve(EVE_ID), cis.resolve(USDT_ID));
solanaWalletEvelynPerpsTest = new SolanaWalletImpl(
"6NyYEoXmJyBXvU4pvv9aoxZNdyqqtkmPBZFEDkRDHcqp",
"evelyn_perps_test",
solanaBlockChain
);
solanaWalletEvelynPerpsProd = new SolanaWalletImpl(
"H5Yrdm7B4FHhTxhPw9SVwFzQyTEL6bAPptZuTyRxcepq",
"evelyn_perps_prod",
solanaBlockChain
);
solanaWalletEvelynBurnerProd = new SolanaWalletImpl(
"5kjVTc1rebYHg56NyTxSSN1XMKqT2E81eWiaSx1CmzmV",
"evelyn_burner_prod",
solanaBlockChain
);
}
private void initializePlugins() {
hardcodedPriceSource = new HardcodedPriceSource(cis);
raydiumPoolPriceSource = new RaydiumPoolPriceSource(raydium, EVE_USDT_RAYDIUM_POOL_ID, eveUSDT);
}
private void initializeServices() {
tickerService = new TickerServiceImpl(
//hardcodedPriceSource, // Activating this could be dangerous as other services rely on these prices
raydiumPoolPriceSource
);
jupiterServicePerpsProd = new AnchorIdlJupiterPerpsServiceImpl(
cachedSolanaBlockChain,
solanaWalletEvelynPerpsProd,
cis
);
jupiterServicePerpsTest = new AnchorIdlJupiterPerpsServiceImpl(
cachedSolanaBlockChain,
solanaWalletEvelynPerpsTest,
cis
);
jupiterPerpsAlarm = new JupiterPerpsAlarmImpl(
solanaWalletEvelynPerpsTest,
jupiterServicePerpsTest,
"--config=conf/alarms.conf"
);
evelynServiceProd = new EvelynImpl("Production", tickerService, eveUSDT, clockUTC);
evelynServiceTest = new EvelynImpl("Test", tickerService, eveUSDT, clockUTC);
jupiterSwapService = new JupiterSwapServiceImpl(solanaBlockChain, solanaWalletEvelynBurnerProd);
discordAssetAZTokenNotificationService = new DiscordNotificationServiceImpl(
URI.create("https://discordapp.com/api/webhooks/1537799046025187458/RtoNR5HnGmnutsMfM8AKP8mLDVqP1AxpEQ3p2IvBiaqVOjuVWNcShMkIh2D9uT27Mt4A"),
"DiscordBot (https://git.r35157.com/r35157/com_r35157_nenjim-hubd-impl_ref, 0.1)",
Duration.ofSeconds(10)
);
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(
solanaWalletEvelynBurnerProd,
jupiterSwapService,
solanaBlockChain,
tickerService,
cis,
discordAssetAZTokenNotificationService,
burnTokenCandidates,
maximumSwapAmountPerIterationInUSD,
200,
2*1000*60L,
Duration.ofSeconds(10),
Duration.ofHours(1)
);
// TODO: Old but more correct way to auto start plugins - but it is currently broken.
/*
String[] processesToAutoStart = {
//"com.r35157.jupiterperpsalarm.impl.ref.JupiterPerpsAlarmImpl"
//"crypto.r35157.nenjim.NenjimHubSocketAdminAdapter",
//"crypto.r35157.nenjim.NenjimHubRestAdminAdapter",
//"crypto.r35157.nenjim.NenjimHubRPCAdminAdapter",
//"crypto.r35157.nenjim.SuwimoHub",
//"crypto.r35157.nenjim.SodaTaskManager",
//"crypto.r35157.assetaz.hub.AssetAZHub"
};
for (String processInterfaceName : processesToAutoStart) {
startProcess(processInterfaceName);
}
*/
}
private void initializeApplications() {
//nenjimComposer = new NenjimComposerImpl();
//processManager = new NenjimProcessManagerImpl();
//testTool = new NenjimTestToolImpl();
//sodaTaskManager = new SodaTaskManagerImpl();
missionControl = new EvelynMissionControlImpl(evelynServiceProd, evelynServiceTest);
//suwimoClient = new SuwimoClientImpl();
}
private void waitForAndShutdown() throws InterruptedException {
/*
try {
processesScope.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
processesScope.close();
*/
shutdownLatch.await();
System.out.println("Nenjim is now shutdown (stopped all processes)!");
}
private static final Logger log = LoggerFactory.getLogger(NenjimHubImpl.class);
private static final ΩRaydiumLiquidityPoolIdΩ EVE_USDT_RAYDIUM_POOL_ID =
"8rN4BTEzbogQosEQYgsEu18XwfKS5Yoxqwit8zEVFwEe";
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
private HashMap<Integer, NenjimProcess> processes;
//private StructuredTaskScope.ShutdownOnFailure processesScope;
private int nextProcessId;
// Dependency components
private ObjectCache objectCache;
private Clock clockUTC;
private CurrencyIdentityService cis;
private SolanaBlockChain solanaBlockChain;
private SolanaBlockChain cachedSolanaBlockChain;
private Raydium raydium;
private TradingPair eveUSDT;
private HttpClient httpClient;
private ObjectMapper objectMapper;
private SolanaWallet evelynPerpsProd;
private SolanaWallet solanaWalletEvelynPerpsProd;
private SolanaWallet solanaWalletEvelynPerpsTest;
private SolanaWallet solanaWalletEvelynBurnerProd;
private JupiterPerpsService jupiterServicePerpsProd;
private JupiterPerpsService jupiterServicePerpsTest;
// Plugins
private PriceSource hardcodedPriceSource;
private PriceSource raydiumPoolPriceSource;
// Services
private TickerService tickerService;
private JupiterPerpsAlarm jupiterPerpsAlarm;
private Evelyn evelynServiceProd;
private Evelyn evelynServiceTest;
private JupiterSwapService jupiterSwapService;
private BoundNotificationService discordAssetAZTokenNotificationService;
private EvelynIOUBurnerService evelynIOUBurnerServiceProd;
// Applications
private EvelynMissionControl missionControl;
private NenjimComposer nenjimComposer;
private NenjimProcessManager processManager;
private NenjimTestTool testTool;
private SodaTaskManager sodaTaskManager;
private SuwimoClient suwimoClient;
}
@@ -1,7 +1,7 @@
package com.r35157.nenjim.kicker;
//import com.r35157.nenjim.hubd.Context;
import com.r35157.nenjim.hubd.NenjimHub;
import crypto.r35157.nenjim.NenjimHub;
import org.jetbrains.annotations.NotNull;
public interface NenjimProcess {
@@ -1,6 +1,5 @@
package com.r35157.nenjim.kicker.impl.ref;
import com.r35157.nenjim.hubd.NenjimHub;
import com.r35157.nenjim.hubd.ctx.Context;
import com.r35157.nenjim.kicker.NenjimKicker;
@@ -34,7 +33,6 @@ public final class Initializer {
private void startNenjimKicker(Path pathToClassCache) throws Exception {
System.out.println("Initializing NenjimKicker...");
NenjimHub nenjimHub = null;
Context defaultContext = new Context();
NenjimClassLoader nenjimClassLoader = new NenjimClassLoader(defaultContext, pathToClassCache);
@@ -1,8 +1,8 @@
package com.r35157.nenjim.kicker.impl.ref;
//import com.r35157.nenjim.hubd.Context;
import com.r35157.nenjim.hubd.NenjimHub;
import com.r35157.nenjim.kicker.NenjimProcess;
import crypto.r35157.nenjim.NenjimHub;
import org.jetbrains.annotations.NotNull;
public final class NenjimProcessImpl implements NenjimProcess {
@@ -0,0 +1,20 @@
package com.r35157.nenjim.service.registry;
import com.r35157.nenjim.component.NenjimComponent;
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/** Read-only catalogue of constructed Nenjim components. */
public interface NenjimRegistryService extends NenjimComponent {
@NotNull
List<NenjimComponentId> getComponentIds(
@NotNull Class<? extends NenjimComponent> componentInterface);
@Nullable
<T extends NenjimComponent> T getComponent(
@NotNull NenjimComponentId componentId,
@NotNull Class<T> expectedInterface);
}
@@ -0,0 +1,8 @@
package com.r35157.nenjim.service.registry;
import com.r35157.nenjim.component.NenjimComponent;
/** Lifecycle owner for the Nenjim Registry and hardcoded component graph. */
public interface NenjimRegistryServiceManager extends NenjimComponent {
void start() throws Exception;
}
@@ -0,0 +1,12 @@
package com.r35157.nenjim.service.registry.impl.ref;
import com.r35157.nenjim.component.NenjimComponent;
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
import org.jetbrains.annotations.NotNull;
/** Internal mutation handle retained only by the Registry service manager. */
interface NenjimRegistryServiceAdmin {
void registerComponent(
@NotNull NenjimComponentId componentId,
@NotNull NenjimComponent component);
}
@@ -0,0 +1,154 @@
package com.r35157.nenjim.service.registry.impl.ref;
import com.r35157.nenjim.component.NenjimApplication;
import com.r35157.nenjim.component.NenjimComponent;
import com.r35157.nenjim.service.registry.NenjimRegistryService;
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/** Reference Registry storage with read-only public and internal admin views. */
final class NenjimRegistryServiceImpl implements
NenjimRegistryService,
NenjimRegistryServiceAdmin,
NenjimApplication {
@Override
public synchronized void start() {
if (startAttempted) {
throw new IllegalStateException(
"Nenjim Registry service start has already been attempted");
}
startAttempted = true;
started = true;
}
@Override
public synchronized void registerComponent(
@NotNull NenjimComponentId componentId,
@NotNull NenjimComponent component) {
Objects.requireNonNull(componentId, "componentId");
Objects.requireNonNull(component, "component");
NenjimComponent existingComponent = componentsById.get(componentId);
if (existingComponent != null) {
throw new IllegalArgumentException(
"Duplicate Nenjim component ID '" + componentId.value()
+ "': existing implementation "
+ existingComponent.getClass().getName()
+ ", attempted implementation "
+ component.getClass().getName());
}
Set<Class<? extends NenjimComponent>> componentInterfaces =
findComponentInterfaces(component.getClass());
componentsById.put(componentId, component);
for (Class<? extends NenjimComponent> componentInterface
: componentInterfaces) {
componentIdsByInterface
.computeIfAbsent(
componentInterface,
ignored -> new ArrayList<>())
.add(componentId);
}
}
@Override
public synchronized @NotNull List<NenjimComponentId> getComponentIds(
@NotNull Class<? extends NenjimComponent> componentInterface) {
validateComponentInterface(componentInterface);
requireStarted();
List<NenjimComponentId> componentIds =
componentIdsByInterface.get(componentInterface);
return componentIds == null ? List.of() : List.copyOf(componentIds);
}
@Override
public synchronized @Nullable <T extends NenjimComponent> T getComponent(
@NotNull NenjimComponentId componentId,
@NotNull Class<T> expectedInterface) {
Objects.requireNonNull(componentId, "componentId");
validateComponentInterface(expectedInterface);
requireStarted();
NenjimComponent component = componentsById.get(componentId);
if (component == null) {
return null;
}
if (!expectedInterface.isInstance(component)) {
throw new IllegalArgumentException(
"Nenjim component '" + componentId.value()
+ "' was requested as " + expectedInterface.getName()
+ " but is implemented by "
+ component.getClass().getName());
}
return expectedInterface.cast(component);
}
private void requireStarted() {
if (!started) {
throw new IllegalStateException(
"Nenjim Registry service has not started successfully");
}
}
private static void validateComponentInterface(@NotNull Class<?> type) {
Objects.requireNonNull(type, "componentInterface");
if (!type.isInterface()
|| !NenjimComponent.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(
"Expected an interface extending "
+ NenjimComponent.class.getName()
+ ", but received " + type.getName());
}
}
private static @NotNull Set<Class<? extends NenjimComponent>>
findComponentInterfaces(@NotNull Class<?> implementationClass) {
LinkedHashSet<Class<? extends NenjimComponent>> componentInterfaces =
new LinkedHashSet<>();
for (Class<?> currentClass = implementationClass;
currentClass != null;
currentClass = currentClass.getSuperclass()) {
for (Class<?> implementedInterface : currentClass.getInterfaces()) {
collectComponentInterfaces(
implementedInterface,
componentInterfaces);
}
}
return componentInterfaces;
}
private static void collectComponentInterfaces(
@NotNull Class<?> interfaceType,
@NotNull Set<Class<? extends NenjimComponent>> destination) {
if (NenjimComponent.class.isAssignableFrom(interfaceType)) {
@SuppressWarnings("unchecked")
Class<? extends NenjimComponent> componentInterface =
(Class<? extends NenjimComponent>) interfaceType;
destination.add(componentInterface);
}
for (Class<?> parentInterface : interfaceType.getInterfaces()) {
collectComponentInterfaces(parentInterface, destination);
}
}
private final Map<NenjimComponentId, NenjimComponent> componentsById =
new LinkedHashMap<>();
private final Map<Class<? extends NenjimComponent>, List<NenjimComponentId>>
componentIdsByInterface = new LinkedHashMap<>();
private boolean startAttempted;
private boolean started;
}
@@ -0,0 +1,351 @@
package com.r35157.nenjim.service.registry.impl.ref;
import com.fanitas.evelyn.core.Evelyn;
import com.fanitas.evelyn.core.impl.ref.EvelynImpl;
import com.fanitas.evelyn.service.burner.EvelynIOUBurnerService;
import com.fanitas.evelyn.service.burner.impl.ref.EvelynIOUBurnerServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r35157.assetaz.services.cis.CurrencyTypeIds;
import com.r35157.assetaz.services.ticker.pricesource.PriceSource;
import com.r35157.assetaz.services.ticker.TickerService;
import com.r35157.assetaz.services.ticker.pricesource.impl.hardcoded.HardcodedPriceSource;
import com.r35157.assetaz.services.ticker.pricesource.impl.raydiumpool.RaydiumPoolPriceSource;
import com.r35157.assetaz.services.ticker.impl.ref.TickerServiceImpl;
import com.r35157.assetaz.services.cis.CurrencyIdentityService;
import com.r35157.assetaz.services.cis.impl.hc.HardcodedCurrencyIdentityService;
import com.r35157.cryptowallet.solana.SolanaWallet;
import com.r35157.cryptowallet.solana.impl.ref.SolanaWalletImpl;
import com.r35157.evelyn.emc.EvelynMissionControl;
import com.r35157.evelyn.emc.impl.ref.EvelynMissionControlImpl;
import com.r35157.jupiterperpsalarm.JupiterPerpsAlarm;
import com.r35157.jupiterperpsalarm.impl.ref.JupiterPerpsAlarmImpl;
import com.r35157.libs.jupiter.perps.JupiterPerpsService;
import com.r35157.libs.jupiter.perps.impl.anchoridl.AnchorIdlJupiterPerpsServiceImpl;
import com.r35157.libs.jupiter.swap.JupiterSwapService;
import com.r35157.libs.jupiter.swap.impl.ref.JupiterSwapServiceImpl;
import com.r35157.libs.objcache.ObjectCache;
import com.r35157.libs.objcache.impl.ref.ObjectCacheImpl;
import com.r35157.libs.solana.impl.cached.CachedSolanaBlockChain;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.nenjim.component.NenjimApplication;
import com.r35157.nenjim.service.registry.NenjimRegistryService;
import com.r35157.nenjim.service.registry.NenjimRegistryServiceManager;
import com.r35157.nenjim.service.registry.valuetypes.NenjimComponentId;
import com.r35157.libs.raydium.Raydium;
import com.r35157.libs.raydium.impl.ref.RaydiumImpl;
import com.r35157.libs.solana.SolanaBlockChain;
import com.r35157.libs.solana.impl.ref.SolanaBlockChainImpl;
import com.r35157.libs.valuetypes.basic.TradingPair;
import com.r35157.service.notification.BoundNotificationService;
import com.r35157.service.notification.impl.discord.DiscordNotificationServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.time.Clock;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.r35157.assetaz.services.cis.CurrencyTypeIds.EVE_ID;
import static com.r35157.assetaz.services.cis.CurrencyTypeIds.USDT_ID;
public final class NenjimRegistryServiceManagerImpl implements
NenjimRegistryServiceManager,
NenjimApplication {
@Override
public void start() throws Exception {
if (!startAttempted.compareAndSet(false, true)) {
throw new IllegalStateException(
"Nenjim Registry service manager start has already been attempted");
}
log.info("Initializing Nenjim Registry and components...");
NenjimRegistryServiceImpl registry = new NenjimRegistryServiceImpl();
NenjimRegistryService registryService = registry;
NenjimRegistryServiceAdmin registryAdmin = registry;
NenjimApplication registryApplication = registry;
registryApplication.start();
registryAdmin.registerComponent(REGISTRY_SERVICE_ID, registry);
registryAdmin.registerComponent(REGISTRY_SERVICE_MANAGER_ID, this);
initializeAndRegisterComponents(registryService, registryAdmin);
log.info("Starting explicitly enabled Nenjim applications...");
startApplication(registryService, TICKER_SERVICE_ID);
startApplication(registryService, EVELYN_SERVICE_PROD_ID);
startApplication(registryService, EVELYN_SERVICE_TEST_ID);
startApplication(registryService, EVELYN_IOU_BURNER_PROD_ID);
startApplication(registryService, EVELYN_MISSION_CONTROL_ID);
System.out.println("Done - Now online!");
waitForAndShutdown();
}
private void initializeAndRegisterComponents(
NenjimRegistryService registryService,
NenjimRegistryServiceAdmin registryAdmin) {
initializeBuildingBlocks(registryAdmin);
initializePriceSources(registryAdmin);
initializeServices(registryService, registryAdmin);
initializeApplications(registryAdmin);
}
private void initializeBuildingBlocks(
NenjimRegistryServiceAdmin registryAdmin) {
objectCache = new ObjectCacheImpl();
registryAdmin.registerComponent(OBJECT_CACHE_ID, objectCache);
clockUTC = Clock.systemUTC();
cis = new HardcodedCurrencyIdentityService();
registryAdmin.registerComponent(CURRENCY_IDENTITY_SERVICE_ID, cis);
httpClient = HttpClient.newHttpClient();
objectMapper = new ObjectMapper();
solanaBlockChain = new SolanaBlockChainImpl(httpClient, objectMapper, cis);
registryAdmin.registerComponent(SOLANA_BLOCKCHAIN_DIRECT_ID, solanaBlockChain);
cachedSolanaBlockChain = new CachedSolanaBlockChain(solanaBlockChain, objectCache);
registryAdmin.registerComponent(SOLANA_BLOCKCHAIN_CACHED_ID, cachedSolanaBlockChain);
raydium = new RaydiumImpl(httpClient, objectMapper, cachedSolanaBlockChain, cis);
registryAdmin.registerComponent(RAYDIUM_SERVICE_ID, raydium);
eveUSDT = new TradingPair(cis.resolve(EVE_ID), cis.resolve(USDT_ID));
solanaWalletEvelynPerpsTest = new SolanaWalletImpl(
"6NyYEoXmJyBXvU4pvv9aoxZNdyqqtkmPBZFEDkRDHcqp",
"evelyn_perps_test",
solanaBlockChain
);
registryAdmin.registerComponent(
SOLANA_WALLET_EVELYN_PERPS_TEST_ID,
solanaWalletEvelynPerpsTest);
solanaWalletEvelynPerpsProd = new SolanaWalletImpl(
"H5Yrdm7B4FHhTxhPw9SVwFzQyTEL6bAPptZuTyRxcepq",
"evelyn_perps_prod",
solanaBlockChain
);
registryAdmin.registerComponent(
SOLANA_WALLET_EVELYN_PERPS_PROD_ID,
solanaWalletEvelynPerpsProd);
solanaWalletEvelynBurnerProd = new SolanaWalletImpl(
"5kjVTc1rebYHg56NyTxSSN1XMKqT2E81eWiaSx1CmzmV",
"evelyn_burner_prod",
solanaBlockChain
);
registryAdmin.registerComponent(
SOLANA_WALLET_EVELYN_BURNER_PROD_ID,
solanaWalletEvelynBurnerProd);
}
private void initializePriceSources(
NenjimRegistryServiceAdmin registryAdmin) {
hardcodedPriceSource = new HardcodedPriceSource(cis);
registryAdmin.registerComponent(
HARDCODED_PRICE_SOURCE_ID,
hardcodedPriceSource);
raydiumPoolPriceSource = new RaydiumPoolPriceSource(raydium, EVE_USDT_RAYDIUM_POOL_ID, eveUSDT);
registryAdmin.registerComponent(
RAYDIUM_POOL_PRICE_SOURCE_ID,
raydiumPoolPriceSource);
}
private void initializeServices(
NenjimRegistryService registryService,
NenjimRegistryServiceAdmin registryAdmin) {
tickerService = new TickerServiceImpl(
registryService,
RAYDIUM_POOL_PRICE_SOURCE_ID
);
registryAdmin.registerComponent(TICKER_SERVICE_ID, tickerService);
jupiterServicePerpsProd = new AnchorIdlJupiterPerpsServiceImpl(
cachedSolanaBlockChain,
solanaWalletEvelynPerpsProd,
cis
);
registryAdmin.registerComponent(
JUPITER_PERPS_EVELYN_PROD_ID,
jupiterServicePerpsProd);
jupiterServicePerpsTest = new AnchorIdlJupiterPerpsServiceImpl(
cachedSolanaBlockChain,
solanaWalletEvelynPerpsTest,
cis
);
registryAdmin.registerComponent(
JUPITER_PERPS_EVELYN_TEST_ID,
jupiterServicePerpsTest);
jupiterPerpsAlarm = new JupiterPerpsAlarmImpl(
solanaWalletEvelynPerpsTest,
jupiterServicePerpsTest,
"--config=conf/alarms.conf"
);
registryAdmin.registerComponent(
JUPITER_PERPS_ALARM_ID,
jupiterPerpsAlarm);
evelynServiceProd = new EvelynImpl("Production", tickerService, eveUSDT, clockUTC);
registryAdmin.registerComponent(EVELYN_SERVICE_PROD_ID, evelynServiceProd);
evelynServiceTest = new EvelynImpl("Test", tickerService, eveUSDT, clockUTC);
registryAdmin.registerComponent(EVELYN_SERVICE_TEST_ID, evelynServiceTest);
jupiterSwapService = new JupiterSwapServiceImpl(solanaBlockChain, solanaWalletEvelynBurnerProd);
registryAdmin.registerComponent(
JUPITER_SWAP_EVELYN_BURNER_PROD_ID,
jupiterSwapService);
discordAssetAZTokenNotificationService = new DiscordNotificationServiceImpl(
URI.create("https://discordapp.com/api/webhooks/1537799046025187458/RtoNR5HnGmnutsMfM8AKP8mLDVqP1AxpEQ3p2IvBiaqVOjuVWNcShMkIh2D9uT27Mt4A"),
"DiscordBot (https://git.r35157.com/r35157/com_r35157_nenjim-hubd-impl_ref, 0.1)",
Duration.ofSeconds(10)
);
registryAdmin.registerComponent(
DISCORD_ASSETAZ_TOKEN_NOTIFICATION_ID,
discordAssetAZTokenNotificationService);
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(
solanaWalletEvelynBurnerProd,
jupiterSwapService,
solanaBlockChain,
tickerService,
cis,
discordAssetAZTokenNotificationService,
burnTokenCandidates,
maximumSwapAmountPerIterationInUSD,
200,
2*1000*60L,
Duration.ofSeconds(10),
Duration.ofHours(1)
);
registryAdmin.registerComponent(
EVELYN_IOU_BURNER_PROD_ID,
evelynIOUBurnerServiceProd);
}
private void initializeApplications(
NenjimRegistryServiceAdmin registryAdmin) {
missionControl = new EvelynMissionControlImpl(evelynServiceProd, evelynServiceTest);
registryAdmin.registerComponent(
EVELYN_MISSION_CONTROL_ID,
missionControl);
}
private static void startApplication(
NenjimRegistryService registryService,
NenjimComponentId componentId) throws Exception {
NenjimApplication application = registryService.getComponent(
componentId,
NenjimApplication.class);
if (application == null) {
throw new IllegalStateException(
"Required Nenjim application '" + componentId.value()
+ "' is not registered as "
+ NenjimApplication.class.getName());
}
application.start();
}
private void waitForAndShutdown() throws InterruptedException {
shutdownLatch.await();
System.out.println("Nenjim is now shut down!");
}
private static final Logger log = LoggerFactory.getLogger(
NenjimRegistryServiceManagerImpl.class);
private static final NenjimComponentId REGISTRY_SERVICE_ID =
new NenjimComponentId("nenjim.registry.service");
private static final NenjimComponentId REGISTRY_SERVICE_MANAGER_ID =
new NenjimComponentId("nenjim.registry.service-manager");
private static final NenjimComponentId OBJECT_CACHE_ID =
new NenjimComponentId("nenjim.object-cache.default");
private static final NenjimComponentId CURRENCY_IDENTITY_SERVICE_ID =
new NenjimComponentId("assetaz.currency-identity.hardcoded");
private static final NenjimComponentId SOLANA_BLOCKCHAIN_DIRECT_ID =
new NenjimComponentId("solana.blockchain.direct");
private static final NenjimComponentId SOLANA_BLOCKCHAIN_CACHED_ID =
new NenjimComponentId("solana.blockchain.cached");
private static final NenjimComponentId RAYDIUM_SERVICE_ID =
new NenjimComponentId("raydium.service.default");
private static final NenjimComponentId SOLANA_WALLET_EVELYN_PERPS_TEST_ID =
new NenjimComponentId("solana.wallet.evelyn-perps-test");
private static final NenjimComponentId SOLANA_WALLET_EVELYN_PERPS_PROD_ID =
new NenjimComponentId("solana.wallet.evelyn-perps-prod");
private static final NenjimComponentId SOLANA_WALLET_EVELYN_BURNER_PROD_ID =
new NenjimComponentId("solana.wallet.evelyn-burner-prod");
private static final NenjimComponentId HARDCODED_PRICE_SOURCE_ID =
new NenjimComponentId("assetaz.price-source.hardcoded");
private static final NenjimComponentId RAYDIUM_POOL_PRICE_SOURCE_ID =
new NenjimComponentId(
"assetaz.price-source.raydium-pool.eve-usdt");
private static final NenjimComponentId TICKER_SERVICE_ID =
new NenjimComponentId("assetaz.ticker.default");
private static final NenjimComponentId JUPITER_PERPS_EVELYN_PROD_ID =
new NenjimComponentId("jupiter.perps.evelyn-prod");
private static final NenjimComponentId JUPITER_PERPS_EVELYN_TEST_ID =
new NenjimComponentId("jupiter.perps.evelyn-test");
private static final NenjimComponentId JUPITER_PERPS_ALARM_ID =
new NenjimComponentId("jupiter-perps-alarm.default");
private static final NenjimComponentId EVELYN_SERVICE_PROD_ID =
new NenjimComponentId("evelyn.service.prod");
private static final NenjimComponentId EVELYN_SERVICE_TEST_ID =
new NenjimComponentId("evelyn.service.test");
private static final NenjimComponentId JUPITER_SWAP_EVELYN_BURNER_PROD_ID =
new NenjimComponentId("jupiter.swap.evelyn-burner-prod");
private static final NenjimComponentId DISCORD_ASSETAZ_TOKEN_NOTIFICATION_ID =
new NenjimComponentId("notification.discord.assetaz-token");
private static final NenjimComponentId EVELYN_IOU_BURNER_PROD_ID =
new NenjimComponentId("evelyn.iou-burner.prod");
private static final NenjimComponentId EVELYN_MISSION_CONTROL_ID =
new NenjimComponentId("evelyn.mission-control.default");
private static final ΩRaydiumLiquidityPoolIdΩ EVE_USDT_RAYDIUM_POOL_ID =
"8rN4BTEzbogQosEQYgsEu18XwfKS5Yoxqwit8zEVFwEe";
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
private final AtomicBoolean startAttempted = new AtomicBoolean();
// Dependency components
private ObjectCache objectCache;
private Clock clockUTC;
private CurrencyIdentityService cis;
private SolanaBlockChain solanaBlockChain;
private SolanaBlockChain cachedSolanaBlockChain;
private Raydium raydium;
private TradingPair eveUSDT;
private HttpClient httpClient;
private ObjectMapper objectMapper;
private SolanaWallet solanaWalletEvelynPerpsProd;
private SolanaWallet solanaWalletEvelynPerpsTest;
private SolanaWallet solanaWalletEvelynBurnerProd;
private JupiterPerpsService jupiterServicePerpsProd;
private JupiterPerpsService jupiterServicePerpsTest;
// Price-source components
private PriceSource hardcodedPriceSource;
private PriceSource raydiumPoolPriceSource;
// Services
private TickerService tickerService;
private JupiterPerpsAlarm jupiterPerpsAlarm;
private Evelyn evelynServiceProd;
private Evelyn evelynServiceTest;
private JupiterSwapService jupiterSwapService;
private BoundNotificationService discordAssetAZTokenNotificationService;
private EvelynIOUBurnerService evelynIOUBurnerServiceProd;
// Application components
private EvelynMissionControl missionControl;
}
@@ -0,0 +1,16 @@
package com.r35157.nenjim.service.registry.valuetypes;
import org.jetbrains.annotations.NotNull;
/** Lookup identity assigned to one component registration in a Registry. */
public record NenjimComponentId(@NotNull String value) {
public NenjimComponentId {
value = value.strip();
if (!value.matches(
"[a-z][a-z0-9]*(?:-[a-z0-9]+)*(?:\\.[a-z][a-z0-9]*(?:-[a-z0-9]+)*)*")) {
throw new IllegalArgumentException(
"Invalid Nenjim component ID: '" + value + "'");
}
}
}
@@ -1,5 +1,6 @@
package com.r35157.service.notification;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -12,7 +13,7 @@ import java.io.IOException;
* or how its destination is configured.</p>
*/
@FunctionalInterface
public interface BoundNotificationService {
public interface BoundNotificationService extends NenjimComponent {
/**
* Sends a notification message.
*