自定义GRPC客户端存根-流未启动

时间:2019-02-09 22:18:16

标签: android ssl grpc

我正在尝试从我的Android应用访问带有TLS的自定义GRPC服务器(Anki Vector机器人)。

我的Android Studio项目中有原始文件,并且所有必需的依赖项都可用。 Proto文件生成Java类,在我的活动中,我使用OkHttpChannelBuilder构建了一个通道。 然后创建一个客户端存根(尝试使用异步和阻塞存根)

之后,我创建一个请求消息并与存根一起发送。

代码可以正常编译,并且该应用程序可以在我的手机上运行。 但是,发送请求时,我收到一条错误消息,指出该流未启动。

在我能找到的所有示例中,我都没有找到启动流的任何方法。

阻止流启动可能是什么问题?

我收到错误消息:

2019-02-10 01:08:59.303 14691-30895/com.test.anki.grpc D/vectorCTRL: Failed... : 
    java.lang.IllegalStateException: Not started
        at com.google.common.base.Preconditions.checkState(Preconditions.java:510)
        at io.grpc.internal.ClientCallImpl.request(ClientCallImpl.java:367)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.request(ForwardingClientCall.java:44)
        at io.grpc.PartialForwardingClientCall.request(PartialForwardingClientCall.java:34)
        at io.grpc.ForwardingClientCall.request(ForwardingClientCall.java:22)
        at io.grpc.stub.ClientCalls.startCall(ClientCalls.java:314)
        at io.grpc.stub.ClientCalls.asyncUnaryRequestCall(ClientCalls.java:280)
        at io.grpc.stub.ClientCalls.futureUnaryCall(ClientCalls.java:189)
        at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:127)
        at Anki.Vector.external_interface.ExternalInterfaceGrpc$ExternalInterfaceBlockingStub.sayText(ExternalInterfaceGrpc.java:3554)
        at com.test.anki.grpc.MainActivity.testapi(MainActivity.java:1106)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:1003)
        at com.test.anki.grpc.MainActivity$GrpcTask.doInBackground(MainActivity.java:996)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

我的代码是:

       ClientInterceptor clientInterceptor = new ClientInterceptor() {
            @Override
            public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions, Channel channel) {
                // Might need to try to inject the token using that?
                return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
                    @Override
                    protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
                        Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
                        metadata.put(key, token);
                    }
                };
            }
        };

        SSLContext sslContext=null ;
        try {
            sslContext  = SSLContext.getInstance("TLS");
            sslContext .init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
            SSLContext.setDefault(sslContext );
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyManagementException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setSslSocketFactory(sslSocketFactory);
        okHttpClient.setHostnameVerifier(new HostnameVerifier() {
            @Override public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

        Channel channel=null;
        try {
            //ManagedChannel channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    channel = OkHttpChannelBuilder.forAddress(ipaddr, Integer.valueOf(port))
                    //.overrideAuthority("Vector")
                    .sslSocketFactory(sslSocketFactory)
                    .intercept(clientInterceptor)
                    .build();

            //ExternalInterfaceGrpc.ExternalInterfaceStub externalInterfaceStub = ExternalInterfaceGrpc.newStub(channel);
            ExternalInterfaceGrpc.ExternalInterfaceBlockingStub externalInterfaceBlockingStub = ExternalInterfaceGrpc.newBlockingStub(channel);

            Messages.SayTextRequest sayTextRequest = Messages.SayTextRequest
                    .newBuilder()
                    .setText("Yolo")
                    .build();

            Messages.SayTextResponse res = externalInterfaceBlockingStub.sayText(sayTextRequest);
            Log.d(TAG, res.getStatus().toString());
} catch (Exception e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            Log.d(TAG,String.format("Failed... : %n%s", sw));
        } finally {
            Log.d(TAG,"finally");
            /*
            try {
                 if(channel!=null) {((ManagedChannel) channel).shutdown().awaitTermination(1, TimeUnit.SECONDS);}
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            */
        }

1 个答案:

答案 0 :(得分:1)

ClientCall需要被调用start()。如果使用存根,则无需调用start(),因为存根本身将调用start()。但是拦截器会暴露于start()

问题出在您的clientInterceptor

protected void checkedStart(Listener listener, Metadata metadata) throws Exception {
    Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
    metadata.put(key, token);
    // FIXME: Missing call to delegate().start(listener, metadata);
}

名为start()的存根最终调用了拦截器的checkedStart(),但随后拦截器没有在真实的ClientCall上调用start。

请注意,由于CheckedForwardingClientCall不会引发任何异常,因此您无需使用checkedStart()ForwardingClientCall是更常用的类。 (覆盖start()而不是checkedStart())。