ven.js 4.7 KB

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