Add service-td

This commit is contained in:
Andrea Cavalli 2021-11-10 01:13:31 +01:00
parent 440a4b2a7b
commit 0f3b446413
35 changed files with 835 additions and 374 deletions

4
.gitignore vendored
View File

@ -150,3 +150,7 @@ modules.xml
# End of https://www.gitignore.io/api/intellij+all # End of https://www.gitignore.io/api/intellij+all
/example/ /example/
**/.cache/
**/mvnw
**/mvnw.cmd
**/.mvn

39
pom.xml Normal file
View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>it.volvox</groupId>
<artifactId>volvox-parent-root</artifactId>
<version>2.0</version>
<packaging>pom</packaging>
<name>Volvox project root</name>
<modules>
</modules>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<finalName>quarkus-volvox</finalName>
<appendAssemblyId>true</appendAssemblyId>
<runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
<attach>false</attach>
<descriptors>
<descriptor>assembly.xml</descriptor>
<descriptor>assembly-complete.xml</descriptor>
</descriptors>
<outputDirectory>dist</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>complete</id>
<modules>
<module>service-td</module>
</modules>
</profile>
</profiles>
</project>

View File

@ -37,6 +37,3 @@ nb-configuration.xml
# Local environment # Local environment
.env .env
/.mvn/
/mvnw
/mvnw.cmd

View File

