|
@@ -1,56 +1,62 @@
|
|
import * as grpc from '@grpc/grpc-js';
|
|
import * as grpc from '@grpc/grpc-js';
|
|
import { Subject, Subscription } from "rxjs";
|
|
import { Subject, Subscription } from "rxjs";
|
|
-import { Message, ConnectionAttribute, ConnectionRequest, GrpcConnectionType, ConnectionState, MessageLog, State, OutGoingInfo } from "../interfaces/general.interface";
|
|
|
|
|
|
+import { Message, ConnectionAttribute, GrpcConnectionType, ConnectionState, MessageLog, ConnectionStatus } from "../interfaces/general.interface";
|
|
import { Status } from '@grpc/grpc-js/build/src/constants';
|
|
import { Status } from '@grpc/grpc-js/build/src/constants';
|
|
import { message_proto } from './protos/server.proto'
|
|
import { message_proto } from './protos/server.proto'
|
|
-import { ServerWritableStreamImpl } from '@grpc/grpc-js/build/src/server-call';
|
|
|
|
|
|
+import * as _ from 'lodash'
|
|
export class GrpcServiceMethod {
|
|
export class GrpcServiceMethod {
|
|
- // Prefilled connection attribute and pass in grpc service method for reference
|
|
|
|
- // Isolate connection attribute referencing issue to server-client service
|
|
|
|
private server: grpc.Server | any
|
|
private server: grpc.Server | any
|
|
private messageToBeSendOver: Message | any
|
|
private messageToBeSendOver: Message | any
|
|
- private clientInfo: any[] = []
|
|
|
|
- // private callRequestsFromRemote: ServerWritableStreamImpl<any, ResponseType>[] = []
|
|
|
|
|
|
+ private clientRequest: Subject<ConnectionAttribute> = new Subject()
|
|
|
|
+ private localServerStatus: Subject<any> = new Subject()
|
|
|
|
|
|
- public async create(request: ConnectionRequest, connectionAttribute: ConnectionAttribute, outGoingInfo: OutGoingInfo): Promise<any> {
|
|
|
|
- // Assuming currently only one client
|
|
|
|
- // this.createGrpcInstance(request.server.serverUrl, { instanceType: 'server' }, connectionAttribute, outGoingInfo)
|
|
|
|
- // this.createGrpcInstance(request.client.targetServer, { instanceType: 'client' }, connectionAttribute, outGoingInfo)
|
|
|
|
|
|
+ // keep track of all the incoming channel request from the servers
|
|
|
|
+ public getClientRequest() {
|
|
|
|
+ return this.clientRequest
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // keep track of all the incoming channel request from the servers
|
|
|
|
+ public getLocalServerStatus() {
|
|
|
|
+ return this.localServerStatus
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public async create(connectionAttribute: ConnectionAttribute): Promise<any> {
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
+ this.createGrpcInstance({ instanceType: 'server' }, connectionAttribute)
|
|
|
|
+ this.createGrpcInstance({ instanceType: 'client' }, connectionAttribute)
|
|
|
|
+ resolve('Just putting it here for now....')
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
private async generateAdditionalAttributes(connectionAttribute: ConnectionAttribute, clientInfo?: any, localInfo?: any) {
|
|
private async generateAdditionalAttributes(connectionAttribute: ConnectionAttribute, clientInfo?: any, localInfo?: any) {
|
|
- if (clientInfo) {
|
|
|
|
- connectionAttribute.inComing.StreamID = clientInfo.StreamID
|
|
|
|
- connectionAttribute.inComing.PublisherID = clientInfo.PublisherID
|
|
|
|
- connectionAttribute.inComing.SubscriberID = clientInfo.SubscriberID
|
|
|
|
- }
|
|
|
|
- if (localInfo) {
|
|
|
|
- connectionAttribute.outGoing.StreamID = localInfo.StreamID
|
|
|
|
- connectionAttribute.outGoing.PublisherID = localInfo.PublisherID
|
|
|
|
- connectionAttribute.outGoing.SubscriberID = localInfo.SubscriberID
|
|
|
|
- }
|
|
|
|
- if (connectionAttribute.outGoing.StreamID && connectionAttribute.inComing.StreamID) {
|
|
|
|
- connectionAttribute.ConnectionID.local = connectionAttribute.outGoing.StreamID + connectionAttribute.inComing.StreamID
|
|
|
|
- connectionAttribute.ConnectionID.remote = connectionAttribute.inComing.StreamID + connectionAttribute.outGoing.StreamID
|
|
|
|
- }
|
|
|
|
|
|
+ // if (clientInfo) {
|
|
|
|
+ // connectionAttribute.inComing.StreamID = clientInfo.StreamID
|
|
|
|
+ // connectionAttribute.inComing.PublisherID = clientInfo.PublisherID
|
|
|
|
+ // connectionAttribute.inComing.SubscriberID = clientInfo.SubscriberID
|
|
|
|
+ // }
|
|
|
|
+ // if (localInfo) {
|
|
|
|
+ // connectionAttribute.outGoing.StreamID = localInfo.StreamID
|
|
|
|
+ // connectionAttribute.outGoing.PublisherID = localInfo.PublisherID
|
|
|
|
+ // connectionAttribute.outGoing.SubscriberID = localInfo.SubscriberID
|
|
|
|
+ // }
|
|
|
|
+ // if (connectionAttribute.outGoing.StreamID && connectionAttribute.inComing.StreamID) {
|
|
|
|
+ // connectionAttribute.ConnectionID.local = connectionAttribute.outGoing.StreamID + connectionAttribute.inComing.StreamID
|
|
|
|
+ // connectionAttribute.ConnectionID.remote = connectionAttribute.inComing.StreamID + connectionAttribute.outGoing.StreamID
|
|
|
|
+ // }
|
|
}
|
|
}
|
|
|
|
|
|
- private async createGrpcInstance(
|
|
|
|
- serverUrl: string,
|
|
|
|
- grpcType: GrpcConnectionType,
|
|
|
|
- connectionAttribute: ConnectionAttribute,
|
|
|
|
- outGoingInfo: OutGoingInfo
|
|
|
|
- ) {
|
|
|
|
|
|
+ private async createGrpcInstance(grpcType: GrpcConnectionType, connectionAttribute: ConnectionAttribute) {
|
|
|
|
+ // Reconnection Logic here
|
|
while (true) {
|
|
while (true) {
|
|
try {
|
|
try {
|
|
let recreatePromise = new Promise((resolve) => {
|
|
let recreatePromise = new Promise((resolve) => {
|
|
if (grpcType.instanceType == 'server') {
|
|
if (grpcType.instanceType == 'server') {
|
|
- this.createServerStreamingServer(serverUrl, connectionAttribute).then(() => {
|
|
|
|
|
|
+ this.createServerStreamingServer(connectionAttribute).then(() => {
|
|
resolve('recreate')
|
|
resolve('recreate')
|
|
})
|
|
})
|
|
}
|
|
}
|
|
if (grpcType.instanceType == 'client') {
|
|
if (grpcType.instanceType == 'client') {
|
|
- this.createServerStreamingClient(serverUrl, connectionAttribute, outGoingInfo).then(() => {
|
|
|
|
|
|
+ this.createServerStreamingClient(connectionAttribute).then(() => {
|
|
resolve('recreate')
|
|
resolve('recreate')
|
|
})
|
|
})
|
|
}
|
|
}
|
|
@@ -65,23 +71,24 @@ export class GrpcServiceMethod {
|
|
}
|
|
}
|
|
|
|
|
|
// Create Server Instance to stream all application Outgoing messages
|
|
// Create Server Instance to stream all application Outgoing messages
|
|
- public async createServerStreamingServer(
|
|
|
|
- serverUrl: string,
|
|
|
|
- connectionAttribute: ConnectionAttribute
|
|
|
|
- ): Promise<any> { // '0.0.0.0:3001'
|
|
|
|
|
|
+ public async createServerStreamingServer(connectionAttribute: ConnectionAttribute): Promise<any> { // '0.0.0.0:3001'
|
|
return new Promise((resolve, reject) => {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
try {
|
|
if (!this.server) {
|
|
if (!this.server) {
|
|
this.server = new grpc.Server()
|
|
this.server = new grpc.Server()
|
|
|
|
+ this.localServerStatus.next({
|
|
|
|
+ connectionStatus: 'ON',
|
|
|
|
+ serverName: connectionAttribute.outGoing.PublisherID,
|
|
|
|
+ message: `${connectionAttribute.outGoing.serverUrl} started.`
|
|
|
|
+ })
|
|
} else {
|
|
} else {
|
|
- console.log(`Grpc server alrady started.`) // this kept calling, that means this function is resolving on it's own, prompting the reconnection logic
|
|
|
|
|
|
+ console.log(`Grpc server alrady started.`)
|
|
}
|
|
}
|
|
|
|
|
|
this.server.addService(message_proto.Message.service, {
|
|
this.server.addService(message_proto.Message.service, {
|
|
HandleMessage: (call) => {
|
|
HandleMessage: (call) => {
|
|
- let clientInfo: OutGoingInfo = JSON.parse(call.request.message)
|
|
|
|
- // console.log(clientInfo)
|
|
|
|
- this.generateAdditionalAttributes(connectionAttribute, clientInfo)
|
|
|
|
|
|
+ let clientInfo: ConnectionAttribute = JSON.parse(call.request.message)
|
|
|
|
+ this.clientRequest.next(clientInfo)
|
|
|
|
|
|
console.log(`Initializing stream. Opening Channel... Confirmation from ${call.request.id}`)
|
|
console.log(`Initializing stream. Opening Channel... Confirmation from ${call.request.id}`)
|
|
|
|
|
|
@@ -106,11 +113,10 @@ export class GrpcServiceMethod {
|
|
resolve('')
|
|
resolve('')
|
|
}
|
|
}
|
|
})
|
|
})
|
|
- console.log(connectionAttribute)
|
|
|
|
let report: ConnectionState = {
|
|
let report: ConnectionState = {
|
|
status: 'DIRECT_PUBLISH'
|
|
status: 'DIRECT_PUBLISH'
|
|
}
|
|
}
|
|
- connectionAttribute.connectionStatus.next(report)
|
|
|
|
|
|
+ connectionAttribute.connectionStatus!.next(report)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
Check: (_, callback) => {
|
|
Check: (_, callback) => {
|
|
@@ -120,8 +126,8 @@ export class GrpcServiceMethod {
|
|
},
|
|
},
|
|
});
|
|
});
|
|
// Bind and start the server
|
|
// Bind and start the server
|
|
- this.server.bindAsync(serverUrl, grpc.ServerCredentials.createInsecure(), () => {
|
|
|
|
- console.log(`gRPC server is running on ${serverUrl}`);
|
|
|
|
|
|
+ this.server.bindAsync(connectionAttribute.outGoing.serverUrl, grpc.ServerCredentials.createInsecure(), () => {
|
|
|
|
+ console.log(`gRPC server is running on ${connectionAttribute.outGoing.serverUrl}`);
|
|
this.server.start();
|
|
this.server.start();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
@@ -132,17 +138,32 @@ export class GrpcServiceMethod {
|
|
}
|
|
}
|
|
|
|
|
|
// Send a request over to the other server to open a channel for this server to emit/stream messages over
|
|
// Send a request over to the other server to open a channel for this server to emit/stream messages over
|
|
- public async createServerStreamingClient(
|
|
|
|
- server: string,
|
|
|
|
- connectionAttribute: ConnectionAttribute,
|
|
|
|
- outGoingInfo: OutGoingInfo
|
|
|
|
- ): Promise<string> {
|
|
|
|
|
|
+ public async createServerStreamingClient(connectionAttribute: ConnectionAttribute): Promise<string> {
|
|
return new Promise(async (resolve, reject) => {
|
|
return new Promise(async (resolve, reject) => {
|
|
- const client = new message_proto.Message(server, grpc.credentials.createInsecure());
|
|
|
|
- this.generateAdditionalAttributes(connectionAttribute, {}, outGoingInfo)
|
|
|
|
|
|
+ const client = new message_proto.Message(connectionAttribute.inComing.serverUrl, grpc.credentials.createInsecure());
|
|
|
|
+ let localInfo: ConnectionAttribute = { // need to make a new copy where it doesn't reference the subjects, otherwise circular ref error
|
|
|
|
+ ConnectionID: connectionAttribute.ConnectionID,
|
|
|
|
+ outGoing: {
|
|
|
|
+ StreamID: connectionAttribute.outGoing.StreamID,
|
|
|
|
+ PublisherID: connectionAttribute.outGoing.PublisherID,
|
|
|
|
+ SubscriberID: connectionAttribute.outGoing.SubscriberID,
|
|
|
|
+ serverUrl: connectionAttribute.outGoing.serverUrl,
|
|
|
|
+ MessageToBePublished: null,
|
|
|
|
+ MessageToBeReceived: null
|
|
|
|
+ },
|
|
|
|
+ inComing: {
|
|
|
|
+ StreamID: connectionAttribute.inComing.StreamID,
|
|
|
|
+ PublisherID: connectionAttribute.inComing.PublisherID,
|
|
|
|
+ SubscriberID: connectionAttribute.inComing.SubscriberID,
|
|
|
|
+ serverUrl: connectionAttribute.inComing.serverUrl,
|
|
|
|
+ MessageToBePublished: null,
|
|
|
|
+ MessageToBeReceived: null
|
|
|
|
+ },
|
|
|
|
+ connectionStatus: null
|
|
|
|
+ }
|
|
|
|
+ let call = client.HandleMessage({ id: connectionAttribute.inComing.serverUrl, message: JSON.stringify(localInfo) })
|
|
|
|
|
|
- let call = client.HandleMessage({ id: server, message: JSON.stringify(outGoingInfo) })
|
|
|
|
- console.log(`Sending request to ${server} to open response channel...`)
|
|
|
|
|
|
+ console.log(`Sending request to ${connectionAttribute.inComing.serverUrl} to open response channel...`)
|
|
|
|
|
|
call.on('status', (status: Status) => {
|
|
call.on('status', (status: Status) => {
|
|
if (status == grpc.status.OK) { // only returns a status when there's error. Otherwise it just waits
|
|
if (status == grpc.status.OK) { // only returns a status when there's error. Otherwise it just waits
|
|
@@ -154,7 +175,7 @@ export class GrpcServiceMethod {
|
|
reason: `Server doesn't seem to be alive. Error returned.`,
|
|
reason: `Server doesn't seem to be alive. Error returned.`,
|
|
payload: this.messageToBeSendOver ?? `There's no message at the moment...`
|
|
payload: this.messageToBeSendOver ?? `There's no message at the moment...`
|
|
}
|
|
}
|
|
- connectionAttribute.connectionStatus.next(report)
|
|
|
|
|
|
+ connectionAttribute.connectionStatus!.next(report)
|
|
resolve('No connection established. Server is not responding..')
|
|
resolve('No connection established. Server is not responding..')
|
|
}
|
|
}
|
|
});
|
|
});
|