OutboundConnectionHandler(StreamsTransport transport, Address remoteAddress, EndPoint remoteSocketAddr)
        {
            var settings           = transport.Settings;
            var transmissionHandle =
                Source.ActorRef <Google.Protobuf.ByteString>(settings.BufferedMessages, OverflowStrategy.Backpressure);
            var fromLocalActors = FromProtobuf().Via(Encode(4, settings.MaxFrameSize, settings.ByteOrder));


            var fromRemoteActors = Decode(4, settings.MaxFrameSize, settings.ByteOrder).Via(ToProtobuf());

            var transmissionRef = transmissionHandle.PreMaterialize(transport.StreamMaterializer);

            var finalOutput = new RemoteOutboundAssociationSink(transport, remoteAddress, remoteSocketAddr, transmissionRef.Item1);

            var dsl = GraphDsl.Create(finalOutput, (builder, remoteOutput) =>
            {
                // local stages
                var localInput       = builder.Add(transmissionRef.Item2);
                var compilerCeremony = builder.Add(Flow.Create <Google.Protobuf.ByteString>());
                var local            = builder.Add(fromLocalActors);
                var merge            = builder.Add(new Merge <Google.Protobuf.ByteString, Google.Protobuf.ByteString>(2, false));
                builder.From(localInput.Outlet).To(merge.In(0));
                builder.From(compilerCeremony.Outlet).To(merge.In(1));
                builder.From(merge.Out).To(local.Inlet);

                // remote stages
                var remote = builder.Add(fromRemoteActors);
                builder.From(remote.Outlet).To(remoteOutput.Inlet);

                return(new BidiShape <ByteString, Google.Protobuf.ByteString, Google.Protobuf.ByteString, ByteString>(remote.Inlet, remote.Outlet, compilerCeremony.Inlet, local.Outlet));
            });

            return(BidiFlow.FromGraph(dsl));
        }
            public RemoteOutboundAssociationLogic(RemoteOutboundAssociationSink sink, TaskCompletionSource <AssociationHandle> associationCompletion)
                : base(sink.Shape)
            {
                _associationCompletion = associationCompletion;
                _sink = sink;

                // start off by buffering pending messages until the association process completes
                SetHandler(_sink.In, () => Buffer(Grab(_sink.In)), Finish, OnUpstreamFailure);
            }