user 6 anni fa
parent
commit
82d997b8fa
14 ha cambiato i file con 189 aggiunte e 47 eliminazioni
  1. 4 3
      lib/index.d.ts
  2. 41 16
      lib/index.js
  3. 1 1
      lib/index.js.map
  4. 8 1
      lib/sample.js
  5. 1 1
      lib/sample.js.map
  6. 3 0
      lib/util.d.ts
  7. 33 0
      lib/util.js
  8. 1 1
      lib/util.js.map
  9. 7 2
      lib/webclient-node.js
  10. 1 1
      lib/webclient-node.js.map
  11. 41 17
      src/index.ts
  12. 8 1
      src/sample.ts
  13. 32 0
      src/util.ts
  14. 8 3
      src/webclient-node.ts

+ 4 - 3
lib/index.d.ts

@@ -24,9 +24,10 @@ export declare class BankClient {
     uploadSlimText(item: string): Promise<any>;
     appendBank(bankAddress: string, bankTopic: 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;
+    appendPrivate(peerAddr: string, topic: string, hash: string, replaceHash?: string): Promise<void>;
+    getOrCreateContact(peerId: string, contactAddr: string): Promise<any>;
+    getContactById(peerId: string, contactId: string): Promise<any>;
+    updateContact(peerId: string, contactId: string, newProperties: any): Promise<any>;
     private getItemsForCommaList;
     private getPriv;
     private makePlaintextPayload;

+ 41 - 16
lib/index.js

@@ -216,9 +216,15 @@ class BankClient {
             return result;
         });
     }
-    appendPrivate(peerAddr, topic, hash) {
+    appendPrivate(peerAddr, topic, hash, replaceHash) {
         return __awaiter(this, void 0, void 0, function* () {
-            const payload = yield this.makePlaintextPayload(hash);
+            const nonce = yield this.getNonce();
+            const payload = yield this.makePlaintextPayload(JSON.stringify({
+                _date: new Date().toISOString(),
+                _nonce: nonce,
+                hash,
+                replaceHash
+            }));
             const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
             const result = yield this.webClient.request({
                 body: JSON.stringify(payload),
@@ -230,43 +236,62 @@ class BankClient {
             });
         });
     }
-    getOrCreateContact(peerAddr, contact, type) {
+    getOrCreateContact(peerId, contactAddr) {
         return __awaiter(this, void 0, void 0, function* () {
-            const contactList = yield this.retrievePrivate(peerAddr, '📇');
+            const contactList = yield this.retrievePrivate(peerId, '📇');
             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];
+            const existing = itemList.filter(item => item.addrs && item.addrs.includes(contactAddr))[0];
             if (existing != null) {
                 return existing;
             }
             const newItem = {
-                contact,
-                contactHash,
-                type,
+                addrs: [
+                    contactAddr
+                ],
+                id: util_1.uuid()
             };
             const newItemHash = yield this.uploadSlimJSON(newItem);
-            yield this.appendPrivate(peerAddr, '📇', newItemHash);
+            yield this.appendPrivate(peerId, '📇', newItemHash);
             return newItem;
         });
     }
-    getContactHash(contact, type) {
+    getContactById(peerId, contactId) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const contactList = yield this.retrievePrivate(peerId, '📇');
+            const itemList = yield this.getItemsForCommaList(contactList);
+            const existing = itemList.filter(item => item.id === contactId)[0];
+            if (!existing) {
+                throw new Error('Cannot find contact with id ' + contactId);
+            }
+            return existing;
+        });
+    }
+    updateContact(peerId, contactId, newProperties) {
         return __awaiter(this, void 0, void 0, function* () {
-            const value = type + ':' + contact;
-            return yield this.uploadSlimText(value);
+            const existing = yield this.getContactById(peerId, contactId);
+            const newProps = util_1.mergeDeep({}, newProperties);
+            delete newProps.id;
+            const newItem = util_1.mergeDeep(existing, newProps);
+            delete newItem.hash;
+            const newItemHash = yield this.uploadSlimJSON(newItem);
+            yield this.appendPrivate(peerId, '📇', newItemHash, existing.hash);
+            return yield this.getContactById(peerId, contactId);
         });
     }
     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 => {
+            const items = yield Promise.all(itemHashes.map(itemId => {
                 return this.webClient.requestJSON({
                     method: 'get',
                     url: this.ipfsUrlBase + '/ipfs/' + itemId,
                 });
             }));
+            for (const item of items) {
+                item.hash = itemHashes.shift();
+            }
+            return items;
         });
     }
     getPriv() {

File diff suppressed because it is too large
+ 1 - 1
lib/index.js.map


+ 8 - 1
lib/sample.js

@@ -28,7 +28,14 @@ const bankClient = new BankClient('http://localhost:8082', 'https://distributing
     // console.log('publishRes', publishRes);
     // const privateRes = await bankClient.retrievePrivate(peerId, 'bleh');
     // console.log('privateRes', privateRes);
-    const newContact = yield bankClient.getOrCreateContact(peerId, '+13065006001', 'phone');
+    const newContact = yield bankClient.getOrCreateContact(peerId, 'phone:+13065006001');
     console.log('newContact', newContact);
+    const updatedContact = yield bankClient.updateContact(peerId, newContact.id, {
+        fullName: 'John Doe4',
+        deepProp: {
+            whatever: [1, '2', true]
+        }
+    });
+    console.log('updated', updatedContact);
 }))();
 //# sourceMappingURL=sample.js.map

