github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/kat/src/clients/app2app.ts (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import io from 'socket.io-client'; 16 import { config } from '../lib/config'; 17 import * as utils from '../lib/utils'; 18 import { AssetTradeMessage, IApp2AppMessage, IApp2AppMessageListener } from '../lib/interfaces'; 19 20 const log = utils.getLogger('clients/app2app.ts'); 21 22 let socket: SocketIOClient.Socket 23 let listeners: IApp2AppMessageListener[] = []; 24 25 export const init = async () => { 26 establishSocketIOConnection(); 27 }; 28 29 function subscribeWithRetry() { 30 log.trace(`App2App subscription: ${config.app2app.destinations.kat}`) 31 socket.emit('subscribe', [config.app2app.destinations.kat], (err: any, data: any) => { 32 if (err) { 33 log.error(`App2App subscription failure (retrying): ${err}`); 34 setTimeout(subscribeWithRetry, utils.constants.SUBSCRIBE_RETRY_INTERVAL); 35 return; 36 } 37 log.trace(`App2App subscription succeeded: ${JSON.stringify(data)}`); 38 }); 39 } 40 41 const establishSocketIOConnection = () => { 42 let error = false; 43 const { APP2APP_BATCH_SIZE, APP2APP_BATCH_TIMEOUT, APP2APP_READ_AHEAD } = utils.constants; 44 socket = io.connect(`${config.app2app.socketIOEndpoint}?auto_commit=false&read_ahead=${APP2APP_READ_AHEAD}&batch_size=${APP2APP_BATCH_SIZE}&batch_timeout=${APP2APP_BATCH_TIMEOUT}`, { 45 transportOptions: { 46 polling: { 47 extraHeaders: { 48 Authorization: 'Basic ' + Buffer.from(`${config.appCredentials.user}` + 49 `:${config.appCredentials.password}`).toString('base64') 50 } 51 } 52 } 53 }).on('connect', () => { 54 if (error) { 55 error = false; 56 log.info('App2App messaging Socket IO connection restored'); 57 } 58 subscribeWithRetry(); 59 }).on('connect_error', (err: Error) => { 60 error = true; 61 log.error(`App2App messaging Socket IO connection error. ${err.toString()}`); 62 }).on('error', (err: Error) => { 63 error = true; 64 log.error(`App2app messaging Socket IO error. ${err.toString()}`); 65 }).on('exception', (err: Error, extra?: any) => { 66 // Exceptions are such things as delivery failures. They do not put the connection in error state 67 log.error(`App2app messaging exception. ${err.toString()}`, extra); 68 }).on('data', (app2appMessage: IApp2AppMessage) => { 69 log.trace(`App2App message ${JSON.stringify(app2appMessage)}`); 70 try { 71 const content: AssetTradeMessage = JSON.parse(app2appMessage.content); 72 log.trace(`App2App message type=${content.type}`) 73 for (const listener of listeners) { 74 listener(app2appMessage.headers, content); 75 } 76 } catch (err) { 77 log.error(`App2App message error ${err}`); 78 } finally { 79 socket.emit('commit'); 80 } 81 }) as SocketIOClient.Socket; 82 }; 83 84 export const addListener = (listener: IApp2AppMessageListener) => { 85 listeners.push(listener); 86 }; 87 88 export const removeListener = (listener: IApp2AppMessageListener) => { 89 listeners = listeners.filter(entry => entry != listener); 90 }; 91 92 export const dispatchMessage = (to: string, content: any) => { 93 log.trace(`App2App dispatch type=${content.type}`) 94 socket.emit('produce', { 95 headers: { 96 from: config.app2app.destinations.kat, 97 to 98 }, 99 content: JSON.stringify(content) 100 }, 'kat', (err: any) => { 101 if(err) { 102 log.error(`Failed to dispatch App2App message.`, err); 103 } 104 }); 105 }; 106 107 export const reset = () => { 108 if (socket) { 109 log.info('App2App Socket IO connection reset'); 110 socket.close(); 111 establishSocketIOConnection(); 112 } 113 };