Prodress Connection fertig implementiert

This commit is contained in:
Nils 2025-05-31 21:55:23 +02:00
parent 7e892e8c42
commit b1f264424c
4 changed files with 218 additions and 49 deletions

View File

@ -1,8 +1,6 @@
import {app, BrowserWindow} from 'electron';
import {Socket} from 'net';
import path from 'path';
import {R2RequestErweiterungsdaten, R2RequestKopfdaten, Request, RequestLeser} from '@prodress/pdr2com';
import {ProdressRequest} from './pdr2com/wrapper.js';
import {ProdressConnection} from './pdr2com/connection.js';
const APPLICATION_PATH = path.join(app.getAppPath(), '/dist-svelte/index.html');
@ -14,23 +12,39 @@ app.on('ready', async () => {
mainWindow.loadFile(APPLICATION_PATH);
}
try {
const socket = new Socket();
socket.connect(4788, 'localhost');
const test = new ProdressRequest('db', 'handler', 'aktion', {});
test.schreibeText('HalloWelt 2355435');
socket.on('connect', () => {
console.log('verbunden');
test.sende(socket);
});
const r2reader = new RequestLeser();
socket.on('data', (data: Buffer) => {
r2reader.verarbeiteDaten(data);
});
const r2request = await r2reader.leseRequest();
console.log(r2request.nächsterText());
} catch (error) {
console.error(error);
}
const req = new ProdressConnection(
{
port: 4788,
host: 'localhost',
database: 'test',
handler: 'Shopify',
action: 'artikelSync',
},
[['string', 'HalloWelt']],
[
['line1', 'string'],
['line2', 'string'],
],
);
const res = await req.handleRequest();
console.log(res);
// try {
// const socket = new Socket();
// socket.connect(4788, 'localhost');
//
// const test = new ProdressRequest('db', 'handler', 'aktion');
// test.schreibeText('HalloWelt 2355435');
// socket.on('connect', () => {
// console.log('verbunden');
// test.sende(socket);
// });
// const r2reader = new RequestLeser();
// socket.on('data', (data: Buffer) => {
// r2reader.verarbeiteDaten(data);
// });
// const r2request = await r2reader.leseRequest();
// console.log(r2request.nächsterText());
// } catch (error) {
// console.error(error);
// }
});

View File

@ -0,0 +1,139 @@
import {RequestLeser as ProdressListener, type R2AnfrageBlaupause} from '@prodress/pdr2com';
import {type ResponseTupel, type ResponseObject, ProdressRequest, type RequestTupel} from './wrapper.js';
import {Socket} from 'node:net';
export interface ProdressHeader {
port?: number;
host?: string;
database: string;
handler: string;
action: string;
}
// @todo move to nyi utils file
function stringifyError(error: Error): string {
const {message, stack} = error;
return JSON.stringify(
{
message,
stack,
},
null,
2,
);
}
export class ProdressConnection {
public static readonly TIMEOUT = 30_000;
private port: number;
private host: string;
private socket: Socket;
private request: ProdressRequest;
private listener: ProdressListener;
private requestTupelList: RequestTupel[];
private responseTupelList: ResponseTupel[];
public constructor(header: ProdressHeader, requestTupelList: RequestTupel[], responseTupelList: ResponseTupel[]) {
this.port = header.port ?? 4788;
this.host = header.host ?? 'localhost';
this.socket = new Socket();
this.request = new ProdressRequest(header.database, header.handler, header.action);
this.listener = new ProdressListener();
this.requestTupelList = requestTupelList;
this.responseTupelList = responseTupelList;
}
public async handleRequest(): Promise<string> {
let response: string = '';
const responseAsPromise = new Promise<string>((resolve) => {
this.socket.once('finished', () => {
if (!this.socket.destroyed) {
this.socket.destroy();
}
resolve(response);
});
});
this.socket.setTimeout(ProdressConnection.TIMEOUT);
this.socket.connect(this.port, this.host);
this.socket.once('connect', () => {
try {
this.request.writeEntries(this.requestTupelList);
this.request.sende(this.socket);
} catch (error) {
response = stringifyError(error as Error);
this.finished();
}
});
// @todo Rework Error Message
this.socket.on('timeout', () => {
const timeoutError = new Error('timeout');
response = stringifyError(timeoutError);
this.finished();
});
this.socket.on('error', (error: Error) => {
response = stringifyError(error);
this.finished();
});
this.socket.on('data', (data: Buffer) => {
this.listener.verarbeiteDaten(data);
this.socket.emit('dataRecieved');
});
this.socket.once('dataRecieved', async () => {
try {
const incomingResponse = await this.listener.leseRequest();
const responseObject = this.readResponse(incomingResponse);
response = JSON.stringify(responseObject, null, 2);
this.finished();
} catch (error) {
response = stringifyError(error as Error);
this.finished();
}
});
return responseAsPromise;
}
private finished(): void {
this.socket.emit('finished');
}
/**
* reads the Reponse based on the provided responseTupelList and creates a ResponseObject
* @param responseInstance The Listener Instance of the active TCP Socket
* @returns ResponseObject
*/
private readResponse(responseInstance: R2AnfrageBlaupause): ResponseObject {
const response: ResponseObject = {};
for (const tupel of this.responseTupelList) {
const [key, type] = tupel;
switch (type) {
case 'string':
response[key] = responseInstance.nächsterText();
break;
case 'integer':
response[key] = responseInstance.nächsteGanzzahl();
break;
case 'float':
response[key] = responseInstance.nächsteDezimalzahl();
break;
case 'date':
response[key] = responseInstance.nächstesDatum();
break;
case 'date_time':
//@todo missing method in lib
response[key] = responseInstance.nächstesDatum();
break;
}
}
return response;
}
}