File diff suppressed because it is too large
+ 1 - 1
lib/sample.js.map


+ 3 - 0
lib/util.d.ts

@@ -1,3 +1,6 @@
 /// <reference types="node" />
 export declare function toArray(msg: any, enc: any): any[];
 export declare function encodeHex(msg: Buffer | Uint8Array): string;
+export declare function uuid(): string;
+export declare function isObject(item: any): boolean;
+export declare function mergeDeep(target: object, source: object): {} & object;

+ 33 - 0
lib/util.js

@@ -55,4 +55,37 @@ function encodeHex(msg) {
     return res;
 }
 exports.encodeHex = encodeHex;
+function uuid() {
+    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
+        // tslint:disable-next-line: no-bitwise
+        const random = Math.random() * 16 | 0;
+        const value = char === "x" ? random : (random % 4 + 8);
+        return value.toString(16);
+    });
+}
+exports.uuid = uuid;
+function isObject(item) {
+    return (item && typeof item === 'object' && !Array.isArray(item));
+}
+exports.isObject = isObject;
+function mergeDeep(target, source) {
+    const output = Object.assign({}, target);
+    if (isObject(target) && isObject(source)) {
+        Object.keys(source).forEach(key => {
+            if (isObject(source[key])) {
+                if (!(key in target)) {
+                    Object.assign(output, { [key]: source[key] });
+                }
+                else {
+                    output[key] = mergeDeep(target[key], source[key]);
+                }
+            }
+            else {
+                Object.assign(output, { [key]: source[key] });
+            }
+        });
+    }
+    return output;
+}
+exports.mergeDeep = mergeDeep;
 //# sourceMappingURL=util.js.map

File diff suppressed because it is too large
+ 1 - 1
lib/util.js.map


+ 7 - 2
lib/webclient-node.js