@ -1,13 +1,12 @@
# Volvox Project # service-td Project
This project uses Quarkus, the Supersonic Subatomic Java Framework. This project uses Quarkus, the Supersonic Subatomic Java Framework.
If you want to learn more about Quarkus, please visit its website: [quarkus.io](https://quarkus.io/). If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
## Running the application in dev mode ## Running the application in dev mode
You can run your application in dev mode that enables live coding using: You can run your application in dev mode that enables live coding using:
```shell script ```shell script
./mvnw compile quarkus:dev ./mvnw compile quarkus:dev
``` ```
@ -17,18 +16,15 @@ You can run your application in dev mode that enables live coding using:
## Packaging and running the application ## Packaging and running the application
The application can be packaged using: The application can be packaged using:
```shell script ```shell script
./mvnw package ./mvnw package
``` ```
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. Be aware that its not an _über-jar_ as Be aware that its not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
the dependencies are copied into the `target/quarkus-app/lib/` directory.
The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
If you want to build an _über-jar_, execute the following command: If you want to build an _über-jar_, execute the following command:
```shell script ```shell script
./mvnw package -Dquarkus.package.type=uber-jar ./mvnw package -Dquarkus.package.type=uber-jar
``` ```
@ -37,40 +33,25 @@ The application, packaged as an _über-jar_, is now runnable using `java -jar ta
## Creating a native executable ## Creating a native executable
You can create a native executable using: You can create a native executable using:
```shell script ```shell script
./mvnw package -Pnative ./mvnw package -Pnative
``` ```
Or, if you don't have GraalVM installed, you can run the native executable build in a container using: Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
```shell script ```shell script
./mvnw package -Pnative -Dquarkus.native.container-build=true ./mvnw package -Pnative -Dquarkus.native.container-build=true
``` ```
You can then execute your native executable with: `./target/volvox-1.0-SNAPSHOT-runner` You can then execute your native executable with: `./target/service-td-1.0.0-SNAPSHOT-runner`
If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html.
.
## Related Guides ## Related Guides
- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): Reactive implementation of JAX-RS with
additional features. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions
that depend on it.
- YAML Configuration ([guide](https://quarkus.io/guides/config#yaml)): Use YAML to configure your Quarkus application
## Provided Code ## Provided Code
### YAML Config
Configure your application with YAML
[Related guide section...](https://quarkus.io/guides/config-reference#configuration-examples)
The Quarkus application configuration is located in `src/main/resources/application.yml`.
### RESTEasy Reactive ### RESTEasy Reactive
Easily start your Reactive RESTful Web Services Easily start your Reactive RESTful Web Services

View File

@ -1,11 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>it.cavallium</groupId> <groupId>it.volvox.service-td</groupId>
<artifactId>volvox</artifactId> <artifactId>service-td</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
<properties> <properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version> <compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters> <maven.compiler.parameters>true</maven.compiler.parameters>
@ -17,7 +16,16 @@
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>2.4.1.Final</quarkus.platform.version> <quarkus.platform.version>2.4.1.Final</quarkus.platform.version>
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version> <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
<volvox.tdlight.version>2.7.9.2</volvox.tdlight.version>
<volvox.tdlight.natives.version>4.0.183</volvox.tdlight.natives.version>
</properties> </properties>
<repositories>
<repository>
<id>mchv</id>
<name>MCHV Apache Maven Packages</name>
<url>https://mvn.mchv.eu/repository/mchv/</url>
</repository>
</repositories>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
@ -27,65 +35,48 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-java</artifactId>
<version>${volvox.tdlight.version}</version>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives-linux-amd64</artifactId>
<version>${volvox.tdlight.natives.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mutiny</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elasticsearch-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-metrics</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-search-orm-elasticsearch</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId> <artifactId>quarkus-reactive-pg-client</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-routes</artifactId> <artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId> <artifactId>quarkus-arc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId> <artifactId>quarkus-junit5</artifactId>
@ -96,6 +87,15 @@
<artifactId>rest-assured</artifactId> <artifactId>rest-assured</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-java</artifactId>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives-linux-amd64</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

View File

@ -7,18 +7,18 @@
# #
# Then, build the image with: # Then, build the image with:
# #
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/volvox-jvm . # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/service-td-jvm .
# #
# Then run the container using: # Then run the container using:
# #
# docker run -i --rm -p 8080:8080 quarkus/volvox-jvm # docker run -i --rm -p 8080:8080 quarkus/service-td-jvm
# #
# If you want to include the debug port into your docker image # If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
# #
# Then run the container using : # Then run the container using :
# #
# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/volvox-jvm # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-td-jvm
# #
### ###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4

View File

@ -7,18 +7,18 @@
# #
# Then, build the image with: # Then, build the image with:
# #
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/volvox-legacy-jar . # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/service-td-legacy-jar .
# #
# Then run the container using: # Then run the container using:
# #
# docker run -i --rm -p 8080:8080 quarkus/volvox-legacy-jar # docker run -i --rm -p 8080:8080 quarkus/service-td-legacy-jar
# #
# If you want to include the debug port into your docker image # If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005 # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
# #
# Then run the container using : # Then run the container using :
# #
# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/volvox-legacy-jar # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-td-legacy-jar
# #
### ###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4

View File

@ -7,11 +7,11 @@
# #
# Then, build the image with: # Then, build the image with:
# #
# docker build -f src/main/docker/Dockerfile.native -t quarkus/volvox . # docker build -f src/main/docker/Dockerfile.native -t quarkus/service-td .
# #
# Then run the container using: # Then run the container using:
# #
# docker run -i --rm -p 8080:8080 quarkus/volvox # docker run -i --rm -p 8080:8080 quarkus/service-td
# #
### ###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4

View File

@ -7,11 +7,11 @@
# #
# Then, build the image with: # Then, build the image with:
# #
# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/volvox . # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/service-td .
# #
# Then run the container using: # Then run the container using:
# #
# docker run -i --rm -p 8080:8080 quarkus/volvox # docker run -i --rm -p 8080:8080 quarkus/service-td
# #
### ###
FROM quay.io/quarkus/quarkus-distroless-image:1.0 FROM quay.io/quarkus/quarkus-distroless-image:1.0

View File

@ -0,0 +1,81 @@
package io.volvox.td;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.buffer.impl.BufferImpl;
import java.io.IOException;
public class BufferUtils {
private static final int CHUNK_SIZE = 8192;
public static void writeBuf(ByteBufOutputStream os, Buffer dataToWrite) throws IOException {
var len = dataToWrite.length();
os.writeInt(len);
byte[] part = new byte[CHUNK_SIZE];
for (int i = 0; i < len; i += CHUNK_SIZE) {
var end = Math.min(i + CHUNK_SIZE, len);
dataToWrite.getBytes(i, end, part, 0);
os.write(part, 0, end - i);
}
}
public static Buffer readBuf(ByteBufInputStream is) throws IOException {
int len = is.readInt();
Buffer buf = Buffer.buffer(len);
byte[] part = new byte[1024];
int readPart = 0;
for (int i = 0; i < len; i += 1024) {
var lenx = (Math.min(i + 1024, len)) - i;
if (lenx > 0) {
readPart = is.readNBytes(part, 0, lenx);
buf.appendBytes(part, 0, readPart);
}
}
return buf;
}
public static io.vertx.core.buffer.Buffer rxReadBuf(ByteBufInputStream is) throws IOException {
int len = is.readInt();
io.vertx.core.buffer.Buffer buf = io.vertx.core.buffer.Buffer.buffer(len);
byte[] part = new byte[1024];
int readPart = 0;
for (int i = 0; i < len; i += 1024) {
var lenx = (Math.min(i + 1024, len)) - i;
if (lenx > 0) {
readPart = is.readNBytes(part, 0, lenx);
buf.appendBytes(part, 0, readPart);
}
}
return buf;
}
public interface Writer {
void write(ByteBufOutputStream os) throws IOException;
}
public interface Reader<T> {
T read(ByteBufInputStream is) throws IOException;
}
public static void encode(Buffer buffer, Writer writer) {
try (var os = new ByteBufOutputStream(((BufferImpl) buffer).byteBuf())) {
writer.write(os);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
public static <T> T decode(int pos, Buffer buffer, Reader<T> reader) {
try (var is = new ByteBufInputStream(buffer.slice(pos, buffer.length()).getByteBuf())) {
return reader.read(is);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@ -0,0 +1,17 @@
package io.volvox.td;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Singleton;
@ApplicationScoped
public class ExecutorProducer {
@Produces
@Singleton
public Executor produceExecutor() {
return Executors.newCachedThreadPool();
}
}

View File

@ -0,0 +1,13 @@
package io.volvox.td;
import java.util.UUID;
public class RandomUUID {
final String uuid;
public RandomUUID() {
this.uuid = UUID.randomUUID().toString();
}
}

View File

@ -0,0 +1,16 @@
package io.volvox.td;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Update;
public interface TdClient {
Multi<Update> updates();
<T extends TdApi.Object> Uni<T> send(TdApi.Function<T> function);
<T extends TdApi.Object> Uni<T> execute(TdApi.Function<T> function);
void dispose();
}

View File

@ -0,0 +1,38 @@
package io.volvox.td;
import io.quarkus.vertx.runtime.VertxProducer;
import it.tdlight.common.Init;
import it.tdlight.common.ReactiveTelegramClient;
import it.tdlight.common.utils.CantLoadLibrary;
import it.tdlight.tdlight.ClientManager;
import java.time.Duration;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Singleton;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
@ApplicationScoped
class TdClientProducers {
private static final Logger LOGGER = Logger.getLogger(VertxProducer.class);
@ConfigProperty(name = "td.requests.timeout")
Duration requestTimeout;
@Produces
ReactiveTelegramClient produceReactiveTelegramClient() {
try {
Init.start();
} catch (CantLoadLibrary e) {
LOGGER.error(e);
}
return ClientManager.createReactive();
}
@Produces
@Singleton
public Duration produceRequestTimeout() {
return requestTimeout;
}
}

View File

@ -0,0 +1,25 @@
package io.volvox.td;
public class TdException extends Exception {
private final int code;
private final String message;
public TdException(int code, String message) {
super(code + ": " + message);
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getErrorMessage() {
return message;
}
@Override public String toString() {
return code + ": " + message;
}
}

View File

@ -0,0 +1,86 @@
package io.volvox.td;
import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import it.tdlight.common.ReactiveTelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Error;
import it.tdlight.jni.TdApi.Update;
import java.time.Duration;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
@Dependent
public class TdNativeClient implements TdClient {
@Inject
ReactiveTelegramClient client;
@Inject
Duration requestTimeout;
private Multi<Update> updates;
@PostConstruct
void init() {
this.updates = Multi.createFrom().<Update>emitter(emitter -> {
client.createAndRegisterClient();
client.setListener(signal -> {
if (signal.isClosed()) {
emitter.complete();
} else if (signal.isUpdate()) {
var update = (TdApi.Update) signal.getUpdate();
emitter.emit(update);
} else if (signal.isException()) {
emitter.fail(signal.getException());
} else {
throw new IllegalStateException("Unknown signal: " + signal);
}
});
emitter.onTermination(client::dispose);
}).broadcast().toAllSubscribers();
}
@Override public Multi<TdApi.Update> updates() {
return updates;
}
@Override @SuppressWarnings("unchecked")
public <T extends TdApi.Object> Uni<T> send(TdApi.Function<T> function) {
return (Uni<T>) Uni
.createFrom()
.publisher(client.send(function, requestTimeout))
.onItem()
.transformToUni(item -> {
if (item.getConstructor() == Error.CONSTRUCTOR) {
TdApi.Error error = (TdApi.Error) item;
return Uni.createFrom().failure(new TdException(error.code, error.message));
} else {
return Uni.createFrom().item(item);
}
});
}
@Override @SuppressWarnings("unchecked")
public <T extends TdApi.Object> Uni<T> execute(TdApi.Function<T> function) {
return (Uni<T>) Uni
.createFrom()
.item(() -> client.execute(function))
.onItem()
.transformToUni(item -> {
if (item.getConstructor() == Error.CONSTRUCTOR) {
TdApi.Error error = (TdApi.Error) item;
return Uni.createFrom().failure(new TdException(error.code, error.message));
} else {
return Uni.createFrom().item(item);
}
});
}
@Override public void dispose() {
this.client.dispose();
}
}

View File

@ -0,0 +1,17 @@
package io.volvox.td;
import it.tdlight.jni.TdApi;
public class TdObject {
private final TdApi.Object object;
public TdObject(TdApi.Object object) {
this.object = object;
}
public <T extends TdApi.Object> T getObject() {
//noinspection unchecked
return (T) object;
}
}

View File

@ -0,0 +1,36 @@
package io.volvox.td;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.MessageCodec;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Deserializer;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Singleton;
@ApplicationScoped
public class TdObjectCodec implements MessageCodec<TdObject, TdObject> {
@Override public void encodeToWire(Buffer buffer, TdObject t) {
BufferUtils.encode(buffer, out -> t.getObject().serialize(out));
}
@Override
public TdObject decodeFromWire(int i, Buffer buffer) {
return new TdObject(BufferUtils.decode(i, buffer, Deserializer::deserialize));
}
@Override public TdObject transform(TdObject t) {
// If a message is sent *locally* across the event bus.
// This sends message just as is
return t;
}
@Override public String name() {
return "TdObjectCodec";
}
@Override public byte systemCodecID() {
// Always "-1"
return -1;
}
}

View File

@ -0,0 +1,33 @@
package io.volvox.td;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/api/td")
public class TdResource {
@Inject TdSessionRegistry tdSessionRegistry;
@Inject TdService tdService;
@Path("/list")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String listSessions() {
StringBuilder sb = new StringBuilder();
for (var session : tdSessionRegistry.getSessions()) {
sb.append(session).append(System.lineSeparator());
}
return sb.toString();
}
@Path("/create-session")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String createSession() {
return tdService.startSession(null);
}
}

View File

@ -0,0 +1,43 @@
package io.volvox.td;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.vertx.ConsumeEvent;
import io.vertx.core.eventbus.EventBus;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
@ApplicationScoped
public class TdService {
private final ConcurrentMap<String, TdClient> clients = new ConcurrentHashMap<>();
@Inject
EventBus bus;
@Inject
Instance<TdSession> sessionInstances;
@ConsumeEvent(value = "td.start-session")
public String startSession(Void param) {
String uuid = generateRandomUUID();
var client = sessionInstances.get();
clients.put(uuid, client);
client.publishUpdates();
return uuid;
}
private String generateRandomUUID() {
return UUID.randomUUID().toString();
}
void shutdown(@Observes ShutdownEvent event) {
clients.forEach((uuid, client) -> client.dispose());
}
}

View File

@ -0,0 +1,84 @@
package io.volvox.td;
import io.quarkus.vertx.ConsumeEvent;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.subscription.Cancellable;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.Object;
import it.tdlight.jni.TdApi.Update;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
@Dependent
public class TdSession implements TdClient {
private static final DeliveryOptions UPDATES_OPTS
= new DeliveryOptions().setCodecName("TdObjectCodec");
private static final DeliveryOptions SEND_OPTS
= new DeliveryOptions().setCodecName("TdObjectCodec");
@Inject
RandomUUID uuid;
@Inject
Executor executor;
@Inject
TdNativeClient client;
@Inject
EventBus bus;
private final AtomicReference<Cancellable> updatesPublisher = new AtomicReference<>();
@Override public Multi<Update> updates() {
return client.updates();
}
public void publishUpdates() {
var newPublisher = this.updates()
.runSubscriptionOn(executor)
.subscribe()
.with(item -> bus.publish("td.update", item, UPDATES_OPTS));
var prev = this.updatesPublisher.getAndSet(newPublisher);
if (prev != null) {
throw new IllegalStateException("Called publishUpdates twice!");
}
}
@ConsumeEvent(value = "td.send", codec = TdObjectCodec.class)
void onSendRequest(Message<TdObject> msg) {
this.send(msg.body().getObject()).subscribe()
.with(message -> msg.reply(message, SEND_OPTS),
ex -> {
if (ex instanceof TdException tdException) {
msg.fail(tdException.getCode(), tdException.getMessage());
} else {
msg.fail(500, ex.toString());
}
}
);
}
@Override public <T extends Object> Uni<T> send(Function<T> function) {
return client.send(function);
}
@SuppressWarnings("unchecked") @Override public <T extends Object> Uni<T> execute(Function<T> function) {
return null;
}
@Override public void dispose() {
var updatesPublisher = this.updatesPublisher.get();
if (updatesPublisher != null) {
updatesPublisher.cancel();
}
client.dispose();
}
}

View File

@ -0,0 +1,28 @@
package io.volvox.td;
import io.vertx.core.impl.ConcurrentHashSet;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class TdSessionRegistry {
private final Set<String> clients = new ConcurrentHashSet<>();
@Produces
public RandomUUID produceUUID() {
var randomUUID = new RandomUUID();
clients.add(randomUUID.uuid);
return randomUUID;
}
public void cleanUUID(@Disposes RandomUUID toClean) {
clients.remove(toClean.uuid);
}
public Set<String> getSessions() {
return clients;
}
}

View File

@ -0,0 +1,175 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>service-td - 1.0.0-SNAPSHOT</title>
<style>
h1, h2, h3, h4, h5, h6 {
margin-bottom: 0.5rem;
font-weight: 400;
line-height: 1.5;
}
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem
}
h3 {
font-size: 1.75rem
}
h4 {
font-size: 1.5rem
}
h5 {
font-size: 1.25rem
}
h6 {
font-size: 1rem
}
.lead {
font-weight: 300;
font-size: 2rem;
}
.banner {
font-size: 2.7rem;
margin: 0;
padding: 2rem 1rem;
background-color: #0d1c2c;
color: white;
}
body {
margin: 0;
font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
code {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 87.5%;
color: #e83e8c;
word-break: break-word;
}
.left-column {
padding: .75rem;
max-width: 75%;
min-width: 55%;
}
.right-column {
padding: .75rem;
max-width: 25%;
}
.container {
display: flex;
width: 100%;
}
li {
margin: 0.75rem;
}
.right-section {
margin-left: 1rem;
padding-left: 0.5rem;
}
.right-section h3 {
padding-top: 0;
font-weight: 200;
}
.right-section ul {
border-left: 0.3rem solid #71aeef;
list-style-type: none;
padding-left: 0;
}
.provided-code {
border-left: 0.3rem solid #71aeef;
padding-left: 10px;
}
.provided-code h3 {
font-weight: 200;
}
</style>
</head>
<body>
<div class="banner lead">
Your new Cloud-Native application is ready!
</div>
<div class="container">
<div class="left-column">
<p class="lead"> Congratulations, you have created a new Quarkus cloud application.</p>
<h2>What is this page?</h2>
<p>This page is served by Quarkus. The source is in
<code>src/main/resources/META-INF/resources/index.html</code>.</p>
<h2>What are your next steps?</h2>
<p>If not already done, run the application in <em>dev mode</em> using: <code>./mvnw compile quarkus:dev</code>.
</p>
<ul>
<li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li>
<li>Configure your application in <code>src/main/resources/application.properties</code>.</li>
<li>Quarkus now ships with a <a href="/q/dev/">Dev UI</a> (available in dev mode only)</li>
<li>Play with the provided code located in <code>src/main/java</code>:</li>
</ul>
<div class="provided-code">
<h3>RESTEasy Reactive</h3>
<p>Easily start your Reactive RESTful Web Services</p>
<p><code>@Path: <a href="/api/td" class="path-link" target="_blank">/api/td</a></code></p>
<p><a href="https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources" class="guide-link" target="_blank">Related guide section...</a></p>
</div>
</div>
<div class="right-column">
<div class="right-section">
<h3>Application</h3>
<ul>
<li>GroupId: <code>it.volvox.service-td</code></li>
<li>ArtifactId: <code>service-td</code></li>
<li>Version: <code>1.0.0-SNAPSHOT</code></li>
<li>Quarkus Version: <code>2.4.1.Final</code></li>
</ul>
</div>
<div class="right-section">
<h3>Do you like Quarkus?</h3>
<ul>
<li>Go give it a star on <a href="https://github.com/quarkusio/quarkus">GitHub</a>.</li>
</ul>
</div>
<div class="right-section">
<h3>Selected extensions guides</h3>
<ul>
</ul>
</div>
<div class="right-section">
<h3>More reading</h3>
<ul>
<li><a href="https://quarkus.io/guides/maven-tooling.html" target="_blank">Setup your IDE</a></li>
<li><a href="https://quarkus.io/guides/getting-started.html" target="_blank">Getting started</a></li>
<li><a href="https://quarkus.io/guides/" target="_blank">All guides</a></li>
<li><a href="https://quarkus.io" target="_blank">Quarkus Web Site</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1 @@
td.requests.timeout = 10s

View File

@ -0,0 +1,9 @@
package io.volvox.td;
import io.quarkus.test.junit.NativeImageTest;
@NativeImageTest
public class NativeTdResourceIT extends TdResourceTest {
// Execute the same tests but in native mode.
}

View File

@ -0,0 +1,21 @@
package io.volvox.td;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class TdResourceTest {
@Test
public void testEmptyList() {
given()
.when().get("/api/td/list")
.then()
.statusCode(200)
.body(is(""));
}
}

View File

@ -1,25 +0,0 @@
package it.cavallium;
import io.smallrye.mutiny.Uni;
import java.time.Duration;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/delay")
public class ExampleDelayedResource {
@Path("{seconds:\\d+}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public Uni<String> delay(int seconds) {
return Uni
// Create the response item
.createFrom().item("Hello from the future! %d seconds have passed".formatted(seconds))
// Delay the response by n seconds
.onItem().delayIt().by(Duration.ofSeconds(seconds));
}
}

View File

@ -1,16 +0,0 @@
package it.cavallium;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class ExampleResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy Reactive";
}
}

View File

@ -1,12 +0,0 @@
package it.cavallium;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithName;
@ConfigMapping(prefix = "greeting")
public interface GreetingConfig {
@WithName("message")
String message();
}

View File

@ -1,180 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>volvox - 1.0-SNAPSHOT</title>
<style>
h1, h2, h3, h4, h5, h6 {
margin-bottom: 0.5rem;
font-weight: 400;
line-height: 1.5;
}
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem
}
h3 {
font-size: 1.75rem
}
h4 {
font-size: 1.5rem
}
h5 {
font-size: 1.25rem
}
h6 {
font-size: 1rem
}
.lead {
font-weight: 300;
font-size: 2rem;
}
.banner {
font-size: 2.7rem;
margin: 0;
padding: 2rem 1rem;
background-color: #0d1c2c;
color: white;
}
body {
margin: 0;
font-family: -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
code {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 87.5%;
color: #e83e8c;
word-break: break-word;
}
.left-column {
padding: .75rem;
max-width: 75%;
min-width: 55%;
}
.right-column {
padding: .75rem;
max-width: 25%;
}
.container {
display: flex;
width: 100%;
}
li {
margin: 0.75rem;
}
.right-section {
margin-left: 1rem;
padding-left: 0.5rem;
}
.right-section h3 {
padding-top: 0;
font-weight: 200;
}
.right-section ul {
border-left: 0.3rem solid #71aeef;
list-style-type: none;
padding-left: 0;
}
.provided-code {
border-left: 0.3rem solid #71aeef;
padding-left: 10px;
}
.provided-code h3 {
font-weight: 200;
}
</style>
</head>
<body>
<div class="banner lead">
Your new Cloud-Native application is ready!
</div>
<div class="container">
<div class="left-column">
<p class="lead"> Congratulations, you have created a new Quarkus cloud application.</p>
<h2>What is this page?</h2>
<p>This page is served by Quarkus. The source is in
<code>src/main/resources/META-INF/resources/index.html</code>.</p>
<h2>What are your next steps?</h2>
<p>If not already done, run the application in <em>dev mode</em> using: <code>./mvnw compile quarkus:dev</code>.
</p>
<ul>
<li>Your static assets are located in <code>src/main/resources/META-INF/resources</code>.</li>
<li>Configure your application in <code>src/main/resources/application.yml</code>.</li>
<li>Quarkus now ships with a <a href="/q/dev/">Dev UI</a> (available in dev mode only)</li>
<li>Play with the provided code located in <code>src/main/java</code>:</li>
</ul>
<div class="provided-code">
<h3>RESTEasy Reactive</h3>
<p>Easily start your Reactive RESTful Web Services</p>
<p><code>@Path: <a href="/hello" class="path-link" target="_blank">/hello</a></code></p>
<p><a href="https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources" class="guide-link"
target="_blank">Related guide section...</a></p>
</div>
</div>
<div class="right-column">
<div class="right-section">
<h3>Application</h3>
<ul>
<li>GroupId: <code>it.cavallium</code></li>
<li>ArtifactId: <code>volvox</code></li>
<li>Version: <code>1.0-SNAPSHOT</code></li>
<li>Quarkus Version: <code>2.4.1.Final</code></li>
</ul>
</div>
<div class="right-section">
<h3>Do you like Quarkus?</h3>
<ul>
<li>Go give it a star on <a href="https://github.com/quarkusio/quarkus">GitHub</a>.</li>
</ul>
</div>
<div class="right-section">
<h3>Selected extensions guides</h3>
<ul>
<li title="Reactive implementation of JAX-RS with additional features. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it.">
<a href="https://quarkus.io/guides/resteasy-reactive" target="_blank">RESTEasy Reactive guide</a></li>
<li title="Use YAML to configure your Quarkus application"><a href="https://quarkus.io/guides/config#yaml"
target="_blank">YAML Configuration guide</a></li>
</ul>
</div>
<div class="right-section">
<h3>More reading</h3>
<ul>
<li><a href="https://quarkus.io/guides/maven-tooling.html" target="_blank">Setup your IDE</a></li>
<li><a href="https://quarkus.io/guides/getting-started.html" target="_blank">Getting started</a></li>
<li><a href="https://quarkus.io/guides/" target="_blank">All guides</a></li>
<li><a href="https://quarkus.io" target="_blank">Quarkus Web Site</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,2 +0,0 @@
greeting:
message: "hello"

View File

@ -1,22 +0,0 @@
package it.cavallium;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class ExampleDelayResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when()
.get("/delay?duration=1")
.then()
.statusCode(200)
.body(is("Hello from the future! %d seconds have passed".formatted(1)));
}
}

View File

@ -1,17 +0,0 @@
package it.cavallium;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class ExampleResourceTest {
@Test
public void testHelloEndpoint() {
given().when().get("/hello").then().statusCode(200).body(is("Hello RESTEasy Reactive"));
}
}

View File

@ -1,9 +0,0 @@
package it.cavallium;
import io.quarkus.test.junit.NativeImageTest;
@NativeImageTest
public class NativeExampleResourceIT extends ExampleResourceTest {
// Execute the same tests but in native mode.
}