Fixing Bridge

This commit is contained in:
Martin Karkowski 2021-04-20 20:49:15 +02:00
parent cb5fb7c808
commit 20d8d313f0
13 changed files with 368 additions and 130 deletions

View File

@ -63,11 +63,11 @@ const UNSPECIFIC_TO_METHODS: {
subscribe: keyof ICommunicationInterface;
};
} = {
aurevoir: {
Aurevoir: {
emit: "emitAurevoir",
subscribe: "onAurevoir"
},
bonjour: {
Bonjour: {
emit: "emitBonjour",
subscribe: "onBonjour"
},
@ -102,7 +102,11 @@ const LAYER_METHOD_TO_EVENT: {
} = {
// Specific:
onEvent: "event/",
emitEvent: "event/"
emitEvent: "event/",
onRpcRequest: "",
emitRpcRequest: "",
onRpcResponse: "",
emitRpcResponse: ""
};
for (const eventName in UNSPECIFIC_TO_METHODS) {
@ -117,12 +121,12 @@ const MIRROR_METHOD_TO_EVENT: {
[P in keyof ICommunicationInterface]: ValidEventTypesOfMirror;
} = copy(LAYER_METHOD_TO_EVENT) as any;
MIRROR_METHOD_TO_EVENT.onEvent = "event";
MIRROR_METHOD_TO_EVENT.emitEvent = "event";
MIRROR_METHOD_TO_EVENT.onRpcRequest = "rpcRequest";
MIRROR_METHOD_TO_EVENT.emitRpcRequest = "rpcRequest";
MIRROR_METHOD_TO_EVENT.onRpcResponse = "rpcResponse";
MIRROR_METHOD_TO_EVENT.emitRpcResponse = "rpcResponse";
MIRROR_METHOD_TO_EVENT.onEvent = "Event";
MIRROR_METHOD_TO_EVENT.emitEvent = "Event";
MIRROR_METHOD_TO_EVENT.onRpcRequest = "RpcRequest";
MIRROR_METHOD_TO_EVENT.emitRpcRequest = "RpcRequest";
MIRROR_METHOD_TO_EVENT.onRpcResponse = "RpcResponse";
MIRROR_METHOD_TO_EVENT.emitRpcResponse = "RpcResponse";
const MIRROR_EVENT_TO_EMIT: {
[P in keyof ValidEventTypesOfMirror]: keyof ICommunicationInterface;
@ -143,28 +147,6 @@ const OFF_METHODS: Array<keyof ICommunicationInterface> = [
"offRpcResponse"
];
const MAPPING_METHODS: {
[P in keyof ICommunicationInterface]: keyof ICommunicationInterface;
} = {
onAurevoir: "emitAurevoir",
onBonjour: "emitBonjour",
onEvent: "emitEvent",
onNewInstanceGeneratorsAvailable: "emitNewInstanceGeneratorsAvailable",
onNewInstancesAvailable: "emitNewInstancesAvailable",
onNewObservablesAvailable: "emitNewObersvablesAvailable",
onNewServicesAvailable: "emitNewServicesAvailable",
onRpcRequest: "emitRpcRequest",
onRpcResponse: "emitRpcResponse",
onTaskCancelation: "emitTaskCancelation",
onStatusUpdate: "emitStatusUpdate"
};
const METHODS_WITH_NAME: Array<keyof ICommunicationInterface> = [
"onRpcResponse",
"onRpcRequest",
"onEvent"
];
//@ts-ignore Ignore the Interface. Its implemented manually
export class Bridge implements ICommunicationBridge {
public connected: INopeObservable<boolean>;
@ -243,6 +225,8 @@ export class Bridge implements ICommunicationBridge {
for (const method of EMITTING_METHODS) {
const eventName = LAYER_METHOD_TO_EVENT[method];
this[method] = async (data) => {
if (method !== "emitStatusUpdate")
console.log("emitting", method, eventName, data);
_this._emit(eventName, null, data);
};
}
@ -291,7 +275,7 @@ export class Bridge implements ICommunicationBridge {
): void {
const _this = this;
if (METHODS_WITH_NAME.includes(method)) {
if (ON_SPECIFIC_METHODS.includes(method)) {
layer[method as any](event, (data) => {
// Define the Method to Forward data.
_this._internalEmitter.emit(event, data);
@ -424,7 +408,7 @@ export class Bridge implements ICommunicationBridge {
toExclude: ICommunicationInterface | ICommunicationMirror = null,
dataToSend: any
): void {
if (this._logger.enabledFor(Logger.DEBUG) && eventName !== "StatusUpdate") {
if (this._logger.enabledFor(Logger.WARN) && eventName !== "StatusUpdate") {
this._logger.debug("emitting", eventName, dataToSend);
}
// Emit the Event on the internal Layer.
@ -584,14 +568,7 @@ export class Bridge implements ICommunicationBridge {
UNSPECIFIC_TO_METHODS[eventName].emit
);
}
// Now Forward the Data.
console.log(
"Fowarding",
eventName,
"->",
MIRROR_EVENT_TO_EMIT[eventName]
);
_this._emit(eventName, mirror, data);
});
} else {

View File

@ -9,21 +9,22 @@
import * as io from "socket.io";
import { getNopeLogger } from "../../logger/getLogger";
import { LoggerLevel } from "../../logger/nopeLogger";
import { ValidEventTypesOfMirror } from "../../types/nope/nopeCommunication.interface";
import { EventMirror } from "./eventMirror";
const EVENTS_TO_FORWARD: Set<string> = new Set([
const EVENTS_TO_FORWARD: Set<ValidEventTypesOfMirror> = new Set([
// Default emitters
"aurevoir",
"bonjour",
"Aurevoir",
"Bonjour",
"NewInstanceGeneratorsAvailable",
"NewInstancesAvailable",
"NewObersvablesAvailable",
"NewServicesAvailable",
"StatusUpdate",
"TaskCancelation",
"event",
"rpcRequest",
"rpcResponse"
"Event",
"RpcRequest",
"RpcResponse"
]);
/**
@ -69,6 +70,7 @@ export class IoSocketMirrorServer extends EventMirror {
// are forwarding the data.
for (const event of EVENTS_TO_FORWARD) {
client.on(event, (data) => {
if (event !== "StatusUpdate") console.log("Forwarding", event, data);
_this._forward(client, event, data);
});
}

View File

@ -141,8 +141,11 @@ export class NopeBaseModule implements INopeModule {
this.identifier = null;
this._registeredFunctions = new Map();
this._registeredProperties = new Map();
this.uiLinks = [];
}
public uiLinks: { name: string; description: string; link: string }[];
/**
* Helper Function to register an Observable (a Property.)
*
@ -401,7 +404,8 @@ export class NopeBaseModule implements INopeModule {
identifier: this.identifier,
properties: this.properties,
type: this.type,
version: this.version
version: this.version,
uiLinks: this.uiLinks
};
return ret;

View File

@ -338,17 +338,17 @@ export interface ICommunicationBridge extends ICommunicationInterface {
export type ValidEventTypesOfMirror =
// Default emitters
| "aurevoir"
| "bonjour"
| "Aurevoir"
| "Bonjour"
| "NewInstanceGeneratorsAvailable"
| "NewInstancesAvailable"
| "NewObersvablesAvailable"
| "NewServicesAvailable"
| "StatusUpdate"
| "TaskCancelation"
| "event"
| "rpcRequest"
| "rpcResponse";
| "Event"
| "RpcRequest"
| "RpcResponse";
export const ValidEventTypesOfMirror = [
// Default emitters

View File

@ -81,6 +81,8 @@ export interface INopeModuleDescription {
readonly functions: { [index: string]: IFunctionOptions };
readonly properties: { [index: string]: IPropertyOptions };
readonly uiLinks: Array<{ name: string; description: string; link: string }>;
}
export interface INopeModule extends INopeModuleDescription {

View File

@ -192,7 +192,7 @@ export class WaMOBaseModule
}) => Promise<string | false>,
resetPlc = true,
autoStart = true,
demo = false,
demo = false
): Promise<void> {
// Define the Author.
this.author = {
@ -308,7 +308,11 @@ export class WaMOBaseModule
// Only if there exists a Carrier, proceed.
if (value) {
if (demo) {
// Demo-Mode
// Wait 10 Seconds at least spend additional 0-5000 Seconds
await sleep(Math.random() * 5000 + 10 * 1000);
} else {
let tasks: MESTask[] = _this._xetics.availableTasks.getContent();
// Only if no tasks are available, try to update the
@ -328,30 +332,28 @@ export class WaMOBaseModule
// Try to assign the new Task for the Product
if (
!demo &&
productToStartTaskWith &&
_this._xetics.selectTaskForProduct(productToStartTaskWith)
(await _this._xetics.selectTaskForProduct(
productToStartTaskWith
))
) {
// We are not running in the demo-mode and we have
// a task to start, which we are able to select.
await _this.performCurrentTask();
} else if (demo) {
// Demo-Mode
// Wait 10 Seconds at least spend additional 0-5000 Seconds
await sleep(Math.random() * 5000 + 10*1000);
}
}
// Now we are done or we dont have a task.
// we release the carrier and wait for a new
// product.
await _this.releaseCarrier();
} else {
// Updating the State of the System. The System
// Waits for a new Carrier
const baseInformation = copy(_this.baseInformation.getContent());
baseInformation.logical.currentState =
"waiting";
const baseInformation = copy(
_this.baseInformation.getContent()
);
baseInformation.logical.currentState = "waiting";
_this.baseInformation.setContent(baseInformation);
}
} catch (e) {
@ -735,7 +737,6 @@ export class WaMOBaseModule
observers = [
// Subscribe to the connectorReplica of the Process Module.
_this._processModule.connector.subscribe((value) => {
// If we have waited to finish a Task, we are able
// to proceed with the task.
if (value.active == false && first == false) {
@ -750,7 +751,9 @@ export class WaMOBaseModule
first = false;
}
}),
_this._plc.dynamicInstanceProperties["input.GVL_IOS.bInputTasterQuittieren"].subscribe((value) => {
_this._plc.dynamicInstanceProperties[
"input.GVL_IOS.bInputTasterQuittieren"
].subscribe((value) => {
console.log("bInputTasterQuittieren =>", value);
if (value) {
// Unsubscribe the Observer

View File

@ -93,14 +93,16 @@ export class WaMOCarrierMapper
// Define the File Name. It is based on the identifier.
this._file = join(_path, this.identifier + "_file.json");
// Now Test if the File exists:
if (!(await exists(this._file))) {
this._logger.warn("No configuration File defined. Creating a new one under:",this._file);
this.carriers.setContent([]);
this.mapping.setContent({});
// Now Test if the File exists:
if (!(await exists(this._file))) {
this._logger.warn(
"No configuration File defined. Creating a new one under:",
this._file
);
// Create an Empty File.
await this.storeConfig();
}
@ -133,10 +135,13 @@ export class WaMOCarrierMapper
paramsHasNoCallback: true
})
public async storeConfig() {
await createFile(this._file, JSON.stringify({
await createFile(
this._file,
JSON.stringify({
carriers: this.carriers.getContent(),
mapping: this.mapping.getContent()
}));
})
);
}
/**

View File

@ -241,13 +241,13 @@ export class XeticsInterfaceClient
})
async startCurrentTask() {
if (this.currentTask.getContent()) {
// We have to consinder, whether the job is allready active or not
if (this.taskActive.getContent()) {
console.log("already active");
return true;
}
return startTask(
return await startTask(
this._station,
this.currentTask.getContent().id,
this._user,
@ -277,7 +277,9 @@ export class XeticsInterfaceClient
// Call the Finish-Task Operation. Use the parameters of the current Task.
// Returns the sucess of the Operation.
if (this._logger) {
this._logger.info("Finishing Task " + this.currentTask.getContent().id.toString());
this._logger.info(
"Finishing Task " + this.currentTask.getContent().id.toString()
);
}
const finished = await finishTask(
@ -328,6 +330,9 @@ export class XeticsInterfaceClient
this._uri,
this._token
);
console.log(this.identifier, "got active tasks", activeTasks);
if (activeTasks.length > 0) {
// If there are multiple Tasks.
this.currentTask.setContent(activeTasks[0]);

View File

@ -10,6 +10,8 @@ import React from "react";
import { Card, ListGroup, Table } from "react-bootstrap";
import { ENopeDispatcherStatus } from "../../../lib/types/nope/nopeDispatcher.interface";
import { INopeModuleDescription } from "../../../lib/types/nope/nopeModule.interface";
import { CustomIFrame } from "../../ui/iframe";
import { StaticPopup } from "../../ui/popup/component";
import { StatusBadgeComponent } from "../generic/StatusBadge";
type ValidColors = "danger" | "warning" | "info" | "success";
@ -31,6 +33,11 @@ export class InstanceDetailsComponent extends React.Component<
},
{
renderDetails: boolean;
customUiProps: {
name: string;
description: string;
link: string;
} | null;
variant: ValidColors;
}
> {
@ -63,7 +70,8 @@ export class InstanceDetailsComponent extends React.Component<
this.state = {
renderDetails: this.props.renderDetails,
variant: dict[this.props.description.status]
variant: dict[this.props.description.status],
customUiProps: null
};
}
@ -76,13 +84,17 @@ export class InstanceDetailsComponent extends React.Component<
});
}
shouldComponentUpdate() {
return this.state.customUiProps === null;
}
render(): JSX.Element {
const renderMethods =
Object.getOwnPropertyNames(this.props.description.functions).length > 0;
const renderProperties =
Object.getOwnPropertyNames(this.props.description.properties).length > 0;
return (
const elements = [
<Card border={this.state.variant}>
<Card.Body>
<Card.Title>
@ -112,8 +124,17 @@ export class InstanceDetailsComponent extends React.Component<
<td>UI</td>
<td>
<ListGroup>
{this.props.description.uiLinks?.map((link, idx) => (
<ListGroup.Item key={idx}>{link}</ListGroup.Item>
{this.props.description.uiLinks?.map((data, idx) => (
<ListGroup.Item
key={idx}
onClick={() => {
this.setState({
customUiProps: data
});
}}
>
{data.name}
</ListGroup.Item>
))}
</ListGroup>
</td>
@ -174,6 +195,47 @@ export class InstanceDetailsComponent extends React.Component<
</small>
</Card.Footer>
</Card>
];
if (this.state.customUiProps) {
elements.push(
<StaticPopup
content={{
component: () => {
return (
<CustomIFrame
link={this.state.customUiProps.link}
height={500}
></CustomIFrame>
);
},
props: {
link: this.state.customUiProps.link
}
}}
onHide={() => {
this.setState({ customUiProps: null });
}}
header={
"Visualization for " +
this.props.description.identifier +
" - " +
this.state.customUiProps.name
}
closeButton={true}
withoutBorder={false}
footer={
this.props.description.author.forename +
" " +
this.props.description.author.surename +
" is responsible for the content. Report Bugs to " +
this.props.description.author.mail
}
size="xl"
></StaticPopup>
);
}
return React.createElement("div", {}, ...elements);
}
}

80
resources/ui/iframe.tsx Normal file
View File

@ -0,0 +1,80 @@
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2021-04-20 18:51:42
* @modify date 2021-04-20 18:55:10
* @desc [description]
*/
import React from "react";
/**
* A Component, used to Render the Staus of a Host.
*
*/
export class CustomIFrame extends React.Component<
{
height?: number;
width?: number;
link: string;
altText?: string;
},
{
height: number;
width: number;
}
> {
ref: React.RefObject<HTMLDivElement>;
/**
* Create the Status to Render.
* @param props
*/
constructor(props) {
super(props);
this.ref = React.createRef();
this.state = {
height: 200,
width: 500
};
}
protected _handleResize: () => void;
componentDidMount() {
const _this = this;
this._handleResize = () => {
setTimeout(() => {
const size = {
width:
_this.props.width |
(_this.ref.current.parentElement.clientWidth - 40),
height:
_this.props.height |
(_this.ref.current.parentElement.clientHeight - 40)
};
console.log(size, _this.ref);
_this.setState(size);
}, 200);
};
this._handleResize();
window.addEventListener("resize", this._handleResize);
}
componentWillUnmount() {
window.removeEventListener("resize", this._handleResize);
}
render(): JSX.Element {
return (
<div ref={this.ref}>
<iframe
src={this.props.link}
height={this.state.height}
width={this.state.width}
></iframe>
</div>
);
}
}

View File

@ -1,13 +1,13 @@
import { IDynamicRenderSettings } from '../../dynamic/interfaces/IDynamicRenderSettings';
import { IDynamicRenderSettings } from "../../dynamic/interfaces/IDynamicRenderSettings";
export interface IModalSettings {
content: IDynamicRenderSettings;
backdrop?: 'staic' | boolean
centered?: boolean
backdrop?: "static" | boolean;
centered?: boolean;
header?: string;
size?: 'sm' | 'lg' | 'xl',
closeButton?: boolean,
closeLabel?: boolean,
size?: "sm" | "lg" | "xl";
closeButton?: boolean;
closeLabel?: boolean;
onHide?: (closeCallback: () => void) => void;
renderInBody?: boolean,
renderInBody?: boolean;
}

View File

@ -0,0 +1,72 @@
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2021-04-20 19:04:57
* @modify date 2021-04-20 19:04:57
* @desc [description]
*/
import React from "react";
import { Modal } from "react-bootstrap";
import DynamicRenderer from "../dynamic/dynamicRenderer";
import { IModalSettings } from "./interfaces/IModalSettings";
export class StaticPopup extends React.Component<
{ withoutBorder?: boolean } & IModalSettings
> {
/**
* Create the Status to Render.
* @param props
*/
constructor(props) {
super(props);
this.state = { modalVisible: true };
}
render(): JSX.Element {
return (
<Modal
show={true}
backdrop={
typeof this.props.backdrop !== undefined
? this.props.backdrop
: "static"
}
keyboard={false}
size={this.props.size}
centered={this.props.centered || false}
onHide={this.props.onHide}
scrollable
>
{this.props.header ? (
<Modal.Header closeButton={this.props.closeButton}>
<Modal.Title>{this.props.header}</Modal.Title>
</Modal.Header>
) : (
""
)}
{this.props.withoutBorder ? (
<DynamicRenderer
component={this.props.content.component}
props={this.props.content.props}
/>
) : (
<Modal.Body style={{ border: 0 }}>
{/* Render the dynamic Component */}
<DynamicRenderer
component={this.props.content.component}
props={this.props.content.props}
/>
</Modal.Body>
)}
{this.props.footer ? (
<Modal.Footer>{this.props.footer}</Modal.Footer>
) : (
""
)}
</Modal>
);
}
}

View File

@ -0,0 +1,26 @@
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2021-04-20 19:06:22
* @modify date 2021-04-20 19:06:28
* @desc [description]
*/
import { IDynamicRenderSettings } from "../../dynamic/interfaces/IDynamicRenderSettings";
export interface IModalSettings {
content: IDynamicRenderSettings;
backdrop?: "static" | boolean;
centered?: boolean;
header?: string;
size?: "sm" | "lg" | "xl";
closeButton?: boolean;
closeLabel?: boolean;
onHide?: (closeCallback: () => void) => void;
renderInBody?: boolean;
footer?:
| string
| React.Component
| React.FunctionComponent
| ((...args) => JSX.Element);
}