ven.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. 'use strict';
  2. const {
  3. serialize: serializeCreatePartyRegistration,
  4. } = require('../xml/register-party/create-party-registration');
  5. const {
  6. serialize: serializeQueryRegistration,
  7. } = require('../xml/register-party/query-registration');
  8. const {
  9. serialize: serializeCancelPartyRegistration,
  10. } = require('../xml/register-party/cancel-party-registration');
  11. const {
  12. serialize: serializeRequestEvent,
  13. } = require('../xml/event/request-event');
  14. const { serialize: serializeOadrPoll } = require('../xml/poll/oadr-poll');
  15. const {
  16. serialize: serializeCreatedEvent,
  17. } = require('../xml/event/created-event');
  18. const {
  19. parse: parseCreatedPartyRegistration,
  20. } = require('../xml/register-party/created-party-registration');
  21. const {
  22. parse: parseCanceledPartyRegistration,
  23. } = require('../xml/register-party/canceled-party-registration');
  24. const {
  25. parse: parseDistributeEvent,
  26. } = require('../xml/event/distribute-event');
  27. const { parse: parsePollResponse } = require('../xml');
  28. const { parse: parseOadrResponse } = require('../xml/poll/oadr-response');
  29. const axios = require('axios');
  30. const { escape } = require('querystring');
  31. class Ven {
  32. constructor(
  33. endpoint,
  34. clientCertPem,
  35. commonName,
  36. venId,
  37. venName,
  38. registrationId,
  39. ) {
  40. if (!endpoint.endsWith('/')) endpoint += '/';
  41. this.endpoint = endpoint;
  42. this.clientCertHeader = escape(clientCertPem);
  43. this.venId = venId;
  44. this.registrationId = registrationId;
  45. this.venName = venName;
  46. this.commonName = commonName;
  47. }
  48. async queryRegistration() {
  49. const message = {
  50. requestId: '2233',
  51. };
  52. const createdResponse = await this.makeRequest(
  53. 'EiRegisterParty',
  54. message,
  55. serializeQueryRegistration,
  56. parseCreatedPartyRegistration,
  57. );
  58. // track registrationId for subsequent requests
  59. this.registrationId = createdResponse.registrationId;
  60. return createdResponse;
  61. }
  62. async cancelRegistration() {
  63. const message = {
  64. requestId: '2233',
  65. registrationId: this.registrationId,
  66. venId: this.venId,
  67. };
  68. const cancelledResponse = await this.makeRequest(
  69. 'EiRegisterParty',
  70. message,
  71. serializeCancelPartyRegistration,
  72. parseCanceledPartyRegistration,
  73. );
  74. // track registrationId for subsequent requests
  75. this.registrationId = undefined;
  76. return cancelledResponse;
  77. }
  78. async register() {
  79. const message = {
  80. requestId: '2233',
  81. registrationId: this.registrationId,
  82. venId: this.venId,
  83. oadrProfileName: '2.0b',
  84. oadrTransportName: 'simpleHttp',
  85. oadrReportOnly: false,
  86. oadrXmlSignature: false,
  87. oadrVenName: this.venName,
  88. oadrHttpPullModel: true,
  89. };
  90. const createdResponse = await this.makeRequest(
  91. 'EiRegisterParty',
  92. message,
  93. serializeCreatePartyRegistration,
  94. parseCreatedPartyRegistration,
  95. );
  96. // track registrationId for subsequent requests
  97. this.registrationId = createdResponse.registrationId;
  98. return createdResponse;
  99. }
  100. async requestEvents() {
  101. const message = {
  102. requestId: '2233',
  103. venId: this.venId,
  104. };
  105. const response = await this.makeRequest(
  106. 'EiEvent',
  107. message,
  108. serializeRequestEvent,
  109. parseDistributeEvent,
  110. );
  111. return response;
  112. }
  113. async poll() {
  114. const message = {
  115. venId: this.venId,
  116. };
  117. const response = await this.makeRequest(
  118. 'OadrPoll',
  119. message,
  120. serializeOadrPoll,
  121. parsePollResponse,
  122. );
  123. return response;
  124. }
  125. async opt(optType, eventId, modificationNumber) {
  126. const message = {
  127. responseCode: '200',
  128. responseDescription: 'OK',
  129. responseRequestId: '',
  130. venId: this.venId,
  131. eventResponses: [
  132. {
  133. responseCode: '200',
  134. responseDescription: 'OK',
  135. responseRequestId: '',
  136. optType: optType,
  137. eventId: eventId,
  138. modificationNumber: modificationNumber,
  139. },
  140. ],
  141. };
  142. return await this.makeRequest(
  143. 'EiEvent',
  144. message,
  145. serializeCreatedEvent,
  146. parseOadrResponse,
  147. );
  148. }
  149. async makeRequest(service, message, serializer, parser) {
  150. const xml = serializer(message);
  151. const config = {
  152. headers: {
  153. 'Content-Type': 'application/xml',
  154. // these next 2 headers are provided manually for now, simulating what nginx is doing.
  155. SSL_CLIENT_S_DN_CN: this.commonName || 'no_client_cert',
  156. SSL_CLIENT_CERTIFICATE: this.clientCertHeader,
  157. },
  158. };
  159. // axios will automatically reject HTTP response codes outside the 200-299 range
  160. const httpResponse = await axios.post(
  161. `${this.endpoint}OpenADR2/Simple/2.0b/${service}`,
  162. xml,
  163. config,
  164. );
  165. const response = await parser(httpResponse.data);
  166. // but OpenADR provides its own response code in the XML envelope, we need to check that
  167. if (response.responseCode < 200 || response.responseCode >= 300) {
  168. throw new Error(
  169. `Error during ${service} call. ResponseCode=${response.responseCode}, ResponseDescription=${response.responseDescription}`,
  170. );
  171. }
  172. return response;
  173. }
  174. }
  175. module.exports = {
  176. Ven,
  177. };