View File

@ -8,32 +8,18 @@ export interface DataTypeConversion {
date_time: () => Date | null;
}
export interface ReponseSchema {
readonly [key: string]: keyof DataTypeConversion;
export interface ResponseObject {
[key: string]: ReturnType<DataTypeConversion[keyof DataTypeConversion]>;
}
export type ResponseTupel = [string, keyof DataTypeConversion];
export type RequestTupel = {
[K in keyof DataTypeConversion]: [K, NonNullable<ReturnType<DataTypeConversion[K]>>];
}[keyof DataTypeConversion];
export class ProdressRequest extends Request {
/**
* Mapping of a datatype to the correspondig read method
*/
public readonly responseSchemaConversion: DataTypeConversion = {
string: this.nächsterText,
integer: this.nächsteGanzzahl,
float: this.nächsteDezimalzahl,
date: this.nächstesDatum,
date_time: this.nächstesDatumMitZeit,
} as const;
/**
* Definition of the Reponse
*/
public readonly responseSchema: ReponseSchema;
public constructor(db: string, handler: string, action: string, responseSchema: ReponseSchema) {
public constructor(db: string, handler: string, action: string) {
super(
{
interneProtokollVersion: 1,
@ -55,6 +41,40 @@ export class ProdressRequest extends Request {
maximalePaketgröße: 0,
},
);
this.responseSchema = responseSchema;
}
/**
* writes entries based on the provided requestTupelList into the request
* @param requestTupelList
*/
public writeEntries(requestTupelList: RequestTupel[]): void {
for (const tupel of requestTupelList) {
this.writeEntry(tupel);
}
}
/**
* writes an entry based on the provided requestTupel into the request
* @param requestTupel
*/
public writeEntry(requestTupel: RequestTupel): void {
const [type, value] = requestTupel;
switch (type) {
case 'string':
this.schreibeText(value);
break;
case 'integer':
this.schreibeGanzzahl(value);
break;
case 'float':
this.schreibeDezimalzahl(value);
break;
case 'date':
this.schreibeDatum(value);
break;
case 'date_time':
this.schreibeDatumMitZeit(value);
break;
}
}
}

View File

@ -1,16 +1,12 @@
{
"compilerOptions": {
// require strict types (null-save)
"strict": true,
// tell TypeScript to generate ESM Syntax
"target": "ESNext",
// tell TypeScript to require ESM Syntax as input (including .js file imports)
"module": "NodeNext",
// define where to put generated JS
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"outDir": "../../dist-electron",
// ignore errors from dependencies
"skipLibCheck": true,
// add global types
"skipLibCheck": true
//"types": ["../../types"]
}
}