telegram-files/api/src/main/java/telegram/files/DataVerticle.java

112 lines
4.4 KiB
Java

package telegram.files;
import cn.hutool.core.lang.Version;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.jdbcclient.JDBCConnectOptions;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.SqlConnection;
import org.jooq.lambda.tuple.Tuple;
import telegram.files.repository.*;
import telegram.files.repository.impl.FileRepositoryImpl;
import telegram.files.repository.impl.SettingRepositoryImpl;
import telegram.files.repository.impl.StatisticRepositoryImpl;
import telegram.files.repository.impl.TelegramRepositoryImpl;
import java.io.File;
import java.util.List;
public class DataVerticle extends AbstractVerticle {
private static final Log log = LogFactory.get();
public static JDBCPool pool;
public static FileRepository fileRepository;
public static TelegramRepository telegramRepository;
public static SettingRepository settingRepository;
public static StatisticRepository statisticRepository;
public void start(Promise<Void> stopPromise) {
pool = JDBCPool.pool(vertx,
new JDBCConnectOptions()
.setJdbcUrl("jdbc:sqlite:%s?journal_mode=WAL&busy_timeout=30000&synchronous=NORMAL&cache_size=-2000".formatted(getDataPath())),
new PoolOptions()
.setMaxSize(8)
.setName("pool-tf")
.setIdleTimeout(300000)
.setPoolCleanerPeriod(300000)
);
settingRepository = new SettingRepositoryImpl(pool);
telegramRepository = new TelegramRepositoryImpl(pool);
fileRepository = new FileRepositoryImpl(pool);
statisticRepository = new StatisticRepositoryImpl(pool);
List<Definition> definitions = List.of(
new SettingRecord.SettingRecordDefinition(),
new TelegramRecord.TelegramRecordDefinition(),
new FileRecord.FileRecordDefinition(),
new StatisticRecord.StatisticRecordDefinition()
);
pool.getConnection()
.compose(conn -> isCompletelyNewInitialization(conn).map(isNew -> Tuple.tuple(conn, isNew)))
.compose(tuple -> Future.all(definitions.stream().map(d -> d.createTable(tuple.v1)).toList()).map(tuple))
.compose(tuple -> settingRepository.<Version>getByKey(SettingKey.version).map(tuple::concat))
.compose(tuple -> {
if (tuple.v2) return Future.succeededFuture();
SqlConnection conn = tuple.v1;
Version version = tuple.v3 == null ? new Version("0.0.0") : tuple.v3;
return Future.all(definitions.stream().map(d -> d.migrate(conn, version, new Version(Start.VERSION))).toList());
})
.compose(r ->
settingRepository.createOrUpdate(SettingKey.version.name(), Start.VERSION))
.onSuccess(r -> {
log.info("Database initialized");
stopPromise.complete();
})
.onFailure(err -> {
log.error("Failed to initialize database: %s".formatted(err.getMessage()));
stopPromise.fail(err);
});
}
@Override
public void stop(Promise<Void> stopPromise) throws Exception {
if (pool != null) {
pool.close().onComplete(r -> {
if (r.succeeded()) {
log.debug("Data verticle stopped!");
} else {
log.error("Failed to close data verticle: %s".formatted(r.cause().getMessage()));
}
stopPromise.complete();
});
}
}
public static String getDataPath() {
String dataPath = System.getenv("DATA_PATH");
dataPath = StrUtil.blankToDefault(dataPath, "data.db");
dataPath = Config.APP_ROOT + File.separator + dataPath;
return dataPath;
}
private Future<Boolean> isCompletelyNewInitialization(SqlConnection conn) {
return conn.query("""
SELECT name
FROM sqlite_master
WHERE type = 'table'
ORDER BY name;
""")
.execute()
.map(rs -> rs.size() == 0);
}
}