|
@@ -0,0 +1,172 @@
|
|
|
|
|
+/* eslint-disable indent */
|
|
|
|
|
+'use strict';
|
|
|
|
|
+
|
|
|
|
|
+const { parseXML, childAttr, required } = require('./parser');
|
|
|
|
|
+const { create, fragment } = require('xmlbuilder2');
|
|
|
|
|
+
|
|
|
|
|
+const oadrPayloadNs = 'http://www.w3.org/2000/09/xmldsig#';
|
|
|
|
|
+const oadrNs = 'http://openadr.org/oadr-2.0b/2012/07';
|
|
|
|
|
+const energyInteropNs = 'http://docs.oasis-open.org/ns/energyinterop/201110';
|
|
|
|
|
+const energyInteropPayloadsNs =
|
|
|
|
|
+ 'http://docs.oasis-open.org/ns/energyinterop/201110/payloads';
|
|
|
|
|
+const calendarNs = 'urn:ietf:params:xml:ns:icalendar-2.0';
|
|
|
|
|
+
|
|
|
|
|
+function parseEiResponse(response) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ code: required(childAttr(response, 'responseCode'), 'responseCode'),
|
|
|
|
|
+ description: childAttr(response, 'responseDescription'),
|
|
|
|
|
+ requestId: required(childAttr(response, 'requestID'), 'requestID'),
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function parseDuration(response) {
|
|
|
|
|
+ return required(childAttr(response, 'duration'), 'duration');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function parse(input) {
|
|
|
|
|
+ const json = await parseXML(input);
|
|
|
|
|
+ const o =
|
|
|
|
|
+ json['oadrPayload']['$$']['oadrSignedObject'][0]['$$'][
|
|
|
|
|
+ 'oadrCreatedPartyRegistration'
|
|
|
|
|
+ ][0]['$$'];
|
|
|
|
|
+
|
|
|
|
|
+ const { code, description, requestId } = parseEiResponse(
|
|
|
|
|
+ o['eiResponse'][0]['$$'],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const result = {
|
|
|
|
|
+ responseCode: code,
|
|
|
|
|
+ responseDescription: description,
|
|
|
|
|
+ responseRequestId: requestId,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (code < 200 || code >= 300) {
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const registrationId = childAttr(o, 'registrationID');
|
|
|
|
|
+ if (registrationId != null) result.registrationId = registrationId;
|
|
|
|
|
+
|
|
|
|
|
+ const venId = childAttr(o, 'venID');
|
|
|
|
|
+ if (venId != null) result.venId = venId;
|
|
|
|
|
+
|
|
|
|
|
+ const vtnId = childAttr(o, 'vtnID');
|
|
|
|
|
+ if (vtnId != null) result.vtnId = vtnId;
|
|
|
|
|
+
|
|
|
|
|
+ const oadrRequestedOadrPollFreq = childAttr(o, 'oadrRequestedOadrPollFreq');
|
|
|
|
|
+ if (oadrRequestedOadrPollFreq != null) {
|
|
|
|
|
+ const oadrRequestedOadrPollFreqDuration = parseDuration(
|
|
|
|
|
+ oadrRequestedOadrPollFreq['$$'],
|
|
|
|
|
+ );
|
|
|
|
|
+ if (oadrRequestedOadrPollFreqDuration != null)
|
|
|
|
|
+ result.pollFreqDuration = oadrRequestedOadrPollFreqDuration;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function serializeEiResponse(code, description, requestId) {
|
|
|
|
|
+ const descriptionFrag =
|
|
|
|
|
+ description != null
|
|
|
|
|
+ ? fragment()
|
|
|
|
|
+ .ele(energyInteropNs, 'ei:responseDescription')
|
|
|
|
|
+ .txt(description)
|
|
|
|
|
+ : fragment();
|
|
|
|
|
+ return fragment()
|
|
|
|
|
+ .ele(energyInteropNs, 'ei:responseCode')
|
|
|
|
|
+ .txt(code)
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .import(descriptionFrag)
|
|
|
|
|
+ .ele(energyInteropPayloadsNs, 'pyld:requestID')
|
|
|
|
|
+ .txt(requestId)
|
|
|
|
|
+ .up();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function serializeDuration(duration) {
|
|
|
|
|
+ return duration != null
|
|
|
|
|
+ ? fragment()
|
|
|
|
|
+ .ele(calendarNs, 'cal:duration')
|
|
|
|
|
+ .txt(duration)
|
|
|
|
|
+ : fragment();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function validate(obj) {
|
|
|
|
|
+ if (!obj.responseCode) {
|
|
|
|
|
+ throw new Error('Missing responseCode');
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!obj.responseRequestId) {
|
|
|
|
|
+ throw new Error('Missing responseRequestId');
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function serialize(obj) {
|
|
|
|
|
+ validate(obj);
|
|
|
|
|
+
|
|
|
|
|
+ const registrationId =
|
|
|
|
|
+ obj.registrationId != null
|
|
|
|
|
+ ? fragment()
|
|
|
|
|
+ .ele(energyInteropNs, 'ei:registrationID')
|
|
|
|
|
+ .txt(obj.registrationId)
|
|
|
|
|
+ : fragment();
|
|
|
|
|
+ const venId =
|
|
|
|
|
+ obj.venId != null
|
|
|
|
|
+ ? fragment()
|
|
|
|
|
+ .ele(energyInteropNs, 'ei:venID')
|
|
|
|
|
+ .txt(obj.venId)
|
|
|
|
|
+ : fragment();
|
|
|
|
|
+ const vtnId =
|
|
|
|
|
+ obj.vtnId != null
|
|
|
|
|
+ ? fragment()
|
|
|
|
|
+ .ele(energyInteropNs, 'ei:vtnID')
|
|
|
|
|
+ .txt(obj.vtnId)
|
|
|
|
|
+ : fragment();
|
|
|
|
|
+
|
|
|
|
|
+ const doc = create({
|
|
|
|
|
+ namespaceAlias: {
|
|
|
|
|
+ ns: oadrPayloadNs,
|
|
|
|
|
+ oadr2b: oadrNs,
|
|
|
|
|
+ ei: energyInteropNs,
|
|
|
|
|
+ pyld: energyInteropPayloadsNs,
|
|
|
|
|
+ cal: calendarNs,
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ .ele('@oadr2b', 'oadr2b:oadrPayload')
|
|
|
|
|
+ .ele('oadr2b:oadrSignedObject')
|
|
|
|
|
+ .ele('oadr2b:oadrCreatedPartyRegistration')
|
|
|
|
|
+ .att('@ei', 'ei:schemaVersion', '2.0b')
|
|
|
|
|
+ .ele('@ei', 'ei:eiResponse')
|
|
|
|
|
+ .import(
|
|
|
|
|
+ serializeEiResponse(
|
|
|
|
|
+ obj.responseCode,
|
|
|
|
|
+ obj.responseDescription,
|
|
|
|
|
+ obj.responseRequestId,
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .import(registrationId)
|
|
|
|
|
+ .import(venId)
|
|
|
|
|
+ .import(vtnId)
|
|
|
|
|
+ .ele('oadr2b:oadrProfiles')
|
|
|
|
|
+ .ele('oadr2b:oadrProfile')
|
|
|
|
|
+ .ele('oadr2b:oadrProfileName')
|
|
|
|
|
+ .txt('2.0b')
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .ele('oadr2b:oadrTransports')
|
|
|
|
|
+ .ele('oadr2b:oadrTransport')
|
|
|
|
|
+ .ele('oadr2b:oadrTransportName')
|
|
|
|
|
+ .txt('simpleHttp')
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .up()
|
|
|
|
|
+ .ele('oadr2b:oadrRequestedOadrPollFreq')
|
|
|
|
|
+ .import(serializeDuration(obj.pollFreqDuration))
|
|
|
|
|
+ .doc();
|
|
|
|
|
+ return doc.end({ headless: true, prettyPrint: false });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ parse,
|
|
|
|
|
+ serialize,
|
|
|
|
|
+};
|