'use strict'; const { serialize: serializeCreatePartyRegistration, } = require('../xml/register-party/create-party-registration'); const { serialize: serializeQueryRegistration, } = require('../xml/register-party/query-registration'); const { serialize: serializeCancelPartyRegistration, } = require('../xml/register-party/cancel-party-registration'); const { serialize: serializeRequestEvent, } = require('../xml/event/request-event'); const { serialize: serializeOadrPoll } = require('../xml/poll/oadr-poll'); const { serialize: serializeCreatedEvent, } = require('../xml/event/created-event'); const { parse: parseCreatedPartyRegistration, } = require('../xml/register-party/created-party-registration'); const { parse: parseCanceledPartyRegistration, } = require('../xml/register-party/canceled-party-registration'); const { parse: parseDistributeEvent, } = require('../xml/event/distribute-event'); const { parse: parsePollResponse } = require('../xml/poll'); const { parse: parseOadrResponse } = require('../xml/poll/oadr-response'); const axios = require('axios'); const { escape } = require('querystring'); class Ven { constructor( endpoint, clientCertPem, commonName, venId, venName, registrationId, ) { if (!endpoint.endsWith('/')) endpoint += '/'; this.endpoint = endpoint; this.clientCertHeader = escape(clientCertPem); this.venId = venId; this.registrationId = registrationId; this.venName = venName; this.commonName = commonName; } async queryRegistration() { const message = { requestId: '2233', }; const createdResponse = await this.makeRequest( 'EiRegisterParty', message, serializeQueryRegistration, parseCreatedPartyRegistration, ); // track registrationId for subsequent requests this.registrationId = createdResponse.registrationId; return createdResponse; } async cancelRegistration() { const message = { requestId: '2233', registrationId: this.registrationId, venId: this.venId, }; const cancelledResponse = await this.makeRequest( 'EiRegisterParty', message, serializeCancelPartyRegistration, parseCanceledPartyRegistration, ); // track registrationId for subsequent requests this.registrationId = undefined; return cancelledResponse; } async register() { const message = { requestId: '2233', registrationId: this.registrationId, venId: this.venId, oadrProfileName: '2.0b', oadrTransportName: 'simplehttp', oadrReportOnly: false, oadrXmlSignature: false, oadrVenName: this.venName, oadrHttpPullModel: true, }; const createdResponse = await this.makeRequest( 'EiRegisterParty', message, serializeCreatePartyRegistration, parseCreatedPartyRegistration, ); // track registrationId for subsequent requests this.registrationId = createdResponse.registrationId; return createdResponse; } async requestEvents() { const message = { requestId: '2233', venId: this.venId, }; const response = await this.makeRequest( 'EiEvent', message, serializeRequestEvent, parseDistributeEvent, ); return response; } async poll() { const message = { venId: this.venId, }; const response = await this.makeRequest( 'OadrPoll', message, serializeOadrPoll, parsePollResponse, ); return response; } async opt(optType, eventId, modificationNumber) { const message = { responseCode: '200', responseDescription: 'OK', responseRequestId: '', venId: this.venId, eventResponses: [ { responseCode: '200', responseDescription: 'OK', responseRequestId: '', optType: optType, eventId: eventId, modificationNumber: modificationNumber, }, ], }; return await this.makeRequest( 'EiEvent', message, serializeCreatedEvent, parseOadrResponse, ); } async makeRequest(service, message, serializer, parser) { const xml = serializer(message); const config = { headers: { 'Content-Type': 'application/xml', // these next 2 headers are provided manually for now, simulating what nginx is doing. SSL_CLIENT_S_DN_CN: this.commonName || 'no_client_cert', SSL_CLIENT_CERTIFICATE: this.clientCertHeader, }, }; // axios will automatically reject HTTP response codes outside the 200-299 range const httpResponse = await axios.post( `${this.endpoint}OpenADR2/Simple/2.0b/${service}`, xml, config, ); const response = await parser(httpResponse.data); // but OpenADR provides its own response code in the XML envelope, we need to check that if (response.responseCode < 200 || response.responseCode >= 300) { throw new Error( `Error during ${service} call. ResponseCode=${response.responseCode}, ResponseDescription=${response.responseDescription}`, ); } return response; } } module.exports = { Ven, };