github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/kat/src/clients/doc-exchange.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 { IDocExchangeTransferData, IDocExchangeListener, IDocExchangeDocumentDetails } from '../lib/interfaces'; 16 import { config } from '../lib/config'; 17 import { Stream, Readable } from 'stream'; 18 import io from 'socket.io-client'; 19 import FormData from 'form-data'; 20 import axios from 'axios'; 21 import * as utils from '../lib/utils'; 22 23 const log = utils.getLogger('clients/doc-exchange.ts'); 24 25 let socket: SocketIOClient.Socket 26 let listeners: IDocExchangeListener[] = []; 27 28 export const init = async () => { 29 try { 30 const response = await axios.get(`${config.docExchange.apiEndpoint}/documents`, { 31 auth: { 32 username: config.appCredentials.user, 33 password: config.appCredentials.password 34 } 35 }); 36 if (!Array.isArray(response.data.entries)) { 37 throw 'Invalid response'; 38 } else { 39 establishSocketIOConnection(); 40 } 41 } catch (err) { 42 throw new Error(`Document exchange REST connection failed. ${err}`); 43 } 44 }; 45 46 const establishSocketIOConnection = () => { 47 let error = false; 48 socket = io.connect(config.docExchange.socketIOEndpoint, { 49 transportOptions: { 50 polling: { 51 extraHeaders: { 52 Authorization: 'Basic ' + Buffer.from(`${config.appCredentials.user}` + 53 `:${config.appCredentials.password}`).toString('base64') 54 } 55 } 56 } 57 }).on('connect', () => { 58 if (error) { 59 error = false; 60 log.info('Document exchange Socket IO connection restored'); 61 } 62 }).on('connect_error', (err: Error) => { 63 error = true; 64 log.error(`Document exchange Socket IO connection error. ${err.toString()}`); 65 }).on('error', (err: Error) => { 66 error = true; 67 log.error(`Document exchange Socket IO error. ${err.toString()}`); 68 }).on('document_received', (transferData: IDocExchangeTransferData) => { 69 log.trace(`Doc exchange transfer event ${JSON.stringify(transferData)}`); 70 for (const listener of listeners) { 71 listener(transferData); 72 } 73 }) as SocketIOClient.Socket; 74 }; 75 76 export const addListener = (listener: IDocExchangeListener) => { 77 listeners.push(listener); 78 }; 79 80 export const removeListener = (listener: IDocExchangeListener) => { 81 listeners = listeners.filter(entry => entry != listener); 82 }; 83 84 export const downloadStream = async (documentPath: string): Promise<Buffer> => { 85 const response = await axios.get(`${config.docExchange.apiEndpoint}/documents/${documentPath}`, { 86 responseType: 'arraybuffer', 87 auth: { 88 username: config.appCredentials.user, 89 password: config.appCredentials.password 90 } 91 }); 92 return response.data; 93 }; 94 95 export const downloadJSON = async <T>(documentPath: string): Promise<T> => { 96 const response = await axios.get(`${config.docExchange.apiEndpoint}/documents/${documentPath}`, { 97 responseType: 'json', 98 auth: { 99 username: config.appCredentials.user, 100 password: config.appCredentials.password 101 } 102 }); 103 return response.data; 104 }; 105 106 export const findDocumentByHash = async (documentHash: string): Promise<string | null> => { 107 const result = await axios({ 108 url: `${config.docExchange.apiEndpoint}/search?query=${documentHash}&by_hash=true`, 109 auth: { 110 username: config.appCredentials.user, 111 password: config.appCredentials.password 112 } 113 }); 114 if (result.data.documents.length > 0) { 115 return result.data.documents[0].full_path; 116 } 117 return null; 118 } 119 120 export const uploadString = async (value: string, path: string): Promise<string> => { 121 const readable = new Readable(); 122 readable.push(value); 123 readable.push(null); 124 return uploadStream(readable, path); 125 }; 126 127 export const uploadStream = async (stream: Stream, path: string): Promise<string> => { 128 const formData = new FormData(); 129 formData.append('document', stream); 130 const result = await axios({ 131 method: 'put', 132 url: `${config.docExchange.apiEndpoint}/documents/${path}`, 133 data: formData, 134 headers: formData.getHeaders(), 135 auth: { 136 username: config.appCredentials.user, 137 password: config.appCredentials.password 138 } 139 }); 140 return result.data.hash; 141 }; 142 143 export const transfer = async (from: string, to: string, document: string) => { 144 await axios({ 145 method: 'post', 146 url: `${config.docExchange.apiEndpoint}/transfers`, 147 auth: { 148 username: config.appCredentials.user, 149 password: config.appCredentials.password 150 }, 151 data: { from, to, document } 152 }); 153 } 154 155 export const getDocumentDetails = async (filePath: string): Promise<IDocExchangeDocumentDetails> => { 156 const result = await axios({ 157 url: `${config.docExchange.apiEndpoint}/documents/${filePath}?details_only=true`, 158 auth: { 159 username: config.appCredentials.user, 160 password: config.appCredentials.password 161 } 162 }); 163 return result.data; 164 }; 165 166 export const reset = () => { 167 if (socket) { 168 log.info('Document exchange Socket IO connection reset'); 169 socket.close(); 170 establishSocketIOConnection(); 171 } 172 };