Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Socket #2618

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public void testContextMethodsCalled() {

private static class ContextImplementation implements Context {
private final Map<Class<?>, Object> map = Maps.newConcurrentMap();
private final Map<Class<?>, DynamicInstanceProvider<?>> providers = Maps.newConcurrentMap();

@Override
public <T> T get(Class<? extends T> type) {
Expand All @@ -107,5 +108,15 @@ public <T> T get(Class<? extends T> type) {
public <T, U extends T> void put(Class<T> type, U object) {
map.put(type, object);
}

@Override
public <T, U extends T> void putInstanceProvider(Class<T> type, DynamicInstanceProvider<U> provider) {
providers.put(type, provider);
}

@Override
public <T> DynamicInstanceProvider<T> getInstanceProvider(Class<? extends T> type) {
return (DynamicInstanceProvider<T>) providers.get(type);
}
}
}
14 changes: 14 additions & 0 deletions engine/src/main/java/org/terasology/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import gnu.trove.set.hash.TIntHashSet;
import org.lwjgl.opengl.PixelFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -44,6 +45,7 @@
import org.terasology.utilities.gson.CaseInsensitiveEnumTypeAdapterFactory;
import org.terasology.utilities.gson.InputHandler;
import org.terasology.utilities.gson.SetMultimapTypeAdapter;
import org.terasology.utilities.gson.TIntHashSetTypeAdapter;
import org.terasology.utilities.gson.UriTypeAdapterFactory;

import java.io.BufferedReader;
Expand Down Expand Up @@ -117,6 +119,15 @@ public NUIEditorConfig getNuiEditor() {
return config.getNuiEditor();
}

/**
* Retrieves the socket config.
*
* @return The socket config.
*/
public SocketConfig getSocket() {
return config.getSocket();
}

public String renderConfigAsJson(Object configObject) {
return createGson().toJsonTree(configObject).toString();
}
Expand Down Expand Up @@ -190,7 +201,10 @@ protected static Gson createGson() {
.registerTypeAdapter(Version.class, new VersionTypeAdapter())
.registerTypeAdapter(BindsConfig.class, new BindsConfig.Handler())
.registerTypeAdapter(SetMultimap.class, new SetMultimapTypeAdapter<>(Input.class))
.registerTypeAdapter(TIntHashSet.class, new TIntHashSetTypeAdapter())
.registerTypeAdapter(SecurityConfig.class, new SecurityConfig.Handler())
.registerTypeAdapter(SocketConfig.Hosts.class, new SocketConfig.Hosts.Handler())
.registerTypeAdapter(SocketConfig.Ports.class, new SocketConfig.Ports.Handler())
.registerTypeAdapter(Input.class, new InputHandler())

.registerTypeAdapter(PixelFormat.class, new PixelFormatHandler())
Expand Down
10 changes: 10 additions & 0 deletions engine/src/main/java/org/terasology/config/RootConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public final class RootConfig {
private NetworkConfig network = new NetworkConfig();
private SecurityConfig security = new SecurityConfig();
private NUIEditorConfig nuiEditor = new NUIEditorConfig();
private SocketConfig socket = new SocketConfig();

/**
* Create a new, empty config
Expand Down Expand Up @@ -96,4 +97,13 @@ public NUIEditorConfig getNuiEditor() {
public Map<SimpleUri, Map<String, JsonElement>> getModuleConfigs() {
return moduleConfigs;
}

/**
* Retrieves the socket config.
*
* @return The socket config.
*/
public SocketConfig getSocket() {
return socket;
}
}
150 changes: 150 additions & 0 deletions engine/src/main/java/org/terasology/config/SocketConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright 2016 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.config;

import com.google.common.collect.Maps;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
import org.terasology.naming.Name;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map;

/**
* Configuration file for all the socket BS you can think of.
*/
// TODO make thread safe and stuff
public class SocketConfig {
/**
* All the TCP whitelists. Keyed by module ID.
*/
private Map<Name, Hosts> tcpWhitelists = Maps.newTreeMap();

/**
* Retrieves the TCP whitelists.
*
* @return The TCP whitelists.
*/
public Map<Name, Hosts> getTcpWhitelists() {
return tcpWhitelists;
}

/**
* POJO representing the hosts a module is allowed to access.
*/
public static class Hosts {
/**
* The hosts themselves.
*/
private Map<String, Ports> hosts = Maps.newTreeMap();

/**
* Retrieves the hosts.
*
* @return The hosts.
*/
public Map<String, Ports> getHosts() {
return hosts;
}

public static class Handler implements JsonSerializer<Hosts>, JsonDeserializer<Hosts> {

@Override
public Hosts deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// We need this for the treemap.
Map<String, Ports> map;
try {
// Ugh java
map = context.deserialize(json, Hosts.class.getDeclaredField("hosts").getGenericType());
} catch (Exception e) {
// Who cares
throw new JsonParseException(e);
}
if (map == null) {
return null;
}
Hosts h = new Hosts();
h.hosts = map;
return h;
}

@Override
public JsonElement serialize(Hosts src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
return context.serialize(src.hosts);
}
}
}

/**
* POJO representing the ports a module is allowed to access.
*/
public static class Ports {
/**
* The ports themselves.
*/
private TIntSet ports = new TIntHashSet();

/**
* Retrieves the ports.
*
* @return The ports.
*/
public TIntSet getPorts() {
return ports;
}

public static class Handler implements JsonSerializer<Ports>, JsonDeserializer<Ports> {
@Override
public Ports deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// We need this custom deserialization (and this class) for 2 reasons:
// 1. We need to control TIntHashSet's no_entry_value.
// 2. We need to sanitize user input.
int[] array = context.deserialize(json, int[].class);
if (array == null) {
return null;
}
Arrays.stream(array).filter(x -> (x < 1 || x > 65535) && x != -1).findAny().ifPresent(x -> {
throw new IllegalStateException("Port must be in range 1 <= port <= 65535, or -1 for wildcard value: " + x);
});
TIntHashSet hashSet = new TIntHashSet(10, .5f, Integer.MIN_VALUE);
hashSet.addAll(array);
Ports p = new Ports();
p.ports = hashSet;
return p;
}

@Override
public JsonElement serialize(Ports src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
// Just defer to standard TIntHashSet serialization. This is fine.
return context.serialize(src.ports);
}
}
}
}
22 changes: 17 additions & 5 deletions engine/src/main/java/org/terasology/context/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@
package org.terasology.context;

import org.terasology.module.sandbox.API;
import org.terasology.registry.DynamicInstanceProvider;

/**
* Provides classes with the utility objects that belong to the context they are running in.
*
* <p>
* Use dependency injection or this interface to get at the objects you want to use.
*
*
* <p>
* <p>
* From this class there can be multiple instances. For example we have the option of letting a client and server run
* concurrently in one VM, by letting them work with two separate context objects.
*
* <p>
* This class is intended to replace the CoreRegistry and other static means to get utility objects.
*
* <p>
* Contexts must be thread safe!
*/
@API
Expand All @@ -43,4 +44,15 @@ public interface Context {
*/
<T, U extends T> void put(Class<T> type, U object);

/**
* Registers an object provider.
*
* @param type The object type.
* @param provider The object provider.
* @param <T> The base type, the type used in @In.
* @param <U> The instance type, the type returned by the provider.
*/
<T, U extends T> void putInstanceProvider(Class<T> type, DynamicInstanceProvider<U> provider);

<T> DynamicInstanceProvider<T> getInstanceProvider(Class<? extends T> type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.common.collect.Maps;
import org.terasology.context.Context;
import org.terasology.registry.DynamicInstanceProvider;

import java.util.Map;

Expand All @@ -26,11 +27,9 @@
public class ContextImpl implements Context {
private final Context parent;

private final Map<Class<? extends Object>, Object> map = Maps.newConcurrentMap();

private final Map<Class<?>, Object> map = Maps.newConcurrentMap();

/**
*
* @param parent can be null. If not null it will be used as a fallback if this context does not contain a
* requested object.
*/
Expand All @@ -54,12 +53,51 @@ public <T> T get(Class<? extends T> type) {
if (parent != null) {
return parent.get(type);
}
return result;
return null;
}

@Override
public <T, U extends T> void put(Class<T> type, U object) {
public <T, U extends T> void put(Class<T> type, U object) {
map.put(type, object);
}

// DynamicInstanceProvider stuff, kinda messy but it works

private final Map<Class<?>, DynamicInstanceProviderHolder<?>> providers = Maps.newConcurrentMap();

@Override
public <T, U extends T> void putInstanceProvider(Class<T> type, DynamicInstanceProvider<U> provider) {
providers.put(type, new DynamicInstanceProviderHolder<>(provider.getClass(), provider));
}

@Override
public <T> DynamicInstanceProvider<T> getInstanceProvider(Class<? extends T> type) {
if (System.getSecurityManager() != null) {
System.getSecurityManager().checkPermission(new RuntimePermission("permGetInstanceProvider"));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to keep the Context interface and the injection concept as simple as possible.

Some idea I could think of to simplify it a little bit would be to have Context have a inject method so that we don't need to have a method that we must protect against all but one caller. Although I am not that happy with that idea.


DynamicInstanceProviderHolder<?> holder = providers.get(type);
DynamicInstanceProvider<T> result = holder != null ? holder.get() : null;
if (result != null) {
return result;
}
if (parent != null) {
return parent.getInstanceProvider(type);
}
return null;
}

private static final class DynamicInstanceProviderHolder<T> {
private final Class<? extends DynamicInstanceProvider> providerClass;
private final DynamicInstanceProvider<T> provider;

private DynamicInstanceProviderHolder(Class<? extends DynamicInstanceProvider> providerClass, DynamicInstanceProvider<T> provider) {
this.providerClass = providerClass;
this.provider = provider;
}

private <U> DynamicInstanceProvider<U> get() {
return providerClass.cast(provider);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.terasology.entitySystem.prefab.internal.PojoPrefab;
import org.terasology.i18n.I18nSubsystem;
import org.terasology.input.InputSystem;
import org.terasology.socket.internal.SocketSubsystem;
import org.terasology.logic.behavior.asset.BehaviorTree;
import org.terasology.logic.behavior.asset.BehaviorTreeData;
import org.terasology.monitoring.Activity;
Expand Down Expand Up @@ -166,6 +167,7 @@ public TerasologyEngine(TimeSubsystem timeSubsystem, Collection<EngineSubsystem>
this.allSubsystems.add(new WorldGenerationSubsystem());
this.allSubsystems.add(new GameSubsystem());
this.allSubsystems.add(new I18nSubsystem());
this.allSubsystems.add(new SocketSubsystem()); // TODO maybe disallow this on the client?
}

private void initialize() {
Expand Down
Loading