From b45caed0a1006bed98a815404149e594795cbf4c Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Mon, 28 Dec 2020 09:26:27 +0300 Subject: [PATCH] fluence js sdk api demos --- src/demo/1_asyncCall.tsx | 78 ++++++++++++++++++++++++ src/demo/2_eventStream.tsx | 106 +++++++++++++++++++++++++++++++++ src/demo/3_service.tsx | 59 ++++++++++++++++++ src/demo/4_grapgql_adapter.tsx | 76 +++++++++++++++++++++++ 4 files changed, 319 insertions(+) create mode 100644 src/demo/1_asyncCall.tsx create mode 100644 src/demo/2_eventStream.tsx create mode 100644 src/demo/3_service.tsx create mode 100644 src/demo/4_grapgql_adapter.tsx diff --git a/src/demo/1_asyncCall.tsx b/src/demo/1_asyncCall.tsx new file mode 100644 index 0000000..5b34a95 --- /dev/null +++ b/src/demo/1_asyncCall.tsx @@ -0,0 +1,78 @@ +// import fluence from 'fluence'; + +import { useEffect, useState } from 'react'; + +const fluence: any = { + call: (script, args, timeout) => { + // register particle id, + // build particle + // listen on "ack" service + + return new Promise((resolve, rejects) => { + // if received "ack" "particle_id" + // resolve with the result + // if "particle_id" timed out reject + }); + }, +}; + +interface Product { + id: string; + name: string; + sku: string; + description: string; + reviews: Review[]; +} + +interface Review { + id: string; + productId: string; + author: string; + text: string; +} + +const getProductInfo = async (): Promise => { + const timeout = 1000; + const script = ` + (seq + (call %init_peer_relay% ("op" "identity") []) + (seq + (call productsNode (productsService "get_products") [] products) + (seq + (call reviewsNode (reviewsService "get_reviews") [] reviews) + (call %init_peer_id% ("ack" %particle_id%) [products reviews]) + ) + ) + )`; + + const params = { + productsNode: '123', // probably discovered + productsService: 'org.acme/products@v1', // probably discovered + + reviewsNode: '123', // probably discovered + reviewsService: 'org.acme/revires@v1', // probably discovered + }; + + const [products, reviews] = await fluence.call(script, params, timeout); + return products.join().with(reviews); +}; + +export const DemoComponent = () => { + const [products, setProducts] = useState([]); + const [isLoading, setIsLoading] = useState(false); + useEffect(() => { + setIsLoading(true); + getProductInfo() + .then((data) => { + setProducts(data); + }) + .catch((err) => { + // catch timeout here + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + return
{isLoading &&
.. render products here {products.length}
}
; +}; diff --git a/src/demo/2_eventStream.tsx b/src/demo/2_eventStream.tsx new file mode 100644 index 0000000..abf4e5c --- /dev/null +++ b/src/demo/2_eventStream.tsx @@ -0,0 +1,106 @@ +// import fluence from 'fluence'; + +import { useEffect, useState } from 'react'; + +const fluence: any = { + on: (channel: string, handler) => { + // add subscription + }, + + registerEvent: (channel: string, eventName: string, validate?: (args: any[], tetraplets: any[][]) => boolean) => { + const registry: any = null; + const pushEvent: any = null; + + const s = registry.getService(channel); + s.registerFunction(eventName, (args: any[], tetraplets: any[][]) => { + if (validate && validate(args, tetraplets)) { + // don't block + setImmediate(() => { + pushEvent(channel, { + type: eventName, + args: args, + }); + }); + return {}; + } + + return { + error: 'something', + }; + }); + }, +}; + +fluence.registerEvent('users', 'join', (args: any[], tetraplets) => { + return args.length === 1 && args[0].is().guid() && args[1].is().string(); +}); + +fluence.registerEvent('users', 'leave', (args: any[], tetraplets) => { + return args.length === 1 && args[0].is().guid(); +}); + +interface User { + id: string; // guid, + name: string; +} + +export const DemoComponent = () => { + const [users, setUsers] = useState([]); + + useEffect(() => { + fluence.on('users', (msg) => { + if (msg.type === 'join') { + setUsers((prev) => [ + ...prev, + { + id: msg.args[0], + name: msg.args[1], + }, + ]); + } + + if (msg.type === 'leave') { + setUsers((prev) => prev.filter((x) => x.id !== msg.args[0])); + } + }); + }, []); + + return ( +
+
    + {users.map((x) => ( +
  • +
    {x.id}
    +
    {x.name}
    +
  • + ))} +
+
+ ); +}; + +// RxJS + +const Observable: any = null; + +const users = Observable.create((observer) => { + fluence.on('users', (msg) => { + observer.next(msg); + }); +}); + +// ELM + +const app: any = null; + +fluence.on('users', (msg) => { + app.ports.eventReceiver.send(msg.type, msg.args); +}); + +// Redux + +const store: any = null; + +fluence.on('users', (msg) => { + store.dispatch(msg); +}); diff --git a/src/demo/3_service.tsx b/src/demo/3_service.tsx new file mode 100644 index 0000000..83fd6ce --- /dev/null +++ b/src/demo/3_service.tsx @@ -0,0 +1,59 @@ +// import fluence, { Service, Function } from 'fluence'; + +import { useEffect, useState } from 'react'; + +abstract class FluenceService { + abstract create(); + abstract destroy(); +} + +const registry: any = null; + +const Service: any = (serviceId) => (constructor) => { + constructor.serviceId = serviceId; + + constructor.create = () => { + registry.registerService(serviceId, this); + }; + + constructor.destroy = () => { + registry.deleteService(serviceId); + }; +}; + +const Function: any = (fnName) => (obj, fn) => { + const s = registry.getService(obj.serviceId); + s.registerFunction(fnName, fn); +}; + +@Service('calc_service') +export class CalcService { + @Function('add') + add(a: number, b: number) { + return { + result: a + b, + }; + } + + @Function('mul') + mul(a: number, b: number) { + return { + result: a * b, + }; + } +} + +const useFluenceService = () => { + const [service, setService] = useState(); + useEffect(() => { + const service: T = undefined as any; + setService(service); + service.create(); + + return () => { + service.destroy(); + }; + }); + + return service; +}; diff --git a/src/demo/4_grapgql_adapter.tsx b/src/demo/4_grapgql_adapter.tsx new file mode 100644 index 0000000..292bbde --- /dev/null +++ b/src/demo/4_grapgql_adapter.tsx @@ -0,0 +1,76 @@ +// import fluence from 'fluence'; + +const useQuery: any = null; + +/* + +graphql + +type Product { + id: String! + name: String! + sku: String! + description: String! +} + +type Review { + id: String! + productId: String! + author: String! + text: String! + appearsIn: [Product!]! +} + +*/ + +/* + + adapter + + type(Product) + .resolvedByService('products_service') + .onNode('123') + .hasMane(Review) + .on('reviews') + .equalTo('id'); + + type(Review) + .resolvedByService('reviews_service') + .onNode('987'); + +*/ + +interface Product { + id: string; + name: string; + sku: string; + description: string; + reviews: Review[]; +} + +interface Review { + id: string; + productId: string; + author: string; + text: string; +} + +export const DemoComponent = () => { + const { isLoading, error, data } = useQuery(` + { + Product { + id, + name, + sku, + description + reviews: { + id, + author, + text + } + } + } + `); + + return
{isLoading &&
.. render products here {data.products.length}
}
; +};