Integrating remoteObservable
This commit is contained in:
parent
3430a33cc2
commit
5612ef0460
@ -4,14 +4,15 @@ const _registeredDispatcherParams_ = Symbol('_registeredDispatcherParams_');
|
|||||||
|
|
||||||
// Interfaces for the Class
|
// Interfaces for the Class
|
||||||
export interface IExportToDispatcherParameters {
|
export interface IExportToDispatcherParameters {
|
||||||
|
uri?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExportMethodToDispatcherParameters {
|
export interface IExportMethodToDispatcherParameters {
|
||||||
url?: string,
|
uri?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExportPropertyToDispatcherParameters {
|
export interface IExportPropertyToDispatcherParameters {
|
||||||
url?: string,
|
uri?: string,
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ export function exportsElementsToDispatcher(options: IExportToDispatcherParamete
|
|||||||
* Decorator, used to export the Method.
|
* Decorator, used to export the Method.
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
export function exportMethodToDispatcher(options: IExportMethodToDispatcherParameters = {}) {
|
export function exportMethodToDispatcher(options: IExportMethodToDispatcherParameters) {
|
||||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
target[_registeredDispatcherMethods_] = target[_registeredDispatcherMethods_] || new Map<string, IExportMethodToDispatcherParameters>();
|
target[_registeredDispatcherMethods_] = target[_registeredDispatcherMethods_] || new Map<string, IExportMethodToDispatcherParameters>();
|
||||||
// Here we just add some information that class decorator will use
|
// Here we just add some information that class decorator will use
|
||||||
@ -71,7 +72,7 @@ export function exportMethodToDispatcher(options: IExportMethodToDispatcherParam
|
|||||||
* Decorator, will create a POST and GET api for the Parameter.
|
* Decorator, will create a POST and GET api for the Parameter.
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
export function exportPropertyToDispatcher(options: IExportPropertyToDispatcherParameters = {}) {
|
export function exportPropertyToDispatcher(options: IExportPropertyToDispatcherParameters) {
|
||||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||||
target[_registeredDispatcherParams_] = target[_registeredDispatcherParams_] || new Map<string, IExportPropertyToDispatcherParameters>();
|
target[_registeredDispatcherParams_] = target[_registeredDispatcherParams_] || new Map<string, IExportPropertyToDispatcherParameters>();
|
||||||
// Here we just add some information that class decorator will use
|
// Here we just add some information that class decorator will use
|
||||||
|
@ -81,7 +81,7 @@ export interface IAnalyzeResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PropertyInformation = ModifierInformation & TypeInformation & { name: string; declaration: PropertyDeclaration; };
|
export type PropertyInformation = DecoratorInformation & ModifierInformation & TypeInformation & { name: string; declaration: PropertyDeclaration; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helperfunction, used to extract a Mapping of imported Files. This allows the user to rename the interfaces
|
* Helperfunction, used to extract a Mapping of imported Files. This allows the user to rename the interfaces
|
||||||
|
@ -19,18 +19,47 @@ export async function generateClientTemplate(options: {
|
|||||||
logger?: Logger
|
logger?: Logger
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
// Create the Output dir (if it doenst exists)
|
|
||||||
await createPath(options.outputDir);
|
|
||||||
|
|
||||||
if (options.logger) {
|
if (options.logger) {
|
||||||
options.logger.info('Templates will be stored in ' + options.outputDir);
|
options.logger.info('Templates will be stored in ' + options.outputDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firstly copy the nopeDispatcher
|
const filesToCopy: {
|
||||||
await copyFile(
|
src: string[],
|
||||||
join(__dirname, '..', '..', '..', 'lib', 'dispatcher', 'nopeDispatcher.ts'),
|
name: string,
|
||||||
join(options.outputDir, 'nopeDispatcher.ts')
|
path: string[]
|
||||||
);
|
}[] = [
|
||||||
|
{
|
||||||
|
name: 'nopeDispatcher.ts',
|
||||||
|
path: ['dispatcher'],
|
||||||
|
src: ['lib', 'dispatcher']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nopeObservable.ts',
|
||||||
|
path: ['observables'],
|
||||||
|
src: ['lib', 'observables']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nopeRemoteObservable.ts',
|
||||||
|
path: ['observables'],
|
||||||
|
src: ['lib', 'observables']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const file of filesToCopy) {
|
||||||
|
// Create the Output dir (if it doenst exists)
|
||||||
|
await createPath(join(options.outputDir, ...file.path));
|
||||||
|
|
||||||
|
// Copy the File.
|
||||||
|
await copyFile(
|
||||||
|
join(__dirname, '..', '..', '..', ...file.src, file.name),
|
||||||
|
join(options.outputDir, ...file.path, file.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options.logger) {
|
||||||
|
options.logger.info('Copied -> ' + file.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to Determine new project files.
|
// Function to Determine new project files.
|
||||||
const project = new Project({
|
const project = new Project({
|
||||||
@ -60,7 +89,27 @@ export async function generateClientTemplate(options: {
|
|||||||
content: string,
|
content: string,
|
||||||
}[] = result.map(item => {
|
}[] = result.map(item => {
|
||||||
|
|
||||||
item.className = item.className + 'ClientInterface'
|
// Extract the Class uri
|
||||||
|
const classUri = item.classDecorator.decoratorSettings.exportsElementsToDispatcher ? item.classDecorator.decoratorSettings.exportsElementsToDispatcher.uri || item.className : item.className;
|
||||||
|
|
||||||
|
item.className = item.className + 'ClientInterface';
|
||||||
|
item.methods = item.methods.map(m => {
|
||||||
|
|
||||||
|
const methodUri = m.decoratorSettings.exportMethodToDispatcher ? m.decoratorSettings.exportMethodToDispatcher.uri || m.name : m.name;
|
||||||
|
|
||||||
|
(m as any).uri = classUri + '_' + methodUri;
|
||||||
|
|
||||||
|
return m;
|
||||||
|
});
|
||||||
|
|
||||||
|
item.properties = item.properties.map(p => {
|
||||||
|
|
||||||
|
const methodUri = p.decoratorSettings.exportPropertyToDispatcher ? p.decoratorSettings.exportPropertyToDispatcher.uri || p.name : p.name;
|
||||||
|
|
||||||
|
(p as any).uri = classUri + '_' + methodUri;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: item.className + '.ts',
|
name: item.className + '.ts',
|
||||||
@ -79,7 +128,7 @@ export async function generateClientTemplate(options: {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (options.logger) {
|
if (options.logger) {
|
||||||
options.logger.info('Generated -> ' + fileName);
|
options.logger.info('Generated -> ' + join('clients', fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to Determine new project files.
|
// Function to Determine new project files.
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import { BehaviorSubject, CompletionObserver, ErrorObserver, NextObserver, Subscription } from 'rxjs';
|
import { BehaviorSubject, CompletionObserver, ErrorObserver, NextObserver, Observable, Subscription } from 'rxjs';
|
||||||
|
|
||||||
export interface nopeObserver {
|
export interface nopeObserver {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type NopePartialObserver<T> = NextObserver<T> & nopeObserver | ErrorObserver<T> & nopeObserver | CompletionObserver<T> & nopeObserver;
|
export declare type NopePartialObserver<T> = NextObserver<T> & nopeObserver | ErrorObserver<T> & nopeObserver | CompletionObserver<T> & nopeObserver;
|
||||||
|
export type pipe<T, K> = (scope: { [index: string]: any }, observable: Observable<T>) => Observable<K>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RsJX based Observable.
|
* RsJX based Observable.
|
||||||
@ -119,4 +122,28 @@ export class nopeObservable<T> extends BehaviorSubject<T> {
|
|||||||
|
|
||||||
return super.subscribe(_observerOrNext, _error, _complete);
|
return super.subscribe(_observerOrNext, _error, _complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to enhance the Subscription
|
||||||
|
* @param next Method, that will be called on next.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
public enhancedSubscribe<K>(next: (data: K) => void, options: {
|
||||||
|
scope?: { [index: string]: any },
|
||||||
|
pipe?: pipe<T, K>
|
||||||
|
} = {}) {
|
||||||
|
|
||||||
|
let observable: Observable<K> = this as any as Observable<K>;
|
||||||
|
if (options.pipe) {
|
||||||
|
observable = options.pipe(options.scope, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscription = observable.subscribe({
|
||||||
|
next
|
||||||
|
});
|
||||||
|
|
||||||
|
const unsubscribe = () => { subscription.unsubscribe(); }
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}
|
||||||
}
|
}
|
70
lib/observables/nopeRemoteObservable.ts
Normal file
70
lib/observables/nopeRemoteObservable.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { nopeDispatcher } from "../dispatcher/nopeDispatcher";
|
||||||
|
import { pipe } from "./nopeObservable";
|
||||||
|
|
||||||
|
|
||||||
|
export class nopeRemoteObservable<T> {
|
||||||
|
protected _currentLocalValue: T;
|
||||||
|
protected _pathes: {
|
||||||
|
get: string,
|
||||||
|
set: string,
|
||||||
|
subscribe: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the Current Value.
|
||||||
|
*/
|
||||||
|
public get currentLocalValue(): T {
|
||||||
|
return this._currentLocalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for the Current value.
|
||||||
|
*/
|
||||||
|
public set currentLocalValue(value: T) {
|
||||||
|
this.setRemoteValue(value).catch(e => {
|
||||||
|
// Catch the Error an rethrow it.
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Remote Dispatcher.
|
||||||
|
* @param _dispatcher
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
protected _dispatcher: nopeDispatcher,
|
||||||
|
public options: {
|
||||||
|
path: string,
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public get currentRemoteValue() {
|
||||||
|
return this.getRemoteValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRemoteValue() {
|
||||||
|
return await this._dispatcher.performCall<T>(this._pathes.get, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setRemoteValue(value: T) {
|
||||||
|
// Update the Local Value as Well
|
||||||
|
this._currentLocalValue = value;
|
||||||
|
// Perform an Update.
|
||||||
|
return await this._dispatcher.performCall<T>(this._pathes.set, [value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to Subscribe a NopeObservable on a Remote.
|
||||||
|
* @param next the callback, which will be called on new Data.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
public async subscribe<K>(next: (data: K) => void, options: {
|
||||||
|
scope?: { [index: string]: any },
|
||||||
|
pipe?: pipe<T, K>
|
||||||
|
} = {}) {
|
||||||
|
return await this._dispatcher.performCall<() => void>(this._pathes.subscribe, [next, options]);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
// Automatic Genearted File for Backendclass: "{{className}}"
|
// Automatic Genearted File for Backendclass: "{{className}}"
|
||||||
// To update run `npm run build:backend`
|
// To update run `npm run build:backend`
|
||||||
|
|
||||||
import { nopeDispatcher } from "../nopeDispatcher"
|
import { nopeDispatcher } from "../dispatcher/nopeDispatcher"
|
||||||
|
import { nopeRemoteObservable } from "../observables/nopeRemoteObservable"
|
||||||
|
|
||||||
{{!--
|
{{!--
|
||||||
/**
|
/**
|
||||||
@ -28,8 +29,17 @@ export interface IAnalyzeResult {
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
export class {{className}} {
|
export class {{className}} {
|
||||||
constructor(protected _dispatcher: nopeDispatcher){
|
|
||||||
|
|
||||||
|
{{#each properties}}
|
||||||
|
public {{name}}: nopeRemoteObservable<{{{simplifiedSubType}}}>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
constructor(protected _dispatcher: nopeDispatcher){
|
||||||
|
{{#each properties}}
|
||||||
|
this.{{name}} = new nopeRemoteObservable(_dispatcher,{
|
||||||
|
path: '{{uri}}'
|
||||||
|
})
|
||||||
|
{{/each}}
|
||||||
}
|
}
|
||||||
{{!--
|
{{!--
|
||||||
declaration: MethodDeclaration;
|
declaration: MethodDeclaration;
|
||||||
@ -47,7 +57,7 @@ export class {{className}} {
|
|||||||
{{{authorDescription}}}
|
{{{authorDescription}}}
|
||||||
public async {{name}}{{{head}}}{
|
public async {{name}}{{{head}}}{
|
||||||
// Perform the Method
|
// Perform the Method
|
||||||
return await this._dispatcher.performCall<{{{returnType.simplifiedSubType}}}>('{{../classDecorator.decoratorSettings.exportsElementsToDispatcher.uri}}/{{decoratorSettings.exportMethodToDispatcher.url}}', [{{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}])
|
return await this._dispatcher.performCall<{{{returnType.simplifiedSubType}}}>('{{uri}}', [{{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}])
|
||||||
}
|
}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
}
|
}
|
@ -9,17 +9,13 @@ export interface IF00 {
|
|||||||
hello: 'world'
|
hello: 'world'
|
||||||
}
|
}
|
||||||
|
|
||||||
@exportsElementsToOpenAPI({
|
@exportsElementsToOpenAPI({})
|
||||||
uri: 'test'
|
@exportsElementsToDispatcher({})
|
||||||
})
|
|
||||||
@exportsElementsToDispatcher({
|
|
||||||
uri: 'test'
|
|
||||||
})
|
|
||||||
export class CLWithInterface {
|
export class CLWithInterface {
|
||||||
@exportPropertyToDispatcher
|
@exportPropertyToDispatcher({})
|
||||||
exportedAttributeSimple = new nopeObservable<boolean>(false);
|
exportedAttributeSimple = new nopeObservable<boolean>(false);
|
||||||
|
|
||||||
@exportPropertyToDispatcher
|
@exportPropertyToDispatcher({})
|
||||||
exportedAttributeComplex = new nopeObservable<{
|
exportedAttributeComplex = new nopeObservable<{
|
||||||
element01: IF00,
|
element01: IF00,
|
||||||
num: number
|
num: number
|
||||||
@ -31,9 +27,7 @@ export class CLWithInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@exportMethodToOpenAPI({})
|
@exportMethodToOpenAPI({})
|
||||||
@exportMethodToDispatcher({
|
@exportMethodToDispatcher({})
|
||||||
url: 'exportedFunction'
|
|
||||||
})
|
|
||||||
async exportedFunctionShouldBeHosted(/* COMMENT */ a: IF00, b?: IF01) {
|
async exportedFunctionShouldBeHosted(/* COMMENT */ a: IF00, b?: IF01) {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
@ -45,9 +39,7 @@ export class CLWithInterface {
|
|||||||
* @param b Parameter b
|
* @param b Parameter b
|
||||||
*/
|
*/
|
||||||
@exportMethodToOpenAPI({})
|
@exportMethodToOpenAPI({})
|
||||||
@exportMethodToDispatcher({
|
@exportMethodToDispatcher({})
|
||||||
url: 'exportedFunction'
|
|
||||||
})
|
|
||||||
async exportedFunctionShouldNotBeHosted(/* COMMENT */ a: number, b: IF00, operator: (a: number, b: IF01) => Promise<{
|
async exportedFunctionShouldNotBeHosted(/* COMMENT */ a: number, b: IF00, operator: (a: number, b: IF01) => Promise<{
|
||||||
test: IF02,
|
test: IF02,
|
||||||
x: string
|
x: string
|
||||||
@ -64,9 +56,7 @@ export class CLWithInterface {
|
|||||||
* @param a Parameter a
|
* @param a Parameter a
|
||||||
* @param b Parameter b
|
* @param b Parameter b
|
||||||
*/
|
*/
|
||||||
@exportMethodToDispatcher({
|
@exportMethodToDispatcher({})
|
||||||
url: 'exportedStringFunction'
|
|
||||||
})
|
|
||||||
async exportedStringFunction(a: string, b: string) {
|
async exportedStringFunction(a: string, b: string) {
|
||||||
// Comment etc.
|
// Comment etc.
|
||||||
return "";
|
return "";
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"downlevelIteration": true
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"stripInternal": true,
|
"stripInternal": true,
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true
|
||||||
"noEmit": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user