user преди 6 години
родител
ревизия
4cc0e6dcec
променени са 11 файла, в които са добавени 261 реда и са изтрити 40 реда
  1. 4 4
      __tests__/index.test.ts
  2. 9 1
      lib/index.d.ts
  3. 103 3
      lib/index.js
  4. 1 1
      lib/index.js.map
  5. 20 13
      lib/sample.js
  6. 1 1
      lib/sample.js.map
  7. 2 0
      lib/webclient-node.js
  8. 1 1
      lib/webclient-node.js.map
  9. 98 3
      src/index.ts
  10. 20 13
      src/sample.ts
  11. 2 0
      src/webclient-node.ts

+ 4 - 4
__tests__/index.test.ts

@@ -17,7 +17,7 @@ describe('BankClient', () => {
           throw new Error("Method not implemented.");
         }
       }
-      const bankClient = new BankClient('/urlBase', storage, new FakeWebClient());
+      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient());
       const strapped = await bankClient.bootstrap();
       expect(strapped).toBeDefined();
   });
@@ -31,7 +31,7 @@ describe('BankClient', () => {
           return Promise.resolve('42');
         }
       }
-      const bankClient = new BankClient('/urlBase', storage, new FakeWebClient());
+      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient());
       await bankClient.bootstrap();
       const nonce = await bankClient.getNonce();
       expect(nonce).toEqual(42);
@@ -40,7 +40,7 @@ describe('BankClient', () => {
   describe('get nonce', () => {
     test('should work with real http client', async () => {
       const webClient = new WebClientNode();
-      const bankClient = new BankClient('http://127.0.0.1:8000', storage, webClient);
+      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient);
       await bankClient.bootstrap();
       nock('http://127.0.0.1:8000')
         .get('/bank/nonce')
@@ -53,7 +53,7 @@ describe('BankClient', () => {
   describe('get balance', () => {
     test('should work with real http client', async () => {
       const webClient = new WebClientNode();
-      const bankClient = new BankClient('http://127.0.0.1:8000', storage, webClient);
+      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient);
       await bankClient.bootstrap();
       nock('http://127.0.0.1:8000')
         .post('/bank/getbalance')

+ 9 - 1
lib/index.d.ts

@@ -3,18 +3,26 @@ import { IWebClient } from './webclient';
 import { UploadItemParameters } from './upload-item-parameters';
 export declare class BankClient {
     private urlBase;
+    private ipfsUrlBase;
     private storage;
     private webClient;
     private privateKey;
     private bootstrapPromise;
     private bootstrapResult;
-    constructor(urlBase: string, storage?: Storage, webClient?: IWebClient);
+    constructor(urlBase: string, ipfsUrlBase: string, storage?: Storage, webClient?: IWebClient);
     getPub(): Promise<string>;
     bootstrap(): any;
     getNonce(): Promise<number>;
     getBalance(): Promise<number>;
     upload(params: UploadItemParameters): Promise<any>;
+    uploadSlimJSON(item: any): Promise<any>;
+    uploadSlimText(item: string): Promise<any>;
     appendBank(bankLink: string, itemHash: string): Promise<void>;
+    retrievePrivate(peerAddr: string, topic: string): Promise<string>;
+    appendPrivate(peerAddr: string, topic: string, hash: string): Promise<void>;
+    getOrCreateContact(peerAddr: string, contact: string, type: string): Promise<any>;
+    private getContactHash;
+    private getItemsForCommaList;
     private getPriv;
     private makePlaintextPayload;
     private parseBankLink;

+ 103 - 3
lib/index.js

@@ -18,8 +18,9 @@ const TextEncoder = util.TextEncoder;
 const util_1 = require("./util");
 const webclient_node_1 = __importDefault(require("./webclient-node"));
 class BankClient {
-    constructor(urlBase, storage = new storage_1.Storage('bankClient'), webClient = new webclient_node_1.default()) {
+    constructor(urlBase, ipfsUrlBase, storage = new storage_1.Storage('bankClient'), webClient = new webclient_node_1.default()) {
         this.urlBase = urlBase;
+        this.ipfsUrlBase = ipfsUrlBase;
         this.storage = storage;
         this.webClient = webClient;
     }
@@ -126,13 +127,40 @@ class BankClient {
                     formData[attr] = params[attr];
                 }
             }
-            console.log('formData', formData);
+            // console.log('formData', formData);
             const uploadResponse = yield this.webClient.requestJSON({
                 formData,
                 method: 'POST',
                 url
             });
-            console.log('uploadResponse', uploadResponse);
+            // console.log('uploadResponse', uploadResponse);
+            return uploadResponse.hash;
+        });
+    }
+    uploadSlimJSON(item) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const url = this.urlBase + '/bank/upload/slim';
+            const uploadResponse = yield this.webClient.requestJSON({
+                body: item,
+                method: 'POST',
+                url
+            });
+            // console.log('uploadResponse', uploadResponse);
+            return uploadResponse.hash;
+        });
+    }
+    uploadSlimText(item) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const url = this.urlBase + '/bank/upload/slim';
+            const uploadResponse = JSON.parse(yield this.webClient.request({
+                body: item,
+                headers: {
+                    'content-type': 'text/plain'
+                },
+                method: 'POST',
+                url
+            }));
+            // console.log('uploadResponse', uploadResponse);
             return uploadResponse.hash;
         });
     }
@@ -148,6 +176,78 @@ class BankClient {
             });
         });
     }
