-
Notifications
You must be signed in to change notification settings - Fork 577
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support gRPC stream API (#855)
- Loading branch information
1 parent
8d90442
commit bd51c46
Showing
19 changed files
with
889 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { Metadata } from '@grpc/grpc-js'; | ||
import { IClientDuplexStreamService } from '../../interface'; | ||
|
||
export class ClientDuplexStreamRequest<reqType, resType> | ||
implements IClientDuplexStreamService<reqType, resType> { | ||
correlationId: number; | ||
timeout_message; | ||
queue; | ||
client; | ||
metadata; | ||
timeout; | ||
stream; | ||
promise; | ||
messageKey: string; | ||
|
||
static get MAX_INT32() { | ||
return 2147483647; | ||
} | ||
|
||
constructor( | ||
client, | ||
original_function, | ||
options: { | ||
metadata?: Metadata; | ||
timeout?: number; | ||
timeoutMessage?: number; | ||
messageKey?: string; | ||
} = {} | ||
) { | ||
this.queue = {}; | ||
this.correlationId = 0; | ||
this.timeout_message = options.timeoutMessage || 1000; | ||
this.metadata = options.metadata || new Metadata(); | ||
this.messageKey = options.messageKey || 'id'; | ||
|
||
// Deadline is advisable to be set | ||
// It should be a timestamp value in milliseconds | ||
let deadline = undefined; | ||
if (options.timeout !== undefined) { | ||
deadline = Date.now() + options.timeout; | ||
} | ||
this.stream = original_function.call(client, this.metadata, { | ||
deadline: deadline, | ||
}); | ||
|
||
this.stream.on('error', () => {}); | ||
this.stream.on('data', data => { | ||
if (this.queue[data[this.messageKey]]) { | ||
clearTimeout(this.queue[data[this.messageKey]]['timeout']); | ||
this.queue[data[this.messageKey]]['cb'](null, data); | ||
delete this.queue[data[this.messageKey]]; | ||
} | ||
}); | ||
} | ||
|
||
_nextId() { | ||
if (this.correlationId >= ClientDuplexStreamRequest.MAX_INT32) { | ||
this.correlationId = 0; | ||
} | ||
return this.correlationId++; | ||
} | ||
|
||
sendMessage(content: reqType = {} as any): Promise<resType> { | ||
return new Promise((resolve, reject) => { | ||
const id = this._nextId(); | ||
|
||
if (this.stream.received_status) { | ||
return reject('stream_closed'); | ||
} | ||
|
||
const cb = (err: Error, response?) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(response); | ||
} | ||
}; | ||
|
||
this.queue[id] = { | ||
cb, | ||
timeout: setTimeout(() => { | ||
delete this.queue[id]; | ||
cb(new Error(`provider response timeout in ${this.timeout_message}`)); | ||
}, this.timeout_message), | ||
}; | ||
content[this.messageKey] = id; | ||
this.stream.write(content); | ||
}); | ||
} | ||
|
||
end(): void { | ||
return this.stream.end(); | ||
} | ||
|
||
getCall() { | ||
return this.stream; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Metadata } from '@grpc/grpc-js'; | ||
import { IClientReadableStreamService } from '../../interface'; | ||
|
||
export class ClientReadableRequest<reqType, resType> | ||
implements IClientReadableStreamService<reqType, resType> { | ||
client; | ||
metadata; | ||
timeout; | ||
stream; | ||
queue; | ||
original_function; | ||
|
||
constructor( | ||
client, | ||
original_function, | ||
options: { | ||
metadata?: Metadata; | ||
timeout?: number; | ||
} = {} | ||
) { | ||
this.queue = []; | ||
this.client = client; | ||
this.metadata = options.metadata || new Metadata(); | ||
this.timeout = options.timeout || undefined; | ||
this.original_function = original_function; | ||
} | ||
|
||
sendMessage(content: reqType): Promise<resType[]> { | ||
return new Promise((resolve, reject) => { | ||
// Deadline is advisable to be set | ||
// It should be a timestamp value in milliseconds | ||
let deadline = undefined; | ||
if (this.timeout !== undefined) { | ||
deadline = Date.now() + this.timeout; | ||
} | ||
this.stream = this.original_function.call( | ||
this.client, | ||
content, | ||
this.metadata, | ||
{ deadline: deadline } | ||
); | ||
this.stream.on('error', error => { | ||
reject(error); | ||
}); | ||
this.stream.on('data', data => { | ||
this.queue.push(data); | ||
}); | ||
this.stream.on('end', () => { | ||
resolve(this.queue); | ||
}); | ||
}); | ||
} | ||
|
||
getCall() { | ||
return this.stream; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { Metadata, ClientUnaryCall } from '@grpc/grpc-js'; | ||
import { IClientUnaryService } from '../../interface'; | ||
|
||
export class ClientUnaryRequest<reqType, resType> | ||
implements IClientUnaryService<reqType, resType> { | ||
client; | ||
metadata; | ||
timeout; | ||
original_function; | ||
|
||
constructor( | ||
client, | ||
original_function, | ||
options: { | ||
metadata?: Metadata; | ||
timeout?: number; | ||
} = {} | ||
) { | ||
this.client = client; | ||
this.metadata = options.metadata || new Metadata(); | ||
this.timeout = options.timeout || undefined; | ||
this.original_function = original_function; | ||
} | ||
|
||
sendMessage( | ||
content: reqType, | ||
handler?: (call: ClientUnaryCall) => void | ||
): Promise<resType> { | ||
return new Promise<resType>((resolve, reject) => { | ||
// Deadline is advisable to be set | ||
// It should be a timestamp value in milliseconds | ||
let deadline = undefined; | ||
if (this.timeout !== undefined) { | ||
deadline = Date.now() + this.timeout; | ||
} | ||
const call = this.original_function.call( | ||
this.client, | ||
content, | ||
this.metadata, | ||
{ deadline: deadline }, | ||
(error, response) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(response); | ||
} | ||
} | ||
); | ||
handler && handler(call); | ||
}); | ||
} | ||
|
||
sendMessageWithCallback(content: reqType, callback): ClientUnaryCall { | ||
// Deadline is advisable to be set | ||
// It should be a timestamp value in milliseconds | ||
let deadline = undefined; | ||
if (this.timeout !== undefined) { | ||
deadline = Date.now() + this.timeout; | ||
} | ||
return this.original_function.call( | ||
this.client, | ||
content, | ||
this.metadata, | ||
{ deadline: deadline }, | ||
callback | ||
); | ||
} | ||
} |
Oops, something went wrong.