32
loading...
This website collects cookies to deliver better user experience
.proto
de forma bem simples. Vamos voltar ao nosso repositório para o segundo artigo da série, lá temos o seguinte arquivo notes.proto
:syntax = "proto3";
service NoteService {
rpc List (Void) returns (NoteListResponse);
rpc Find (NoteFindRequest) returns (NoteFindResponse);
}
// Entities
message Note {
int32 id = 1;
string title = 2;
string description = 3;
}
message Void {}
// Requests
message NoteFindRequest {
int32 id = 1;
}
// Responses
message NoteFindResponse {
Note note = 1;
}
message NoteListResponse {
repeated Note notes = 1;
}
List
, podemos simplesmente adicionar a palavra stream
na direção que queremos:service NoteService {
rpc List (Void) returns (stream NoteListResponse);
rpc Find (NoteFindRequest) returns (NoteFindResponse);
}
NoteListResponse
.service NoteService {
rpc List (Void) returns (NoteListResponse);
rpc Find (stream NoteFindRequest) returns (NoteFindResponse);
}
stream
em ambos os lados:service NoteService {
rpc List (Void) returns (stream NoteListResponse);
rpc Find (stream NoteFindRequest) returns (stream NoteFindResponse);
}
O código desta demonstração está no meu GitHub
.proto
para adicionar uma stream ao serviço de listagem de notas.stream
no rpc List
. E depois vamos remover o NoteListResponse
para que tenhamos uma resposta somente como Note
, o arquivo fica assim:syntax = "proto3";
service NoteService {
rpc List (Void) returns (stream Note);
rpc Find (NoteFindRequest) returns (NoteFindResponse);
}
// Entities
message Note {
int32 id = 1;
string title = 2;
string description = 3;
}
message Void {}
// Requests
message NoteFindRequest {
int32 id = 1;
}
// Responses
message NoteFindResponse {
Note note = 1;
}
{ note: { } }
, a cada chunk da stream teríamos um novo objeto note
que teria (claro), uma nota dentro... Isso é bastante repetitivo.notes.json
que vai representar uma quantidade grande de dados.[
{
"id": 0,
"title": "Note by Lucas Houston",
"description": "Content http://hoateluh.md/caahaese"
}, {
"id": 1,
"title": "Note by Brandon Tran",
"description": "Content http://ki.bo/kuwokal"
}, {
"id": 2,
"title": "Note by Michael Gonzalez",
"description": "Content http://hifuhi.edu/cowkucgan"
}, { ...
Lembrando que 200 notas não é, nem de perto, uma quantidade grande de dados. Este é apenas um exemplo.
require
(lembrando que isto não funciona para ES Modules:const grpc = require('grpc')
const protoLoader = require('@grpc/proto-loader')
const path = require('path')
const notes = require('../notes.json')
List
. Para isso vamos olhar a definição antiga por um momento:function List (_, callback) {
return callback(null, { notes })
}
{ notes }
, porque não vamos mais devolver um objetocall
:function List (call) {
//
}
call
é uma implementação de uma stream de escrita juntamente com o registro da chamada, portanto, se tivéssemos algum tipo de parâmetro para ser enviado, poderíamos obte-los através de call.request.parametro
.function List (call) {
for (const note of notes) {
call.write(note)
}
call.end()
}
call.write
e passando diretamente a nota, isto porque alteramos nossa resposta para ser somente uma nota e não um objeto com uma chave note
.write
é detectada, a resposta vai ser enviada e o cliente vai receber a mesma, isso é interessante quando temos que fazer algum tipo de processamento, por exemplo, se precisássemos transformar todos os títulos em letras maiúsculas, poderíamos fazer essa transformação e ir enviando os resultados sem esperar que todas as notas fossem carregadas.call.end()
, o que é importante, pois instrui o cliente a fechar a conexão, se isso não for feito, o mesmo cliente não poderá fazer outra chamada para o mesmo serviço.client.listAsync({}).then(console.log)
client.list({}, (err, notes) => {
if (err) throw err
console.log(notes)
})
const noteStream = client.list({})
noteStream.on('data', console.log)
const noteStream = client.list({})
noteStream.on('data', (note) => console.log(note))
end
, que é executado quando a stream do servidor chama o método call.end()
. Para escutá-lo, basta criar outro listener;noteStream.on('end', () => {})
rpc Find (stream NoteFindRequest) returns (NoteFindResponse);
Find
, do lado do servidor receberá, como primeiro parâmetro, a stream do cliente e o segundo continuará sendo o callback.function Find ({ request: { id } }, callback) { }
request
. Mas não temos o método on
, então vamos atualizar para:function Find (call, callback) { }
function Find (call, callback) {
call.on('data', (data) => {
// fazer algo
})
call.on('end', () => {
// a chamada terminou
})
}
const call = client.find((err, response) => {
if (err) throw err
console.log(response)
})
call.write({ id: 1 })
call.end()
find
só será executada após o método end()
ser chamado.call
. Este parâmetro é uma stream bidirecional que contém tanto o método on
quanto o write
.function duplex (call) {
call.on('data', (data) => {
// recebendo dados do cliente
})
call.write('devolvendo dados para o cliente')
call.end() // servidor encerra a conexão
}
const duplex = client.duplex()
duplex.on('data' (data) => {
// recebe dados do servidor
})
duplex.write('envia dados ao servidor')
duplex.close() // client fecha conexão