+    retrievePrivate(peerAddr, topic) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const nonce = yield this.getNonce();
+            const retrieveRequest = yield this.makePlaintextPayload(JSON.stringify({
+                _date: new Date().toISOString(),
+                _nonce: nonce
+            }));
+            const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
+            const result = yield this.webClient.request({
+                body: JSON.stringify(retrieveRequest),
+                headers: {
+                    'content-type': 'application/json'
+                },
+                method: 'POST',
+                url: topicURL
+            });
+            return result;
+        });
+    }
+    appendPrivate(peerAddr, topic, hash) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const payload = yield this.makePlaintextPayload(hash);
+            const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
+            const result = yield this.webClient.request({
+                body: JSON.stringify(payload),
+                headers: {
+                    'content-type': 'application/json'
+                },
+                method: 'PUT',
+                url: topicURL
+            });
+        });
+    }
+    getOrCreateContact(peerAddr, contact, type) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const contactList = yield this.retrievePrivate(peerAddr, '📇');
+            const itemList = yield this.getItemsForCommaList(contactList);
+            const contactHash = yield this.getContactHash(contact, type);
+            // console.log('contact hash for', contact, type, 'is', contactHash);
+            const existing = itemList.filter(item => item.contactHash === contactHash)[0];
+            if (existing != null) {
+                return existing;
+            }
+            const newItem = {
+                contact,
+                contactHash,
+                type,
+            };
+            const newItemHash = yield this.uploadSlimJSON(newItem);
+            yield this.appendPrivate(peerAddr, '📇', newItemHash);
+            return newItem;
+        });
+    }
+    getContactHash(contact, type) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const value = type + ':' + contact;
+            return yield this.uploadSlimText(value);
+        });
+    }
+    getItemsForCommaList(commaList) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // console.log('commaList', commaList);
+            const itemHashes = commaList.split(',').filter(x => x.trim() !== '');
+            // console.log('itemHashes', itemHashes);
+            return yield Promise.all(itemHashes.map(itemId => {
+                return this.webClient.requestJSON({
+                    method: 'get',
+                    url: this.ipfsUrlBase + '/ipfs/' + itemId,
+                });
+            }));
+        });
+    }
     getPriv() {
         if (!this.privateKey) {
             throw new Error('missing private key');

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
lib/index.js.map


+ 20 - 13
lib/sample.js

@@ -8,20 +8,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
     });
 };
 const { BankClient } = require('./index');
