Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
qixils committed Jun 18, 2024
1 parent 169397b commit f5149a3
Show file tree
Hide file tree
Showing 31 changed files with 1,575 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.qixils.crowdcontrol;

import dev.qixils.crowdcontrol.socket.Request;
import dev.qixils.crowdcontrol.socket.RequestNew;
import dev.qixils.crowdcontrol.socket.SocketManager;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand All @@ -19,5 +19,5 @@ public interface RequestManager extends ServiceManager {
* @since 3.3.0
*/
@ApiStatus.AvailableSince("3.3.0")
void handle(@NotNull Request request);
void handle(@NotNull RequestNew request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* @since 3.0.0
*/
@ApiStatus.AvailableSince("3.0.0")
@Deprecated
public final class NoApplicableTarget extends CrowdControlException {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.qixils.crowdcontrol.fields;

import com.google.gson.reflect.TypeToken;
import dev.qixils.crowdcontrol.socket.Field;
import dev.qixils.crowdcontrol.socket.ObjectTypes;
import dev.qixils.crowdcontrol.socket.SocketManager;
import org.jetbrains.annotations.NotNull;

public class CommonFields {
private CommonFields() {
}

public static <T> Field.Builder<T> packet(@NotNull TypeToken<T> type) {
return new Field.Builder<>(type).addSupports(ObjectTypes.REQUEST.id(), ObjectTypes.RESPONSE.id());
}

public static <T> Field.Builder<T> packet(@NotNull Class<T> type) {
return new Field.Builder<>(type).addSupports(ObjectTypes.REQUEST.id(), ObjectTypes.RESPONSE.id());
}

/**
* The ID of the packet. Corresponds to a unique transaction.
*
* @since 4.0.0
*/
public static final Field<Integer> ID = packet(Integer.class).addId("id").build();

/**
* The message describing or explaining the packet.
*
* @since 4.0.0
*/
public static final Field<String> MESSAGE = packet(String.class).addId("message").build();

/**
* The socket from which a packet was received from or will be sent to.
*
* @since 4.0.0
*/
public static final Field<SocketManager> SOCKET = packet(SocketManager.class).addId("socket").isTransient(true).build();

// TODO: `LOGIN` (request, request target, request source)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.function.Function;

class ByteAdapter<T extends ByteObject> extends TypeAdapter<T> {
@Deprecated
static final @NotNull Gson GSON = new GsonBuilder()
.registerTypeAdapterFactory(new PostProcessor())
.registerTypeAdapter(Request.Type.class, new ByteAdapter<>(Request.Type::from))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.qixils.crowdcontrol.socket;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import dev.qixils.crowdcontrol.util.PostProcessable;
import org.jetbrains.annotations.ApiStatus;

import java.io.IOException;

@ApiStatus.Internal
public class CCAdapterFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonObject> objectDelegate = gson.getDelegateAdapter(this, new TypeToken<JsonObject>(){});

return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}

public T read(JsonReader in) throws IOException {
final T obj;

// handle
if (TypeToken.get(JsonHolder.class).isAssignableFrom(type)) {
try {
JsonObject jsonObject = objectDelegate.read(in);
obj = (T) type.getRawType().getConstructor(JsonObject.class).newInstance(jsonObject);
} catch (Exception e) {
throw new IllegalStateException("Failed to instantiate JsonHolder", e);
}
} else {
obj = delegate.read(in);
}

if (obj instanceof PostProcessable) {
((PostProcessable)obj).postProcess();
}

return obj;
}
};
}
}
118 changes: 118 additions & 0 deletions pojos/src/main/java/dev/qixils/crowdcontrol/socket/Field.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package dev.qixils.crowdcontrol.socket;

import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;

import java.util.*;

public class Field<T> {

private final List<String> ids;
private final boolean isTransient;
private final TypeToken<T> type;
private final Set<String> supports;

private Field(Collection<String> ids, Collection<String> supports, TypeToken<T> type, boolean isTransient) {
this.ids = Collections.unmodifiableList(new ArrayList<>(new LinkedHashSet<>(ids)));
this.supports = Collections.unmodifiableSet(new HashSet<>(supports));
this.type = type;
this.isTransient = isTransient;

assert !this.ids.isEmpty();
assert !this.supports.isEmpty();
}

public String id() {
return ids.get(0);
}

public List<String> ids() {
return ids;
}

public boolean isTransient() {
return isTransient;
}

public TypeToken<T> type() {
return type;
}

public boolean supports(String objectType) {
return supports.contains(objectType);
}

public boolean supports(ObjectType<?> objectType) {
return supports(objectType.id());
}

public static final class Builder<T> {
// TODO: this feels counter to the point of JsonHolder but i think making a dynamic builder here might be too meta, or maybe not IDK i guess i could detach dynamic building from json
private final List<String> ids = new ArrayList<>();
private boolean isTransient;
private final TypeToken<T> type;
private final Set<String> supports = new HashSet<>();

public Builder(TypeToken<T> type) {
this.type = type;
}

public Builder(Class<T> clazz) {
this.type = TypeToken.get(clazz);
}

public Builder<T> addId(@NotNull String id) {
this.ids.add(id);
return this;
}

public Builder<T> addIds(@NotNull String @NotNull ... ids) {
this.ids.addAll(Arrays.asList(ids));
return this;
}

public Builder<T> setId(@NotNull String id) {
this.ids.clear();
return addId(id);
}

public Builder<T> setIds(@NotNull String @NotNull ... ids) {
this.ids.clear();
return addIds(ids);
}

public Builder<T> isTransient(boolean isTransient) {
this.isTransient = isTransient;
return this;
}

public Builder<T> setTransient() {
return isTransient(true);
}

public Builder<T> addSupport(String objectType) {
this.supports.add(objectType);
return this;
}

public Builder<T> addSupports(String... objectTypes) {
this.supports.addAll(Arrays.asList(objectTypes));
return this;
}

public Builder<T> setSupport(String objectType) {
this.supports.clear();
return addSupport(objectType);
}

public Builder<T> setSupport(String... objectTypes) {
this.supports.clear();
return addSupports(objectTypes);
}

public Field<T> build() {
return new Field<>(ids, supports, type, isTransient);
}
}

}
73 changes: 73 additions & 0 deletions pojos/src/main/java/dev/qixils/crowdcontrol/socket/IHolder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package dev.qixils.crowdcontrol.socket;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import java.util.Optional;
import java.util.function.Supplier;

/**
* A holder of {@link Field}s.
*
* @since 4.0.0
*/
public interface IHolder {

/**
* Attempts to get a field from this object.
* May return empty if the field is {@link Field#supports(ObjectType) unsupported}
* or undefined.
*
* @param field the field to get
* @param <T> the type of the field
* @return the deserialized field
* @since 4.0.0
*/
<T> @NotNull Optional<T> get(@NotNull Field<T> field);

/**
* Attempts to get a field from this object.
* Returns the default if the field is {@link Field#supports(ObjectType) unsupported}
* or undefined.
*
* @param field the field to get
* @param <T> the type of the field
* @return the deserialized field
* @since 4.0.0
*/
@Contract(value = "_, !null -> !null", pure = true)
default <T> @Nullable T getOrDef(@NotNull Field<T> field, @Nullable T def) {
return get(field).orElse(def);
}

/**
* Attempts to get a field from this object.
* Returns the default if the field is {@link Field#supports(ObjectType) unsupported}
* or undefined.
*
* @param field the field to get
* @param <T> the type of the field
* @return the deserialized field
* @since 4.0.0
*/
@UnknownNullability("May be null if the supplier produces a null value")
default <T> T getOrSupply(@NotNull Field<T> field, @NotNull Supplier<@Nullable T> def) {
return get(field).orElseGet(def);
}

/**
* Attempts to get a field from this object.
* Returns null if the field is {@link Field#supports(ObjectType) unsupported}
* or undefined.
*
* @param field the field to get
* @param <T> the type of the field
* @return the deserialized field
* @since 4.0.0
*/
default <T> @Nullable T getOrNull(@NotNull Field<T> field) {
return getOrDef(field, null);
}
}
Loading

0 comments on commit f5149a3

Please sign in to comment.