aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/framework/src/services')
-rw-r--r--sdnr/wt/odlux/framework/src/services/applicationApi.ts25
-rw-r--r--sdnr/wt/odlux/framework/src/services/applicationManager.ts36
-rw-r--r--sdnr/wt/odlux/framework/src/services/authenticationService.ts16
-rw-r--r--sdnr/wt/odlux/framework/src/services/index.ts4
-rw-r--r--sdnr/wt/odlux/framework/src/services/notificationService.ts137
-rw-r--r--sdnr/wt/odlux/framework/src/services/restAccessorService.ts76
-rw-r--r--sdnr/wt/odlux/framework/src/services/restService.ts29
-rw-r--r--sdnr/wt/odlux/framework/src/services/snackbarService.ts5
8 files changed, 328 insertions, 0 deletions
diff --git a/sdnr/wt/odlux/framework/src/services/applicationApi.ts b/sdnr/wt/odlux/framework/src/services/applicationApi.ts
new file mode 100644
index 000000000..bddfb24c6
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/applicationApi.ts
@@ -0,0 +1,25 @@
+import { ApplicationStore } from '../store/applicationStore';
+
+
+let resolveApplicationStoreInitialized: (store: ApplicationStore) => void;
+let applicationStore: ApplicationStore | null = null;
+const applicationStoreInitialized: Promise<ApplicationStore> = new Promise((resolve) => resolveApplicationStoreInitialized = resolve);
+
+export const setApplicationStore = (store: ApplicationStore) => {
+ if (!applicationStore && store) {
+ applicationStore = store;
+ resolveApplicationStoreInitialized(store);
+ }
+}
+
+export const applicationApi = {
+ get applicationStore(): ApplicationStore | null {
+ return applicationStore;
+ },
+
+ get applicationStoreInitialized(): Promise<ApplicationStore> {
+ return applicationStoreInitialized;
+ }
+};
+
+export default applicationApi; \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/services/applicationManager.ts b/sdnr/wt/odlux/framework/src/services/applicationManager.ts
new file mode 100644
index 000000000..b7a6f2efc
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/applicationManager.ts
@@ -0,0 +1,36 @@
+import { ApplicationInfo } from '../models/applicationInfo';
+import { Event } from '../common/event';
+
+import { applicationApi } from './applicationApi';
+
+/** Represents registry to manage all applications. */
+class ApplicationManager {
+
+ /** Stores all registerd applications. */
+ private _applications: { [key: string]: ApplicationInfo };
+
+ /** Initializes a new instance of this class. */
+ constructor() {
+ this._applications = {};
+ this.changed = new Event<void>();
+ }
+
+ /** The chaged event will fire if the registration has changed. */
+ public changed: Event<void>;
+
+ /** Registers a new application. */
+ public registerApplication(applicationInfo: ApplicationInfo) {
+ this._applications[applicationInfo.name] = applicationInfo;
+ this.changed.invoke();
+ return applicationApi;
+ }
+
+ /** Gets all registered applications. */
+ public get applications() {
+ return this._applications;
+ }
+}
+
+/** A singleton instance of the application manager. */
+export const applicationManager = new ApplicationManager();
+export default applicationManager; \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/services/authenticationService.ts b/sdnr/wt/odlux/framework/src/services/authenticationService.ts
new file mode 100644
index 000000000..5e6fc81a8
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/authenticationService.ts
@@ -0,0 +1,16 @@
+function timeout(ms:number) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+class AuthenticationService {
+ public async authenticateUser(email: string, password: string) : Promise<string | null> {
+ await timeout(650);
+ if (email === "max@odlux.com" && password === "geheim") {
+ return "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPRExVWCIsImlhdCI6MTUzODQ2NDMyMCwiZXhwIjoxNTcwMDAwMzIwLCJhdWQiOiJsb2NhbGhvc3QiLCJzdWIiOiJsb2NhbGhvc3QiLCJmaXJzdE5hbWUiOiJNYXgiLCJsYXN0TmFtZSI6Ik11c3Rlcm1hbm4iLCJlbWFpbCI6Im1heEBvZGx1eC5jb20iLCJyb2xlIjpbInVzZXIiLCJhZG1pbiJdfQ.9e5hDi2uxmIXNwHkJoScBZsHBk0jQ8CcZ7YIcZhDtuI"
+ }
+ return null;
+ }
+}
+
+export const authenticationService = new AuthenticationService();
+export default authenticationService; \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/services/index.ts b/sdnr/wt/odlux/framework/src/services/index.ts
new file mode 100644
index 000000000..2bff79ac6
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/index.ts
@@ -0,0 +1,4 @@
+export { applicationManager } from './applicationManager';
+export { subscribe, unsubscribe } from './notificationService';
+export { requestRest } from './restService';
+
diff --git a/sdnr/wt/odlux/framework/src/services/notificationService.ts b/sdnr/wt/odlux/framework/src/services/notificationService.ts
new file mode 100644
index 000000000..242a6c03b
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/notificationService.ts
@@ -0,0 +1,137 @@
+import * as X2JS from 'x2js';
+
+const socketUrl = [ location.protocol === 'https:' ? 'wss://' : 'ws://', 'admin', ':', 'admin', '@', location.hostname, ':',location.port,'/websocket'].join('');
+const subscriptions: { [scope: string]: SubscriptionCallback[] } = { };
+
+export interface IFormatedMessage {
+ notifType: string | null;
+ time: string;
+}
+
+export type SubscriptionCallback<TMessage extends IFormatedMessage = IFormatedMessage> = (msg: TMessage) => void;
+
+function formatData(event: MessageEvent) : IFormatedMessage | undefined {
+
+ var x2js = new X2JS();
+ var jsonObj: { [key: string]: IFormatedMessage } = x2js.xml2js(event.data);
+ if (jsonObj && typeof (jsonObj) === 'object') {
+
+ const notifType = Object.keys(jsonObj)[0];
+ const formated = jsonObj[notifType];
+ formated.notifType = notifType ;
+ formated.time = new Date().toISOString();
+ return formated;
+ }
+ return undefined;
+
+}
+
+export function subscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
+ return socketReady.then((notificationSocket) => {
+ const scopes = scope instanceof Array ? scope : [scope];
+
+ // send all new scopes to subscribe
+ const newScopesToSubscribe: string[] = scopes.reduce((acc: string[], cur: string) => {
+ const currentCallbacks = subscriptions[cur];
+ if (currentCallbacks) {
+ if (!currentCallbacks.some(c => c === callback)) {
+ currentCallbacks.push(callback);
+ }
+ } else {
+ subscriptions[cur] = [callback];
+ acc.push(cur);
+ }
+ return acc;
+ }, []);
+
+ if (newScopesToSubscribe.length === 0) {
+ return true;
+ }
+
+ // send a subscription to all active scopes
+ const scopesToSubscribe = Object.keys(subscriptions);
+ if (notificationSocket.readyState === notificationSocket.OPEN) {
+ const data = {
+ 'data': 'scopes',
+ 'scopes': scopesToSubscribe
+ };
+ notificationSocket.send(JSON.stringify(data));
+ return true;
+ }
+ return false;
+ });
+}
+
+export function unsubscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
+ return socketReady.then((notificationSocket) => {
+ const scopes = scope instanceof Array ? scope : [scope];
+ scopes.forEach(s => {
+ const callbacks = subscriptions[s];
+ const index = callbacks && callbacks.indexOf(callback);
+ if (index > -1) {
+ callbacks.splice(index, 1);
+ }
+ if (callbacks.length === 0) {
+ subscriptions[s] === undefined;
+ }
+ });
+
+ // send a subscription to all active scopes
+ const scopesToSubscribe = Object.keys(subscriptions);
+ if (notificationSocket.readyState === notificationSocket.OPEN) {
+ const data = {
+ 'data': 'scopes',
+ 'scopes': scopesToSubscribe
+ };
+ notificationSocket.send(JSON.stringify(data));
+ return true;
+ }
+ return false;
+ });
+}
+
+const connect = (): Promise<WebSocket> => {
+ return new Promise((resolve, reject) => {
+ const notificationSocket = new WebSocket(socketUrl);
+
+ notificationSocket.onmessage = (event) => {
+ // process received event
+ if (typeof event.data === 'string') {
+ const formated = formatData(event);
+ if (formated && formated.notifType) {
+ const callbacks = subscriptions[formated.notifType];
+ if (callbacks) {
+ callbacks.forEach(cb => {
+ // ensure all callbacks will be called
+ try {
+ return cb(formated);
+ } catch (reason) {
+ console.error(reason);
+ }
+ });
+ }
+ }
+ }
+ };
+
+ notificationSocket.onerror = function (error) {
+ console.log("Socket error: " + error);
+ reject("Socket error: " + error);
+ };
+
+ notificationSocket.onopen = function (event) {
+ console.log("Socket connection opened.");
+ resolve(notificationSocket);
+ };
+
+ notificationSocket.onclose = function (event) {
+ socketReady = connect();
+ };
+ });
+}
+
+let socketReady = connect();
+
+
+
+
diff --git a/sdnr/wt/odlux/framework/src/services/restAccessorService.ts b/sdnr/wt/odlux/framework/src/services/restAccessorService.ts
new file mode 100644
index 000000000..66bf12b15
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/restAccessorService.ts
@@ -0,0 +1,76 @@
+import * as $ from 'jquery';
+import { Action, IActionHandler } from '../flux/action';
+import { MiddlewareArg } from '../flux/middleware';
+import { Dispatch } from '../flux/store';
+
+import { IApplicationStoreState } from '../store/applicationStore';
+import { AddErrorInfoAction, ErrorInfo } from '../actions/errorActions';
+import { PlainObject, AjaxParameter } from 'models/restService';
+
+export const absoluteUri = /^(https?:\/\/|blob:)/i;
+export const baseUrl = `${ window.location.origin }${ window.location.pathname }`;
+
+class RestBaseAction extends Action { }
+
+export const createRestApiAccessor = <TResult extends PlainObject>(urlOrPath: string, initialValue: TResult) => {
+ const isLocalRequest = !absoluteUri.test(urlOrPath);
+ const uri = isLocalRequest ? `${ baseUrl }/${ urlOrPath }`.replace(/\/{2,}/, '/') : urlOrPath ;
+
+ class RestRequestAction extends RestBaseAction { constructor(public settings?: AjaxParameter) { super(); } }
+
+ class RestResponseAction extends RestBaseAction { constructor(public result: TResult) { super(); } }
+
+ class RestErrorAction extends RestBaseAction { constructor(public error?: Error | string) { super(); } }
+
+ type RestAction = RestRequestAction | RestResponseAction | RestErrorAction;
+
+ /** Represents our middleware to handle rest backend requests */
+ const restMiddleware = (api: MiddlewareArg<IApplicationStoreState>) =>
+ (next: Dispatch) => (action: RestAction): RestAction => {
+
+ // pass all actions through by default
+ next(action);
+ // handle the RestRequestAction
+ if (action instanceof RestRequestAction) {
+ const state = api.getState();
+ const authHeader = isLocalRequest && state && state.framework.authenticationState.user && state.framework.authenticationState.user.token
+ ? { "Authentication": "Bearer " + state.framework.authenticationState.user.token } : { };
+ $.ajax({
+ url: uri,
+ method: (action.settings && action.settings.method) || "GET",
+ headers: { ...authHeader, ...action.settings && action.settings.headers ? action.settings.headers : { } },
+ }).then((data: TResult) => {
+ next(new RestResponseAction(data));
+ }).catch((err: any) => {
+ next(new RestErrorAction());
+ next(new AddErrorInfoAction((err instanceof Error) ? { error: err } : { message: err.toString() }));
+ });
+ }
+ // allways return action
+ return action;
+ };
+
+ /** Represents our action handler to handle our actions */
+ const restActionHandler: IActionHandler<TResult> = (state = initialValue, action) => {
+ if (action instanceof RestRequestAction) {
+ return {
+ ...(state as any),
+ busy: true
+ };
+ } else if (action instanceof RestResponseAction) {
+ return action.result;
+ } else if (action instanceof RestErrorAction) {
+ return initialValue;
+ }
+ return state;
+ };
+
+ return {
+ requestAction: RestRequestAction,
+ actionHandler: restActionHandler,
+ middleware: restMiddleware,
+ };
+}
+
+
+
diff --git a/sdnr/wt/odlux/framework/src/services/restService.ts b/sdnr/wt/odlux/framework/src/services/restService.ts
new file mode 100644
index 000000000..83c005c13
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/restService.ts
@@ -0,0 +1,29 @@
+
+const baseUri = `${ window.location.origin }`;
+const absUrlPattern = /^https?:\/\//;
+
+export async function requestRest<TData>(path: string = '', init: RequestInit = {}, authenticate: boolean = false): Promise<TData|false|null> {
+ const isAbsUrl = absUrlPattern.test(path);
+ const uri = isAbsUrl ? path : (baseUri) + ('/' + path).replace(/\/{2,}/i, '/');
+ init.headers = {
+ 'method': 'GET',
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ ...init.headers
+ };
+ if (!isAbsUrl && authenticate) {
+ init.headers = {
+ ...init.headers,
+ 'Authorization': 'Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=='
+ };
+ }
+ const result = await fetch(uri, init);
+ const contentType = result.headers.get("Content-Type") || result.headers.get("content-type");
+ const isJson = contentType && contentType.toLowerCase().startsWith("application/json");
+ try {
+ const data = result.ok && (isJson ? await result.json() : await result.text()) as TData ;
+ return data;
+ } catch {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/services/snackbarService.ts b/sdnr/wt/odlux/framework/src/services/snackbarService.ts
new file mode 100644
index 000000000..a8bbf1602
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/services/snackbarService.ts
@@ -0,0 +1,5 @@
+import { OptionsObject } from "notistack";
+
+export const snackbarService = {
+ enqueueSnackbar: (message: string, options?: OptionsObject) =>{ }
+} \ No newline at end of file