Skip to content

Commit 3bf1674

Browse files
author
Dennis Labordus
committed
Added support for Websocket to Data Service, including erro handling also for Validator.
Signed-off-by: Dennis Labordus <[email protected]>
1 parent d714f45 commit 3bf1674

File tree

7 files changed

+201
-102
lines changed

7 files changed

+201
-102
lines changed

src/compas-services/CompasSclDataService.ts

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { formatXml } from '../file.js';
22

33
import { CompasSettings } from '../compas/CompasSettings.js';
44
import {
5-
extractSclFromResponse,
5+
extractSclFromResponse, getWebsocketUri,
66
handleError,
77
handleResponse,
8-
parseXml,
8+
parseXml
99
} from './foundation.js';
10+
import { Websockets } from './Websockets.js';
1011

1112
export const SDS_NAMESPACE =
1213
'https://www.lfenergy.org/compas/SclDataService/v1';
@@ -30,14 +31,48 @@ export interface UpdateRequestBody {
3031
}
3132

3233
export function CompasSclDataService() {
33-
function getCompasSettings() {
34-
return CompasSettings().compasSettings;
34+
function getSclDataServiceUrl(): string {
35+
return CompasSettings().compasSettings.sclDataServiceUrl;
36+
}
37+
38+
function createCreateRequest(
39+
sclName: string,
40+
comment: string | null,
41+
doc: Document
42+
): string {
43+
return `<?xml version="1.0" encoding="UTF-8"?>
44+
<sds:CreateRequest xmlns:sds="${SDS_NAMESPACE}">
45+
<sds:Name>${sclName}</sds:Name>
46+
<sds:Comment>${comment ?? ''}</sds:Comment>
47+
<sds:SclData><![CDATA[${formatXml(
48+
new XMLSerializer().serializeToString(
49+
doc.documentElement))}]]></sds:SclData>
50+
</sds:CreateRequest>`;
51+
}
52+
53+
function createUpdateRequest(
54+
changeSet: ChangeSet,
55+
comment: string | null,
56+
doc: Document
57+
): string {
58+
return `<?xml version="1.0" encoding="UTF-8"?>
59+
<sds:UpdateRequest xmlns:sds="${SDS_NAMESPACE}">
60+
<sds:ChangeSet>${changeSet}</sds:ChangeSet>
61+
<sds:Comment>${comment ?? ''}</sds:Comment>
62+
<sds:SclData><![CDATA[${formatXml(
63+
new XMLSerializer().serializeToString(
64+
doc.documentElement))}]]></sds:SclData>
65+
</sds:UpdateRequest>`;
3566
}
3667

3768
return {
69+
useWebsocket(): boolean {
70+
return CompasSettings().useWebsockets();
71+
},
72+
3873
listSclTypes(): Promise<Document> {
3974
const sclUrl =
40-
getCompasSettings().sclDataServiceUrl + '/common/v1/type/list';
75+
getSclDataServiceUrl() + '/common/v1/type/list';
4176
return fetch(sclUrl)
4277
.catch(handleError)
4378
.then(handleResponse)
@@ -64,7 +99,7 @@ export function CompasSclDataService() {
6499

65100
listScls(type: string): Promise<Document> {
66101
const sclUrl =
67-
getCompasSettings().sclDataServiceUrl + '/scl/v1/' + type + '/list';
102+
getSclDataServiceUrl() + '/scl/v1/' + type + '/list';
68103
return fetch(sclUrl)
69104
.catch(handleError)
70105
.then(handleResponse)
@@ -73,7 +108,7 @@ export function CompasSclDataService() {
73108

74109
listVersions(type: string, id: string): Promise<Document> {
75110
const sclUrl =
76-
getCompasSettings().sclDataServiceUrl +
111+
getSclDataServiceUrl() +
77112
'/scl/v1/' +
78113
type +
79114
'/' +
@@ -87,7 +122,7 @@ export function CompasSclDataService() {
87122

88123
getSclDocument(type: string, id: string): Promise<Document> {
89124
const sclUrl =
90-
getCompasSettings().sclDataServiceUrl + '/scl/v1/' + type + '/' + id;
125+
getSclDataServiceUrl() + '/scl/v1/' + type + '/' + id;
91126
return fetch(sclUrl)
92127
.catch(handleError)
93128
.then(handleResponse)
@@ -101,7 +136,7 @@ export function CompasSclDataService() {
101136
version: string
102137
): Promise<Document> {
103138
const sclUrl =
104-
getCompasSettings().sclDataServiceUrl +
139+
getSclDataServiceUrl() +
105140
'/scl/v1/' +
106141
type +
107142
'/' +
@@ -121,7 +156,7 @@ export function CompasSclDataService() {
121156
version: string
122157
): Promise<string> {
123158
const sclUrl =
124-
getCompasSettings().sclDataServiceUrl +
159+
getSclDataServiceUrl() +
125160
'/scl/v1/' +
126161
type +
127162
'/' +
@@ -135,63 +170,80 @@ export function CompasSclDataService() {
135170

136171
deleteSclDocument(type: string, id: string): Promise<string> {
137172
const sclUrl =
138-
getCompasSettings().sclDataServiceUrl + '/scl/v1/' + type + '/' + id;
173+
getSclDataServiceUrl() + '/scl/v1/' + type + '/' + id;
139174
return fetch(sclUrl, { method: 'DELETE' })
140175
.catch(handleError)
141176
.then(handleResponse);
142177
},
143178

144-
addSclDocument(type: string, body: CreateRequestBody): Promise<Document> {
145-
const sclUrl = getCompasSettings().sclDataServiceUrl + '/scl/v1/' + type;
179+
addSclDocumentUsingRest(type: string, body: CreateRequestBody): Promise<Document> {
180+
const sclUrl = getSclDataServiceUrl() + '/scl/v1/' + type;
146181
return fetch(sclUrl, {
147182
method: 'POST',
148183
headers: {
149184
'Content-Type': 'application/xml',
150185
},
151-
body: `<?xml version="1.0" encoding="UTF-8"?>
152-
<sds:CreateRequest xmlns:sds="${SDS_NAMESPACE}">
153-
<sds:Name>${body.sclName}</sds:Name>
154-
<sds:Comment>${body.comment ?? ''}</sds:Comment>
155-
<sds:SclData><![CDATA[${formatXml(
156-
new XMLSerializer().serializeToString(
157-
body.doc.documentElement
158-
)
159-
)}]]></sds:SclData>
160-
</sds:CreateRequest>`,
186+
body: createCreateRequest(body.sclName, body.comment, body.doc),
161187
})
162188
.catch(handleError)
163189
.then(handleResponse)
164190
.then(parseXml)
165191
.then(extractSclFromResponse);
166192
},
167193

168-
updateSclDocument(
194+
addSclDocumentUsingWebsockets(
195+
element: Element,
196+
type: string,
197+
body: CreateRequestBody,
198+
callback: (scl: Document) => void,
199+
) {
200+
const sclUrl = getSclDataServiceUrl() + '/scl-ws/v1/' + type + '/create';
201+
Websockets(element, 'CompasSclDataService').execute(
202+
getWebsocketUri(sclUrl),
203+
createCreateRequest(body.sclName, body.comment, body.doc),
204+
async (response: Document) => {
205+
const scl = await extractSclFromResponse(response);
206+
callback(scl);
207+
}
208+
);
209+
},
210+
211+
updateSclDocumentUsingRest(
169212
type: string,
170213
id: string,
171214
body: UpdateRequestBody
172215
): Promise<Document> {
173216
const sclUrl =
174-
getCompasSettings().sclDataServiceUrl + '/scl/v1/' + type + '/' + id;
217+
getSclDataServiceUrl() + '/scl/v1/' + type + '/' + id;
175218
return fetch(sclUrl, {
176219
method: 'PUT',
177220
headers: {
178221
'Content-Type': 'application/xml',
179222
},
180-
body: `<?xml version="1.0" encoding="UTF-8"?>
181-
<sds:UpdateRequest xmlns:sds="${SDS_NAMESPACE}">
182-
<sds:ChangeSet>${body.changeSet}</sds:ChangeSet>
183-
<sds:Comment>${body.comment ?? ''}</sds:Comment>
184-
<sds:SclData><![CDATA[${formatXml(
185-
new XMLSerializer().serializeToString(
186-
body.doc.documentElement
187-
)
188-
)}]]></sds:SclData>
189-
</sds:UpdateRequest>`,
223+
body: createUpdateRequest(body.changeSet, body.comment, body.doc),
190224
})
191225
.catch(handleError)
192226
.then(handleResponse)
193227
.then(parseXml)
194228
.then(extractSclFromResponse);
195229
},
230+
231+
updateSclDocumentUsingWebsockets(
232+
element: Element,
233+
type: string,
234+
id: string,
235+
body: UpdateRequestBody,
236+
callback: (scl: Document) => void,
237+
) {
238+
const sclUrl = getSclDataServiceUrl() + '/scl-ws/v1/' + type + '/update/' + id;
239+
Websockets(element, 'CompasSclDataService').execute(
240+
getWebsocketUri(sclUrl),
241+
createUpdateRequest(body.changeSet, body.comment, body.doc),
242+
async (response: Document) => {
243+
const scl = await extractSclFromResponse(response);
244+
callback(scl);
245+
}
246+
);
247+
},
196248
};
197249
}

src/compas-services/CompasValidatorService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function CompasSclValidatorService() {
4747
element: Element,
4848
type: string,
4949
doc: Document,
50-
callback: (doc: Document) => void,
50+
callback: (response: Document) => void,
5151
onCloseCallback: () => void
5252
) {
5353
Websockets(element, 'CompasValidatorService').execute(

src/compas-services/Websockets.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { newPendingStateEvent } from '../foundation.js';
2-
import { createLogEvent, parseXml } from './foundation.js';
2+
import { APPLICATION_ERROR, createLogEvent, extractErrorMessage, parseXml, processErrorMessage } from './foundation.js';
33

44
export function Websockets(element: Element, serviceName: string) {
55
let websocket: WebSocket | undefined;
@@ -8,7 +8,7 @@ export function Websockets(element: Element, serviceName: string) {
88
return new Promise(resolve => setTimeout(resolve, sleepTime));
99
}
1010

11-
async function waitUntilValidated(): Promise<void> {
11+
async function waitUntilExecuted(): Promise<void> {
1212
while (websocket !== undefined) {
1313
await sleep(250);
1414
}
@@ -30,7 +30,12 @@ export function Websockets(element: Element, serviceName: string) {
3030
websocket.onmessage = evt => {
3131
parseXml(evt.data)
3232
.then(doc => {
33-
onMessageCallback(doc);
33+
if (doc.documentElement.localName === 'ErrorResponse') {
34+
const message = extractErrorMessage(doc);
35+
createLogEvent(element, {type: APPLICATION_ERROR, message});
36+
} else {
37+
onMessageCallback(doc);
38+
}
3439
websocket?.close();
3540
})
3641
.catch(reason => {
@@ -54,7 +59,7 @@ export function Websockets(element: Element, serviceName: string) {
5459
}
5560
};
5661

57-
element.dispatchEvent(newPendingStateEvent(waitUntilValidated()));
62+
element.dispatchEvent(newPendingStateEvent(waitUntilExecuted()));
5863
},
5964
};
6065
}

src/compas-services/foundation.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,21 @@ export async function handleResponse(response: Response): Promise<string> {
2525
}
2626

2727
export async function processErrorMessage(response: Response): Promise<string> {
28-
// default we will return the status text from the response.
29-
let errorMessage = response.statusText;
30-
3128
const body = await response.text();
3229
const doc = await parseXml(body);
30+
const errorMessage = extractErrorMessage(doc);
31+
32+
// Default we will return the status text from the response.
33+
return errorMessage ?? response.statusText;
34+
}
35+
36+
export function extractErrorMessage(doc: Document): string | undefined {
3337
const messages = Array.from(
3438
doc.querySelectorAll('ErrorResponse > ErrorMessage') ?? []
3539
);
3640
// But if there are messages found in the body, we will process these and replace the status text with that.
3741
if (messages.length > 0) {
38-
errorMessage = '';
42+
let errorMessage = '';
3943
messages.forEach((errorMessageElement, index) => {
4044
const code = errorMessageElement
4145
.getElementsByTagNameNS(COMMONS_NAMESPACE, 'Code')!
@@ -53,9 +57,9 @@ export async function processErrorMessage(response: Response): Promise<string> {
5357
errorMessage += ' (' + code + ')';
5458
}
5559
});
60+
return errorMessage;
5661
}
57-
58-
return errorMessage;
62+
return undefined;
5963
}
6064

6165
export function parseXml(textContent: string): Promise<Document> {

0 commit comments

Comments
 (0)