io.datakernel.crdt.CrdtServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of datakernel-crdt Show documentation
Show all versions of datakernel-crdt Show documentation
Conflict-free replicated data type implementation for DataKernel Framework.
/*
* Copyright (C) 2015-2019 SoftIndex LLC.
*
* 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 io.datakernel.crdt;
import io.datakernel.common.exception.StacklessException;
import io.datakernel.csp.net.MessagingWithBinaryStreaming;
import io.datakernel.datastream.StreamConsumer;
import io.datakernel.datastream.csp.ChannelDeserializer;
import io.datakernel.datastream.csp.ChannelSerializer;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.net.AbstractServer;
import io.datakernel.net.AsyncTcpSocket;
import io.datakernel.promise.Promise;
import io.datakernel.serializer.BinarySerializer;
import java.net.InetAddress;
import static io.datakernel.crdt.CrdtMessaging.*;
import static io.datakernel.csp.binary.ByteBufSerializer.ofJsonCodec;
public final class CrdtServer, S> extends AbstractServer> {
private final CrdtStorage client;
private final CrdtDataSerializer serializer;
private final BinarySerializer keySerializer;
private CrdtServer(Eventloop eventloop, CrdtStorage client, CrdtDataSerializer serializer) {
super(eventloop);
this.client = client;
this.serializer = serializer;
keySerializer = serializer.getKeySerializer();
}
public static , S> CrdtServer create(Eventloop eventloop, CrdtStorage client, CrdtDataSerializer serializer) {
return new CrdtServer<>(eventloop, client, serializer);
}
public static , S> CrdtServer create(Eventloop eventloop, CrdtStorage client, BinarySerializer keySerializer, BinarySerializer stateSerializer) {
return new CrdtServer<>(eventloop, client, new CrdtDataSerializer<>(keySerializer, stateSerializer));
}
@Override
protected void serve(AsyncTcpSocket socket, InetAddress remoteAddress) {
MessagingWithBinaryStreaming messaging =
MessagingWithBinaryStreaming.create(socket, ofJsonCodec(MESSAGE_CODEC, RESPONSE_CODEC));
messaging.receive()
.then(msg -> {
if (msg == null) {
return Promise.ofException(new StacklessException(CrdtServer.class, "Unexpected end of stream"));
}
if (msg == CrdtMessages.UPLOAD) {
return messaging.receiveBinaryStream()
.transformWith(ChannelDeserializer.create(serializer))
.streamTo(StreamConsumer.ofPromise(client.upload()))
.then($ -> messaging.send(CrdtResponses.UPLOAD_FINISHED))
.then($ -> messaging.sendEndOfStream())
.whenResult($ -> messaging.close());
}
if (msg == CrdtMessages.REMOVE) {
return messaging.receiveBinaryStream()
.transformWith(ChannelDeserializer.create(keySerializer))
.streamTo(StreamConsumer.ofPromise(client.remove()))
.then($ -> messaging.send(CrdtResponses.REMOVE_FINISHED))
.then($ -> messaging.sendEndOfStream())
.whenResult($ -> messaging.close());
}
if (msg instanceof Download) {
return client.download(((Download) msg).getToken())
.whenResult($ -> messaging.send(new DownloadStarted()))
.then(supplier -> supplier
.transformWith(ChannelSerializer.create(serializer))
.streamTo(messaging.sendBinaryStream()));
}
return Promise.ofException(new StacklessException(CrdtServer.class, "Message type was added, but no handling code for it"));
})
.whenComplete(($, e) -> {
if (e == null) {
return;
}
logger.warn("got an error while handling message (" + e + ") : " + this);
String prefix = e.getClass() != StacklessException.class ? e.getClass().getSimpleName() + ": " : "";
messaging.send(new ServerError(prefix + e.getMessage()))
.then($1 -> messaging.sendEndOfStream())
.whenResult($1 -> messaging.close());
});
}
}