Я столкнулся с проблемой курицы и яйца.
Случай: файл создается на удаленном клиенте. Клиент должен передать файл на сервер через asynccstub. Клиент также должен передавать метаданные через блокирующую заглушку для хранения в базе данных.
Проблемы:
Если я сначала выполняю асинхронную операцию, то данные файла отправляются до метаданных, и поэтому у сервера нет контекста относительно того, как назвать файл или куда его поместить. Первоначально я намеревался вернуть эту информацию с сервера (двунаправленно), однако наблюдатели потока не позволяют устанавливать переменные вне их анонимного определения.
Если я сначала выполню синхронную операцию, я смогу получить информацию об именах файлов обратно с сервера; однако мне нужно будет упаковать ее в блоки данных. Это также потребует постоянного открытия и закрытия файла сохранения, в то время как GRPC выполняет итерацию по его потоковым данным, поскольку итераторы нелегко сбросить (поэтому я не могу просто отклеить первый запрос).
В качестве последнего варианта я мог бы упаковать все это в асинхронный запрос и отправить с любым синхронным вызовом. Я считаю, что это обеспечит рабочее решение, но меня беспокоит объем данных, отправляемых по и без того большим запросам, а также упомянутая ранее неэффективность.
Итак, мой вопрос:
- Есть ли способ установить глобальную переменную в value.Message из наблюдателя ответа.
- В качестве альтернативы, есть ли способ передать информацию из синхронного вызова в асинхронный вызов на стороне сервера?
Наблюдатель за асинхронным ответом:
StreamObserver<GrpcServerComm.UploadStatus> responseObserver = new StreamObserver<GrpcServerComm.UploadStatus>() {
@Override
public void onNext(GrpcServerComm.UploadStatus value) {
if (value.getCode() != 1) {
Log.d("Error", "Upload Procedure Failure");
finishLatch.countDown();
}
}
@Override
public void onError(Throwable t) {
Log.d("Error", "Upload Response");
finishLatch.countDown();
}
@Override
public void onCompleted() {
finishLatch.countDown();
}
};
Соответствующие протоколы
message UploadStatus {
string filename=1;
int32 code = 2;
}
message DataChunk
{
string filename=1;
bytes chunk = 2;
}
message VideoMetadata
{
string publisher =1;
string description =2;
string tags = 3;
double videolat= 4;
double videolong=5;
}
service DataUpload
{
rpc UploadData (stream DataChunk) returns(UploadStatus);
}
service ContentMetaData
{
rpc UploadMetaData(VideoMetadata) returns (UploadStatus);
}
Серверные функции Python
class DataUploadServicer(proto_test_pb2_grpc.DataUploadServicer):
def UploadData(self,request_it,context):
response = proto_test_pb2.UploadStatus()
filename = str(random.getrandbits(32)) #server decides filename
response = filestream.writefile(filename,request_it)
return response
def writefile(filename, chunks):
response = proto_test_pb2.UploadStatus()
filename='tmp/'+filename
app_file = open(filename,"ab")
for chunk in chunks:
app_file.write(chunk.chunk)
app_file.close()
print('File Written')
response.Code=1
response.Message = "Succsesful write"
return response