From 921fb030a2a56f72323fba99240d5b119e96560b Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 19 Nov 2019 13:14:48 +0200 Subject: [PATCH 01/37] Join room: protocol definition and API handler (not implemented yet). --- .../api/ConferenceFactoryGrpcApi.java | 42 +++++--- .../api/ConferenceFactoryWebApi.java | 98 +++++++++++-------- .../service/ConferenceFactory.java | 13 ++- .../service/ConferenceFactoryVerticle.java | 12 --- .../nccs/lib/grpcutil/PathHandler.java | 15 +++ .../nccs/lib/grpcutil/WebApiCallConsumer.java | 11 +++ protocol/public/src/main/proto | 2 +- 7 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java create mode 100644 lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index e570967d..16e84014 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -3,29 +3,35 @@ package com.nynjacoin.nccs.conferencefactory.api; import com.nynjacoin.nccs.conferencefactory.service.ConferenceFactoryVerticle; import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; import com.nynjacoin.nccs.protocol.cfp.ConferenceFactoryGrpc; +import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; +import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import io.vertx.core.Future; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; public class ConferenceFactoryGrpcApi extends ConferenceFactoryGrpc.ConferenceFactoryVertxImplBase { - private static final Logger LOGGER = LogManager.getLogger(ConferenceFactoryGrpcApi.class); - private final ConferenceFactoryVerticle conferenceFactoryVerticle; + private final ConferenceFactoryVerticle verticle; public ConferenceFactoryGrpcApi(ConferenceFactoryVerticle conferenceFactoryVerticle) { - this.conferenceFactoryVerticle = conferenceFactoryVerticle; + this.verticle = conferenceFactoryVerticle; } @Override - public void createConference(com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest request, - io.vertx.core.Future response) { + public void createConference( + CreateConferenceRequest request, + Future response) { String accountId = GrpcContextKeys.ACCOUNT_ID.get(); - conferenceFactoryVerticle.createConference(accountId, request, response); + verticle.runOnContext( + () -> verticle.conferenceFactory.createConference(accountId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); } @Override @@ -35,12 +41,24 @@ public class ConferenceFactoryGrpcApi String accountId = GrpcContextKeys.ACCOUNT_ID.get(); - conferenceFactoryVerticle.runOnContext( - () -> { - conferenceFactoryVerticle.conferenceFactory.getConferenceId(accountId, request, response); - }, + verticle.runOnContext( + () -> verticle.conferenceFactory.getConferenceId(accountId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); + } + + @Override + public void joinRoom( + JoinRoomRequest request, + Future response) { + String accountId = GrpcContextKeys.ACCOUNT_ID.get(); + + verticle.runOnContext( + () -> verticle.conferenceFactory.joinRoom(accountId, request, response), response, GrpcContextKeys.LOG_CONTEXT.get() ); } + } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index 59dcff8a..d6e1e399 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -1,7 +1,8 @@ package com.nynjacoin.nccs.conferencefactory.api; +import com.google.protobuf.InvalidProtocolBufferException; import com.nynjacoin.nccs.conferencefactory.service.ConferenceFactoryVerticle; -import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; +import com.nynjacoin.nccs.lib.grpcutil.PathHandler; import com.nynjacoin.nccs.lib.grpcutil.WebApi; import com.nynjacoin.nccs.lib.grpcutil.WebMetadata; import com.nynjacoin.nccs.lib.grpcutil.WebResponseHandler; @@ -9,58 +10,70 @@ import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.error.NccsWrappingException; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; -import io.grpc.Context; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; public class ConferenceFactoryWebApi implements WebApi { public ConferenceFactoryWebApi(ConferenceFactoryVerticle conferenceFactoryVerticle) { - this.conferenceFactoryVerticle = conferenceFactoryVerticle; + this.verticle = conferenceFactoryVerticle; } - private final ConferenceFactoryVerticle conferenceFactoryVerticle; - - private void createConference(RoutingContext ctx) { - ctx.request().bodyHandler(NccsWrappingException.wrap(bodyBuffer -> { - WebMetadata webMetadata = new WebMetadata(ctx); - String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - - CreateConferenceRequest request = CreateConferenceRequest.parseFrom(bodyBuffer.getBytes()); - Future response = WebResponseHandler.future(ctx); - - Context logGrpcContext = Context.current() - .withValue(GrpcContextKeys.LOG_CONTEXT, webMetadata.getLogContext()); - Context prevGrpcContext = logGrpcContext.attach(); - try { - conferenceFactoryVerticle.createConference(accountId, request, response); - } finally { - logGrpcContext.detach(prevGrpcContext); - } - })); + private final ConferenceFactoryVerticle verticle; + + private void createConference(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + CreateConferenceRequest request = CreateConferenceRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.createConference(accountId, request, response), + response, + webMetadata.getLogContext() + ); } - private void getConferenceId(RoutingContext ctx) { - ctx.request().bodyHandler(NccsWrappingException.wrap(bodyBuffer -> { - WebMetadata webMetadata = new WebMetadata(ctx); - String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - - GetConferenceIdRequest request = GetConferenceIdRequest.parseFrom(bodyBuffer.getBytes()); - Future response = WebResponseHandler.future(ctx); - - conferenceFactoryVerticle.runOnContext( - () -> { - conferenceFactoryVerticle.conferenceFactory - .getConferenceId(accountId, request, response); - }, - response, - webMetadata.getLogContext() - ); - })); + private void getConferenceId(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + GetConferenceIdRequest request = GetConferenceIdRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.getConferenceId(accountId, request, response), + response, + webMetadata.getLogContext() + ); + } + + private void joinRoom(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + JoinRoomRequest request = JoinRoomRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.joinRoom(accountId, request, response), + response, + webMetadata.getLogContext() + ); } @Override @@ -74,10 +87,13 @@ public class ConferenceFactoryWebApi implements WebApi { router .route("/CreateConference") - .handler(this::createConference); + .handler(PathHandler.compose(this::createConference)); router .route("/GetConferenceId") - .handler(this::getConferenceId); + .handler(PathHandler.compose(this::getConferenceId)); + router + .route("/JoinRoom") + .handler(PathHandler.compose(this::joinRoom)); return router; } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index c1929922..07a67f1e 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -7,6 +7,8 @@ import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.error.NccsError; import io.vertx.core.Future; import io.vertx.core.Vertx; @@ -26,19 +28,19 @@ public class ConferenceFactory { .findFirst(); } - } + } private final Map accountConferences; private final Map conferences; + private final Map conferencesByLink; private final int membersCountLimit; private final JoinLinkComposer joinLinkComposer; private final LinkIdGenerator linkIdGenerator; - - public ConferenceFactory(JsonObject config, JoinLinkComposer joinLinkComposer) { + ConferenceFactory(JsonObject config, JoinLinkComposer joinLinkComposer) { this.accountConferences = new HashMap<>(); this.conferences = new HashMap<>(); this.conferencesByLink = new HashMap<>(); @@ -49,7 +51,7 @@ public class ConferenceFactory { this.linkIdGenerator = new LinkIdGenerator(); } - void createConference(String accountId, + public void createConference(String accountId, com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest request, io.vertx.core.Future response) { @@ -96,6 +98,9 @@ public class ConferenceFactory { response.complete(responseBuilder.build()); } + public void joinRoom(String accountId, JoinRoomRequest request, Future response) { + } + public void discardConference(String conferenceId) { ConferenceInfo conferenceInfo = conferences.remove(conferenceId); if (conferenceInfo == null) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java index 2c92b13a..f46053d7 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java @@ -16,18 +16,6 @@ public class ConferenceFactoryVerticle extends NccsVerticle { this.conferenceFactory = new ConferenceFactory(config, joinLinkComposer); } - public void createConference(String accountId, - com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest request, - io.vertx.core.Future response) { - - final var logContext = GrpcContextKeys.LOG_CONTEXT.get(); - context.runOnContext(v -> { - try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { - conferenceFactory.createConference(accountId, request, response); - } - }); - } - public void getConferenceInfo(String conferenceId, Future response) { final var logContext = ThreadContext.getContext(); context.runOnContext(v -> { diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java new file mode 100644 index 00000000..09365df0 --- /dev/null +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java @@ -0,0 +1,15 @@ +package com.nynjacoin.nccs.lib.grpcutil; + +import com.nynjacoin.nccs.protocol.error.NccsWrappingException; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +public class PathHandler { + + public static Handler compose(WebApiCallConsumer consumer) { + return ctx -> ctx.request().bodyHandler( + NccsWrappingException.wrap(bodyBuffer -> consumer.accept(ctx, bodyBuffer)) + ); + } + +} diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java new file mode 100644 index 00000000..46b151b6 --- /dev/null +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java @@ -0,0 +1,11 @@ +package com.nynjacoin.nccs.lib.grpcutil; + +import com.google.protobuf.InvalidProtocolBufferException; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.RoutingContext; + +public interface WebApiCallConsumer { + + void accept(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException; + +} diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 30370c0a..e5806675 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 30370c0a2ee2e314c9b3dfac124182f9ab7d3789 +Subproject commit e5806675766cf6a1e7b381db704cc6c404d6de52 -- GitLab From 59d3962f8fc32744101eedc4721cb73d89d2068f Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 20 Nov 2019 09:10:36 +0200 Subject: [PATCH 02/37] Implement get limits. --- .../api/ConferenceFactoryGrpcApi.java | 14 +++++++++++++ .../api/ConferenceFactoryWebApi.java | 21 +++++++++++++++++++ .../service/ConferenceFactory.java | 17 ++++++++++++++- protocol/public/src/main/proto | 2 +- 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index 16e84014..6528f0f9 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -7,6 +7,8 @@ import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import io.vertx.core.Future; @@ -20,6 +22,18 @@ public class ConferenceFactoryGrpcApi this.verticle = conferenceFactoryVerticle; } + @Override + public void getLimits(GetLimitsRequest request, Future response) { + + String accountId = GrpcContextKeys.ACCOUNT_ID.get(); + + verticle.runOnContext( + () -> verticle.conferenceFactory.getLimits(accountId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); + } + @Override public void createConference( CreateConferenceRequest request, diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index d6e1e399..6094a92c 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -10,6 +10,8 @@ import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.error.NccsWrappingException; @@ -28,6 +30,22 @@ public class ConferenceFactoryWebApi implements WebApi { private final ConferenceFactoryVerticle verticle; + private void getLimits(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + GetLimitsRequest request = GetLimitsRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.getLimits(accountId, request, response), + response, + webMetadata.getLogContext() + ); + } + private void createConference(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException { @@ -85,6 +103,9 @@ public class ConferenceFactoryWebApi implements WebApi { public Router createRouter(Vertx vertx) { Router router = Router.router(vertx); + router + .route("/GetLimits") + .handler(PathHandler.compose(this::getLimits)); router .route("/CreateConference") .handler(PathHandler.compose(this::createConference)); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 07a67f1e..d859f562 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -7,6 +7,8 @@ import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; +import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.error.NccsError; @@ -51,6 +53,14 @@ public class ConferenceFactory { this.linkIdGenerator = new LinkIdGenerator(); } + public void getLimits( + String accountId, + GetLimitsRequest request, + Future response) { + + response.complete(GetLimitsResponse.newBuilder().setMaxMembers(membersCountLimit).build()); + } + public void createConference(String accountId, com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest request, io.vertx.core.Future response) { @@ -98,7 +108,12 @@ public class ConferenceFactory { response.complete(responseBuilder.build()); } - public void joinRoom(String accountId, JoinRoomRequest request, Future response) { + public void joinRoom( + String accountId, + JoinRoomRequest request, + Future response) { + + } public void discardConference(String conferenceId) { diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index e5806675..fc8151d0 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit e5806675766cf6a1e7b381db704cc6c404d6de52 +Subproject commit fc8151d0f0f514f131b160ef8c96dccb5748215c -- GitLab From 00d8793fc6ff94783e8a8daa98cfba4934258704 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 25 Nov 2019 23:06:58 +0200 Subject: [PATCH 03/37] WIP to be reviewed: start room conference partially implemented. --- app/focus/build.gradle | 3 +- .../nynjacoin/nccs/app/focus/FocusApp.java | 2 + .../api/ConferenceControlGrpcApi.java | 16 +- .../api/ConferenceControlWebApi.java | 28 +-- .../conferencecontrol/service/Conference.java | 84 ++++---- .../service/ConferenceControl.java | 86 ++++++-- .../service/ConferenceControlVerticle.java | 31 +-- .../api/ConferenceFactoryGrpcApi.java | 16 ++ .../service/AccountConferences.java | 51 +++++ .../service/ConferenceFactory.java | 183 ++++++++++++++---- .../service/ConferenceFactoryVerticle.java | 5 + .../service/ConferenceInfo.java | 11 +- .../service/ConferenceInfoBuilder.java | 10 +- .../service/ConferenceRoomInfo.java | 31 +++ .../nccs/protocol/error/NccsError.java | 6 + protocol/public/src/main/proto | 2 +- 16 files changed, 435 insertions(+), 130 deletions(-) create mode 100644 focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java create mode 100644 focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java diff --git a/app/focus/build.gradle b/app/focus/build.gradle index 75726506..0edddce3 100644 --- a/app/focus/build.gradle +++ b/app/focus/build.gradle @@ -20,7 +20,8 @@ task confereceFocus(type: CreateStartScripts) { outputDir = new File(project.buildDir, 'tmp') classpath = jar.outputs.files + project.configurations.runtime defaultJvmOpts = [ - "-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" + "-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager", + "-enableassertions:com.nynjacoin.nccs.conferencefactory..." ] } diff --git a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java index 7e919efd..38844912 100644 --- a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java +++ b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java @@ -124,6 +124,8 @@ public class FocusApp extends VertxApp { chatRoomClient); vertx.deployVerticle(conferenceControlVerticle); + conferenceFactoryVerticle.setConferenceControlVerticle(conferenceControlVerticle); + MediaController mediaController = new MediaController(vertx, config); Focus focus = new Focus(conferenceControlVerticle, stateHolderVerticle, mediaController); CallVerticle callVerticle = new CallVerticle(focus); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlGrpcApi.java index bf3e3e6b..84ee54bd 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlGrpcApi.java @@ -2,8 +2,6 @@ package com.nynjacoin.nccs.conferencecontrol.api; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; -import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; -import com.nynjacoin.nccs.protocol.ccp.AddMemberResponse; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.ConferenceGrpc; @@ -15,6 +13,8 @@ import com.nynjacoin.nccs.protocol.ccp.ManageParticipanRequest; import com.nynjacoin.nccs.protocol.ccp.RejectRequest; import com.nynjacoin.nccs.protocol.ccp.RemoveMemberRequest; import com.nynjacoin.nccs.protocol.ccp.UpdateConferenceInfoRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.MemberInfo; import com.nynjacoin.nccs.protocol.def.Void; import io.vertx.core.Future; @@ -43,11 +43,17 @@ public class ConferenceControlGrpcApi @Override public void addMember(AddMemberRequest request, Future response) { - String accountId = GrpcContextKeys.ACCOUNT_ID.get(); String conferenceId = getConferenceId(); - - conferenceControlVerticle.addMember(accountId, conferenceId, request, response); + conferenceControlVerticle.runOnContext( + () -> conferenceControlVerticle.conferenceControl.addMember( + accountId, + conferenceId, + request, + response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); } @Override diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlWebApi.java index f7f57317..b2e8bbec 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/api/ConferenceControlWebApi.java @@ -9,8 +9,6 @@ import com.nynjacoin.nccs.lib.grpcutil.WebApi; import com.nynjacoin.nccs.lib.grpcutil.WebEventTarget; import com.nynjacoin.nccs.lib.grpcutil.WebMetadata; import com.nynjacoin.nccs.lib.grpcutil.WebResponseHandler; -import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; -import com.nynjacoin.nccs.protocol.ccp.AddMemberResponse; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; @@ -21,6 +19,8 @@ import com.nynjacoin.nccs.protocol.ccp.ManageParticipanRequest; import com.nynjacoin.nccs.protocol.ccp.RejectRequest; import com.nynjacoin.nccs.protocol.ccp.RemoveMemberRequest; import com.nynjacoin.nccs.protocol.ccp.UpdateConferenceInfoRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.MemberInfo; import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.protocol.error.NccsWrappingException; @@ -127,18 +127,18 @@ public class ConferenceControlWebApi implements WebApi { AddMemberRequest request = AddMemberRequest.parseFrom(bodyBuffer.getBytes()); Future response = WebResponseHandler.future(ctx); - Context logGrpcContext = Context.current() - .withValue(GrpcContextKeys.LOG_CONTEXT, webMetadata.getLogContext()); - Context prevGrpcContext = logGrpcContext.attach(); - - try (final CloseableThreadContext.Instance tc = - CloseableThreadContext.putAll(webMetadata.getLogContext())) { - - LOGGER.debug("AddMember {{}}", TextFormat.shortDebugString(request)); - conferenceControlVerticle.addMember(accountId, conferenceId, request, response); - } finally { - logGrpcContext.detach(prevGrpcContext); - } + conferenceControlVerticle.runOnContext( + () -> { + LOGGER.debug("AddMember {{}}", TextFormat.shortDebugString(request)); + conferenceControlVerticle.conferenceControl.addMember( + accountId, + conferenceId, + request, + response); + }, + response, + webMetadata.getLogContext() + ); })); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java index a62902c4..ce3f7441 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java @@ -10,8 +10,6 @@ import com.nynjacoin.nccs.lib.util.InstanceLogger; import com.nynjacoin.nccs.lib.util.UuidGenerator; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender.AnswerStatus; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender.ContentType; -import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; -import com.nynjacoin.nccs.protocol.ccp.AddMemberResponse; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; @@ -22,6 +20,8 @@ import com.nynjacoin.nccs.protocol.ccp.ManageParticipanRequest; import com.nynjacoin.nccs.protocol.ccp.RejectRequest; import com.nynjacoin.nccs.protocol.ccp.RemoveMemberRequest; import com.nynjacoin.nccs.protocol.ccp.UpdateConferenceInfoRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.Address; import com.nynjacoin.nccs.protocol.def.Address.Type; import com.nynjacoin.nccs.protocol.def.CallEndedBy; @@ -46,6 +46,7 @@ import io.vertx.core.Vertx; import io.vertx.grpc.GrpcWriteStream; import io.prometheus.client.Gauge; +import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.Date; @@ -120,6 +121,13 @@ class Conference { return hasReadAccess(accountId); } + private void authorizeChangeAccess(String accountId) { + if (hasChangeAccess(accountId)) { + return; + } + throw NccsError.UNAUTHORIZED.exception(); + } + private boolean authorizeJoin(String accountId, Member member) { return member != null && @@ -150,24 +158,9 @@ class Conference { response.complete(Void.getDefaultInstance()); } - void addMember(String accountId, AddMemberRequest request, - Future response) { - - if (!hasChangeAccess(accountId)) { - response.fail(NccsError.UNAUTHORIZED.exception()); - return; - } - Future addFuture = Future.future(); - addFuture.setHandler(event -> { - if (event.succeeded()) { - response.complete(AddMemberResponse.newBuilder() - .setMemberId(event.result().getMemberId()) - .build()); - } else { - response.fail(event.cause()); - } - }); - addMember(request, addFuture); + String addMember(String accountId, AddMemberRequest request) { + authorizeChangeAccess(accountId); + return addMember(request).getMemberId(); } void bindByLink( @@ -188,17 +181,8 @@ class Conference { logger.info("Bound by link: {{}}", TextFormat.shortDebugString(address)); } - Future addFuture = Future.future(); - addFuture.setHandler(event -> { - if (event.succeeded()) { - response.complete(BindByLinkResponse.newBuilder() - .setMemberId(event.result().getMemberId()) - .build()); - } else { - response.fail(event.cause()); - } - }); - addMember(addMemberRequest, addFuture); + String memberId = addMember(addMemberRequest).getMemberId(); + response.complete(BindByLinkResponse.newBuilder().setMemberId(memberId).build()); } void removeMember(String accountId, RemoveMemberRequest request, Future response) { @@ -379,25 +363,36 @@ class Conference { CONFERENCE_ACTIVE.dec(); } - private void addMember(AddMemberRequest request, Future response) { - getMemberByAddress(request.getAddress()).ifPresentOrElse( - member -> response.complete(member.getInfo()) - , - () -> { + List addMembers(String accountId, List memberRequests) { + authorizeChangeAccess(accountId); + List result = new ArrayList<>(); + for (var request : memberRequests) { + MemberInfo member = addMember(request); + result.add(AddMemberResponse.newBuilder() + .setMemberId(member.getMemberId()) + .setAddress(request.getAddress()) + .build()); + } + return result; + } + + private MemberInfo addMember(AddMemberRequest request) { + Member member = getMemberByAddress(request.getAddress()) + .orElseGet(() -> { + if (conferenceInfo.getMembersCountLimit() > 0 + && members.size() >= conferenceInfo.getMembersCountLimit()) { + + throw NccsError.CONFERENCE_MEMBERS_LIMIT_REACHED.exception(); + } MemberInfo memberInfo = MemberInfo.newBuilder() .setMemberId("mbr_" + UuidGenerator.generate()) .setAddress(request.getAddress()) .setDisplayName(request.getDisplayName()) .addAllOption(request.getOptionList()) .build(); - if (conferenceInfo.getMembersCountLimit() > 0 - && members.size() >= conferenceInfo.getMembersCountLimit()) { - response.fail(NccsError.CONFERENCE_MEMBERS_LIMIT_REACHED.exception()); - return; - } - addMember(memberInfo); - response.complete(memberInfo); + return addMember(memberInfo); }); + return member.getInfo(); } private Address getBindByLinkAddress(String accountId) { @@ -443,7 +438,7 @@ class Conference { .anyMatch(memberInfo -> isMatchingAccountAddress(memberInfo.getAddress(), accountId)); } - private void addMember(MemberInfo memberInfo) { + private Member addMember(MemberInfo memberInfo) { Member member = new Member(memberInfo, conferenceVersion); members.put(memberInfo.getMemberId(), member); if (conferenceInfo.isOngoing()) { @@ -452,6 +447,7 @@ class Conference { .addMember(conferenceInfo.getConferenceId(), memberInfo, conferenceVersion); chatRoomManager.onMemberAdded(member.getAddress()); } + return member; } private void notifyMembersForStart() { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java index 46a898b7..3ec40563 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java @@ -7,8 +7,6 @@ import com.nynjacoin.nccs.focus.internal.api.client.FocusInternalApiClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender; import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.push.PushNotificationSender; -import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; -import com.nynjacoin.nccs.protocol.ccp.AddMemberResponse; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; @@ -19,6 +17,8 @@ import com.nynjacoin.nccs.protocol.ccp.ManageParticipanRequest; import com.nynjacoin.nccs.protocol.ccp.RejectRequest; import com.nynjacoin.nccs.protocol.ccp.RemoveMemberRequest; import com.nynjacoin.nccs.protocol.ccp.UpdateConferenceInfoRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.MemberInfo; import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.protocol.error.NccsError; @@ -28,11 +28,16 @@ import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; import io.vertx.core.Future; import io.vertx.grpc.GrpcWriteStream; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class ConferenceControl { + private static final Logger LOGGER = LogManager.getLogger(ConferenceControl.class); + private final ConferenceFactoryVerticle conferenceFactoryVerticle; private final StateHolderVerticle stateHolderVerticle; @@ -77,8 +82,6 @@ public class ConferenceControl { return history; } - ChatRoomClient getChatRoomClient() { return chatRoomClient; } - public void getConferenceInfo(String conferenceId, Future future) { @@ -140,7 +143,11 @@ public class ConferenceControl { return; } Conference conference = conferenceResponse.result(); - conference.addMember(accountId, request, response); + String memberId = conference.addMember(accountId, request); + response.complete(AddMemberResponse.newBuilder() + .setMemberId(memberId) + .setAddress(request.getAddress()) + .build()); }); } @@ -255,14 +262,7 @@ public class ConferenceControl { handleConference(accountId, conference, conferenceFuture); } else { ConferenceInfo conferenceInfo = event.result(); - conference = - new Conference( - this, - conferenceInfo, - stateHolderVerticle, - focusInternalApiClient); - conference.setChatRoomManager(getChatRoomManager(conference)); - conferences.put(conference.getConferenceInfo().getConferenceId(), conference); + conference = createAndStoreConference(conferenceInfo); conferenceFuture.complete(conference); } } @@ -270,6 +270,66 @@ public class ConferenceControl { conferenceFactoryVerticle.getConferenceInfo(conferenceId, conferenceInfoFuture); } + private Conference createAndStoreConference(ConferenceInfo conferenceInfo) { + Conference conference = + new Conference( + this, + conferenceInfo, + stateHolderVerticle, + focusInternalApiClient); + conference.setChatRoomManager(getChatRoomManager(conference)); + conferences.put(conference.getConferenceInfo().getConferenceId(), conference); + return conference; + } + + void createAddMembersStart( + ConferenceInfo conferenceInfo, + List members, + boolean start, + Future> result) { + + Conference conference = getOrCreate(conferenceInfo); + String ownerAccountId = conferenceInfo.getOwnerAccountId(); + List addMembersResult; + try { + addMembersResult = conference.addMembers(ownerAccountId, members); + } catch (Exception e) { + result.fail(e); + return; + } + if (start) { + Future startFuture = Future.future(); + conference.start(ownerAccountId, Void.getDefaultInstance(), startFuture); + startFuture.setHandler(startResult -> { + if (startResult.succeeded()) { + result.complete(addMembersResult); + } else { + cleanupConference(conferenceInfo.getConferenceId()); + result.fail(startResult.cause()); + } + }); + } + } + + private void cleanupConference(String conferenceId) { + try { + conferences.remove(conferenceId); + } catch (Exception e) { + LOGGER.error("Failed to cleanup created session after another failure", e); + } + } + + private Conference getOrCreate(ConferenceInfo ci) { + Conference conference = conferences.get(ci.getConferenceId()); + if (conference == null) { + return createAndStoreConference(ci); + } + if (!ci.getOwnerAccountId().equals(conference.getConferenceInfo().getOwnerAccountId())) { + throw NccsError.INTERNAL.exception("Unexpected owner mismatch"); + } + return conference; + } + public void join(String accountId, String conferenceId, JoinRequest request, Future response) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java index b944eb64..dd8f9bee 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java @@ -9,14 +9,14 @@ import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender; import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.push.PushNotificationSender; -import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; -import com.nynjacoin.nccs.protocol.ccp.AddMemberResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; import com.nynjacoin.nccs.protocol.ccp.JoinRequest; import com.nynjacoin.nccs.protocol.ccp.JoinResponse; import com.nynjacoin.nccs.protocol.ccp.RejectRequest; import com.nynjacoin.nccs.protocol.ccp.RemoveMemberRequest; import com.nynjacoin.nccs.protocol.ccp.UpdateConferenceInfoRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.MemberInfo; import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; @@ -24,6 +24,7 @@ import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.grpc.GrpcWriteStream; +import java.util.List; import org.apache.logging.log4j.CloseableThreadContext; import org.apache.logging.log4j.ThreadContext; @@ -65,17 +66,6 @@ public class ConferenceControlVerticle extends NccsVerticle { }); } - public void addMember(String accountId, String conferenceId, AddMemberRequest request, - Future response) { - - final var logContext = GrpcContextKeys.LOG_CONTEXT.get(); - context.runOnContext(v -> { - try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { - conferenceControl.addMember(accountId, conferenceId, request, response); - } - }); - } - public void removeMember(String accountId, String conferenceId, RemoveMemberRequest request, Future response) { @@ -194,4 +184,19 @@ public class ConferenceControlVerticle extends NccsVerticle { } }); } + + public void createAddMembersStart( + ConferenceInfo conferenceInfo, + List members, + boolean startConference, + Future> result) { + + final var logContext = ThreadContext.getContext(); + context.runOnContext(v -> { + try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { + conferenceControl.createAddMembersStart(conferenceInfo, members, startConference, result); + } + }); + } + } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index 6528f0f9..2d6d98f9 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -11,6 +11,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import io.vertx.core.Future; public class ConferenceFactoryGrpcApi @@ -48,6 +50,20 @@ public class ConferenceFactoryGrpcApi ); } + @Override + public void startConference( + StartConferenceRequest request, + Future response) { + + String accountId = GrpcContextKeys.ACCOUNT_ID.get(); + + verticle.runOnContext( + () -> verticle.conferenceFactory.startConference(accountId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); + } + @Override public void getConferenceId( GetConferenceIdRequest request, diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java new file mode 100644 index 00000000..2adc0634 --- /dev/null +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java @@ -0,0 +1,51 @@ +package com.nynjacoin.nccs.conferencefactory.service; + +import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; +import java.util.HashMap; + +class AccountConferences { + + private static class CachedCreateResponse { + + private final CreateConferenceResponse response; + private final String externalId; + CachedCreateResponse(CreateConferenceResponse response, String externalId) { + this.response = response; + this.externalId = externalId; + } + + CreateConferenceResponse getResponse() { + return response; + } + + String getExternalId() { + return externalId; + } + + } + private final HashMap container; + + AccountConferences() { + container = new HashMap<>(); + } + + boolean isEmpty() { + return container.isEmpty(); + } + + void put(ConferenceInfo ci, CreateConferenceResponse response) { + container.put(ci.getConferenceId(), new CachedCreateResponse(response, ci.getExternalId())); + } + + void remove(String conferenceId) { + container.remove(conferenceId); + } + + CreateConferenceResponse getByExternalId(String externalId) { + return container.values().stream() + .filter(cachedResponse -> cachedResponse.getExternalId().equals(externalId)) + .findFirst() + .map(CachedCreateResponse::getResponse) + .orElse(null); + } +} diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index d859f562..b42ff83e 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -1,5 +1,6 @@ package com.nynjacoin.nccs.conferencefactory.service; +import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; import com.nynjacoin.nccs.lib.util.UuidGenerator; @@ -11,41 +12,38 @@ import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; +import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.error.NccsError; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class ConferenceFactory { - static class AccountConferences extends HashMap { - - public Optional getByExternalId(String externalId) { - return this.values().stream() - .filter(conferenceInfo -> conferenceInfo.getExternalId().equals(externalId)) - .findFirst(); - } - - - } + private static Logger LOGGER = LogManager.getLogger(ConferenceFactory.class); private final Map accountConferences; - private final Map conferences; - private final Map conferencesByLink; + private final Map rooms; private final int membersCountLimit; private final JoinLinkComposer joinLinkComposer; private final LinkIdGenerator linkIdGenerator; + private ConferenceControlVerticle conferenceControlVerticle; ConferenceFactory(JsonObject config, JoinLinkComposer joinLinkComposer) { this.accountConferences = new HashMap<>(); this.conferences = new HashMap<>(); this.conferencesByLink = new HashMap<>(); + this.rooms = new HashMap<>(); this.membersCountLimit = config.getInteger( ConfigKey.CONFERENCE_MEMBERS_COUNT_LIMIT.key(), 30); @@ -61,27 +59,99 @@ public class ConferenceFactory { response.complete(GetLimitsResponse.newBuilder().setMaxMembers(membersCountLimit).build()); } - public void createConference(String accountId, - com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest request, - io.vertx.core.Future response) { + void setConferenceControlVerticle(ConferenceControlVerticle conferenceControlVerticle) { + this.conferenceControlVerticle = conferenceControlVerticle; + } + + public void createConference( + String accountId, + CreateConferenceRequest request, + Future response) { + + createAndStartConference(accountId, request, false, "") + .compose(response::complete, response); + } + + private Future createAndStartConference( + String accountId, + CreateConferenceRequest request, + boolean start, + String roomId) { AccountConferences accountConferences = getOrCreateAccountConferences(accountId); final String externalId = request.getExternalId(); if (!externalId.isEmpty()) { - accountConferences.getByExternalId(externalId).ifPresent(ci -> { + var cachedResponse = accountConferences.getByExternalId(externalId); + if (cachedResponse != null) { // found by external id, so treat it as a retry - response.complete(toCreateConferenceResponse(ci)); - return; - }); + return Future.succeededFuture(cachedResponse); + } } - ConferenceInfo ci = createNewConference(accountId, request); + ConferenceInfo ci = createNewConference(accountId, request, roomId); conferences.put(ci.getConferenceId(), ci); conferencesByLink.put(ci.getLinkId(), ci); - if (!ci.getExternalId().isEmpty()) { - accountConferences.put(ci.getExternalId(), ci); + if (request.getAddMemberCount() == 0 && !start) { + assert roomId.isEmpty(); + var createResponse = toCreateConferenceResponse(ci, List.of()); + if (!ci.getExternalId().isEmpty()) { + accountConferences.put(ci, createResponse); + } + return Future.succeededFuture(createResponse); + } + + ConferenceRoomInfo room; + if (roomId.isEmpty()) { + room = null; + } else { + assert start; + if (rooms.get(roomId) != null) { + return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); + } + room = new ConferenceRoomInfo(ci.getConferenceId()); + rooms.put(roomId, room); + } + + Future> ccResult = Future.future(); + conferenceControlVerticle.createAddMembersStart( + ci, + request.getAddMemberList(), + start, + ccResult); + Future result = Future.future(); + ccResult.setHandler(ar -> { + if (ar.succeeded()) { + var createResponse = toCreateConferenceResponse(ci, ar.result()); + if (!ci.getExternalId().isEmpty()) { + accountConferences.put(ci, createResponse); + } + if (room != null) { + room.onConferenceStarted(); + } + result.complete(createResponse); + } else { + discardConference(ci.getConferenceId()); + result.fail(ar.cause()); + } + }); + return result; + } + + public void startConference( + String accountId, + StartConferenceRequest request, + Future response) { + + Future f; + if (!request.getRoomId().isEmpty()) { + f = createAndStartConference(accountId, request.getCreateRequest(), true, ""); + } else { + f = createRoomConference(accountId, request.getCreateRequest(), request.getRoomId()); } - response.complete(toCreateConferenceResponse(ci)); + f.compose( + createResponse -> response.complete( + StartConferenceResponse.newBuilder().setCreateResponse(createResponse).build()), + response); } public void getConferenceId( @@ -116,31 +186,70 @@ public class ConferenceFactory { } - public void discardConference(String conferenceId) { - ConferenceInfo conferenceInfo = conferences.remove(conferenceId); - if (conferenceInfo == null) { + void discardConference(String conferenceId) { + ConferenceInfo ci = conferences.remove(conferenceId); + if (ci == null) { return; } - AccountConferences ac = accountConferences.get(conferenceInfo.getOwnerAccountId()); + assert ci.getConferenceId().equals(conferenceId); + AccountConferences ac = accountConferences.get(ci.getOwnerAccountId()); if (ac == null) { return; } ac.remove(conferenceId); if (ac.isEmpty()) { - accountConferences.remove(conferenceInfo.getOwnerAccountId()); + accountConferences.remove(ci.getOwnerAccountId()); } - final String linkId = conferenceInfo.getLinkId(); + final String linkId = ci.getLinkId(); // make the link to point to a dummy conference, to mark the fact it existed conferencesByLink.put(linkId, ConferenceInfo.newBuilder().build()); // and remove this mark latter: - Vertx.currentContext().owner().setTimer(5 * 60000, v -> { - conferencesByLink.remove(linkId); - }); + Vertx.currentContext().owner().setTimer(5 * 60000, v -> conferencesByLink.remove(linkId)); + + String roomId = ci.getRoomId(); + if (roomId.isEmpty()) { + return; + } + ConferenceRoomInfo room = rooms.get(roomId); + if (room == null) { + LOGGER.warn("Discard room conference {} with empty room {}", conferenceId, roomId); + return; + } + if (!room.getConferenceId().equals(conferenceId)) { + LOGGER.warn("Discard conference {} room {} mismatch (room conference id {})", + conferenceId, + roomId, + room.getConferenceId()); + return; + } + room.onConferenceDiscarded(); + rooms.remove(roomId); + } + + private Future + createRoomConference(String accountId, CreateConferenceRequest request, String roomId) { + return authorizeAccessToRoom(accountId, roomId) + .compose(ignoredVoid -> createAndStartConference(accountId, request, true, roomId)); + } + + private Future authorizeAccessToRoom(String accountId, String roomId) { + // FIXME: implement checks + return Future.succeededFuture(); } - private ConferenceInfo createNewConference(String accountId, CreateConferenceRequest request) { + private Future allocateRoom(String roomId) { + if (rooms.containsKey(roomId)) { + return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); + } + return Future.succeededFuture(); + } + + private ConferenceInfo createNewConference( + String accountId, + CreateConferenceRequest request, + String roomId) { return ConferenceInfo.newBuilder() .setAccountId(accountId) .setConferenceId(UuidGenerator.generate()) @@ -152,14 +261,18 @@ public class ConferenceFactory { .setChatRoomId(request.getChatRoomId()) .setChatRoomOptions(request.getChatRoomOptions()) .setReplaceRef(request.getReplaceRef()) + .setRoomId(roomId) .build(); } - private CreateConferenceResponse toCreateConferenceResponse(ConferenceInfo ci) { + private CreateConferenceResponse toCreateConferenceResponse( + ConferenceInfo ci, + List addedMembers) { return CreateConferenceResponse.newBuilder() .setConferenceId(ci.getConferenceId()) .setMembersCountLimit(ci.getMembersCountLimit()) .setJoinLink(joinLinkComposer.compose(ci.getLinkId())) + .addAllMemberResult(addedMembers) .build(); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java index f46053d7..8679b283 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java @@ -1,5 +1,6 @@ package com.nynjacoin.nccs.conferencefactory.service; +import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; @@ -16,6 +17,10 @@ public class ConferenceFactoryVerticle extends NccsVerticle { this.conferenceFactory = new ConferenceFactory(config, joinLinkComposer); } + public void setConferenceControlVerticle(ConferenceControlVerticle conferenceControlVerticle) { + conferenceFactory.setConferenceControlVerticle(conferenceControlVerticle); + } + public void getConferenceInfo(String conferenceId, Future response) { final var logContext = ThreadContext.getContext(); context.runOnContext(v -> { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java index 017fb741..0e792cf0 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java @@ -12,7 +12,6 @@ public class ConferenceInfo { private final String ownerAccountId; private final String conferenceId; private final String externalId; - private final String replaceRef; private String externalInfo; private final int membersCountLimit; private final String linkId; @@ -20,6 +19,8 @@ public class ConferenceInfo { private String chatRoomId; private ChatRoomType chatRoomType; private final ChatRoomOptions chatRoomOptions; + private final String replaceRef; + private final String roomId; private Date startTime; private ConferenceState state; @@ -33,7 +34,8 @@ public class ConferenceInfo { String subject, String chatRoomId, ChatRoomOptions chatRoomOptions, - String replaceRef) { + String replaceRef, + String roomId) { this.ownerAccountId = ownerAccountId; this.conferenceId = conferenceId; @@ -48,6 +50,7 @@ public class ConferenceInfo { this.chatRoomOptions = chatRoomOptions; this.replaceRef = replaceRef; this.state = ConferenceState.CREATED; + this.roomId = roomId; } public static ConferenceInfoBuilder newBuilder() { return new ConferenceInfoBuilder(); } @@ -107,6 +110,10 @@ public class ConferenceInfo { return replaceRef; } + public String getRoomId() { + return roomId; + } + public Date getStartTime() { return startTime; } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfoBuilder.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfoBuilder.java index b6e10e7f..8b41e61c 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfoBuilder.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfoBuilder.java @@ -1,6 +1,5 @@ package com.nynjacoin.nccs.conferencefactory.service; -import com.nynjacoin.nccs.conferencecontrol.service.ParticipantInfo.Builder; import com.nynjacoin.nccs.protocol.cfp.ChatRoomOptions; public class ConferenceInfoBuilder { @@ -15,6 +14,7 @@ public class ConferenceInfoBuilder { private String chatRoomId = ""; private ChatRoomOptions chatRoomOptions; private String replaceRef; + private String roomId = ""; public ConferenceInfoBuilder setAccountId(String accountId) { this.accountId = accountId; @@ -66,6 +66,11 @@ public class ConferenceInfoBuilder { return this; } + public ConferenceInfoBuilder setRoomId(String roomId) { + this.roomId = roomId; + return this; + } + public ConferenceInfo build() { return new ConferenceInfo( accountId, @@ -77,6 +82,7 @@ public class ConferenceInfoBuilder { subject, chatRoomId, chatRoomOptions, - replaceRef); + replaceRef, + roomId); } } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java new file mode 100644 index 00000000..0edabd92 --- /dev/null +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java @@ -0,0 +1,31 @@ +package com.nynjacoin.nccs.conferencefactory.service; + +import com.nynjacoin.nccs.protocol.error.NccsError; + +public class ConferenceRoomInfo { + + private final String conferenceId; + private boolean started; + + ConferenceRoomInfo(String conferenceId) { + this.conferenceId = conferenceId; + this.started = false; + } + + public String getConferenceId() { + if (started) { + return conferenceId; + } + // FIXME: implement + throw NccsError.UNIMPLEMENTED.exception("Wait for room conference to start not implemented"); + } + + public void onConferenceStarted() { + this.started = true; + // FIXME: callbacks + } + + public void onConferenceDiscarded() { + // FIXME: invoke callbacks with if any with error + } +} diff --git a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsError.java b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsError.java index 439e0af4..70af5dfb 100644 --- a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsError.java +++ b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsError.java @@ -10,10 +10,15 @@ public enum NccsError { FAILED_PRECONDITION(Status.FAILED_PRECONDITION), UNIMPLEMENTED(Status.UNIMPLEMENTED), + SERVICE_UNAVAILABLE_RETRY( + "service-unavailable-retry", + Status.DEADLINE_EXCEEDED, + "Operation failed, please retry"), BAD_PROTO3("bad-proto3", Status.INVALID_ARGUMENT, "Failed to parse proto.3 message"), CONFERENCE_NOT_FOUND("conf-not-found", Status.NOT_FOUND, "Conference not found"), CONFERENCE_BAD_STATE("conf-bad-state", Status.FAILED_PRECONDITION, "Invalid conference state"), CONFERENCE_MEMBERS_LIMIT_REACHED("conf-max-members", Status.FAILED_PRECONDITION, "Conference members limit reached"), + CONFERENCE_ROOM_BUSY("conf-room-busy", Status.FAILED_PRECONDITION, "The room already hosts a conference"), LINK_NOT_FOUND("link-not-found", Status.NOT_FOUND, "Unknown link id"), LINK_EXPIRED("link-expired", Status.OUT_OF_RANGE, "Link expired"), MEMBER_NOT_FOUND("conf-member-not-found", Status.NOT_FOUND, "Member not found"), @@ -64,4 +69,5 @@ public enum NccsError { } public String getNccsReason() { return nccsReason; } + } diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index fc8151d0..78f52898 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit fc8151d0f0f514f131b160ef8c96dccb5748215c +Subproject commit 78f52898dfec8ab9ba68bd68c26857b5a1fef84d -- GitLab From f78737abae308fe48cd2df426ab0e0f24291d4d3 Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Tue, 26 Nov 2019 10:30:23 +0200 Subject: [PATCH 04/37] merge files --- .../service/AccountConferences.java | 51 +++++++++++++++++++ .../service/ConferenceRoomInfo.java | 31 +++++++++++ 2 files changed, 82 insertions(+) create mode 100644 focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java create mode 100644 focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java new file mode 100644 index 00000000..2adc0634 --- /dev/null +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/AccountConferences.java @@ -0,0 +1,51 @@ +package com.nynjacoin.nccs.conferencefactory.service; + +import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; +import java.util.HashMap; + +class AccountConferences { + + private static class CachedCreateResponse { + + private final CreateConferenceResponse response; + private final String externalId; + CachedCreateResponse(CreateConferenceResponse response, String externalId) { + this.response = response; + this.externalId = externalId; + } + + CreateConferenceResponse getResponse() { + return response; + } + + String getExternalId() { + return externalId; + } + + } + private final HashMap container; + + AccountConferences() { + container = new HashMap<>(); + } + + boolean isEmpty() { + return container.isEmpty(); + } + + void put(ConferenceInfo ci, CreateConferenceResponse response) { + container.put(ci.getConferenceId(), new CachedCreateResponse(response, ci.getExternalId())); + } + + void remove(String conferenceId) { + container.remove(conferenceId); + } + + CreateConferenceResponse getByExternalId(String externalId) { + return container.values().stream() + .filter(cachedResponse -> cachedResponse.getExternalId().equals(externalId)) + .findFirst() + .map(CachedCreateResponse::getResponse) + .orElse(null); + } +} diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java new file mode 100644 index 00000000..0edabd92 --- /dev/null +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java @@ -0,0 +1,31 @@ +package com.nynjacoin.nccs.conferencefactory.service; + +import com.nynjacoin.nccs.protocol.error.NccsError; + +public class ConferenceRoomInfo { + + private final String conferenceId; + private boolean started; + + ConferenceRoomInfo(String conferenceId) { + this.conferenceId = conferenceId; + this.started = false; + } + + public String getConferenceId() { + if (started) { + return conferenceId; + } + // FIXME: implement + throw NccsError.UNIMPLEMENTED.exception("Wait for room conference to start not implemented"); + } + + public void onConferenceStarted() { + this.started = true; + // FIXME: callbacks + } + + public void onConferenceDiscarded() { + // FIXME: invoke callbacks with if any with error + } +} -- GitLab From 4ba25f6453bca8d6753b9d1c3976a7d66c16ed54 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 26 Nov 2019 14:51:36 +0200 Subject: [PATCH 05/37] Protocol styling change. --- .../com/nynjacoin/nccs/protocol/metadata/CommonMetadataKey.java | 1 - protocol/public/src/main/proto | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/metadata/CommonMetadataKey.java b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/metadata/CommonMetadataKey.java index 86e184dc..5e63b967 100644 --- a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/metadata/CommonMetadataKey.java +++ b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/metadata/CommonMetadataKey.java @@ -1,6 +1,5 @@ package com.nynjacoin.nccs.protocol.metadata; -import io.grpc.Context; import io.grpc.Metadata; import io.grpc.Metadata.Key; diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 78f52898..58330d07 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 78f52898dfec8ab9ba68bd68c26857b5a1fef84d +Subproject commit 58330d075e118a28c1b0f2565fd0a267b141e0e2 -- GitLab From f0e6dd8181a73bf748432f5e0c3010a3db754bf7 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 26 Nov 2019 14:52:55 +0200 Subject: [PATCH 06/37] Fix: ConferenceControl.CreateAddStart complete when start=false. --- .../nccs/conferencecontrol/service/ConferenceControl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java index 3ec40563..75ef61cb 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java @@ -308,6 +308,8 @@ public class ConferenceControl { result.fail(startResult.cause()); } }); + } else { + result.complete(addMembersResult); } } -- GitLab From 8f10387eb468e11726ec0d13914d84427698c8da Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 26 Nov 2019 14:53:29 +0200 Subject: [PATCH 07/37] Fix: ConferenceFactory: empty room check --- .../nccs/conferencefactory/service/ConferenceFactory.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index b42ff83e..51250b7c 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -16,6 +16,7 @@ import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.error.NccsError; +import com.nynjacoin.nccs.protocol.validation.NccsValidator; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; @@ -143,7 +144,7 @@ public class ConferenceFactory { Future response) { Future f; - if (!request.getRoomId().isEmpty()) { + if (request.getRoomId().isEmpty()) { f = createAndStartConference(accountId, request.getCreateRequest(), true, ""); } else { f = createRoomConference(accountId, request.getCreateRequest(), request.getRoomId()); @@ -230,6 +231,7 @@ public class ConferenceFactory { private Future createRoomConference(String accountId, CreateConferenceRequest request, String roomId) { + assert !roomId.isEmpty(); return authorizeAccessToRoom(accountId, roomId) .compose(ignoredVoid -> createAndStartConference(accountId, request, true, roomId)); } -- GitLab From d16226775d978716b1509dbce435bb28ca8a8fef Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 27 Nov 2019 12:36:36 +0200 Subject: [PATCH 08/37] Fix: conference cleanup after failure. --- .../nccs/conferencecontrol/service/ConferenceControl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java index 75ef61cb..63b8e5e9 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java @@ -294,6 +294,7 @@ public class ConferenceControl { try { addMembersResult = conference.addMembers(ownerAccountId, members); } catch (Exception e) { + cleanupConference(conferenceInfo.getConferenceId()); result.fail(e); return; } @@ -314,10 +315,11 @@ public class ConferenceControl { } private void cleanupConference(String conferenceId) { + Conference conference = conferences.remove(conferenceId); try { - conferences.remove(conferenceId); + conference.conferenceCompleted(); } catch (Exception e) { - LOGGER.error("Failed to cleanup created session after another failure", e); + LOGGER.error("Failed to complete created conference after another failure", e); } } -- GitLab From fc0102c793024db4210607afe674b8be98340334 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 27 Nov 2019 12:37:37 +0200 Subject: [PATCH 09/37] WebApi StartConference. --- .../api/ConferenceFactoryWebApi.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index 6094a92c..4ac1f3f2 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -14,7 +14,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; -import com.nynjacoin.nccs.protocol.error.NccsWrappingException; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; +import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; import io.vertx.core.Future; import io.vertx.core.Vertx; @@ -62,6 +63,22 @@ public class ConferenceFactoryWebApi implements WebApi { ); } + private void startConference(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + StartConferenceRequest request = StartConferenceRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.startConference(accountId, request, response), + response, + webMetadata.getLogContext() + ); + } + private void getConferenceId(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException { @@ -109,6 +126,9 @@ public class ConferenceFactoryWebApi implements WebApi { router .route("/CreateConference") .handler(PathHandler.compose(this::createConference)); + router + .route("/StartConference") + .handler(PathHandler.compose(this::startConference)); router .route("/GetConferenceId") .handler(PathHandler.compose(this::getConferenceId)); -- GitLab From 20c618eea35b03cee8577fbf296ebef0bfef7e77 Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Fri, 29 Nov 2019 17:01:40 +0200 Subject: [PATCH 10/37] buildspec: Updated branch name --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1917b998..205dc4cd 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -91,7 +91,7 @@ pipeline { // Application name APP_NAME = "nccs-focus" // BRANCH_NAME="development" - BRANCH_NAME="${BRANCH_NAME ? BRANCH_NAME :'temp-development'}" + BRANCH_NAME="${BRANCH_NAME ? BRANCH_NAME :'permanent-chat-group-meeting-room'}" IMAGE_NAME = "eu.gcr.io/nynja-ci-201610/${NAMESPACE}/${APP_NAME}" IMAGE_TAG = "${BRANCH_NAME == 'master' ? 'latest' : 'latest-' + BRANCH_NAME}" IMAGE_BUILD_TAG = "$BRANCH_NAME-$BUILD_NUMBER" -- GitLab From e085a5c5eedac22058aa0fcf0951c34e6692c38c Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Fri, 29 Nov 2019 17:25:17 +0200 Subject: [PATCH 11/37] Build fix --- .../nccs/conferencefactory/service/ConferenceFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 51250b7c..a1ca2b81 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -16,7 +16,6 @@ import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.error.NccsError; -import com.nynjacoin.nccs.protocol.validation.NccsValidator; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; -- GitLab From 25c41570a70261245dae807746ce2597d9987f8a Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Fri, 29 Nov 2019 17:42:49 +0200 Subject: [PATCH 12/37] Disabled test client --- .../java/com/nynjacoin/nccs/sandbox/grpc/NccsClientTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sandbox/grpc/src/test/java/com/nynjacoin/nccs/sandbox/grpc/NccsClientTest.java b/sandbox/grpc/src/test/java/com/nynjacoin/nccs/sandbox/grpc/NccsClientTest.java index ef5859b3..99bd3b43 100644 --- a/sandbox/grpc/src/test/java/com/nynjacoin/nccs/sandbox/grpc/NccsClientTest.java +++ b/sandbox/grpc/src/test/java/com/nynjacoin/nccs/sandbox/grpc/NccsClientTest.java @@ -1,5 +1,5 @@ package com.nynjacoin.nccs.sandbox.grpc; - +/* import com.nynjacoin.nccs.protocol.ccp.AddMemberRequest; import com.nynjacoin.nccs.protocol.ccp.JoinResponse; import com.nynjacoin.nccs.protocol.chp.Range; @@ -364,3 +364,4 @@ public class NccsClientTest extends BaseTest { } } +*/ -- GitLab From aadd2d97725e4c4a8103aa7c5cba26067474cd28 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 08:01:55 +0200 Subject: [PATCH 13/37] Join room implemented. --- .../service/ConferenceControlVerticle.java | 16 ++++ .../service/ConferenceFactory.java | 88 +++++++++++++++++-- .../service/ConferenceRoomInfo.java | 16 +++- .../protocol/validation/NccsValidator.java | 25 ++++++ protocol/public/src/main/proto | 2 +- 5 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 protocol/public/src/main/java/com/nynjacoin/nccs/protocol/validation/NccsValidator.java diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java index dd8f9bee..794eb8c4 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java @@ -9,6 +9,8 @@ import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender; import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.push.PushNotificationSender; +import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; +import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; import com.nynjacoin.nccs.protocol.ccp.JoinRequest; import com.nynjacoin.nccs.protocol.ccp.JoinResponse; @@ -199,4 +201,18 @@ public class ConferenceControlVerticle extends NccsVerticle { }); } + public void bindByLink( + String accountId, + String conferenceId, + BindByLinkRequest request, + Future response) { + + final var logContext = ThreadContext.getContext(); + context.runOnContext(v -> { + try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { + conferenceControl.bindByLink(accountId, conferenceId, request, response); + } + }); + } + } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index a1ca2b81..b1360cc5 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -4,6 +4,8 @@ import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; import com.nynjacoin.nccs.lib.util.UuidGenerator; +import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; +import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; @@ -14,8 +16,13 @@ import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; +import com.nynjacoin.nccs.protocol.def.AddMemberRequest; import com.nynjacoin.nccs.protocol.def.AddMemberResponse; +import com.nynjacoin.nccs.protocol.def.Address; +import com.nynjacoin.nccs.protocol.def.Address.Type; +import com.nynjacoin.nccs.protocol.def.MemberOption; import com.nynjacoin.nccs.protocol.error.NccsError; +import com.nynjacoin.nccs.protocol.validation.NccsValidator; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; @@ -146,7 +153,7 @@ public class ConferenceFactory { if (request.getRoomId().isEmpty()) { f = createAndStartConference(accountId, request.getCreateRequest(), true, ""); } else { - f = createRoomConference(accountId, request.getCreateRequest(), request.getRoomId()); + f = createAndStartRoomConference(accountId, request.getCreateRequest(), request.getRoomId()); } f.compose( createResponse -> response.complete( @@ -181,9 +188,61 @@ public class ConferenceFactory { public void joinRoom( String accountId, JoinRoomRequest request, - Future response) { - - + Future responseFuture) { + + String roomId = request.getRoomId(); + NccsValidator.requireNonEmpty(roomId, "room_id"); + + checkAccessToRoom(accountId, roomId) + .compose(accessType -> { + ConferenceRoomInfo room = rooms.get(roomId); + switch (accessType) { + case START_CONFERENCE: + if (room == null) { + // no conference in the room, so create one + CreateConferenceRequest createReq = CreateConferenceRequest.newBuilder() + .addAddMember(AddMemberRequest.newBuilder() + .setAddress(Address.newBuilder().setType(Type.ACCOUNT).setValue(accountId)) + .addOption(MemberOption.DIALOUT)) + .setChatRoomId(roomId) + .build(); + createAndStartConference(accountId, createReq, true, roomId) + .map(createResponse -> JoinRoomResponse.newBuilder() + .setConferenceId(createResponse.getConferenceId()) + .setMemberId(createResponse.getMemberResult(0).getMemberId()) + .build()) + .compose(responseFuture::complete, responseFuture); + return; + } + if (!room.conferenceStarted()) { + room.addCompletionWaiter(() -> joinRoom(accountId, request, responseFuture)); + return; + } + break; + case JOIN: + if (room == null || !room.conferenceStarted()) { + responseFuture.complete(JoinRoomResponse.getDefaultInstance()); + return; + } + break; + default: + throw NccsError.UNAUTHORIZED.exception( + "Access to conference room not allowed"); + } + String conferenceId = room.getConferenceId(); + BindByLinkRequest bindReq = BindByLinkRequest.newBuilder() + .setDisplayName(request.getDisplayName()) + .setPii(request.getPii()) + .build(); + Future bindFuture = Future.future(); + conferenceControlVerticle.bindByLink(accountId, conferenceId, bindReq, bindFuture); + bindFuture + .map(bindResp -> JoinRoomResponse.newBuilder() + .setConferenceId(conferenceId) + .setMemberId(bindResp.getMemberId()) + .build()) + .compose(responseFuture::complete, responseFuture); + }, responseFuture); } void discardConference(String conferenceId) { @@ -229,15 +288,26 @@ public class ConferenceFactory { } private Future - createRoomConference(String accountId, CreateConferenceRequest request, String roomId) { + createAndStartRoomConference(String accountId, CreateConferenceRequest request, String roomId) { assert !roomId.isEmpty(); - return authorizeAccessToRoom(accountId, roomId) - .compose(ignoredVoid -> createAndStartConference(accountId, request, true, roomId)); + return checkAccessToRoom(accountId, roomId) + .compose(accessType -> { + if (accessType == RoomAccess.START_CONFERENCE) { + return createAndStartConference(accountId, request, true, roomId); + } + throw NccsError.UNAUTHORIZED.exception(); + }); } - private Future authorizeAccessToRoom(String accountId, String roomId) { + private enum RoomAccess { + NONE, + JOIN, + START_CONFERENCE + } + + private Future checkAccessToRoom(String accountId, String roomId) { // FIXME: implement checks - return Future.succeededFuture(); + return Future.succeededFuture(RoomAccess.START_CONFERENCE); } private Future allocateRoom(String roomId) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java index 0edabd92..9e7963ac 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java @@ -1,15 +1,23 @@ package com.nynjacoin.nccs.conferencefactory.service; import com.nynjacoin.nccs.protocol.error.NccsError; +import java.util.ArrayList; +import java.util.List; public class ConferenceRoomInfo { private final String conferenceId; private boolean started; + private List waitingForCompletion; ConferenceRoomInfo(String conferenceId) { this.conferenceId = conferenceId; this.started = false; + this.waitingForCompletion = new ArrayList<>(); + } + + boolean conferenceStarted() { + return started; } public String getConferenceId() { @@ -20,12 +28,16 @@ public class ConferenceRoomInfo { throw NccsError.UNIMPLEMENTED.exception("Wait for room conference to start not implemented"); } - public void onConferenceStarted() { + void onConferenceStarted() { this.started = true; // FIXME: callbacks } - public void onConferenceDiscarded() { + void onConferenceDiscarded() { // FIXME: invoke callbacks with if any with error } + + void addCompletionWaiter(Runnable waiting) { + waitingForCompletion.add(waiting); + } } diff --git a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/validation/NccsValidator.java b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/validation/NccsValidator.java new file mode 100644 index 00000000..c2d7f387 --- /dev/null +++ b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/validation/NccsValidator.java @@ -0,0 +1,25 @@ +package com.nynjacoin.nccs.protocol.validation; + +import com.nynjacoin.nccs.protocol.error.NccsError; + +public class NccsValidator { + + public static void requireNonNull(String value, String what) { + if (value == null) { + throw NccsError.INVALID_ARGUMENT.exception("Required but missing: " + what); + } + } + + public static void requireNonEmpty(String value, String what) { + if (value == null) { + throw NccsError.INVALID_ARGUMENT.exception("Required non empty value: " + what); + } + } + + public static void checkRequiredHeader(String value, String header) { + if (value == null || value.isEmpty()) { + throw NccsError.INVALID_ARGUMENT.exception("Missing required header: " + header); + } + } + +} diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 58330d07..8de6ef86 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 58330d075e118a28c1b0f2565fd0a267b141e0e2 +Subproject commit 8de6ef869927c8445cefbb551635fe45976a66e1 -- GitLab From 2633178805fe207559fb767c6d9501db1163abf0 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 08:13:34 +0200 Subject: [PATCH 14/37] JoinRoom -> EnterRoom --- .../api/ConferenceFactoryGrpcApi.java | 12 ++++++------ .../api/ConferenceFactoryWebApi.java | 16 ++++++++-------- .../service/ConferenceFactory.java | 18 +++++++++--------- protocol/public/src/main/proto | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index 2d6d98f9..b4212c66 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -5,12 +5,12 @@ import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; import com.nynjacoin.nccs.protocol.cfp.ConferenceFactoryGrpc; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import io.vertx.core.Future; @@ -79,13 +79,13 @@ public class ConferenceFactoryGrpcApi } @Override - public void joinRoom( - JoinRoomRequest request, - Future response) { + public void enterRoom( + EnterRoomRequest request, + Future response) { String accountId = GrpcContextKeys.ACCOUNT_ID.get(); verticle.runOnContext( - () -> verticle.conferenceFactory.joinRoom(accountId, request, response), + () -> verticle.conferenceFactory.enterRoom(accountId, request, response), response, GrpcContextKeys.LOG_CONTEXT.get() ); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index 4ac1f3f2..4c8075b6 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -8,12 +8,12 @@ import com.nynjacoin.nccs.lib.grpcutil.WebMetadata; import com.nynjacoin.nccs.lib.grpcutil.WebResponseHandler; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; @@ -95,17 +95,17 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void joinRoom(RoutingContext ctx, Buffer bodyBuffer) + private void enterRoom(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - JoinRoomRequest request = JoinRoomRequest.parseFrom(bodyBuffer.getBytes()); - Future response = WebResponseHandler.future(ctx); + var request = EnterRoomRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); verticle.runOnContext( - () -> verticle.conferenceFactory.joinRoom(accountId, request, response), + () -> verticle.conferenceFactory.enterRoom(accountId, request, response), response, webMetadata.getLogContext() ); @@ -133,8 +133,8 @@ public class ConferenceFactoryWebApi implements WebApi { .route("/GetConferenceId") .handler(PathHandler.compose(this::getConferenceId)); router - .route("/JoinRoom") - .handler(PathHandler.compose(this::joinRoom)); + .route("/EnterRoom") + .handler(PathHandler.compose(this::enterRoom)); return router; } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index b1360cc5..463197b2 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -8,12 +8,12 @@ import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceResponse; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomRequest; +import com.nynjacoin.nccs.protocol.cfp.EnterRoomResponse; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomRequest; -import com.nynjacoin.nccs.protocol.cfp.JoinRoomResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.def.AddMemberRequest; @@ -185,10 +185,10 @@ public class ConferenceFactory { response.complete(responseBuilder.build()); } - public void joinRoom( + public void enterRoom( String accountId, - JoinRoomRequest request, - Future responseFuture) { + EnterRoomRequest request, + Future responseFuture) { String roomId = request.getRoomId(); NccsValidator.requireNonEmpty(roomId, "room_id"); @@ -207,7 +207,7 @@ public class ConferenceFactory { .setChatRoomId(roomId) .build(); createAndStartConference(accountId, createReq, true, roomId) - .map(createResponse -> JoinRoomResponse.newBuilder() + .map(createResponse -> EnterRoomResponse.newBuilder() .setConferenceId(createResponse.getConferenceId()) .setMemberId(createResponse.getMemberResult(0).getMemberId()) .build()) @@ -215,13 +215,13 @@ public class ConferenceFactory { return; } if (!room.conferenceStarted()) { - room.addCompletionWaiter(() -> joinRoom(accountId, request, responseFuture)); + room.addCompletionWaiter(() -> enterRoom(accountId, request, responseFuture)); return; } break; case JOIN: if (room == null || !room.conferenceStarted()) { - responseFuture.complete(JoinRoomResponse.getDefaultInstance()); + responseFuture.complete(EnterRoomResponse.getDefaultInstance()); return; } break; @@ -237,7 +237,7 @@ public class ConferenceFactory { Future bindFuture = Future.future(); conferenceControlVerticle.bindByLink(accountId, conferenceId, bindReq, bindFuture); bindFuture - .map(bindResp -> JoinRoomResponse.newBuilder() + .map(bindResp -> EnterRoomResponse.newBuilder() .setConferenceId(conferenceId) .setMemberId(bindResp.getMemberId()) .build()) diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 8de6ef86..c38a104a 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 8de6ef869927c8445cefbb551635fe45976a66e1 +Subproject commit c38a104af20b73fd5c9870fb0545a56a40b6aa0c -- GitLab From 89e1e0165ccb14476082afecf9212748c5db0abc Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 12:51:38 +0200 Subject: [PATCH 15/37] Wait pending conference creation to complete. --- .../service/ConferenceFactory.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 463197b2..63b3fb30 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -112,8 +112,17 @@ public class ConferenceFactory { room = null; } else { assert start; - if (rooms.get(roomId) != null) { - return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); + ConferenceRoomInfo existingRoom = rooms.get(roomId); + if (existingRoom != null) { + if (existingRoom.conferenceStarted()) { + return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); + } + Future waitCompletionFuture = Future.future(); + existingRoom.addCompletionWaiter(() -> + createAndStartConference(accountId, request, start, roomId) + .compose(waitCompletionFuture::complete, waitCompletionFuture) + ); + return waitCompletionFuture; } room = new ConferenceRoomInfo(ci.getConferenceId()); rooms.put(roomId, room); @@ -300,7 +309,6 @@ public class ConferenceFactory { } private enum RoomAccess { - NONE, JOIN, START_CONFERENCE } @@ -310,13 +318,6 @@ public class ConferenceFactory { return Future.succeededFuture(RoomAccess.START_CONFERENCE); } - private Future allocateRoom(String roomId) { - if (rooms.containsKey(roomId)) { - return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); - } - return Future.succeededFuture(); - } - private ConferenceInfo createNewConference( String accountId, CreateConferenceRequest request, -- GitLab From 65902991f088b201fd9e740a6000eaaf2a692880 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 12:52:00 +0200 Subject: [PATCH 16/37] Sync proto --- protocol/public/src/main/proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index c38a104a..d19471a6 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit c38a104af20b73fd5c9870fb0545a56a40b6aa0c +Subproject commit d19471a61346deebac867764e28f86d8ea8dbc42 -- GitLab From 4cf2d197f583927446671c031cd70ddb53be8561 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 13:39:26 +0200 Subject: [PATCH 17/37] Room conference state publishing. --- .../nynjacoin/nccs/app/focus/FocusApp.java | 6 +++- .../service/ConferenceFactory.java | 21 +++++++++++- .../service/ConferenceFactoryVerticle.java | 10 ++++-- .../nccs/stateholder/service/Topic.java | 1 + .../statepackage/RoomPublisher.java | 32 +++++++++++++++++++ protocol/public/src/main/proto | 2 +- 6 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java diff --git a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java index 38844912..ce3f6145 100644 --- a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java +++ b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java @@ -44,6 +44,7 @@ import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; import com.nynjacoin.nccs.stateholder.api.StateHolderGrpcApi; import com.nynjacoin.nccs.stateholder.api.StateHolderWebApi; import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; +import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; import com.nynjacoin.nccs.stateholder.statepackage.UserActivityPublisher; import io.grpc.ServerInterceptors; import io.vertx.core.Vertx; @@ -92,7 +93,10 @@ public class FocusApp extends VertxApp { new JoinLinkComposer(config.getString(ConfigKey.JOIN_LINK_BASE_URL.key())); ConferenceFactoryVerticle conferenceFactoryVerticle = - new ConferenceFactoryVerticle(config,joinLinkComposer); + new ConferenceFactoryVerticle( + config, + joinLinkComposer, + new RoomPublisher(stateHolderVerticle)); vertx.deployVerticle(conferenceFactoryVerticle); PushNotificationSender pushNotificationSender = diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 63b3fb30..df946324 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -3,6 +3,7 @@ package com.nynjacoin.nccs.conferencefactory.service; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; +import com.nynjacoin.nccs.lib.grpcutil.GrpcTimestamp; import com.nynjacoin.nccs.lib.util.UuidGenerator; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; @@ -22,7 +23,9 @@ import com.nynjacoin.nccs.protocol.def.Address; import com.nynjacoin.nccs.protocol.def.Address.Type; import com.nynjacoin.nccs.protocol.def.MemberOption; import com.nynjacoin.nccs.protocol.error.NccsError; +import com.nynjacoin.nccs.protocol.sp.conference.RoomConferenceRecord; import com.nynjacoin.nccs.protocol.validation.NccsValidator; +import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; @@ -44,9 +47,14 @@ public class ConferenceFactory { private final int membersCountLimit; private final JoinLinkComposer joinLinkComposer; private final LinkIdGenerator linkIdGenerator; + private final RoomPublisher roomPublisher; private ConferenceControlVerticle conferenceControlVerticle; - ConferenceFactory(JsonObject config, JoinLinkComposer joinLinkComposer) { + ConferenceFactory( + JsonObject config, + JoinLinkComposer joinLinkComposer, + RoomPublisher roomPublisher) { + this.accountConferences = new HashMap<>(); this.conferences = new HashMap<>(); this.conferencesByLink = new HashMap<>(); @@ -56,6 +64,7 @@ public class ConferenceFactory { 30); this.joinLinkComposer = joinLinkComposer; this.linkIdGenerator = new LinkIdGenerator(); + this.roomPublisher = roomPublisher; } public void getLimits( @@ -142,6 +151,13 @@ public class ConferenceFactory { accountConferences.put(ci, createResponse); } if (room != null) { + roomPublisher.publishConference( + roomId, + RoomConferenceRecord.newBuilder() + .setOwnerAccountId(ci.getOwnerAccountId()) + .setSubject(ci.getSubject()) + .setStartTime(GrpcTimestamp.create(ci.getStartTime())) + ); room.onConferenceStarted(); } result.complete(createResponse); @@ -292,6 +308,9 @@ public class ConferenceFactory { room.getConferenceId()); return; } + if (room.conferenceStarted()) { + roomPublisher.discardConference(roomId); + } room.onConferenceDiscarded(); rooms.remove(roomId); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java index 8679b283..270f79c0 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java @@ -2,8 +2,8 @@ package com.nynjacoin.nccs.conferencefactory.service; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; -import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; +import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; import io.vertx.core.Future; import io.vertx.core.json.JsonObject; import org.apache.logging.log4j.CloseableThreadContext; @@ -13,8 +13,12 @@ public class ConferenceFactoryVerticle extends NccsVerticle { public final ConferenceFactory conferenceFactory; - public ConferenceFactoryVerticle(JsonObject config, JoinLinkComposer joinLinkComposer) { - this.conferenceFactory = new ConferenceFactory(config, joinLinkComposer); + public ConferenceFactoryVerticle( + JsonObject config, + JoinLinkComposer joinLinkComposer, + RoomPublisher roomPublisher) { + + this.conferenceFactory = new ConferenceFactory(config, joinLinkComposer, roomPublisher); } public void setConferenceControlVerticle(ConferenceControlVerticle conferenceControlVerticle) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/Topic.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/Topic.java index 75c7c63c..0fe80893 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/Topic.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/Topic.java @@ -6,6 +6,7 @@ public enum Topic { USER_ACTIVITY("user-activity", "account", true), @Deprecated USER_CONFERENCE("user-conference", "account", true), + ROOM("room", "room", true), ; private String wireName; diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java new file mode 100644 index 00000000..7a5adc3a --- /dev/null +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java @@ -0,0 +1,32 @@ +package com.nynjacoin.nccs.stateholder.statepackage; + +import com.nynjacoin.nccs.protocol.def.Void; +import com.nynjacoin.nccs.protocol.sp.conference.RoomConferenceRecord; +import com.nynjacoin.nccs.protocol.sp.conference.RoomRecord; +import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; +import com.nynjacoin.nccs.stateholder.service.Topic; +import io.vertx.core.Future; + +public class RoomPublisher extends StatePublisher { + + public static final Topic TOPIC = Topic.CONFERENCE; + public static final String ROOM_CONFERENCE_KEY = "room-conference"; + + public RoomPublisher(StateHolderVerticle stateHolderVerticle) { + super(stateHolderVerticle, TOPIC); + } + + public Future publishConference( + String roomId, + RoomConferenceRecord.Builder roomConference) { + + return publish(roomId, ROOM_CONFERENCE_KEY, + RoomRecord.newBuilder() + .setConference(roomConference) + .build()); + } + + public void discardConference(String roomId) { + discard(roomId, ROOM_CONFERENCE_KEY); + } +} diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index d19471a6..0ce01282 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit d19471a61346deebac867764e28f86d8ea8dbc42 +Subproject commit 0ce012827d522630d4cbad491542aaeed69a717d -- GitLab From 27bf34ef74a50841199ccee404fc216d2600b47d Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 14:04:21 +0200 Subject: [PATCH 18/37] Get room id dummy implementation. --- .../api/ConferenceFactoryGrpcApi.java | 16 +++++++++++++ .../api/ConferenceFactoryWebApi.java | 21 ++++++++++++++++ .../service/ConferenceFactory.java | 24 +++++++++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index b4212c66..67b5cb02 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -11,6 +11,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import io.vertx.core.Future; @@ -78,6 +80,20 @@ public class ConferenceFactoryGrpcApi ); } + @Override + public void getRoomId( + GetRoomIdRequest request, + Future response) { + + String accountId = GrpcContextKeys.ACCOUNT_ID.get(); + + verticle.runOnContext( + () -> verticle.conferenceFactory.getRoomId(accountId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); + } + @Override public void enterRoom( EnterRoomRequest request, diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index 4c8075b6..4efcf83b 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -14,6 +14,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; @@ -95,6 +97,22 @@ public class ConferenceFactoryWebApi implements WebApi { ); } + private void getRoomId(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + + var request = GetRoomIdRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.conferenceFactory.getRoomId(accountId, request, response), + response, + webMetadata.getLogContext() + ); + } + private void enterRoom(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException { @@ -132,6 +150,9 @@ public class ConferenceFactoryWebApi implements WebApi { router .route("/GetConferenceId") .handler(PathHandler.compose(this::getConferenceId)); + router + .route("/GetRoomId") + .handler(PathHandler.compose(this::getRoomId)); router .route("/EnterRoom") .handler(PathHandler.compose(this::enterRoom)); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index df946324..ef1f8323 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -15,6 +15,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.def.AddMemberRequest; @@ -205,11 +207,29 @@ public class ConferenceFactory { .setConferenceId(ci.getConferenceId()) ; if (Objects.isNull(accountId) || accountId.isEmpty()) { - responseBuilder.setAnonymousId(ConferenceInfo.ANONYMOUS_PREFIX + UuidGenerator.generate()); + responseBuilder.setAnonymousId(generateAnonymousId()); } response.complete(responseBuilder.build()); } + public void getRoomId( + String accountId, + GetRoomIdRequest request, + Future response) { + + // FIXME: for quick testing dummy implementation that returns the link id as if it was the room id + // real implementation is due here + var responseBuilder = GetRoomIdResponse.newBuilder().setRoomId(request.getLinkId()); + if (Objects.isNull(accountId) || accountId.isEmpty()) { + responseBuilder.setAnonymousId(generateAnonymousId()); + } + response.complete(responseBuilder.build()); + } + + private String generateAnonymousId() { + return ConferenceInfo.ANONYMOUS_PREFIX + UuidGenerator.generate(); + } + public void enterRoom( String accountId, EnterRoomRequest request, @@ -329,7 +349,7 @@ public class ConferenceFactory { private enum RoomAccess { JOIN, - START_CONFERENCE + START_CONFERENCE; } private Future checkAccessToRoom(String accountId, String roomId) { -- GitLab From 06db6174fadfe278112d677935afeaee3d9af74e Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Mon, 2 Dec 2019 23:03:08 +0200 Subject: [PATCH 19/37] Get room id implemented. --- .../nynjacoin/nccs/app/focus/FocusApp.java | 4 +- app/focus/src/main/resources/nccs-config.json | 4 +- .../service/ConferenceFactory.java | 22 +++-- .../service/ConferenceFactoryVerticle.java | 12 ++- .../nynjacoin/nccs/lib/config/ConfigKey.java | 6 ++ .../vertxutil/restclient/HttpException.java | 19 +++++ .../restclient/JsonHttpException.java | 17 ++++ .../vertxutil/restclient/RetryExecutor.java | 7 ++ .../restclient/roomlink/RoomLinkClient.java | 80 +++++++++++++++++++ 9 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/HttpException.java create mode 100644 lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/JsonHttpException.java create mode 100644 lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java diff --git a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java index ce3f6145..21740dea 100644 --- a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java +++ b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java @@ -35,6 +35,7 @@ import com.nynjacoin.nccs.lib.grpcutil.MetadataServerInterceptor; import com.nynjacoin.nccs.lib.vertxutil.restclient.push.PushNotificationSender; import com.nynjacoin.nccs.lib.vertxutil.app.VertxApp; import com.nynjacoin.nccs.lib.grpcutil.WebApiServer; +import com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink.RoomLinkClient; import com.nynjacoin.nccs.mediacontroller.MediaController; import com.nynjacoin.nccs.protocol.chp.CallHistoryDeletion; import com.nynjacoin.nccs.protocol.chp.CallHistoryRecord; @@ -96,7 +97,8 @@ public class FocusApp extends VertxApp { new ConferenceFactoryVerticle( config, joinLinkComposer, - new RoomPublisher(stateHolderVerticle)); + new RoomPublisher(stateHolderVerticle), + RoomLinkClient.create(vertx, config)); vertx.deployVerticle(conferenceFactoryVerticle); PushNotificationSender pushNotificationSender = diff --git a/app/focus/src/main/resources/nccs-config.json b/app/focus/src/main/resources/nccs-config.json index 91286186..2350f0bb 100644 --- a/app/focus/src/main/resources/nccs-config.json +++ b/app/focus/src/main/resources/nccs-config.json @@ -16,5 +16,7 @@ "chat_room_key": "nynja:nynjaTS", "bubble_enabled": false, "bubble_url": "http://nynja-dev-uw1-messaging01.dev-eu.nynja.net:8888/cri/bubbles", - "bubble_key": "nynja:nynjaTS" + "bubble_key": "nynja:nynjaTS", + "room_link_url": "http://nynja:nynjaTS@nynja-dev-uw1-messaging02.dev-eu.nynja.net:8888/link", + "room_link_key": "nynja:nynjaTS" } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index ef1f8323..cafb45a4 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -5,6 +5,7 @@ import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; import com.nynjacoin.nccs.lib.grpcutil.GrpcTimestamp; import com.nynjacoin.nccs.lib.util.UuidGenerator; +import com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink.RoomLinkClient; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.cfp.CreateConferenceRequest; @@ -50,12 +51,14 @@ public class ConferenceFactory { private final JoinLinkComposer joinLinkComposer; private final LinkIdGenerator linkIdGenerator; private final RoomPublisher roomPublisher; + private final RoomLinkClient roomLinkClient; private ConferenceControlVerticle conferenceControlVerticle; ConferenceFactory( JsonObject config, JoinLinkComposer joinLinkComposer, - RoomPublisher roomPublisher) { + RoomPublisher roomPublisher, + RoomLinkClient roomLinkClient) { this.accountConferences = new HashMap<>(); this.conferences = new HashMap<>(); @@ -67,6 +70,7 @@ public class ConferenceFactory { this.joinLinkComposer = joinLinkComposer; this.linkIdGenerator = new LinkIdGenerator(); this.roomPublisher = roomPublisher; + this.roomLinkClient = roomLinkClient; } public void getLimits( @@ -217,13 +221,15 @@ public class ConferenceFactory { GetRoomIdRequest request, Future response) { - // FIXME: for quick testing dummy implementation that returns the link id as if it was the room id - // real implementation is due here - var responseBuilder = GetRoomIdResponse.newBuilder().setRoomId(request.getLinkId()); - if (Objects.isNull(accountId) || accountId.isEmpty()) { - responseBuilder.setAnonymousId(generateAnonymousId()); - } - response.complete(responseBuilder.build()); + roomLinkClient.getRoomId(request.getLinkId()) + .map(roomId -> { + var responseBuilder = GetRoomIdResponse.newBuilder().setRoomId(roomId); + if (Objects.isNull(accountId) || accountId.isEmpty()) { + responseBuilder.setAnonymousId(generateAnonymousId()); + } + return responseBuilder.build(); + }) + .setHandler(response); } private String generateAnonymousId() { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java index 270f79c0..454400ee 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java @@ -3,6 +3,7 @@ package com.nynjacoin.nccs.conferencefactory.service; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; +import com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink.RoomLinkClient; import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; import io.vertx.core.Future; import io.vertx.core.json.JsonObject; @@ -16,9 +17,14 @@ public class ConferenceFactoryVerticle extends NccsVerticle { public ConferenceFactoryVerticle( JsonObject config, JoinLinkComposer joinLinkComposer, - RoomPublisher roomPublisher) { - - this.conferenceFactory = new ConferenceFactory(config, joinLinkComposer, roomPublisher); + RoomPublisher roomPublisher, + RoomLinkClient roomLinkClient) { + + this.conferenceFactory = new ConferenceFactory( + config, + joinLinkComposer, + roomPublisher, + roomLinkClient); } public void setConferenceControlVerticle(ConferenceControlVerticle conferenceControlVerticle) { diff --git a/lib/nccs-config/src/main/java/com/nynjacoin/nccs/lib/config/ConfigKey.java b/lib/nccs-config/src/main/java/com/nynjacoin/nccs/lib/config/ConfigKey.java index 008c967a..9b519fe7 100644 --- a/lib/nccs-config/src/main/java/com/nynjacoin/nccs/lib/config/ConfigKey.java +++ b/lib/nccs-config/src/main/java/com/nynjacoin/nccs/lib/config/ConfigKey.java @@ -51,6 +51,12 @@ public enum ConfigKey { CHAT_ROOM_RETRY_AFTER_MILLISECONDS("chat_room_retry_after_milliseconds"), CHAT_ROOM_PER_REQUEST_POOL_SIZE("chat_room_per_request_pool_size"), CHAT_ROOM_KEY("chat_room_key"), + + ROOM_LINK_URL("room_link_url"), + ROOM_LINK_MAX_RETRIES("room_link_max_retries"), + ROOM_LINK_RETRY_AFTER_MILLISECONDS("room_link_retry_after_milliseconds"), + ROOM_LINK_PER_REQUEST_POOL_SIZE("room_link_per_request_pool_size"), + ROOM_LINK_KEY("room_link_key"), ; private final String key; diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/HttpException.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/HttpException.java new file mode 100644 index 00000000..62cdad18 --- /dev/null +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/HttpException.java @@ -0,0 +1,19 @@ +package com.nynjacoin.nccs.lib.vertxutil.restclient; + +public class HttpException extends RuntimeException { + private final int statusCode; + private final String statusMessage; + + public HttpException(int statusCode, String statusMessage) { + this.statusCode = statusCode; + this.statusMessage = statusMessage; + } + + public int getStatusCode() { + return statusCode; + } + + public String getStatusMessage() { + return statusMessage; + } +} diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/JsonHttpException.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/JsonHttpException.java new file mode 100644 index 00000000..fdac0d9c --- /dev/null +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/JsonHttpException.java @@ -0,0 +1,17 @@ +package com.nynjacoin.nccs.lib.vertxutil.restclient; + +import io.vertx.core.json.JsonObject; + +public class JsonHttpException extends HttpException { + + private final JsonObject body; + + public JsonHttpException(int statusCode, String statusMessage, JsonObject body) { + super(statusCode, statusMessage); + this.body = body; + } + + public JsonObject getBody() { + return body; + } +} diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/RetryExecutor.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/RetryExecutor.java index bfd5646f..a4e5bf2f 100644 --- a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/RetryExecutor.java +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/RetryExecutor.java @@ -169,6 +169,13 @@ public class RetryExecutor { if (ar.failed()) { return ar.cause(); } + if (ar.result() != null) { + JsonObject body = ar.result().body(); + if (body == null) { + return new HttpException(ar.result().statusCode(), ar.result().statusMessage()); + } + return new JsonHttpException(ar.result().statusCode(), ar.result().statusMessage(), body); + } return new RuntimeException("HTTP error: " + getError(ar)); } diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java new file mode 100644 index 00000000..af54ee7c --- /dev/null +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java @@ -0,0 +1,80 @@ +package com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink; + +import com.nynjacoin.nccs.lib.config.ConfigKey; +import com.nynjacoin.nccs.lib.vertxutil.restclient.AuthenticationHandler; +import com.nynjacoin.nccs.lib.vertxutil.restclient.JsonHttpException; +import com.nynjacoin.nccs.lib.vertxutil.restclient.RestClientBase; +import com.nynjacoin.nccs.lib.vertxutil.restclient.RetryExecutor; +import com.nynjacoin.nccs.lib.vertxutil.restclient.ValidatingJsonObject; +import com.nynjacoin.nccs.lib.vertxutil.restclient.WebClientFactory; +import com.nynjacoin.nccs.protocol.error.NccsError; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.client.WebClient; +import java.util.Objects; + +public class RoomLinkClient extends RestClientBase { + + private static final String FIELD_ROOM_ID = "room_id"; + + public static RoomLinkClient create(Vertx vertx, JsonObject config) { + int poolSize = config.getInteger(ConfigKey.ROOM_LINK_PER_REQUEST_POOL_SIZE.key(), 32); + WebClient webClient = WebClientFactory.create(vertx, poolSize); + + String auth = config.getString(ConfigKey.ROOM_LINK_KEY.key()); + AuthenticationHandler authenticationHandler = AuthenticationHandler.create(auth); + + RetryExecutor retryExecutor = RetryExecutor.newBuilder(vertx) + .setOrDefaultMaxRetries(config.getInteger( + ConfigKey.ROOM_LINK_MAX_RETRIES.key())) + .setOrDefaultRetryMilliseconds(config.getLong( + ConfigKey.ROOM_LINK_RETRY_AFTER_MILLISECONDS.key())) + .build(); + + String rootUrl = config.getString(ConfigKey.ROOM_LINK_URL.key()); + Objects.requireNonNull(rootUrl); + + return new RoomLinkClient(webClient, authenticationHandler, retryExecutor, rootUrl); + } + + private RoomLinkClient(WebClient webClient, + AuthenticationHandler authenticationHandler, + RetryExecutor retryExecutor, + String rootUrl) { + + super(webClient, authenticationHandler, retryExecutor, rootUrl); + } + + public Future getRoomId(String linkId) { + var request = getWebClient().getAbs(getRoomUrl(linkId)); + request = getAuthenticationHandler().apply(request); + var response = getRetryExecutor().execute(request); + return response + .map(rawBody -> { + ValidatingJsonObject body = ValidatingJsonObject.wrap(rawBody); + return body.getRequiredString(FIELD_ROOM_ID); + }) + .recover(cause -> Future.failedFuture(translateLinkNotFound(cause))); + } + + private static Throwable translateLinkNotFound(Throwable cause) { + if (cause instanceof JsonHttpException) { + JsonHttpException jsonHttpException = (JsonHttpException) cause; + if (jsonHttpException.getStatusCode() == 404) { + JsonObject body = jsonHttpException.getBody(); + try { + if ("not_found".equals(body.getString("error"))) { + return NccsError.INVALID_ARGUMENT.exception("Invalid link_id"); + } + } catch (Exception ignored) { + } + } + } + return cause; + } + + private String getRoomUrl(String linkId) { + return getRootUrl() + '/' + linkId + "/room_id"; + } +} -- GitLab From b927a49bcf2fae2dcecd0a3bdb60f83d765af6f5 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 3 Dec 2019 12:18:29 +0200 Subject: [PATCH 20/37] Config changes. --- app/focus/src/main/resources/nccs-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/focus/src/main/resources/nccs-config.json b/app/focus/src/main/resources/nccs-config.json index 2350f0bb..dd014714 100644 --- a/app/focus/src/main/resources/nccs-config.json +++ b/app/focus/src/main/resources/nccs-config.json @@ -17,6 +17,6 @@ "bubble_enabled": false, "bubble_url": "http://nynja-dev-uw1-messaging01.dev-eu.nynja.net:8888/cri/bubbles", "bubble_key": "nynja:nynjaTS", - "room_link_url": "http://nynja:nynjaTS@nynja-dev-uw1-messaging02.dev-eu.nynja.net:8888/link", + "room_link_url": "http://nynja-dev-uw1-messaging02.dev-eu.nynja.net:8888/link", "room_link_key": "nynja:nynjaTS" } -- GitLab From 05dc9c592f494c4037cbba3f24d067ab752ec327 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 3 Dec 2019 12:19:26 +0200 Subject: [PATCH 21/37] Call waiting for pending room conference creation result. --- .../service/ConferenceFactory.java | 4 +- .../service/ConferenceRoomInfo.java | 43 +++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index cafb45a4..3731d1cf 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -139,7 +139,7 @@ public class ConferenceFactory { ); return waitCompletionFuture; } - room = new ConferenceRoomInfo(ci.getConferenceId()); + room = new ConferenceRoomInfo(roomId, ci.getConferenceId()); rooms.put(roomId, room); } @@ -337,8 +337,8 @@ public class ConferenceFactory { if (room.conferenceStarted()) { roomPublisher.discardConference(roomId); } - room.onConferenceDiscarded(); rooms.remove(roomId); + room.onConferenceDiscarded(); } private Future diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java index 9e7963ac..a69f15f8 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java @@ -1,18 +1,25 @@ package com.nynjacoin.nccs.conferencefactory.service; -import com.nynjacoin.nccs.protocol.error.NccsError; import java.util.ArrayList; import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class ConferenceRoomInfo { + private static Logger LOGGER = LogManager.getLogger(ConferenceRoomInfo.class); + private final String conferenceId; + private final String roomId; private boolean started; + private boolean completed; private List waitingForCompletion; - ConferenceRoomInfo(String conferenceId) { + ConferenceRoomInfo(String roomId, String conferenceId) { + this.roomId = roomId; this.conferenceId = conferenceId; this.started = false; + this.completed = false; this.waitingForCompletion = new ArrayList<>(); } @@ -21,23 +28,41 @@ public class ConferenceRoomInfo { } public String getConferenceId() { - if (started) { - return conferenceId; - } - // FIXME: implement - throw NccsError.UNIMPLEMENTED.exception("Wait for room conference to start not implemented"); + return conferenceId; } void onConferenceStarted() { this.started = true; - // FIXME: callbacks + this.completed = true; + callWaiting(); } void onConferenceDiscarded() { - // FIXME: invoke callbacks with if any with error + this.completed = true; + callWaiting(); } void addCompletionWaiter(Runnable waiting) { + assert !completed; waitingForCompletion.add(waiting); } + + private void callWaiting() { + assert completed; + List localWaiting = waitingForCompletion; + waitingForCompletion = null; + localWaiting.forEach(this::callWaiting); + } + + private void callWaiting(Runnable waiting) { + try { + waiting.run(); + } catch (Throwable e) { + LOGGER.error("Exception calling waiting for a room {} conference {} started: {}", + roomId, + conferenceId, + started, + e); + } + } } -- GitLab From 77257c5d52bbd7bbac2bada09b5c395c59bb05c4 Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Tue, 3 Dec 2019 14:41:29 +0200 Subject: [PATCH 22/37] Deployment: Added roomlink values --- charts/calling-service/Chart.yaml | 2 +- charts/calling-service/templates/deployment.yaml | 6 ++++++ charts/calling-service/values.yaml | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/charts/calling-service/Chart.yaml b/charts/calling-service/Chart.yaml index 02a88a1c..c352b3d6 100644 --- a/charts/calling-service/Chart.yaml +++ b/charts/calling-service/Chart.yaml @@ -2,4 +2,4 @@ apiVersion: v1 appVersion: "1.0" description: Calling service Helm chart name: calling-service -version: 0.2.0 +version: 0.2.1 diff --git a/charts/calling-service/templates/deployment.yaml b/charts/calling-service/templates/deployment.yaml index ff33e35d..f86b4c94 100644 --- a/charts/calling-service/templates/deployment.yaml +++ b/charts/calling-service/templates/deployment.yaml @@ -73,6 +73,12 @@ spec: value: "{{ .Values.chatroom.url }}" - name: chat_room_key value: "{{ .Values.chatroom.key }}" + - name: chat_link_enabled + value: "{{ .Values.roomlink.enabled }}" + - name: room_link_url + value: "{{ .Values.roomlink.url }}" + - name: room_link_key + value: "{{ .Values.roomlink.key }}" args: - "sleep 5;cd /app; bin/nccs-focus" diff --git a/charts/calling-service/values.yaml b/charts/calling-service/values.yaml index 8fa88687..c3ae0259 100644 --- a/charts/calling-service/values.yaml +++ b/charts/calling-service/values.yaml @@ -40,6 +40,14 @@ push: host: messaging-service.messaging.svc.cluster.local apiKey: nynja apiSecret: secret +chatroom: + enabled: true + url: http://messaging-service.messaging.svc.cluster.local:8888/cri/rooms + key: nynja:nynjaTS +roomlink: + enabled: true + url: http://messaging-service.messaging.svc.cluster.local:8888/link + key: nynja:nynjaTS nodeSelector: {} -- GitLab From 15d29c69f0e418c7972e9bb7fc48133fdb3ee42c Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Tue, 3 Dec 2019 15:01:28 +0200 Subject: [PATCH 23/37] Deployment: room_link --- charts/calling-service/templates/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/calling-service/templates/deployment.yaml b/charts/calling-service/templates/deployment.yaml index f86b4c94..52bfbf12 100644 --- a/charts/calling-service/templates/deployment.yaml +++ b/charts/calling-service/templates/deployment.yaml @@ -73,7 +73,7 @@ spec: value: "{{ .Values.chatroom.url }}" - name: chat_room_key value: "{{ .Values.chatroom.key }}" - - name: chat_link_enabled + - name: room_link_enabled value: "{{ .Values.roomlink.enabled }}" - name: room_link_url value: "{{ .Values.roomlink.url }}" -- GitLab From 55dffe904502b7b65acb06eb64649b35f66c325e Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 3 Dec 2019 15:40:30 +0200 Subject: [PATCH 24/37] Room membership check - implemented but disabled as not working yet in erlang. Fixed ROOM topic. Fixed NPE while calling waiting pending room conference completion. Class renamed. --- .../nynjacoin/nccs/app/focus/FocusApp.java | 12 ++++----- app/focus/src/main/resources/nccs-config.json | 2 +- .../service/ConferenceFactory.java | 26 +++++++++++++------ .../service/ConferenceFactoryVerticle.java | 7 +++-- ...RoomInfo.java => ConferenceRoomState.java} | 15 +++++++---- .../statepackage/RoomPublisher.java | 2 +- 6 files changed, 40 insertions(+), 24 deletions(-) rename focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/{ConferenceRoomInfo.java => ConferenceRoomState.java} (83%) diff --git a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java index 21740dea..b03e1289 100644 --- a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java +++ b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java @@ -93,12 +93,15 @@ public class FocusApp extends VertxApp { JoinLinkComposer joinLinkComposer = new JoinLinkComposer(config.getString(ConfigKey.JOIN_LINK_BASE_URL.key())); + ChatRoomClient chatRoomClient = ChatRoomClient.create(vertx, config); + ConferenceFactoryVerticle conferenceFactoryVerticle = new ConferenceFactoryVerticle( config, joinLinkComposer, new RoomPublisher(stateHolderVerticle), - RoomLinkClient.create(vertx, config)); + RoomLinkClient.create(vertx, config), + chatRoomClient); vertx.deployVerticle(conferenceFactoryVerticle); PushNotificationSender pushNotificationSender = @@ -113,11 +116,6 @@ public class FocusApp extends VertxApp { FocusInternalApiClient focusInternalApiClient = new FocusInternalApiClient(); - ChatRoomClient chatRoomClient = - config.getBoolean(ConfigKey.CHAT_ROOM_ENABLED.key(), true) - ? ChatRoomClient.create(vertx, config) - : null; - ConferenceControlVerticle conferenceControlVerticle = new ConferenceControlVerticle( conferenceFactoryVerticle, @@ -127,7 +125,7 @@ public class FocusApp extends VertxApp { joinLinkComposer, historyEventsProcessor, bubbleSender, - chatRoomClient); + config.getBoolean(ConfigKey.CHAT_ROOM_ENABLED.key(), true) ? chatRoomClient : null); vertx.deployVerticle(conferenceControlVerticle); conferenceFactoryVerticle.setConferenceControlVerticle(conferenceControlVerticle); diff --git a/app/focus/src/main/resources/nccs-config.json b/app/focus/src/main/resources/nccs-config.json index dd014714..7446cca5 100644 --- a/app/focus/src/main/resources/nccs-config.json +++ b/app/focus/src/main/resources/nccs-config.json @@ -17,6 +17,6 @@ "bubble_enabled": false, "bubble_url": "http://nynja-dev-uw1-messaging01.dev-eu.nynja.net:8888/cri/bubbles", "bubble_key": "nynja:nynjaTS", - "room_link_url": "http://nynja-dev-uw1-messaging02.dev-eu.nynja.net:8888/link", + "room_link_url": "http://nynja-dev-uw1-messaging01.dev-eu.nynja.net:8888/link", "room_link_key": "nynja:nynjaTS" } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 3731d1cf..2bdab5a9 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -1,10 +1,12 @@ package com.nynjacoin.nccs.conferencefactory.service; +import com.google.common.base.Strings; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; import com.nynjacoin.nccs.lib.grpcutil.GrpcTimestamp; import com.nynjacoin.nccs.lib.util.UuidGenerator; +import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink.RoomLinkClient; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; @@ -46,19 +48,21 @@ public class ConferenceFactory { private final Map accountConferences; private final Map conferences; private final Map conferencesByLink; - private final Map rooms; + private final Map rooms; private final int membersCountLimit; private final JoinLinkComposer joinLinkComposer; private final LinkIdGenerator linkIdGenerator; private final RoomPublisher roomPublisher; private final RoomLinkClient roomLinkClient; + private final ChatRoomClient chatRoomClient; private ConferenceControlVerticle conferenceControlVerticle; ConferenceFactory( JsonObject config, JoinLinkComposer joinLinkComposer, RoomPublisher roomPublisher, - RoomLinkClient roomLinkClient) { + RoomLinkClient roomLinkClient, + ChatRoomClient chatRoomClient) { this.accountConferences = new HashMap<>(); this.conferences = new HashMap<>(); @@ -71,6 +75,7 @@ public class ConferenceFactory { this.linkIdGenerator = new LinkIdGenerator(); this.roomPublisher = roomPublisher; this.roomLinkClient = roomLinkClient; + this.chatRoomClient = chatRoomClient; } public void getLimits( @@ -122,12 +127,12 @@ public class ConferenceFactory { return Future.succeededFuture(createResponse); } - ConferenceRoomInfo room; + ConferenceRoomState room; if (roomId.isEmpty()) { room = null; } else { assert start; - ConferenceRoomInfo existingRoom = rooms.get(roomId); + ConferenceRoomState existingRoom = rooms.get(roomId); if (existingRoom != null) { if (existingRoom.conferenceStarted()) { return Future.failedFuture(NccsError.CONFERENCE_ROOM_BUSY.exception()); @@ -139,7 +144,7 @@ public class ConferenceFactory { ); return waitCompletionFuture; } - room = new ConferenceRoomInfo(roomId, ci.getConferenceId()); + room = new ConferenceRoomState(roomId, ci.getConferenceId()); rooms.put(roomId, room); } @@ -246,7 +251,7 @@ public class ConferenceFactory { checkAccessToRoom(accountId, roomId) .compose(accessType -> { - ConferenceRoomInfo room = rooms.get(roomId); + ConferenceRoomState room = rooms.get(roomId); switch (accessType) { case START_CONFERENCE: if (room == null) { @@ -322,7 +327,7 @@ public class ConferenceFactory { if (roomId.isEmpty()) { return; } - ConferenceRoomInfo room = rooms.get(roomId); + ConferenceRoomState room = rooms.get(roomId); if (room == null) { LOGGER.warn("Discard room conference {} with empty room {}", conferenceId, roomId); return; @@ -359,8 +364,13 @@ public class ConferenceFactory { } private Future checkAccessToRoom(String accountId, String roomId) { - // FIXME: implement checks + if (Strings.isNullOrEmpty(accountId)) { + return Future.succeededFuture(RoomAccess.JOIN); + } + // FIXME: revert the real implementation below when erlang API is fixed return Future.succeededFuture(RoomAccess.START_CONFERENCE); +// return chatRoomClient.areAllMembers(accountId, roomId, List.of(accountId)) +// .map(isMember -> isMember ? RoomAccess.START_CONFERENCE : RoomAccess.JOIN); } private ConferenceInfo createNewConference( diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java index 454400ee..24ccc04a 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactoryVerticle.java @@ -3,6 +3,7 @@ package com.nynjacoin.nccs.conferencefactory.service; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; +import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink.RoomLinkClient; import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; import io.vertx.core.Future; @@ -18,13 +19,15 @@ public class ConferenceFactoryVerticle extends NccsVerticle { JsonObject config, JoinLinkComposer joinLinkComposer, RoomPublisher roomPublisher, - RoomLinkClient roomLinkClient) { + RoomLinkClient roomLinkClient, + ChatRoomClient chatRoomClient) { this.conferenceFactory = new ConferenceFactory( config, joinLinkComposer, roomPublisher, - roomLinkClient); + roomLinkClient, + chatRoomClient); } public void setConferenceControlVerticle(ConferenceControlVerticle conferenceControlVerticle) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomState.java similarity index 83% rename from focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java rename to focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomState.java index a69f15f8..57479a02 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomInfo.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceRoomState.java @@ -5,9 +5,9 @@ import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class ConferenceRoomInfo { +public class ConferenceRoomState { - private static Logger LOGGER = LogManager.getLogger(ConferenceRoomInfo.class); + private static Logger LOGGER = LogManager.getLogger(ConferenceRoomState.class); private final String conferenceId; private final String roomId; @@ -15,7 +15,7 @@ public class ConferenceRoomInfo { private boolean completed; private List waitingForCompletion; - ConferenceRoomInfo(String roomId, String conferenceId) { + ConferenceRoomState(String roomId, String conferenceId) { this.roomId = roomId; this.conferenceId = conferenceId; this.started = false; @@ -32,14 +32,18 @@ public class ConferenceRoomInfo { } void onConferenceStarted() { + assert !started; + assert !completed; this.started = true; this.completed = true; callWaiting(); } void onConferenceDiscarded() { - this.completed = true; - callWaiting(); + if (!completed) { + this.completed = true; + callWaiting(); + } } void addCompletionWaiter(Runnable waiting) { @@ -56,6 +60,7 @@ public class ConferenceRoomInfo { private void callWaiting(Runnable waiting) { try { + LOGGER.debug("Calling {}", waiting); waiting.run(); } catch (Throwable e) { LOGGER.error("Exception calling waiting for a room {} conference {} started: {}", diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java index 7a5adc3a..be373782 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/statepackage/RoomPublisher.java @@ -9,7 +9,7 @@ import io.vertx.core.Future; public class RoomPublisher extends StatePublisher { - public static final Topic TOPIC = Topic.CONFERENCE; + public static final Topic TOPIC = Topic.ROOM; public static final String ROOM_CONFERENCE_KEY = "room-conference"; public RoomPublisher(StateHolderVerticle stateHolderVerticle) { -- GitLab From a501cde7c59f9589863446438dec7955d254f450 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 3 Dec 2019 15:51:41 +0200 Subject: [PATCH 25/37] Switch the protocol submodule to the development commit. --- protocol/public/src/main/proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 0ce01282..2c1c7c2b 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 0ce012827d522630d4cbad491542aaeed69a717d +Subproject commit 2c1c7c2b559af12d72fa736fae417dd4e2c3b814 -- GitLab From 9b84bd15b5d9fbbee8b4dcb2cc0ae436600a406c Mon Sep 17 00:00:00 2001 From: "A.Popov" Date: Tue, 3 Dec 2019 15:59:15 +0200 Subject: [PATCH 26/37] Deployment:updated branch --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 205dc4cd..1917b998 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -91,7 +91,7 @@ pipeline { // Application name APP_NAME = "nccs-focus" // BRANCH_NAME="development" - BRANCH_NAME="${BRANCH_NAME ? BRANCH_NAME :'permanent-chat-group-meeting-room'}" + BRANCH_NAME="${BRANCH_NAME ? BRANCH_NAME :'temp-development'}" IMAGE_NAME = "eu.gcr.io/nynja-ci-201610/${NAMESPACE}/${APP_NAME}" IMAGE_TAG = "${BRANCH_NAME == 'master' ? 'latest' : 'latest-' + BRANCH_NAME}" IMAGE_BUILD_TAG = "$BRANCH_NAME-$BUILD_NUMBER" -- GitLab From 67c1724dacda621ee25a700d49c938cac8cbf525 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 3 Dec 2019 16:02:49 +0200 Subject: [PATCH 27/37] Add grpcurl-commands.txt - some sample command lines useful for testing. --- grpcurl-commands.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 grpcurl-commands.txt diff --git a/grpcurl-commands.txt b/grpcurl-commands.txt new file mode 100644 index 00000000..833616e9 --- /dev/null +++ b/grpcurl-commands.txt @@ -0,0 +1,33 @@ +grpcurl --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"some-room-id"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.GetLimits + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.CreateConference + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"add_member":[{"address":{"value":"peshko"}}, {"address":{"value":"meshko"}}]}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.CreateConference + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"create_request":{"add_member":[{"address":{"value":"peshko"}}, {"address":{"value":"meshko"}}]}}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.StartConference + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"my_room", "create_request":{"add_member":[{"address":{"value":"peshko"}}, {"address":{"value":"meshko"}}]}}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.StartConference + +grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_280' -H 'Instance-ID: aXaNH0BUH2DfAVa2Xi9kJ6' --proto conference_control.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{}' localhost:41414 nynjacoin.nccs.ccp.Conference.End + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"link_id":"some-room-id"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.GetRoomId + +grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"link_id":"a5ad9dc2"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.GetRoomId + +grpcurl -H 'Account-ID: 4d13c5cc-a153-4dd3-98e4-effdd69f30c9' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"link_id":"81d5db27"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.GetRoomId + +// guest enter +grpcurl -H 'Account-ID: 5ef289e7-3c9b-44e2-9dce-637e30f3f02a_2807' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"4d13c5cc-a153-4dd3-98e4-effdd69f30c9"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom + +// host enter +grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_280' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"4d13c5cc-a153-4dd3-98e4-effdd69f30c9"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom + + +ilia account id: +37936e07-1930-4317-8719-aadac2524184_280 + +ilia_email account id: +5ef289e7-3c9b-44e2-9dce-637e30f3f02a_2807 + +4d13c5cc-a153-4dd3-98e4-effdd69f30c9, 81d5db27 - ilia +d57061b1-3313-43bb-b745-7612677d3195, 1f3869fe - ilia, ilia_email -- GitLab From c3fced210437eceab29d6c09109ab82cee5597df Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 4 Dec 2019 11:58:13 +0200 Subject: [PATCH 28/37] Room membership check - re-enable. Turned out that the issue is with the test. --- .../nccs/conferencefactory/service/ConferenceFactory.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 2bdab5a9..3126e649 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -367,10 +367,8 @@ public class ConferenceFactory { if (Strings.isNullOrEmpty(accountId)) { return Future.succeededFuture(RoomAccess.JOIN); } - // FIXME: revert the real implementation below when erlang API is fixed - return Future.succeededFuture(RoomAccess.START_CONFERENCE); -// return chatRoomClient.areAllMembers(accountId, roomId, List.of(accountId)) -// .map(isMember -> isMember ? RoomAccess.START_CONFERENCE : RoomAccess.JOIN); + return chatRoomClient.areAllMembers(accountId, roomId, List.of(accountId)) + .map(isMember -> isMember ? RoomAccess.START_CONFERENCE : RoomAccess.JOIN); } private ConferenceInfo createNewConference( -- GitLab From e800fa53a87e65d5733eb14378a3c290656e7e61 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 4 Dec 2019 17:16:25 +0200 Subject: [PATCH 29/37] Extend State Holder - protocol and implementation - to allow cancel (release) held long poll request. NccsVerticle - ability to handle server to client stream. State holder GRPC and Web API moved to use NccsVerticle. --- .../api/ConferenceFactoryWebApi.java | 24 ++--- .../stateholder/api/StateHolderGrpcApi.java | 27 +++++- .../stateholder/api/StateHolderWebApi.java | 88 ++++++++----------- .../nccs/stateholder/service/StateHolder.java | 11 +++ .../service/StateHolderService.java | 34 ++++++- .../service/StateHolderVerticle.java | 49 ++--------- .../nccs/stateholder/service/TopicDb.java | 56 +++++++----- .../stateholder/service/TopicSubscriber.java | 41 +++++---- grpcurl-commands.txt | 10 ++- .../GrpcWriteStreamEventSourceAdapter.java | 18 ++++ .../nccs/lib/grpcutil/PathHandler.java | 25 +++++- .../nccs/lib/grpcutil/WebApiCallConsumer.java | 4 +- .../nccs/lib/grpcutil/WebResponseHandler.java | 2 +- .../nccs/lib/vertxdispatch/NccsVerticle.java | 10 +-- .../error/NccsWebEndpointException.java | 7 ++ protocol/public/src/main/proto | 2 +- 16 files changed, 241 insertions(+), 167 deletions(-) create mode 100644 protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsWebEndpointException.java diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index 4efcf83b..dd4e02ee 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -138,24 +138,12 @@ public class ConferenceFactoryWebApi implements WebApi { public Router createRouter(Vertx vertx) { Router router = Router.router(vertx); - router - .route("/GetLimits") - .handler(PathHandler.compose(this::getLimits)); - router - .route("/CreateConference") - .handler(PathHandler.compose(this::createConference)); - router - .route("/StartConference") - .handler(PathHandler.compose(this::startConference)); - router - .route("/GetConferenceId") - .handler(PathHandler.compose(this::getConferenceId)); - router - .route("/GetRoomId") - .handler(PathHandler.compose(this::getRoomId)); - router - .route("/EnterRoom") - .handler(PathHandler.compose(this::enterRoom)); + PathHandler.route(router, "/GetLimits", this::getLimits); + PathHandler.route(router, "/CreateConference", this::createConference); + PathHandler.route(router, "/StartConference", this::startConference); + PathHandler.route(router, "/GetConferenceId", this::getConferenceId); + PathHandler.route(router, "/GetRoomId", this::getRoomId); + PathHandler.route(router, "/EnterRoom", this::enterRoom); return router; } diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderGrpcApi.java index 1b745f1c..70d97122 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderGrpcApi.java @@ -1,18 +1,21 @@ package com.nynjacoin.nccs.stateholder.api; import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; +import com.nynjacoin.nccs.protocol.def.Void; +import com.nynjacoin.nccs.protocol.shp.CancelRequest; import com.nynjacoin.nccs.protocol.shp.FetchRequest; import com.nynjacoin.nccs.protocol.shp.StateHolderGrpc; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; +import io.vertx.core.Future; import io.vertx.grpc.GrpcWriteStream; public class StateHolderGrpcApi extends StateHolderGrpc.StateHolderVertxImplBase { - private final StateHolderVerticle stateHolderVerticle; + private final StateHolderVerticle verticle; - public StateHolderGrpcApi(StateHolderVerticle stateHolderVerticle) { - this.stateHolderVerticle = stateHolderVerticle; + public StateHolderGrpcApi(StateHolderVerticle verticle) { + this.verticle = verticle; } @Override @@ -21,7 +24,23 @@ public class StateHolderGrpcApi extends StateHolderGrpc.StateHolderVertxImplBase String accountId = GrpcContextKeys.ACCOUNT_ID.get(); String instanceId = GrpcContextKeys.INSTANCE_ID.get(); - stateHolderVerticle.fetch(accountId, instanceId, request, response); + verticle.runOnContext( + () -> verticle.stateHolderService.fetch(accountId, instanceId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); + } + + @Override + public void cancelLongPoll(CancelRequest request, Future response) { + String accountId = GrpcContextKeys.ACCOUNT_ID.get(); + String instanceId = GrpcContextKeys.INSTANCE_ID.get(); + + verticle.runOnContext( + () -> verticle.stateHolderService.cancelLongPoll(accountId, instanceId, request, response), + response, + GrpcContextKeys.LOG_CONTEXT.get() + ); } } diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java index 8720e989..87ac7540 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java @@ -1,34 +1,32 @@ package com.nynjacoin.nccs.stateholder.api; import com.google.protobuf.InvalidProtocolBufferException; -import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; import com.nynjacoin.nccs.lib.grpcutil.GrpcWriteStreamEventSourceAdapter; +import com.nynjacoin.nccs.lib.grpcutil.PathHandler; import com.nynjacoin.nccs.lib.grpcutil.WebApi; -import com.nynjacoin.nccs.lib.grpcutil.WebEventTarget; import com.nynjacoin.nccs.lib.grpcutil.WebMetadata; +import com.nynjacoin.nccs.lib.grpcutil.WebResponseHandler; +import com.nynjacoin.nccs.protocol.def.Void; +import com.nynjacoin.nccs.protocol.error.NccsWebEndpointException; import com.nynjacoin.nccs.protocol.metadata.CallingMetadataKey; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; +import com.nynjacoin.nccs.protocol.shp.CancelRequest; import com.nynjacoin.nccs.protocol.shp.FetchRequest; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; -import io.grpc.Context; -import io.vertx.core.MultiMap; +import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.grpc.GrpcWriteStream; -import java.io.IOException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; public class StateHolderWebApi implements WebApi { - private static final Logger LOGGER = LogManager.getLogger(StateHolderWebApi.class); + private final StateHolderVerticle verticle; - private final StateHolderVerticle stateHolderVerticle; - - public StateHolderWebApi(StateHolderVerticle stateHolderVerticle) { - this.stateHolderVerticle = stateHolderVerticle; + public StateHolderWebApi(StateHolderVerticle verticle) { + this.verticle = verticle; } @Override @@ -40,54 +38,44 @@ public class StateHolderWebApi implements WebApi { public Router createRouter(Vertx vertx) { Router router = Router.router(vertx); - router - .route("/Fetch") - .handler(this::fetch); + PathHandler.route(router, "/Fetch", this::fetch); + PathHandler.route(router, "/CancelLongPoll", this::cancelLongPoll); return router; } - private void fetch(RoutingContext ctx) { + private void fetch(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException, NccsWebEndpointException { + WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); String instanceId = webMetadata.get(CallingMetadataKey.INSTANCE_ID); - FetchRequest request; - try { - request = parseFetchRequest(ctx.request().params()); - } catch (InvalidProtocolBufferException e) { - ctx.fail(e); - return; - } - - WebEventTarget target = new WebEventTarget(ctx); - - try { - target.open(); - } catch (IOException e) { - LOGGER.warn("Error while opening event source!", e); - return; - } - - GrpcWriteStream response = - new GrpcWriteStreamEventSourceAdapter(target, Vertx.currentContext()); - - LOGGER.debug("Fetch account: {} instance: {} request {}", accountId, instanceId, request); - - Context logGrpcContext = Context.current() - .withValue(GrpcContextKeys.LOG_CONTEXT, webMetadata.getLogContext()); - Context prevGrpcContext = logGrpcContext.attach(); - try { - stateHolderVerticle.fetch(accountId, instanceId, request, response); - } finally { - logGrpcContext.detach(prevGrpcContext); - } + FetchRequest request = FetchRequest.parseFrom(bodyBuffer.getBytes()); + GrpcWriteStream response = GrpcWriteStreamEventSourceAdapter.create(ctx); + + verticle.runOnContext( + () -> verticle.stateHolderService.fetch(accountId, instanceId, request, response), + response, + webMetadata.getLogContext() + ); } - private FetchRequest parseFetchRequest(MultiMap params) throws InvalidProtocolBufferException { - byte[] body = WebEventTarget.getEventSourceRequestBody(params); - FetchRequest fetchRequest = FetchRequest.parseFrom(body); - return fetchRequest; + private void cancelLongPoll(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException { + + WebMetadata webMetadata = new WebMetadata(ctx); + String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); + String instanceId = webMetadata.get(CallingMetadataKey.INSTANCE_ID); + + var request = CancelRequest.parseFrom(bodyBuffer.getBytes()); + Future response = WebResponseHandler.future(ctx); + + verticle.runOnContext( + () -> verticle.stateHolderService.cancelLongPoll(accountId, instanceId, request, response), + response, + webMetadata.getLogContext() + ); } } diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolder.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolder.java index 6ff40163..0ef92bd9 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolder.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolder.java @@ -1,10 +1,12 @@ package com.nynjacoin.nccs.stateholder.service; import com.nynjacoin.nccs.lib.util.UuidGenerator; +import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.protocol.error.NccsError; import com.nynjacoin.nccs.protocol.shp.FetchRequest; import com.nynjacoin.nccs.protocol.shp.Record; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; +import io.vertx.core.Future; import io.vertx.grpc.GrpcWriteStream; import java.util.HashMap; import java.util.Map; @@ -54,6 +56,15 @@ public class StateHolder { .fetch(request.getVersion(), request.getLongPoll(), response, subscriberInfo); } + void cancelLongPoll(String topic, Future response, String subscriberId) { + TopicDb topicDb = topicDbs.get(topic); + if (topicDb == null) { + response.complete(); + return; + } + topicDb.cancelLongPoll(response, subscriberId); + } + void publish(String topic, Record record) { getOrCreateTopicDb(topic).publish(record); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderService.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderService.java index cef45a63..35280a09 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderService.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderService.java @@ -1,9 +1,12 @@ package com.nynjacoin.nccs.stateholder.service; +import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.protocol.error.NccsError; +import com.nynjacoin.nccs.protocol.shp.CancelRequest; import com.nynjacoin.nccs.protocol.shp.FetchRequest; import com.nynjacoin.nccs.protocol.shp.Record; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.grpc.GrpcWriteStream; import java.util.HashMap; @@ -62,7 +65,24 @@ public class StateHolderService { FetchRequest request, GrpcWriteStream response) { getOrCreateAndAuthorizeStateHolder(accountId, instanceId, request.getTopic()) - .fetch(request, response, accountId + '@' + request.hashCode()); + .fetch(request, response, getSubscriberId(accountId, request)); + } + + public void cancelLongPoll( + String accountId, + String instanceId, + CancelRequest request, + Future response) { + + StateHolder stateHolder = stateHolders.get(instanceId); + if (stateHolder == null) { + response.complete(); + return; + } + stateHolder.cancelLongPoll( + request.getTopic(), + response, + getSubscriberId(accountId, request.getClientId())); } public void publish(String instanceId, String topic, Record record) { @@ -77,6 +97,18 @@ public class StateHolderService { return longPollMaxTime; } + private String getSubscriberId(String accountId, FetchRequest request) { + String clientId = request.getClientId(); + if (clientId.isEmpty()) { + clientId = Integer.toString(request.hashCode()); + } + return getSubscriberId(accountId, clientId); + } + + private String getSubscriberId(String accountId, String clientId) { + return accountId + '@' + clientId; + } + private StateHolder getOrCreateStateHolder(String instanceId, String topic) { StateHolder stateHolder = stateHolders.get(instanceId); if (stateHolder == null) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderVerticle.java index 2ae73f07..9cab5161 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/StateHolderVerticle.java @@ -1,59 +1,24 @@ package com.nynjacoin.nccs.stateholder.service; -import com.nynjacoin.nccs.lib.grpcutil.GrpcContextKeys; +import com.nynjacoin.nccs.lib.vertxdispatch.NccsVerticle; import com.nynjacoin.nccs.protocol.def.Void; -import com.nynjacoin.nccs.protocol.shp.FetchRequest; import com.nynjacoin.nccs.protocol.shp.Record; -import com.nynjacoin.nccs.protocol.shp.UpdatePacket; -import io.vertx.core.AbstractVerticle; -import io.vertx.core.Context; import io.vertx.core.Future; -import io.vertx.core.Vertx; -import io.vertx.grpc.GrpcWriteStream; import org.apache.logging.log4j.CloseableThreadContext; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; -public class StateHolderVerticle extends AbstractVerticle { +public class StateHolderVerticle extends NccsVerticle { - private static final Logger LOGGER = LogManager.getLogger(StateHolderVerticle.class); - - private final StateHolderService stateHolderService; - private Context verticleContext; + public final StateHolderService stateHolderService; public StateHolderVerticle(long expireInterval, long longPollMaxTime) { stateHolderService = new StateHolderService(expireInterval, longPollMaxTime); } - @Override - public void start() { - LOGGER.info("Starting ..."); - verticleContext = Vertx.currentContext(); - stateHolderService.start(); - } - - @Override - public void stop() { - stateHolderService.stop(); - LOGGER.info("Stopped."); - } - - public void fetch(String accountId, String instanceId, - FetchRequest request, GrpcWriteStream response) { - - final var logContext = GrpcContextKeys.LOG_CONTEXT.get(); - verticleContext.runOnContext(v -> { - try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { - stateHolderService.fetch(accountId, instanceId, request, response); - } - }); - } - public Future publish(String instanceId, String topic, Record record) { Future f = Future.future(); final var logContext = ThreadContext.getContext(); - verticleContext.runOnContext(v -> { + context.runOnContext(v -> { try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { stateHolderService.publish(instanceId, topic, record); f.complete(Void.getDefaultInstance()); @@ -66,7 +31,7 @@ public class StateHolderVerticle extends AbstractVerticle { public void recant(String instanceId, String topic, String key) { final var logContext = ThreadContext.getContext(); - verticleContext.runOnContext(v -> { + context.runOnContext(v -> { try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { stateHolderService.recant(instanceId, topic, key); } @@ -76,7 +41,7 @@ public class StateHolderVerticle extends AbstractVerticle { public Future createTopic(String instanceId, String topic) { Future f = Future.future(); final var logContext = ThreadContext.getContext(); - verticleContext.runOnContext(v -> { + context.runOnContext(v -> { try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { stateHolderService.createTopic(instanceId, topic); f.complete(Void.getDefaultInstance()); @@ -89,7 +54,7 @@ public class StateHolderVerticle extends AbstractVerticle { public void discardTopic(String instanceId, String topic) { final var logContext = ThreadContext.getContext(); - verticleContext.runOnContext(v -> { + context.runOnContext(v -> { try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { stateHolderService.discardTopic(instanceId, topic); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicDb.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicDb.java index 1f006e7d..129dddb8 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicDb.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicDb.java @@ -2,6 +2,7 @@ package com.nynjacoin.nccs.stateholder.service; import com.google.protobuf.TextFormat; import com.nynjacoin.nccs.lib.util.InstanceLogger; +import com.nynjacoin.nccs.protocol.def.Void; import com.nynjacoin.nccs.protocol.error.NccsError; import com.nynjacoin.nccs.protocol.shp.Deletion; import com.nynjacoin.nccs.protocol.shp.EndMarker; @@ -10,6 +11,7 @@ import com.nynjacoin.nccs.protocol.shp.StartMarker; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; import com.nynjacoin.nccs.protocol.shp.UpdateType; import com.nynjacoin.nccs.protocol.shp.Version; +import io.vertx.core.Future; import io.vertx.grpc.GrpcWriteStream; import java.util.ArrayDeque; import java.util.ArrayList; @@ -96,29 +98,40 @@ public class TopicDb { Version version, boolean longPoll, GrpcWriteStream response, - String subsInfo) { + String subsId) { logger.debug("{} fetch version: {{}} longPoll: {}", - subsInfo, TextFormat.shortDebugString(version), longPoll); + subsId, TextFormat.shortDebugString(version), longPoll); logNextVersion(); if (!version.getGeneration().equals(generation)) { - sendFullUpdate(response, subsInfo); + sendFullUpdate(response, subsId); } else if (version.getSequence() > nextDelta.getSequence()) { - logger.warn("{} invalid version sequence", subsInfo); + logger.warn("{} invalid version sequence", subsId); logNextVersion(); response.fail(NccsError.INVALID_ARGUMENT.exception("Invalid version sequence")); } else if (version.getSequence() == nextDelta.getSequence()) { nextDelta.releaseReference(); if (longPoll) { - registerSubscriber(response, subsInfo); + registerSubscriber(response, subsId); } else { - sendEmptyUpdate(response, subsInfo); + sendEmptyUpdate(response, subsId); } } else { - fetchDelta(version.getSequence(), response, subsInfo); + fetchDelta(version.getSequence(), response, subsId); } } + void cancelLongPoll(Future response, String subsId) { + List toCancel = subscribers.stream() + .filter(subscriber -> subsId.equals(subscriber.getSubsId())) + .collect(Collectors.toList()); + toCancel.forEach(subscriber -> { + subscribers.remove(subscriber); + sendSpecialUpdate(subscriber, UpdateType.POLL_CANCEL); + }); + response.complete(); + } + void publish(Record record) { logger.debug("publish {}", record); logNextVersion(); @@ -155,7 +168,7 @@ public class TopicDb { .collect(Collectors.toList()); expired.forEach(subscriber -> { subscribers.remove(subscriber); - sendKeepAliveUpdate(subscriber); + sendSpecialUpdate(subscriber, UpdateType.KEEP_ALIVE); }); } @@ -209,15 +222,15 @@ public class TopicDb { badSubscribers.forEach(subscribers::remove); } - private void registerSubscriber(GrpcWriteStream response, String subsInfo) { - TopicSubscriber topicSubscriber = new TopicSubscriber(response, subsInfo); + private void registerSubscriber(GrpcWriteStream response, String subsId) { + TopicSubscriber topicSubscriber = new TopicSubscriber(response, subsId); logger.info("Subscriber added: {}", topicSubscriber); subscribers.add(topicSubscriber); } - private void fetchDelta(int sequence, GrpcWriteStream response, String subsInfo) { + private void fetchDelta(int sequence, GrpcWriteStream response, String subsId) { if (deltas.isEmpty() || sequence < deltas.getLast().getSequence()) { - sendFullUpdate(response, subsInfo); + sendFullUpdate(response, subsId); return; } @@ -233,7 +246,7 @@ public class TopicDb { } if (versionDelta == null) { - sendFullUpdate(response, subsInfo); + sendFullUpdate(response, subsId); return; } @@ -243,19 +256,19 @@ public class TopicDb { sendDeltas(it.next(), response); } response.write(createEndMarker()); - logger.info("{} got delta", subsInfo); + logger.info("{} got delta", subsId); logNextVersion(); response.end(); } - private void sendFullUpdate(GrpcWriteStream response, String subsInfo) { + private void sendFullUpdate(GrpcWriteStream response, String subsId) { response.write(createStartMarker(UpdateType.FULL)); records.values().forEach(record -> { UpdatePacket updatePacket = createUpdate(record); response.write(updatePacket); }); response.write(createEndMarker()); - logger.info("{} got full", subsInfo); + logger.info("{} got full", subsId); logNextVersion(); response.end(); } @@ -266,20 +279,21 @@ public class TopicDb { ); } - private void sendEmptyUpdate(GrpcWriteStream response, String subsInfo) { + private void sendEmptyUpdate(GrpcWriteStream response, String subsId) { response.write(createStartMarker(UpdateType.INCREMENTAL)); response.write(createEndMarker()); - logger.info("req: {} got empty", subsInfo); + logger.info("{} got empty", subsId); logNextVersion(); response.end(); } - private void sendKeepAliveUpdate(TopicSubscriber subscriber) { + private void sendSpecialUpdate(TopicSubscriber subscriber, UpdateType type) { + assert type == UpdateType.KEEP_ALIVE || type == UpdateType.POLL_CANCEL; try { var response = subscriber.getResponseStream(); - response.write(createStartMarker(UpdateType.KEEP_ALIVE)); + response.write(createStartMarker(type)); response.write(createEndMarker()); - logger.info("{} got keep-alive", subscriber); + logger.info("{} got {}", subscriber.getSubsId(), type); logNextVersion(); response.end(); } catch (Throwable ignored) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicSubscriber.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicSubscriber.java index f854dadf..82eb6fb3 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicSubscriber.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/service/TopicSubscriber.java @@ -2,29 +2,34 @@ package com.nynjacoin.nccs.stateholder.service; import com.nynjacoin.nccs.protocol.shp.UpdatePacket; import io.vertx.grpc.GrpcWriteStream; -import java.util.Date; public class TopicSubscriber { private final GrpcWriteStream responseStream; - private final long requestTime; - private final String logId; + private final String subsId; + private final long requestTime; + private final String logId; - TopicSubscriber(GrpcWriteStream responseStream, String subsInfo) { - this.responseStream = responseStream; - this.requestTime = System.currentTimeMillis(); - this.logId = subsInfo + '/' + String.valueOf(requestTime); - } + TopicSubscriber(GrpcWriteStream responseStream, String subsId) { + this.responseStream = responseStream; + this.subsId = subsId; + this.requestTime = System.currentTimeMillis(); + this.logId = subsId + '/' + String.valueOf(requestTime); + } - GrpcWriteStream getResponseStream() { - return responseStream; - } + GrpcWriteStream getResponseStream() { + return responseStream; + } - long getRequestTime() { - return requestTime; - } + long getRequestTime() { + return requestTime; + } - @Override - public String toString() { - return logId; - } + @Override + public String toString() { + return logId; + } + + String getSubsId() { + return subsId; + } } diff --git a/grpcurl-commands.txt b/grpcurl-commands.txt index 833616e9..04c04e91 100644 --- a/grpcurl-commands.txt +++ b/grpcurl-commands.txt @@ -8,7 +8,7 @@ grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path pro grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"my_room", "create_request":{"add_member":[{"address":{"value":"peshko"}}, {"address":{"value":"meshko"}}]}}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.StartConference -grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_280' -H 'Instance-ID: aXaNH0BUH2DfAVa2Xi9kJ6' --proto conference_control.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{}' localhost:41414 nynjacoin.nccs.ccp.Conference.End +grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_2806' -H 'Instance-ID: aXaNH0BUH2DfAVa2Xi9kJ6' --proto conference_control.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{}' localhost:41414 nynjacoin.nccs.ccp.Conference.End grpcurl -H 'Account-ID: acc1' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"link_id":"some-room-id"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.GetRoomId @@ -20,11 +20,15 @@ grpcurl -H 'Account-ID: 4d13c5cc-a153-4dd3-98e4-effdd69f30c9' --proto conference grpcurl -H 'Account-ID: 5ef289e7-3c9b-44e2-9dce-637e30f3f02a_2807' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"4d13c5cc-a153-4dd3-98e4-effdd69f30c9"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom // host enter -grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_280' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"4d13c5cc-a153-4dd3-98e4-effdd69f30c9"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom +grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_2806' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"4d13c5cc-a153-4dd3-98e4-effdd69f30c9"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom + +// owner and non-owner hosts enter +grpcurl -H 'Account-ID: 37936e07-1930-4317-8719-aadac2524184_2806' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"d57061b1-3313-43bb-b745-7612677d3195"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom +grpcurl -H 'Account-ID: 5ef289e7-3c9b-44e2-9dce-637e30f3f02a_2807' --proto conference_factory.proto --import-path protocol/public/src/main/proto --plaintext --emit-defaults -d '{"room_id":"d57061b1-3313-43bb-b745-7612677d3195"}' localhost:41414 nynjacoin.nccs.cfp.ConferenceFactory.EnterRoom ilia account id: -37936e07-1930-4317-8719-aadac2524184_280 +37936e07-1930-4317-8719-aadac2524184_2806 ilia_email account id: 5ef289e7-3c9b-44e2-9dce-637e30f3f02a_2807 diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/GrpcWriteStreamEventSourceAdapter.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/GrpcWriteStreamEventSourceAdapter.java index 8e81401d..0efd13d7 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/GrpcWriteStreamEventSourceAdapter.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/GrpcWriteStreamEventSourceAdapter.java @@ -1,12 +1,16 @@ package com.nynjacoin.nccs.lib.grpcutil; import com.google.protobuf.GeneratedMessageV3; +import com.nynjacoin.nccs.protocol.error.NccsWebEndpointException; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; import io.vertx.core.Context; import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.ext.web.RoutingContext; import io.vertx.grpc.GrpcWriteStream; +import java.io.IOException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -18,6 +22,20 @@ public class GrpcWriteStreamEventSourceAdapter GrpcWriteStream create(RoutingContext ctx) + throws NccsWebEndpointException { + + WebEventTarget target = new WebEventTarget(ctx); + + try { + target.open(); + } catch (IOException e) { + throw new NccsWebEndpointException("Error while opening event source!", e); + } + + return new GrpcWriteStreamEventSourceAdapter<>(target, Vertx.currentContext()); + } + public GrpcWriteStreamEventSourceAdapter(WebEventTarget target, Context vertxContext) { this.target = target; this.vertxContext = vertxContext; diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java index 09365df0..bc27093d 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java @@ -1,15 +1,36 @@ package com.nynjacoin.nccs.lib.grpcutil; -import com.nynjacoin.nccs.protocol.error.NccsWrappingException; +import com.google.protobuf.InvalidProtocolBufferException; +import com.nynjacoin.nccs.protocol.error.NccsWebEndpointException; import io.vertx.core.Handler; +import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class PathHandler { + private static Logger LOGGER = LogManager.getLogger(PathHandler.class); + public static Handler compose(WebApiCallConsumer consumer) { + return compose("UNKNOWN PATH", consumer); + } + + public static Handler compose(String path, WebApiCallConsumer consumer) { return ctx -> ctx.request().bodyHandler( - NccsWrappingException.wrap(bodyBuffer -> consumer.accept(ctx, bodyBuffer)) + bodyBuffer -> { + try { + consumer.accept(ctx, bodyBuffer); + } catch (InvalidProtocolBufferException e) { + LOGGER.warn("{}: body is not a valid proto.3: {}", path, bodyBuffer); + } catch (NccsWebEndpointException e) { + LOGGER.error("{}: failure processing request: {}", path, bodyBuffer, e); + } + } ); } + public static void route(Router router, String path, WebApiCallConsumer consumer) { + router.route(path).handler(compose(consumer)); + } } diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java index 46b151b6..cb2f3f8b 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java @@ -1,11 +1,13 @@ package com.nynjacoin.nccs.lib.grpcutil; import com.google.protobuf.InvalidProtocolBufferException; +import com.nynjacoin.nccs.protocol.error.NccsWebEndpointException; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.RoutingContext; public interface WebApiCallConsumer { - void accept(RoutingContext ctx, Buffer bodyBuffer) throws InvalidProtocolBufferException; + void accept(RoutingContext ctx, Buffer bodyBuffer) + throws InvalidProtocolBufferException, NccsWebEndpointException; } diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebResponseHandler.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebResponseHandler.java index 60498318..b138dab9 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebResponseHandler.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebResponseHandler.java @@ -26,7 +26,7 @@ public class WebResponseHandler implements Handler private final RoutingContext ctx; - public WebResponseHandler(RoutingContext ctx) { + private WebResponseHandler(RoutingContext ctx) { this.ctx = ctx; } diff --git a/lib/vertx-dispatch/src/main/java/com/nynjacoin/nccs/lib/vertxdispatch/NccsVerticle.java b/lib/vertx-dispatch/src/main/java/com/nynjacoin/nccs/lib/vertxdispatch/NccsVerticle.java index 2d1dc5b7..3455eb1b 100644 --- a/lib/vertx-dispatch/src/main/java/com/nynjacoin/nccs/lib/vertxdispatch/NccsVerticle.java +++ b/lib/vertx-dispatch/src/main/java/com/nynjacoin/nccs/lib/vertxdispatch/NccsVerticle.java @@ -3,7 +3,7 @@ package com.nynjacoin.nccs.lib.vertxdispatch; import com.nynjacoin.nccs.protocol.error.NccsException; import io.vertx.core.AbstractVerticle; import io.vertx.core.Future; -import io.vertx.grpc.GrpcBidiExchange; +import io.vertx.grpc.GrpcWriteStream; import java.util.Map; import org.apache.logging.log4j.CloseableThreadContext; import org.apache.logging.log4j.ThreadContext; @@ -24,20 +24,20 @@ public class NccsVerticle extends AbstractVerticle { }); } - public void runOnContext(Runnable action, GrpcBidiExchange exchange) { - runOnContext(action, exchange, ThreadContext.getContext()); + public void runOnContext(Runnable action, GrpcWriteStream response) { + runOnContext(action, response, ThreadContext.getContext()); } public void runOnContext( Runnable action, - GrpcBidiExchange exchange, + GrpcWriteStream response, Map logContext) { context.runOnContext(v -> { try (final CloseableThreadContext.Instance tc = CloseableThreadContext.putAll(logContext)) { action.run(); } catch (NccsException e) { - exchange.fail(e); + response.fail(e); } }); } diff --git a/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsWebEndpointException.java b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsWebEndpointException.java new file mode 100644 index 00000000..47edd3f3 --- /dev/null +++ b/protocol/public/src/main/java/com/nynjacoin/nccs/protocol/error/NccsWebEndpointException.java @@ -0,0 +1,7 @@ +package com.nynjacoin.nccs.protocol.error; + +public class NccsWebEndpointException extends Exception { + public NccsWebEndpointException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index 2c1c7c2b..d1cf379a 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit 2c1c7c2b559af12d72fa736fae417dd4e2c3b814 +Subproject commit d1cf379a32512b7f9e9fbf24d7ef24f9b34a351a -- GitLab From fdd579275bf27daa7ed1690a44712a4d436f75a8 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Thu, 5 Dec 2019 09:48:12 +0200 Subject: [PATCH 30/37] Fix warnings. --- .../service/ConferenceControl.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java index 63b8e5e9..354f1cf4 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java @@ -49,7 +49,7 @@ public class ConferenceControl { private final BubbleSender bubbleSender; private final ChatRoomClient chatRoomClient; - public ConferenceControl( + ConferenceControl( ConferenceFactoryVerticle conferenceFactoryVerticle, StateHolderVerticle stateHolderVerticle, FocusInternalApiClient focusInternalApiClient, PushNotificationSender pushClient, @@ -93,7 +93,7 @@ public class ConferenceControl { } } - public void getMembers(String accountId, String conferenceId, GetMembersRequest request, + void getMembers(String accountId, String conferenceId, GetMembersRequest request, GrpcWriteStream response) { Conference conference = conferences.get(conferenceId); @@ -104,7 +104,7 @@ public class ConferenceControl { } } - public void getParticipant(String conferenceId, String participantId, + void getParticipant(String conferenceId, String participantId, Future future) { Conference conference = conferences.get(conferenceId); @@ -120,7 +120,7 @@ public class ConferenceControl { } } - public void updateConferenceInfo(String accountId, String conferenceId, + void updateConferenceInfo(String accountId, String conferenceId, UpdateConferenceInfoRequest request, Future response) { @@ -165,7 +165,7 @@ public class ConferenceControl { } } - public void removeMember(String accountId, String conferenceId, RemoveMemberRequest request, + void removeMember(String accountId, String conferenceId, RemoveMemberRequest request, Future response) { Conference conference = conferences.get(conferenceId); @@ -228,7 +228,7 @@ public class ConferenceControl { } } - Future getConference(String accountId, String conferenceId) { + private Future getConference(String accountId, String conferenceId) { Future conferenceFuture = Future.future(); Conference conference = conferences.get(conferenceId); if (conference != null) { @@ -239,7 +239,7 @@ public class ConferenceControl { return conferenceFuture; } - void handleConference(String accountId, Conference conference, + private void handleConference(String accountId, Conference conference, Future future) { if (!conference.getConferenceInfo().getOwnerAccountId().equals(accountId)) { @@ -356,7 +356,7 @@ public class ConferenceControl { } } - public void conferenceCompleted(String conferenceId) { + void conferenceCompleted(String conferenceId) { Conference conference = conferences.get(conferenceId); if (conference == null) { return; -- GitLab From f8b66d8c5d52664cd568454ebd45e327896b6267 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Thu, 5 Dec 2019 10:29:42 +0200 Subject: [PATCH 31/37] Let room members end the conference. --- .../nynjacoin/nccs/app/focus/FocusApp.java | 3 +- .../conferencecontrol/service/Conference.java | 51 ++++++++++++++----- .../service/ConferenceControl.java | 10 ++-- .../service/ConferenceControlVerticle.java | 6 ++- .../service/ConferenceFactory.java | 2 +- .../restclient/chatroom/ChatRoomClient.java | 4 ++ 6 files changed, 56 insertions(+), 20 deletions(-) diff --git a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java index b03e1289..cfb9997f 100644 --- a/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java +++ b/app/focus/src/main/java/com/nynjacoin/nccs/app/focus/FocusApp.java @@ -125,7 +125,8 @@ public class FocusApp extends VertxApp { joinLinkComposer, historyEventsProcessor, bubbleSender, - config.getBoolean(ConfigKey.CHAT_ROOM_ENABLED.key(), true) ? chatRoomClient : null); + chatRoomClient, + config.getBoolean(ConfigKey.CHAT_ROOM_ENABLED.key(), true)); vertx.deployVerticle(conferenceControlVerticle); conferenceFactoryVerticle.setConferenceControlVerticle(conferenceControlVerticle); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java index ce3f7441..85f1862e 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java @@ -10,6 +10,7 @@ import com.nynjacoin.nccs.lib.util.InstanceLogger; import com.nynjacoin.nccs.lib.util.UuidGenerator; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender.AnswerStatus; import com.nynjacoin.nccs.lib.vertxutil.restclient.bubble.BubbleSender.ContentType; +import com.nynjacoin.nccs.lib.vertxutil.restclient.chatroom.ChatRoomClient; import com.nynjacoin.nccs.protocol.ccp.BindByLinkRequest; import com.nynjacoin.nccs.protocol.ccp.BindByLinkResponse; import com.nynjacoin.nccs.protocol.ccp.GetMembersRequest; @@ -62,7 +63,7 @@ class Conference { private static final Logger LOGGER = LogManager.getLogger(Conference.class); - static final Gauge CONFERENCE_ACTIVE = Gauge.build() + private static final Gauge CONFERENCE_ACTIVE = Gauge.build() .name("nccs_conference_active") .help("Active conference calls") .create(); @@ -77,6 +78,7 @@ class Conference { private final StateHolderVerticle stateHolderVerticle; private final ConferencePublisher conferencePublisher; private final FocusInternalApiClient focusInternalApiClient; + private final ChatRoomClient chatRoomClient; private final Map members; private final Map participants; private ChatRoomManager chatRoomManager; @@ -87,13 +89,15 @@ class Conference { ConferenceControl parent, ConferenceInfo conferenceInfo, StateHolderVerticle stateHolderVerticle, - FocusInternalApiClient focusInternalApiClient) { + FocusInternalApiClient focusInternalApiClient, + ChatRoomClient chatRoomClient) { this.parent = parent; this.conferenceInfo = conferenceInfo; this.stateHolderVerticle = stateHolderVerticle; this.conferencePublisher = new ConferencePublisher(stateHolderVerticle); this.focusInternalApiClient = focusInternalApiClient; + this.chatRoomClient = chatRoomClient; this.members = new HashMap<>(); this.participants = new HashMap<>(); this.userConferenceTemplate = null; @@ -121,6 +125,27 @@ class Conference { return hasReadAccess(accountId); } + // TODO: addMember() updateSubject()... should follow end() suite by calling this method + // TODO: and letting room members do changes; at that point we should remove sync methods + // TODO: hasChangeAccess and authorizeChangeAccess and rename xxxAsync() to xxx() + private Future authorizeChangeAccessAsync(String accountId) { + return hasChangeAccessAsync(accountId) + .compose(hasChangeAccess -> + hasChangeAccess ? + Future.succeededFuture() : Future.failedFuture(NccsError.UNAUTHORIZED.exception())); + } + + private Future hasChangeAccessAsync(String accountId) { + String roomId = conferenceInfo.getRoomId(); + if (roomId.isEmpty()) { + return Future.succeededFuture(hasChangeAccess(accountId)); + } + if (isOwner(accountId)) { + return Future.succeededFuture(Boolean.TRUE); + } + return chatRoomClient.isMember(conferenceInfo.getOwnerAccountId(), roomId, accountId); + } + private void authorizeChangeAccess(String accountId) { if (hasChangeAccess(accountId)) { return; @@ -259,17 +284,17 @@ class Conference { } public void end(String accountId, Void request, Future response) { - if (!isOwner(accountId)) { - response.fail(NccsError.UNAUTHORIZED.exception()); - return; - } - if (conferenceInfo.isOngoing()) { - conferenceCompleted(); - focusInternalApiClient.endConference(conferenceInfo.getConferenceId()); - } else { - selfRemove(); - } - response.complete(Void.getDefaultInstance()); + authorizeChangeAccessAsync(accountId).compose( + ignoredVoid -> { + if (conferenceInfo.isOngoing()) { + conferenceCompleted(); + focusInternalApiClient.endConference(conferenceInfo.getConferenceId()); + } else { + selfRemove(); + } + response.complete(Void.getDefaultInstance()); + }, + response); } void manageParticipant(String accountId, ManageParticipanRequest request, Future response) { diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java index 354f1cf4..0a2f81cb 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControl.java @@ -48,6 +48,7 @@ public class ConferenceControl { private final HistoryEventsProcessor history; private final BubbleSender bubbleSender; private final ChatRoomClient chatRoomClient; + private final Boolean isChatRoomIntegrationEnabled; ConferenceControl( ConferenceFactoryVerticle conferenceFactoryVerticle, @@ -56,7 +57,8 @@ public class ConferenceControl { JoinLinkComposer joinLinkComposer, HistoryEventsProcessor history, BubbleSender bubbleSender, - ChatRoomClient chatRoomClient) { + ChatRoomClient chatRoomClient, + Boolean isChatRoomIntegrationEnabled) { this.conferenceFactoryVerticle = conferenceFactoryVerticle; this.stateHolderVerticle = stateHolderVerticle; @@ -66,6 +68,7 @@ public class ConferenceControl { this.history = history; this.bubbleSender = bubbleSender; this.chatRoomClient = chatRoomClient; + this.isChatRoomIntegrationEnabled = isChatRoomIntegrationEnabled; Conference.registerMetrics(); } @@ -276,7 +279,8 @@ public class ConferenceControl { this, conferenceInfo, stateHolderVerticle, - focusInternalApiClient); + focusInternalApiClient, + chatRoomClient); conference.setChatRoomManager(getChatRoomManager(conference)); conferences.put(conference.getConferenceInfo().getConferenceId(), conference); return conference; @@ -371,7 +375,7 @@ public class ConferenceControl { private ChatRoomManager getChatRoomManager(Conference conference) { ConferenceInfo ci = conference.getConferenceInfo(); - if (Objects.isNull(chatRoomClient)) { + if (!isChatRoomIntegrationEnabled) { // chat room management disabled by server config // TODO: remove this backward compatibility diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java index 794eb8c4..79a47ebe 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/ConferenceControlVerticle.java @@ -43,7 +43,8 @@ public class ConferenceControlVerticle extends NccsVerticle { JoinLinkComposer joinLinkComposer, HistoryEventsProcessor history, BubbleSender bubbleSender, - ChatRoomClient chatRoomClient) { + ChatRoomClient chatRoomClient, + Boolean isChatRoomIntegrationEnabled) { this.focusInternalApiClient = focusInternalApiClient; this.conferenceControl = new ConferenceControl( @@ -54,7 +55,8 @@ public class ConferenceControlVerticle extends NccsVerticle { joinLinkComposer, history, bubbleSender, - chatRoomClient); + chatRoomClient, + isChatRoomIntegrationEnabled); } public void updateConferenceInfo(String accountId, String conferenceId, diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 3126e649..00233f4d 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -367,7 +367,7 @@ public class ConferenceFactory { if (Strings.isNullOrEmpty(accountId)) { return Future.succeededFuture(RoomAccess.JOIN); } - return chatRoomClient.areAllMembers(accountId, roomId, List.of(accountId)) + return chatRoomClient.isMember(accountId, roomId, accountId) .map(isMember -> isMember ? RoomAccess.START_CONFERENCE : RoomAccess.JOIN); } diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClient.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClient.java index d88b0512..1372c936 100644 --- a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClient.java +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClient.java @@ -86,6 +86,10 @@ public class ChatRoomClient extends RestClientBase { return result; } + public Future isMember(String ownerAccountId, String roomId, String accountId) { + return areAllMembers(ownerAccountId, roomId, List.of(accountId)); + } + public Future areAllMembers(String ownerAccountId, String roomId, List accountIds) { var request = getWebClient() .getAbs(membersPath) -- GitLab From 8fec366f4754ae0a60073e608fc15a8863e162e6 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Fri, 6 Dec 2019 00:05:20 +0200 Subject: [PATCH 32/37] Ignore manual test that requires external service to run. --- .../vertxutil/restclient/chatroom/ChatRoomClientManualTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vertx-util/src/test/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClientManualTest.java b/lib/vertx-util/src/test/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClientManualTest.java index 32f408d1..8ee8a26f 100644 --- a/lib/vertx-util/src/test/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClientManualTest.java +++ b/lib/vertx-util/src/test/java/com/nynjacoin/nccs/lib/vertxutil/restclient/chatroom/ChatRoomClientManualTest.java @@ -18,7 +18,7 @@ import org.junit.Test; import org.junit.runner.RunWith; @RunWith(VertxUnitRunner.class) -//@Ignore +@Ignore public class ChatRoomClientManualTest { private ChatRoomClient chatRoomClient; -- GitLab From 4ad629194e1647850151aba4bbb93f0fd8e985f9 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Fri, 6 Dec 2019 00:11:02 +0200 Subject: [PATCH 33/37] Regression fix: SSE requests send data as query param instead of body. --- .../api/ConferenceFactoryWebApi.java | 24 ++++----- .../stateholder/api/StateHolderWebApi.java | 11 ++-- .../nccs/lib/grpcutil/PathHandler.java | 50 +++++++++++++------ .../nccs/lib/grpcutil/WebApiCallConsumer.java | 2 +- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index dd4e02ee..cdc03371 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -33,13 +33,13 @@ public class ConferenceFactoryWebApi implements WebApi { private final ConferenceFactoryVerticle verticle; - private void getLimits(RoutingContext ctx, Buffer bodyBuffer) + private void getLimits(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - GetLimitsRequest request = GetLimitsRequest.parseFrom(bodyBuffer.getBytes()); + GetLimitsRequest request = GetLimitsRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( @@ -49,13 +49,13 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void createConference(RoutingContext ctx, Buffer bodyBuffer) + private void createConference(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - CreateConferenceRequest request = CreateConferenceRequest.parseFrom(bodyBuffer.getBytes()); + CreateConferenceRequest request = CreateConferenceRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( @@ -65,13 +65,13 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void startConference(RoutingContext ctx, Buffer bodyBuffer) + private void startConference(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - StartConferenceRequest request = StartConferenceRequest.parseFrom(bodyBuffer.getBytes()); + StartConferenceRequest request = StartConferenceRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( @@ -81,13 +81,13 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void getConferenceId(RoutingContext ctx, Buffer bodyBuffer) + private void getConferenceId(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - GetConferenceIdRequest request = GetConferenceIdRequest.parseFrom(bodyBuffer.getBytes()); + GetConferenceIdRequest request = GetConferenceIdRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( @@ -97,13 +97,13 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void getRoomId(RoutingContext ctx, Buffer bodyBuffer) + private void getRoomId(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - var request = GetRoomIdRequest.parseFrom(bodyBuffer.getBytes()); + var request = GetRoomIdRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( @@ -113,13 +113,13 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void enterRoom(RoutingContext ctx, Buffer bodyBuffer) + private void enterRoom(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - var request = EnterRoomRequest.parseFrom(bodyBuffer.getBytes()); + var request = EnterRoomRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( diff --git a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java index 87ac7540..d1d8d294 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/stateholder/api/StateHolderWebApi.java @@ -16,7 +16,6 @@ import com.nynjacoin.nccs.protocol.shp.UpdatePacket; import com.nynjacoin.nccs.stateholder.service.StateHolderVerticle; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.grpc.GrpcWriteStream; @@ -38,20 +37,20 @@ public class StateHolderWebApi implements WebApi { public Router createRouter(Vertx vertx) { Router router = Router.router(vertx); - PathHandler.route(router, "/Fetch", this::fetch); + PathHandler.routeSSE(router, "/Fetch", this::fetch); PathHandler.route(router, "/CancelLongPoll", this::cancelLongPoll); return router; } - private void fetch(RoutingContext ctx, Buffer bodyBuffer) + private void fetch(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException, NccsWebEndpointException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); String instanceId = webMetadata.get(CallingMetadataKey.INSTANCE_ID); - FetchRequest request = FetchRequest.parseFrom(bodyBuffer.getBytes()); + FetchRequest request = FetchRequest.parseFrom(body); GrpcWriteStream response = GrpcWriteStreamEventSourceAdapter.create(ctx); verticle.runOnContext( @@ -61,14 +60,14 @@ public class StateHolderWebApi implements WebApi { ); } - private void cancelLongPoll(RoutingContext ctx, Buffer bodyBuffer) + private void cancelLongPoll(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); String instanceId = webMetadata.get(CallingMetadataKey.INSTANCE_ID); - var request = CancelRequest.parseFrom(bodyBuffer.getBytes()); + var request = CancelRequest.parseFrom(body); Future response = WebResponseHandler.future(ctx); verticle.runOnContext( diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java index bc27093d..3ed872b2 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/PathHandler.java @@ -12,25 +12,47 @@ public class PathHandler { private static Logger LOGGER = LogManager.getLogger(PathHandler.class); - public static Handler compose(WebApiCallConsumer consumer) { - return compose("UNKNOWN PATH", consumer); + public static void route(Router router, String path, WebApiCallConsumer consumer) { + router.route(path).handler(compose(path, consumer)); + } + + public static void routeSSE(Router router, String path, WebApiCallConsumer consumer) { + router.route(path).handler(composeSSE(path, consumer)); } - public static Handler compose(String path, WebApiCallConsumer consumer) { + private static Handler compose(String path, WebApiCallConsumer consumer) { + var invoker = new ConsumerInvoker(path, consumer); return ctx -> ctx.request().bodyHandler( - bodyBuffer -> { - try { - consumer.accept(ctx, bodyBuffer); - } catch (InvalidProtocolBufferException e) { - LOGGER.warn("{}: body is not a valid proto.3: {}", path, bodyBuffer); - } catch (NccsWebEndpointException e) { - LOGGER.error("{}: failure processing request: {}", path, bodyBuffer, e); - } - } + bodyBuffer -> invoker.invoke(ctx, bodyBuffer.getBytes()) ); } - public static void route(Router router, String path, WebApiCallConsumer consumer) { - router.route(path).handler(compose(consumer)); + private static Handler composeSSE(String path, WebApiCallConsumer consumer) { + var invoker = new ConsumerInvoker(path, consumer); + return ctx -> { + byte[] body = WebEventTarget.getEventSourceRequestBody(ctx.request().params()); + invoker.invoke(ctx, body); + }; } + + private static class ConsumerInvoker { + private final String path; + private final WebApiCallConsumer consumer; + + private ConsumerInvoker(String path, WebApiCallConsumer consumer) { + this.path = path; + this.consumer = consumer; + } + + void invoke(RoutingContext ctx, byte[] body) { + try { + consumer.accept(ctx, body); + } catch (InvalidProtocolBufferException e) { + LOGGER.warn("{}: body is not a valid proto.3: {}", path, body); + } catch (NccsWebEndpointException e) { + LOGGER.error("{}: failure processing request: {}", path, body, e); + } + } + } + } diff --git a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java index cb2f3f8b..a47b1875 100644 --- a/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java +++ b/lib/grpc-util/src/main/java/com/nynjacoin/nccs/lib/grpcutil/WebApiCallConsumer.java @@ -7,7 +7,7 @@ import io.vertx.ext.web.RoutingContext; public interface WebApiCallConsumer { - void accept(RoutingContext ctx, Buffer bodyBuffer) + void accept(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException, NccsWebEndpointException; } -- GitLab From b4864b01c522db955b9e3674ea5cd8c48b9c536b Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 10 Dec 2019 10:55:30 +0200 Subject: [PATCH 34/37] Fix: EnterRoom for anonymous client. --- .../nccs/conferencecontrol/service/Conference.java | 4 +--- .../service/ConferenceFactory.java | 13 ++++++------- .../conferencefactory/service/ConferenceInfo.java | 11 ++++++++++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java index 85f1862e..e395e9bb 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencecontrol/service/Conference.java @@ -421,10 +421,8 @@ class Conference { } private Address getBindByLinkAddress(String accountId) { - final boolean isAnonymous = accountId.toLowerCase() - .startsWith(ConferenceInfo.ANONYMOUS_PREFIX); return Address.newBuilder() - .setType(isAnonymous ? Type.ANONYMOUS : Type.ACCOUNT) + .setType(ConferenceInfo.isAnonymous(accountId) ? Type.ANONYMOUS : Type.ACCOUNT) .setValue(accountId) .build(); } diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 00233f4d..25e48cb1 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -28,6 +28,7 @@ import com.nynjacoin.nccs.protocol.def.Address; import com.nynjacoin.nccs.protocol.def.Address.Type; import com.nynjacoin.nccs.protocol.def.MemberOption; import com.nynjacoin.nccs.protocol.error.NccsError; +import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; import com.nynjacoin.nccs.protocol.sp.conference.RoomConferenceRecord; import com.nynjacoin.nccs.protocol.validation.NccsValidator; import com.nynjacoin.nccs.stateholder.statepackage.RoomPublisher; @@ -216,7 +217,7 @@ public class ConferenceFactory { .setConferenceId(ci.getConferenceId()) ; if (Objects.isNull(accountId) || accountId.isEmpty()) { - responseBuilder.setAnonymousId(generateAnonymousId()); + responseBuilder.setAnonymousId(ConferenceInfo.generateAnonymousId()); } response.complete(responseBuilder.build()); } @@ -230,17 +231,13 @@ public class ConferenceFactory { .map(roomId -> { var responseBuilder = GetRoomIdResponse.newBuilder().setRoomId(roomId); if (Objects.isNull(accountId) || accountId.isEmpty()) { - responseBuilder.setAnonymousId(generateAnonymousId()); + responseBuilder.setAnonymousId(ConferenceInfo.generateAnonymousId()); } return responseBuilder.build(); }) .setHandler(response); } - private String generateAnonymousId() { - return ConferenceInfo.ANONYMOUS_PREFIX + UuidGenerator.generate(); - } - public void enterRoom( String accountId, EnterRoomRequest request, @@ -248,6 +245,7 @@ public class ConferenceFactory { String roomId = request.getRoomId(); NccsValidator.requireNonEmpty(roomId, "room_id"); + NccsValidator.requireNonEmpty(accountId, CommonMetadataKey.ACCOUNT_ID.name()); checkAccessToRoom(accountId, roomId) .compose(accessType -> { @@ -364,7 +362,8 @@ public class ConferenceFactory { } private Future checkAccessToRoom(String accountId, String roomId) { - if (Strings.isNullOrEmpty(accountId)) { + if (ConferenceInfo.isAnonymous(accountId)) { + // TODO: real authorization based on access to the particular room in the access token return Future.succeededFuture(RoomAccess.JOIN); } return chatRoomClient.isMember(accountId, roomId, accountId) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java index 0e792cf0..7a21becc 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceInfo.java @@ -1,5 +1,6 @@ package com.nynjacoin.nccs.conferencefactory.service; +import com.nynjacoin.nccs.lib.util.UuidGenerator; import com.nynjacoin.nccs.protocol.cfp.ChatRoomOptions; import com.nynjacoin.nccs.protocol.error.NccsError; import com.nynjacoin.nccs.protocol.sp.conference.ChatRoomType; @@ -7,7 +8,15 @@ import java.util.Date; public class ConferenceInfo { - public static final String ANONYMOUS_PREFIX = "ann_"; + private static final String ANONYMOUS_PREFIX = "ann_"; + + public static boolean isAnonymous(String accountId) { + return accountId.toLowerCase().startsWith(ConferenceInfo.ANONYMOUS_PREFIX); + } + + static String generateAnonymousId() { + return ConferenceInfo.ANONYMOUS_PREFIX + UuidGenerator.generate(); + } private final String ownerAccountId; private final String conferenceId; -- GitLab From ac57d9d8337d642ad55c2da7268e5a00a4c94c84 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Tue, 10 Dec 2019 14:22:52 +0200 Subject: [PATCH 35/37] Cleanup. --- .../nccs/conferencefactory/api/ConferenceFactoryWebApi.java | 1 - 1 file changed, 1 deletion(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index cdc03371..da32c2d1 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -21,7 +21,6 @@ import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; -- GitLab From f4d00aace95267521947c06fc6575b46dfb3a96c Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 11 Dec 2019 09:46:39 +0200 Subject: [PATCH 36/37] Disable DIALOUT for the owner of auto created room conference. --- .../nccs/conferencefactory/service/ConferenceFactory.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 25e48cb1..3d28de14 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -256,8 +256,7 @@ public class ConferenceFactory { // no conference in the room, so create one CreateConferenceRequest createReq = CreateConferenceRequest.newBuilder() .addAddMember(AddMemberRequest.newBuilder() - .setAddress(Address.newBuilder().setType(Type.ACCOUNT).setValue(accountId)) - .addOption(MemberOption.DIALOUT)) + .setAddress(Address.newBuilder().setType(Type.ACCOUNT).setValue(accountId))) .setChatRoomId(roomId) .build(); createAndStartConference(accountId, createReq, true, roomId) -- GitLab From 107ba1822a80ea38ba94b80202d32345e9bccc88 Mon Sep 17 00:00:00 2001 From: Ilia Krustev Date: Wed, 11 Dec 2019 10:44:23 +0200 Subject: [PATCH 37/37] Rename GetRoomId to GetRoomInfo and add room_name to the response. --- .../api/ConferenceFactoryGrpcApi.java | 12 +++++----- .../api/ConferenceFactoryWebApi.java | 14 ++++++------ .../service/ConferenceFactory.java | 22 +++++++++---------- .../restclient/roomlink/RoomInfo.java | 20 +++++++++++++++++ .../restclient/roomlink/RoomLinkClient.java | 7 ++++-- protocol/public/src/main/proto | 2 +- 6 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomInfo.java diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java index 67b5cb02..fbf72fae 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryGrpcApi.java @@ -11,8 +11,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import io.vertx.core.Future; @@ -81,14 +81,14 @@ public class ConferenceFactoryGrpcApi } @Override - public void getRoomId( - GetRoomIdRequest request, - Future response) { + public void getRoomInfo( + GetRoomInfoRequest request, + Future response) { String accountId = GrpcContextKeys.ACCOUNT_ID.get(); verticle.runOnContext( - () -> verticle.conferenceFactory.getRoomId(accountId, request, response), + () -> verticle.conferenceFactory.getRoomInfo(accountId, request, response), response, GrpcContextKeys.LOG_CONTEXT.get() ); diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java index da32c2d1..ccf15672 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/api/ConferenceFactoryWebApi.java @@ -14,8 +14,8 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; @@ -96,17 +96,17 @@ public class ConferenceFactoryWebApi implements WebApi { ); } - private void getRoomId(RoutingContext ctx, byte[] body) + private void getRoomInfo(RoutingContext ctx, byte[] body) throws InvalidProtocolBufferException { WebMetadata webMetadata = new WebMetadata(ctx); String accountId = webMetadata.get(CommonMetadataKey.ACCOUNT_ID); - var request = GetRoomIdRequest.parseFrom(body); - Future response = WebResponseHandler.future(ctx); + var request = GetRoomInfoRequest.parseFrom(body); + Future response = WebResponseHandler.future(ctx); verticle.runOnContext( - () -> verticle.conferenceFactory.getRoomId(accountId, request, response), + () -> verticle.conferenceFactory.getRoomInfo(accountId, request, response), response, webMetadata.getLogContext() ); @@ -141,7 +141,7 @@ public class ConferenceFactoryWebApi implements WebApi { PathHandler.route(router, "/CreateConference", this::createConference); PathHandler.route(router, "/StartConference", this::startConference); PathHandler.route(router, "/GetConferenceId", this::getConferenceId); - PathHandler.route(router, "/GetRoomId", this::getRoomId); + PathHandler.route(router, "/GetRoomInfo", this::getRoomInfo); PathHandler.route(router, "/EnterRoom", this::enterRoom); return router; diff --git a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java index 3d28de14..10e8503a 100644 --- a/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java +++ b/focus/src/main/java/com/nynjacoin/nccs/conferencefactory/service/ConferenceFactory.java @@ -1,6 +1,5 @@ package com.nynjacoin.nccs.conferencefactory.service; -import com.google.common.base.Strings; import com.nynjacoin.nccs.conferencecontrol.service.ConferenceControlVerticle; import com.nynjacoin.nccs.conferencecontrol.service.JoinLinkComposer; import com.nynjacoin.nccs.lib.config.ConfigKey; @@ -18,15 +17,14 @@ import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdRequest; import com.nynjacoin.nccs.protocol.cfp.GetConferenceIdResponse; import com.nynjacoin.nccs.protocol.cfp.GetLimitsRequest; import com.nynjacoin.nccs.protocol.cfp.GetLimitsResponse; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdRequest; -import com.nynjacoin.nccs.protocol.cfp.GetRoomIdResponse; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoRequest; +import com.nynjacoin.nccs.protocol.cfp.GetRoomInfoResponse; import com.nynjacoin.nccs.protocol.cfp.StartConferenceRequest; import com.nynjacoin.nccs.protocol.cfp.StartConferenceResponse; import com.nynjacoin.nccs.protocol.def.AddMemberRequest; import com.nynjacoin.nccs.protocol.def.AddMemberResponse; import com.nynjacoin.nccs.protocol.def.Address; import com.nynjacoin.nccs.protocol.def.Address.Type; -import com.nynjacoin.nccs.protocol.def.MemberOption; import com.nynjacoin.nccs.protocol.error.NccsError; import com.nynjacoin.nccs.protocol.metadata.CommonMetadataKey; import com.nynjacoin.nccs.protocol.sp.conference.RoomConferenceRecord; @@ -222,14 +220,16 @@ public class ConferenceFactory { response.complete(responseBuilder.build()); } - public void getRoomId( + public void getRoomInfo( String accountId, - GetRoomIdRequest request, - Future response) { - - roomLinkClient.getRoomId(request.getLinkId()) - .map(roomId -> { - var responseBuilder = GetRoomIdResponse.newBuilder().setRoomId(roomId); + GetRoomInfoRequest request, + Future response) { + + roomLinkClient.getRoomInfo(request.getLinkId()) + .map(roomInfo -> { + var responseBuilder = GetRoomInfoResponse.newBuilder() + .setRoomId(roomInfo.getId()) + .setRoomName(roomInfo.getName()); if (Objects.isNull(accountId) || accountId.isEmpty()) { responseBuilder.setAnonymousId(ConferenceInfo.generateAnonymousId()); } diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomInfo.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomInfo.java new file mode 100644 index 00000000..9ec4fe08 --- /dev/null +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomInfo.java @@ -0,0 +1,20 @@ +package com.nynjacoin.nccs.lib.vertxutil.restclient.roomlink; + +public class RoomInfo { + + private final String id; + private final String name; + + RoomInfo(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java index af54ee7c..df8d248f 100644 --- a/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java +++ b/lib/vertx-util/src/main/java/com/nynjacoin/nccs/lib/vertxutil/restclient/roomlink/RoomLinkClient.java @@ -17,6 +17,7 @@ import java.util.Objects; public class RoomLinkClient extends RestClientBase { private static final String FIELD_ROOM_ID = "room_id"; + private static final String FIELD_ROOM_NAME = "room_name"; public static RoomLinkClient create(Vertx vertx, JsonObject config) { int poolSize = config.getInteger(ConfigKey.ROOM_LINK_PER_REQUEST_POOL_SIZE.key(), 32); @@ -46,14 +47,16 @@ public class RoomLinkClient extends RestClientBase { super(webClient, authenticationHandler, retryExecutor, rootUrl); } - public Future getRoomId(String linkId) { + public Future getRoomInfo(String linkId) { var request = getWebClient().getAbs(getRoomUrl(linkId)); request = getAuthenticationHandler().apply(request); var response = getRetryExecutor().execute(request); return response .map(rawBody -> { ValidatingJsonObject body = ValidatingJsonObject.wrap(rawBody); - return body.getRequiredString(FIELD_ROOM_ID); + return new RoomInfo( + body.getRequiredString(FIELD_ROOM_ID), + rawBody.getString(FIELD_ROOM_NAME, "")); }) .recover(cause -> Future.failedFuture(translateLinkNotFound(cause))); } diff --git a/protocol/public/src/main/proto b/protocol/public/src/main/proto index d1cf379a..e93c9e59 160000 --- a/protocol/public/src/main/proto +++ b/protocol/public/src/main/proto @@ -1 +1 @@ -Subproject commit d1cf379a32512b7f9e9fbf24d7ef24f9b34a351a +Subproject commit e93c9e597e9d4b25f6ab45436183a16aee905d27 -- GitLab