@@ -12,12 +12,17 @@ const request = require("request-promise");
 class WebClientNode {
     request(options) {
         return __awaiter(this, void 0, void 0, function* () {
+            if (!options.headers) {
+                options.headers = {};
+            }
             const rpOptions = {
-                body: options.body,
+                headers: options.headers,
                 method: options.method,
                 uri: options.url,
-                headers: options.headers
             };
+            if (options.body) {
+                rpOptions.body = options.body;
+            }
             // console.log('rpOptions', rpOptions);
             const result = yield request(rpOptions);
             return result;

File diff suppressed because it is too large
+ 1 - 1
lib/webclient-node.js.map


+ 41 - 17
src/index.ts

@@ -5,7 +5,7 @@ import { Storage } from './storage';
 import { IWebClient } from './webclient';
 const TextEncoder = util.TextEncoder;
 import { UploadItemParameters } from './upload-item-parameters';
-import { encodeHex } from './util';
+import { encodeHex, mergeDeep, uuid } from './util';
 import WebClientNode from './webclient-node';
 
 export class BankClient {
@@ -209,8 +209,14 @@ export class BankClient {
       return result;
     }
 
-    public async appendPrivate(peerAddr: string, topic: string, hash: string) {
-      const payload = await this.makePlaintextPayload(hash);
+    public async appendPrivate(peerAddr: string, topic: string, hash: string, replaceHash?: string) {
+      const nonce = await this.getNonce();
+      const payload = await this.makePlaintextPayload(JSON.stringify({
+        _date: new Date().toISOString(),
+        _nonce: nonce,
+        hash,
+        replaceHash
+      }));
       const topicURL = this.urlBase + '/bank/private/' + encodeURIComponent(peerAddr) + '/' + encodeURIComponent(topic);
       const result = await this.webClient.request({
         body: JSON.stringify(payload),
@@ -222,40 +228,58 @@ export class BankClient {
       });
     }
 
-    public async getOrCreateContact(peerAddr: string, contact: string, type: string) {
-      const contactList = await this.retrievePrivate(peerAddr, '📇');
+    public async getOrCreateContact(peerId: string, contactAddr: string) {
+      const contactList = await this.retrievePrivate(peerId, '📇');
       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];
+      const existing = itemList.filter(item => item.addrs && item.addrs.includes(contactAddr))[0];
       if (existing != null) {
         return existing;
       }
       const newItem = {
-        contact,
-        contactHash,
-        type,
+        addrs: [
+          contactAddr
+        ],
+        id: uuid()
       };
       const newItemHash = await this.uploadSlimJSON(newItem);
-      await this.appendPrivate(peerAddr, '📇', newItemHash);
+      await this.appendPrivate(peerId, '📇', newItemHash);
       return newItem;
     }
 
-    private async getContactHash(contact: string, type: string) {
-      const value = type + ':' + contact;
-      return await this.uploadSlimText(value);
+    public async getContactById(peerId: string, contactId: string) {
+      const contactList = await this.retrievePrivate(peerId, '📇');
+      const itemList = await this.getItemsForCommaList(contactList);
+      const existing = itemList.filter(item => item.id === contactId)[0];
+      if (!existing) {
+        throw new Error('Cannot find contact with id ' + contactId);
+      }
+      return existing;
+    }
+
+    public async updateContact(peerId: string, contactId: string, newProperties: any) {
+      const existing = await this.getContactById(peerId, contactId);
+      const newProps: any = mergeDeep({}, newProperties);
+      delete newProps.id;
+      const newItem: any = mergeDeep(existing, newProps);
+      delete newItem.hash;
+      const newItemHash = await this.uploadSlimJSON(newItem);
+      await this.appendPrivate(peerId, '📇', newItemHash, existing.hash);
+      return await this.getContactById(peerId, contactId);
     }
 
     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 => {
+      const items: any[] = await Promise.all(itemHashes.map(itemId => {
         return this.webClient.requestJSON({
           method: 'get',
           url: this.ipfsUrlBase + '/ipfs/' + itemId,
         });
       }));
+      for (const item of items) {
+        item.hash = itemHashes.shift();
+      }
+      return items;
     }
 
     private getPriv(): RsaPrivateKey {

+ 8 - 1
src/sample.ts

@@ -20,6 +20,13 @@ const bankClient = new BankClient('http://localhost:8082', 'https://distributing
     // console.log('publishRes', publishRes);
     // const privateRes = await bankClient.retrievePrivate(peerId, 'bleh');
     // console.log('privateRes', privateRes);
-    const newContact = await bankClient.getOrCreateContact(peerId, '+13065006001', 'phone');
+    const newContact = await bankClient.getOrCreateContact(peerId, 'phone:+13065006001');
     console.log('newContact', newContact);
+    const updatedContact = await bankClient.updateContact(peerId, newContact.id, {
+        fullName: 'John Doe4',
+        deepProp: {
+            whatever: [1, '2', true]
+        }
+    });
+    console.log('updated', updatedContact);
 })();

+ 32 - 0
src/util.ts

@@ -52,3 +52,35 @@ export function encodeHex(msg: Buffer | Uint8Array) {
   }
   return res;
 }
+
+export function uuid(): string {
+  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
+    // tslint:disable-next-line: no-bitwise
+    const random = Math.random() * 16 | 0; 
+    const value = char === "x" ? random : (random % 4 + 8);
+    return value.toString(16);
+  });
+}
+
+export function isObject(item) {
+  return (item && typeof item === 'object' && !Array.isArray(item));
+}
+
+export function mergeDeep(target: object, source: object) {
+  const output = Object.assign({}, target);
+  if (isObject(target) && isObject(source)) {
+    Object.keys(source).forEach(key => {
+      if (isObject(source[key])) {
+        if (!(key in target)) {
+          Object.assign(output, { [key]: source[key] });
+        }
+        else {
+          output[key] = mergeDeep(target[key], source[key]);
+        }
+      } else {
+        Object.assign(output, { [key]: source[key] });
+      }
+    });
+  }
+  return output;
+}

+ 8 - 3
src/webclient-node.ts

@@ -5,12 +5,17 @@ import { IWebClientOptions } from "./webclient-options";
 export default class WebClientNode implements IWebClient {
 
     public async request(options: IWebClientOptions): Promise<string> {
-        const rpOptions = {
-            body: options.body,
+        if (!options.headers) {
+            options.headers = {};
+        }
+        const rpOptions: any = {
+            headers: options.headers,
             method: options.method,
             uri: options.url,
-            headers: options.headers
         };
+        if (options.body) {
+            rpOptions.body = options.body;
+        }
         // console.log('rpOptions', rpOptions);
         const result = await request(rpOptions);
         return result;