-const bankClient = new BankClient('https://hostname');
+const bankClient = new BankClient('http://localhost:8082', 'https://distributing.fun');
 (() => __awaiter(this, void 0, void 0, function* () {
     yield bankClient.bootstrap();
-    const balance = yield bankClient.getBalance();
-    const uploadResult = yield bankClient.upload({
-        fileData: 't2',
-        fileName: 't3.txt',
-        type: 'file',
-        title: '442a',
-        text: 'txt'
-    });
-    console.log('my balance', balance);
-    console.log('upl', uploadResult);
-    yield bankClient.appendBank('bank:qmlink/📥', uploadResult);
-    console.log('added.');
+    const peerId = yield bankClient.getPub();
+    // const balance = await bankClient.getBalance();
+    // const uploadResult = await bankClient.upload({
+    //     fileData: 't2',
+    //     fileName: 't3.txt',
+    //     type: 'file',
+    //     title: '442a',
+    //     text: 'txt'
+    // });
+    // console.log('my balance', balance);
+    // console.log('upl', uploadResult);
+    // await bankClient.appendBank('bank:qmlink/📥', uploadResult);
+    // console.log('added.');
+    // const publishRes = await bankClient.appendPrivate(peerId, 'bleh', 'zdj7Wjbc1NqWsVVRaQjWhvvc49MGtszd2VZQ3pWnVKbh6tDWi');
+    // console.log('publishRes', publishRes);
+    // const privateRes = await bankClient.retrievePrivate(peerId, 'bleh');
+    // console.log('privateRes', privateRes);
+    const newContact = yield bankClient.getOrCreateContact(peerId, '+13065006001', 'phone');
+    console.log('newContact', newContact);
 }))();
 //# sourceMappingURL=sample.js.map

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
lib/sample.js.map


+ 2 - 0
lib/webclient-node.js

@@ -18,6 +18,7 @@ class WebClientNode {
                 uri: options.url,
                 headers: options.headers
             };
+            // console.log('rpOptions', rpOptions);
             const result = yield request(rpOptions);
             return result;
         });
@@ -45,6 +46,7 @@ class WebClientNode {
             if (options.body) {
                 rpOptions.body = options.body;
             }
+            // console.log('rpOptions', rpOptions);
             const result = yield request(rpOptions);
             return JSON.parse(result);
         });

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
lib/webclient-node.js.map


+ 98 - 3
src/index.ts

@@ -14,7 +14,7 @@ export class BankClient {
     private bootstrapPromise: any;
     private bootstrapResult: any;
 
-    constructor(private urlBase: string, private storage: Storage = new Storage('bankClient'), private webClient: IWebClient = new WebClientNode()) {
+    constructor(private urlBase: string, private ipfsUrlBase: string, private storage: Storage = new Storage('bankClient'), private webClient: IWebClient = new WebClientNode()) {
 
     }
 
@@ -120,13 +120,40 @@ export class BankClient {
           formData[attr] = params[attr];
         }
       }
-      console.log('formData', formData);
+      // console.log('formData', formData);
       const uploadResponse: any = await this.webClient.requestJSON({
         formData,
         method: 'POST',
         url
       });
-      console.log('uploadResponse', uploadResponse);
+      // console.log('uploadResponse', uploadResponse);
+      return uploadResponse.hash;
+    }
+
+    public async uploadSlimJSON(item: any) {
+      const url = this.urlBase + '/bank/upload/slim';
+
+      const uploadResponse: any = await this.webClient.requestJSON({
+        body: item,
+        method: 'POST',
+        url
+      });
+      // console.log('uploadResponse', uploadResponse);
+      return uploadResponse.hash;
+    }
+
+    public async uploadSlimText(item: string) {
+      const url = this.urlBase + '/bank/upload/slim';
+
+      const uploadResponse: any = JSON.parse(await this.webClient.request({
+        body: item,
+        headers: {
+          'content-type': 'text/plain'
+        },
+        method: 'POST',
+        url
+      }));
+      // console.log('uploadResponse', uploadResponse);
       return uploadResponse.hash;
     }
 
@@ -141,6 +168,74 @@ export class BankClient {
       });
     }
 
