Skip to content

Commit

Permalink
Implement separate server settings
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexProgrammerDE committed Dec 29, 2024
1 parent 35458a7 commit 33d589a
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 14 deletions.
4 changes: 4 additions & 0 deletions proto/src/main/proto/soulfire/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ enum GlobalPermission {
READ_CLIENT_DATA = 2;
READ_SERVER_CONFIG = 3;
UPDATE_SERVER_CONFIG = 4;
CREATE_USER = 5;
READ_USER = 6;
UPDATE_USER = 7;
DELETE_USER = 8;
}

enum InstancePermission {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,6 @@ private void start() {
throw new IllegalStateException("Another attack is still running");
}

SoulFireServer.setupLoggingAndVia(settingsSource);

this.attackLifecycle(AttackLifecycle.STARTING);

var address = settingsSource.get(BotSettings.ADDRESS);
Expand Down
28 changes: 23 additions & 5 deletions server/src/main/java/com/soulfiremc/server/SoulFireServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
import com.soulfiremc.server.data.TranslationMapper;
import com.soulfiremc.server.database.DatabaseManager;
import com.soulfiremc.server.database.InstanceEntity;
import com.soulfiremc.server.database.ServerConfigEntity;
import com.soulfiremc.server.database.UserEntity;
import com.soulfiremc.server.grpc.RPCServer;
import com.soulfiremc.server.settings.*;
import com.soulfiremc.server.settings.lib.InstanceSettingsSource;
import com.soulfiremc.server.settings.lib.ServerSettingsDelegate;
import com.soulfiremc.server.settings.lib.ServerSettingsRegistry;
import com.soulfiremc.server.spark.SFSparkPlugin;
import com.soulfiremc.server.user.AuthSystem;
Expand All @@ -41,6 +42,7 @@
import com.soulfiremc.server.util.SFPathConstants;
import com.soulfiremc.server.util.SFUpdateChecker;
import com.soulfiremc.server.util.TimeUtil;
import com.soulfiremc.server.util.structs.CachedLazyObject;
import com.soulfiremc.server.util.structs.ShutdownManager;
import com.soulfiremc.server.viaversion.SFVLLoaderImpl;
import com.soulfiremc.server.viaversion.SFViaPlatform;
Expand All @@ -67,6 +69,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
* The main class of the SoulFire server.
Expand All @@ -90,6 +93,7 @@ public class SoulFireServer {
private final SoulFireScheduler scheduler = new SoulFireScheduler(log);
private final Map<UUID, InstanceManager> instances = new ConcurrentHashMap<>();
private final MetadataHolder metadata = new MetadataHolder();
private final ServerSettingsDelegate settingsSource;
private final RPCServer rpcServer;
private final AuthSystem authSystem;
private final ServerSettingsRegistry serverSettingsRegistry;
Expand Down Expand Up @@ -117,6 +121,16 @@ public SoulFireServer(
this.sessionFactory = DatabaseManager.forSqlite(baseDirectory.resolve("soulfire.sqlite"));
injector.register(SessionFactory.class, sessionFactory);

this.settingsSource = new ServerSettingsDelegate(new CachedLazyObject<>(() ->
sessionFactory.fromTransaction(session -> {
var entity = session.find(ServerConfigEntity.class, 1);
if (entity == null) {
entity = new ServerConfigEntity();
session.persist(entity);
}

return entity.settings();
}), 1, TimeUnit.SECONDS));
this.authSystem = new AuthSystem(this);
this.rpcServer = new RPCServer(host, port, injector, authSystem);

Expand Down Expand Up @@ -156,6 +170,9 @@ public SoulFireServer(

CompletableFuture.allOf(viaStart, sparkStart, updateCheck).join();

// Via is ready, we can now set up all config stuff
setupLoggingAndVia();

var newVersion = updateCheck.join();
if (newVersion != null) {
log.warn(
Expand Down Expand Up @@ -202,12 +219,13 @@ public SoulFireServer(
"Finished loading! (Took {}ms)", Duration.between(startTime, Instant.now()).toMillis());
}

public static void setupLoggingAndVia(InstanceSettingsSource settingsSource) {
Via.getManager().debugHandler().setEnabled(settingsSource.get(DevSettings.VIA_DEBUG));
setupLogging(settingsSource);
public void configUpdateHook() {
setupLoggingAndVia();
}

public static void setupLogging(InstanceSettingsSource settingsSource) {
public void setupLoggingAndVia() {
Via.getManager().debugHandler().setEnabled(settingsSource.get(DevSettings.VIA_DEBUG));

Configurator.setRootLevel(settingsSource.get(DevSettings.CORE_DEBUG) ? Level.DEBUG : Level.INFO);
Configurator.setLevel("io.netty", settingsSource.get(DevSettings.NETTY_DEBUG) ? Level.DEBUG : Level.INFO);
Configurator.setLevel("io.grpc", settingsSource.get(DevSettings.GRPC_DEBUG) ? Level.DEBUG : Level.INFO);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public static SessionFactory forSqlite(Path dbFile) {
metadataSources.addPackage("com.soulfiremc.server.database");
metadataSources.addAnnotatedClasses(
UserEntity.class,
InstanceEntity.class
InstanceEntity.class,
ServerConfigEntity.class
);

return metadataSources.getMetadataBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class InstanceEntity {
@Column(nullable = false)
private AttackLifecycle attackLifecycle = AttackLifecycle.STOPPED;

@Convert(converter = SettingsConverter.class)
@Convert(converter = InstanceSettingsConverter.class)
@Column(nullable = false)
private InstanceSettingsImpl settings = InstanceSettingsImpl.EMPTY;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import jakarta.persistence.Converter;

@Converter(autoApply = true)
public class SettingsConverter implements AttributeConverter<InstanceSettingsImpl, String> {
public class InstanceSettingsConverter implements AttributeConverter<InstanceSettingsImpl, String> {
@Override
public String convertToDatabaseColumn(InstanceSettingsImpl attribute) {
return GsonInstance.GSON.toJson(attribute.serializeToTree());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* SoulFire
* Copyright (C) 2024 AlexProgrammerDE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.soulfiremc.server.database;

import com.soulfiremc.server.settings.lib.ServerSettingsImpl;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name = "server_config")
public class ServerConfigEntity {
@Id
private Long id = 1L;

@Convert(converter = ServerSettingsConverter.class)
@Column(nullable = false)
private ServerSettingsImpl settings = ServerSettingsImpl.EMPTY;

@Version
private long version;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SoulFire
* Copyright (C) 2024 AlexProgrammerDE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.soulfiremc.server.database;

import com.google.gson.JsonElement;
import com.soulfiremc.server.settings.lib.ServerSettingsImpl;
import com.soulfiremc.server.util.structs.GsonInstance;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;

@Converter(autoApply = true)
public class ServerSettingsConverter implements AttributeConverter<ServerSettingsImpl, String> {
@Override
public String convertToDatabaseColumn(ServerSettingsImpl attribute) {
return GsonInstance.GSON.toJson(attribute.serializeToTree());
}

@Override
public ServerSettingsImpl convertToEntityAttribute(String dbData) {
return ServerSettingsImpl.deserialize(GsonInstance.GSON.fromJson(dbData, JsonElement.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public RPCServer(
.addService(injector.getSingleton(ProxyCheckServiceImpl.class))
.addService(injector.getSingleton(DownloadServiceImpl.class))
.addService(injector.getSingleton(ObjectStorageServiceImpl.class))
.addService(injector.getSingleton(ServerServiceImpl.class))
// Allow collecting info about callable methods.
.addService(ProtoReflectionServiceV1.newInstance())
.maxRequestMessageLength(Integer.MAX_VALUE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* SoulFire
* Copyright (C) 2024 AlexProgrammerDE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.soulfiremc.server.grpc;

import com.soulfiremc.grpc.generated.*;
import com.soulfiremc.server.SoulFireServer;
import com.soulfiremc.server.database.ServerConfigEntity;
import com.soulfiremc.server.settings.lib.ServerSettingsImpl;
import com.soulfiremc.server.user.PermissionContext;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.SessionFactory;

import javax.inject.Inject;

@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Inject)
public class ServerServiceImpl extends ServerServiceGrpc.ServerServiceImplBase {
private final SoulFireServer soulFireServer;
private final SessionFactory sessionFactory;

@Override
public void getServerInfo(ServerInfoRequest request, StreamObserver<ServerInfoResponse> responseObserver) {
ServerRPCConstants.USER_CONTEXT_KEY.get().hasPermissionOrThrow(PermissionContext.global(GlobalPermission.READ_SERVER_CONFIG));

try {
var configEntity = sessionFactory.fromTransaction(session -> session.find(ServerConfigEntity.class, 1));
ServerSettingsImpl config;
if (configEntity == null) {
config = ServerSettingsImpl.EMPTY;
} else {
config = configEntity.settings();
}

responseObserver.onNext(ServerInfoResponse.newBuilder()
.setConfig(config.toProto())
.build());
responseObserver.onCompleted();
} catch (Throwable t) {
log.error("Error getting server info", t);
throw new StatusRuntimeException(Status.INTERNAL.withDescription(t.getMessage()).withCause(t));
}
}

@Override
public void updateServerConfig(ServerUpdateConfigRequest request, StreamObserver<ServerUpdateConfigResponse> responseObserver) {
ServerRPCConstants.USER_CONTEXT_KEY.get().hasPermissionOrThrow(PermissionContext.global(GlobalPermission.UPDATE_SERVER_CONFIG));

try {
sessionFactory.inTransaction(session -> {
var currentConfigEntity = session.find(ServerConfigEntity.class, 1);
if (currentConfigEntity == null) {
var newConfigEntity = new ServerConfigEntity();
newConfigEntity.settings(ServerSettingsImpl.fromProto(request.getConfig()));
session.persist(newConfigEntity);
} else {
currentConfigEntity.settings(ServerSettingsImpl.fromProto(request.getConfig()));
session.merge(currentConfigEntity);
}
});

soulFireServer.configUpdateHook();
responseObserver.onNext(ServerUpdateConfigResponse.newBuilder().build());
responseObserver.onCompleted();
} catch (Throwable t) {
log.error("Error getting server info", t);
throw new StatusRuntimeException(Status.INTERNAL.withDescription(t.getMessage()).withCause(t));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import com.google.gson.JsonObject;
import com.google.protobuf.Value;
import com.google.protobuf.util.JsonFormat;
import com.soulfiremc.grpc.generated.InstanceConfig;
import com.soulfiremc.grpc.generated.ServerConfig;
import com.soulfiremc.grpc.generated.SettingsEntry;
import com.soulfiremc.grpc.generated.SettingsNamespace;
import com.soulfiremc.server.settings.PropertyKey;
Expand Down Expand Up @@ -51,7 +51,7 @@ public static ServerSettingsImpl deserialize(JsonElement json) {
}

@SneakyThrows
public static ServerSettingsImpl fromProto(InstanceConfig request) {
public static ServerSettingsImpl fromProto(ServerConfig request) {
var settingsProperties = new HashMap<String, Map<String, JsonElement>>();

for (var namespace : request.getSettingsList()) {
Expand All @@ -72,7 +72,7 @@ public JsonObject serializeToTree() {
}

@SneakyThrows
public InstanceConfig toProto() {
public ServerConfig toProto() {
var settingsProperties = new HashMap<String, Map<String, Value>>();
for (var entry : this.settings.entrySet()) {
var namespace = entry.getKey();
Expand All @@ -91,7 +91,7 @@ public InstanceConfig toProto() {
settingsProperties.put(namespace, innerMap);
}

return InstanceConfig.newBuilder()
return ServerConfig.newBuilder()
.addAllSettings(settingsProperties.entrySet().stream().map(entry -> {
var namespace = entry.getKey();

Expand Down

0 comments on commit 33d589a

Please sign in to comment.