+    public async retrievePrivate(peerAddr: string, topic: string) {
+      const nonce = await this.getNonce();
+      const retrieveRequest = await this.makePlaintextPayload(JSON.stringify({
+        _date: new Date().toISOString(),
+        _nonce: nonce
+      }));
+  
+      const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
+      const result = await this.webClient.request({
+        body: JSON.stringify(retrieveRequest),
+        headers: {
+          'content-type': 'application/json'
+        },
+        method: 'POST',
+        url: topicURL
+      });
+      return result;
+    }
+
+    public async appendPrivate(peerAddr: string, topic: string, hash: string) {
+      const payload = await this.makePlaintextPayload(hash);
+      const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
+      const result = await this.webClient.request({
+        body: JSON.stringify(payload),
+        headers: {
+          'content-type': 'application/json'
+        },
+        method: 'PUT',
+        url: topicURL
+      });
+    }
+
+    public async getOrCreateContact(peerAddr: string, contact: string, type: string) {
+      const contactList = await this.retrievePrivate(peerAddr, '📇');
+      const itemList = await this.getItemsForCommaList(contactList);
+      const contactHash = await this.getContactHash(contact, type);
+      // console.log('contact hash for', contact, type, 'is', contactHash);
+      const existing = itemList.filter(item => item.contactHash === contactHash)[0];
+      if (existing != null) {
+        return existing;
+      }
+      const newItem = {
+        contact,
+        contactHash,
+        type,
+      };
+      const newItemHash = await this.uploadSlimJSON(newItem);
+      await this.appendPrivate(peerAddr, '📇', newItemHash);
+      return newItem;
+    }
+
+    private async getContactHash(contact: string, type: string) {
+      const value = type + ':' + contact;
+      return await this.uploadSlimText(value);
+    }
+
+    private async getItemsForCommaList(commaList: string): Promise<any[]> {
+      // console.log('commaList', commaList);
+      const itemHashes = commaList.split(',').filter(x => x.trim() !== '');
+      // console.log('itemHashes', itemHashes);
+      return await Promise.all(itemHashes.map(itemId => {
+        return this.webClient.requestJSON({
+          method: 'get',
+          url: this.ipfsUrlBase + '/ipfs/' + itemId,
+        });
+      }));
+    }
+
     private getPriv(): RsaPrivateKey {
       if (!this.privateKey) {
         throw new Error('missing private key');

+ 20 - 13
src/sample.ts

@@ -1,18 +1,25 @@
 const { BankClient } = require('./index');
-const bankClient = new BankClient('https://hostname');
+const bankClient = new BankClient('http://localhost:8082', 'https://distributing.fun');
 
 (async () => {
     await bankClient.bootstrap();
-    const balance = await bankClient.getBalance();
-    const uploadResult = await bankClient.upload({
-        fileData: 't2',
-        fileName: 't3.txt',
-        type: 'file',
-        title: '442a',
-        text: 'txt'
-    });
-    console.log('my balance', balance);
-    console.log('upl', uploadResult);
-    await bankClient.appendBank('bank:qmlink/📥', uploadResult);
-    console.log('added.');
+    const peerId = await bankClient.getPub();
+    // const balance = await bankClient.getBalance();
+    // const uploadResult = await bankClient.upload({
+    //     fileData: 't2',
+    //     fileName: 't3.txt',
+    //     type: 'file',
+    //     title: '442a',
+    //     text: 'txt'
+    // });
+    // console.log('my balance', balance);
+    // console.log('upl', uploadResult);
+    // await bankClient.appendBank('bank:qmlink/📥', uploadResult);
+    // console.log('added.');
+    // const publishRes = await bankClient.appendPrivate(peerId, 'bleh', 'zdj7Wjbc1NqWsVVRaQjWhvvc49MGtszd2VZQ3pWnVKbh6tDWi');
+    // console.log('publishRes', publishRes);
+    // const privateRes = await bankClient.retrievePrivate(peerId, 'bleh');
+    // console.log('privateRes', privateRes);
+    const newContact = await bankClient.getOrCreateContact(peerId, '+13065006001', 'phone');
+    console.log('newContact', newContact);
 })();

+ 2 - 0
src/webclient-node.ts

@@ -11,6 +11,7 @@ export default class WebClientNode implements IWebClient {
             uri: options.url,
             headers: options.headers
         };
+        // console.log('rpOptions', rpOptions);
         const result = await request(rpOptions);
         return result;
     }    
@@ -37,6 +38,7 @@ export default class WebClientNode implements IWebClient {
         if (options.body) {
             rpOptions.body = options.body;
         }
+        // console.log('rpOptions', rpOptions);
         const result = await request(rpOptions);
         return JSON.parse(result);
     }