diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8f8dae..ea968084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,281 @@ +# [3.2.0-next.4](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.2.0-next.3...v3.2.0-next.4) (2024-10-16) + + +### Bug Fixes + +* Native SDK unit tests support framework ([#223](https://github.com/rdkcentral/firebolt-openrpc/issues/223)) ([819cc21](https://github.com/rdkcentral/firebolt-openrpc/commit/819cc210a53d80fefe547b41c463620cb668624d)) + +# [3.2.0-next.3](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.2.0-next.2...v3.2.0-next.3) (2024-09-17) + + +### Bug Fixes + +* Add open-rpc to generated C++ SDK ([#217](https://github.com/rdkcentral/firebolt-openrpc/issues/217)) ([a02980a](https://github.com/rdkcentral/firebolt-openrpc/commit/a02980a2aebb4a8c0cd675ea8752ee7b5ecd9fd7)) + +# [3.2.0-next.2](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.2.0-next.1...v3.2.0-next.2) (2024-09-16) + + +### Features + +* Cpp global subscriber type ([#218](https://github.com/rdkcentral/firebolt-openrpc/issues/218)) ([45cbf0a](https://github.com/rdkcentral/firebolt-openrpc/commit/45cbf0abd289294315a484ef85f2fe5d70e6fd63)) + +# [3.2.0-next.1](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.2-next.1...v3.2.0-next.1) (2024-09-11) + + +### Features + +* Make private method and private events more hidden ([#216](https://github.com/rdkcentral/firebolt-openrpc/issues/216)) ([d3d5bdd](https://github.com/rdkcentral/firebolt-openrpc/commit/d3d5bddc7a2f979bd5efea960786ea1b488b0751)) + +## [3.1.2-next.1](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1...v3.1.2-next.1) (2024-09-04) + +### Bug Fixes + +* Void provider methods have JSONRPC errors ([#212](https://github.com/rdkcentral/firebolt-openrpc/issues/212)) ([d984304](https://github.com/rdkcentral/firebolt-openrpc/commit/d9843044cc1da2656edd70c01cc57ebcee3dedfb)) + +## [3.1.1-next.6](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1-next.5...v3.1.1-next.6) (2024-09-04) + + +### Bug Fixes + +* Merge latest main to next ([#214](https://github.com/rdkcentral/firebolt-openrpc/issues/214)) ([650360c](https://github.com/rdkcentral/firebolt-openrpc/commit/650360c2b48fccb91a2743cec03ba5b47734fb0e)) + +## [3.1.1-next.5](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1-next.4...v3.1.1-next.5) (2024-09-04) + +### Bug Fixes + +* Void provider methods have JSONRPC errors ([#212](https://github.com/rdkcentral/firebolt-openrpc/issues/212)) ([d984304](https://github.com/rdkcentral/firebolt-openrpc/commit/d9843044cc1da2656edd70c01cc57ebcee3dedfb)) + + +## [3.1.1](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.0...v3.1.1) (2024-08-30) + + +### Bug Fixes +* Add provider-selection tag to validation schema ([756e88a](https://github.com/rdkcentral/firebolt-openrpc/commit/756e88a92782c8d65ec481182c31c8edb218c9d6)) +* CPP Enum/AnyOf ([#210](https://github.com/rdkcentral/firebolt-openrpc/issues/210)) ([eb768fb](https://github.com/rdkcentral/firebolt-openrpc/commit/eb768fb5f0d8ce4c123daab428bd53ca7225333c)) +* Quote unsafe property names in languages that support it ([647043d](https://github.com/rdkcentral/firebolt-openrpc/commit/647043d59ea0399b725d32e4a2e48ee017965288)) +* Return empty config, not null ([f02aadc](https://github.com/rdkcentral/firebolt-openrpc/commit/f02aadcb57f3936f1dcebfe570e418c1d04f626d)) +* Update getSuffix to properly work in pipeline ([#209](https://github.com/rdkcentral/firebolt-openrpc/issues/209)) ([16b4e6e](https://github.com/rdkcentral/firebolt-openrpc/commit/16b4e6eb5a8739a7715eb975104d7bb33053b28c)) + +## [3.1.1-next.4](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1-next.3...v3.1.1-next.4) (2024-08-30) + + +### Bug Fixes + +* CPP Enum/AnyOf ([#210](https://github.com/rdkcentral/firebolt-openrpc/issues/210)) ([eb768fb](https://github.com/rdkcentral/firebolt-openrpc/commit/eb768fb5f0d8ce4c123daab428bd53ca7225333c)) + +## [3.1.1-next.3](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1-next.2...v3.1.1-next.3) (2024-08-26) + + +### Bug Fixes + +* Update getSuffix to properly work in pipeline ([#209](https://github.com/rdkcentral/firebolt-openrpc/issues/209)) ([16b4e6e](https://github.com/rdkcentral/firebolt-openrpc/commit/16b4e6eb5a8739a7715eb975104d7bb33053b28c)) + +## [3.1.1-next.2](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.1-next.1...v3.1.1-next.2) (2024-08-23) + + +### Bug Fixes + +* Quote unsafe property names in languages that support it ([647043d](https://github.com/rdkcentral/firebolt-openrpc/commit/647043d59ea0399b725d32e4a2e48ee017965288)) +* Return empty config, not null ([f02aadc](https://github.com/rdkcentral/firebolt-openrpc/commit/f02aadcb57f3936f1dcebfe570e418c1d04f626d)) + +## [3.1.1-next.1](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.1.0...v3.1.1-next.1) (2024-08-21) + + +### Bug Fixes + +* Add provider-selection tag to validation schema ([756e88a](https://github.com/rdkcentral/firebolt-openrpc/commit/756e88a92782c8d65ec481182c31c8edb218c9d6)) + +# [3.1.0](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0...v3.1.0) (2024-08-08) + + +### Bug Fixes + +* Account for new OpenRPC spec URL contents ([#186](https://github.com/rdkcentral/firebolt-openrpc/issues/186)) ([66bd6ac](https://github.com/rdkcentral/firebolt-openrpc/commit/66bd6acc1ffdaefadcb46d78864d615a116b5a85)) +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) +* Added x-response-name in EventTag ([#200](https://github.com/rdkcentral/firebolt-openrpc/issues/200)) ([d2130a8](https://github.com/rdkcentral/firebolt-openrpc/commit/d2130a8bfa88a4a43c033596c9a8aa4d7b1864fa)) +* Build issues with CPP Manage SDK ([#203](https://github.com/rdkcentral/firebolt-openrpc/issues/203)) ([e06f6e2](https://github.com/rdkcentral/firebolt-openrpc/commit/e06f6e2b8c103d44c177351eaa05f9d965b61518)) +* Manual release 3.1.0-next.4 ([53d4a14](https://github.com/rdkcentral/firebolt-openrpc/commit/53d4a1436c6deef9508a96ec24e8203a170a1447)) +* Manually create 3.1.0-next.2 ([f9c2c3c](https://github.com/rdkcentral/firebolt-openrpc/commit/f9c2c3c987fc61ebdac8dc54b707338527723d2f)) +* Manually release 3.1.0-next.3 ([e8b0075](https://github.com/rdkcentral/firebolt-openrpc/commit/e8b0075823a9d2f124c03797cb3f9d71bfbfdbf1)) +* Manually update version to 3.1.0-next.1 ([#204](https://github.com/rdkcentral/firebolt-openrpc/issues/204)) ([699fd65](https://github.com/rdkcentral/firebolt-openrpc/commit/699fd653999e42b6ba1bee977fcfb75241adf123)) +* Resolve conflicts ([adf6762](https://github.com/rdkcentral/firebolt-openrpc/commit/adf6762c02e1ccd6e7cd708d5249630252bd7c44)) +* SchemasMatch handling null ([#199](https://github.com/rdkcentral/firebolt-openrpc/issues/199)) ([07c47db](https://github.com/rdkcentral/firebolt-openrpc/commit/07c47db16ca2a533ee29e6586703834658928bc4)) + + +### Features + +* App Pass-through ([#188](https://github.com/rdkcentral/firebolt-openrpc/issues/188)) ([83fa0fc](https://github.com/rdkcentral/firebolt-openrpc/commit/83fa0fcb62cade7ed3b527de6b3fe1ebb42b54e0)) +* CPP App-Passthrough ([#196](https://github.com/rdkcentral/firebolt-openrpc/issues/196)) ([eeabccb](https://github.com/rdkcentral/firebolt-openrpc/commit/eeabccb8c65761e06447bf7be460d61f47992161)) + +# [3.0.0](https://github.com/rdkcentral/firebolt-openrpc/compare/v2.3.0...v3.0.0) (2024-08-08) + + +### Bug Fixes + +* Account for new OpenRPC spec URL contents ([#186](https://github.com/rdkcentral/firebolt-openrpc/issues/186)) ([66bd6ac](https://github.com/rdkcentral/firebolt-openrpc/commit/66bd6acc1ffdaefadcb46d78864d615a116b5a85)) +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) +* Added x-response-name in EventTag ([#200](https://github.com/rdkcentral/firebolt-openrpc/issues/200)) ([d2130a8](https://github.com/rdkcentral/firebolt-openrpc/commit/d2130a8bfa88a4a43c033596c9a8aa4d7b1864fa)) +* Build issues with CPP Manage SDK ([#203](https://github.com/rdkcentral/firebolt-openrpc/issues/203)) ([e06f6e2](https://github.com/rdkcentral/firebolt-openrpc/commit/e06f6e2b8c103d44c177351eaa05f9d965b61518)) +* Manually create 3.1.0-next.2 ([f9c2c3c](https://github.com/rdkcentral/firebolt-openrpc/commit/f9c2c3c987fc61ebdac8dc54b707338527723d2f)) +* Manually release 3.1.0-next.3 ([e8b0075](https://github.com/rdkcentral/firebolt-openrpc/commit/e8b0075823a9d2f124c03797cb3f9d71bfbfdbf1)) +* Manually update version to 3.1.0-next.1 ([#204](https://github.com/rdkcentral/firebolt-openrpc/issues/204)) ([699fd65](https://github.com/rdkcentral/firebolt-openrpc/commit/699fd653999e42b6ba1bee977fcfb75241adf123)) +* Resolve conflicts ([adf6762](https://github.com/rdkcentral/firebolt-openrpc/commit/adf6762c02e1ccd6e7cd708d5249630252bd7c44)) +* SchemasMatch handling null ([#199](https://github.com/rdkcentral/firebolt-openrpc/issues/199)) ([07c47db](https://github.com/rdkcentral/firebolt-openrpc/commit/07c47db16ca2a533ee29e6586703834658928bc4)) + + +* Integration of CPPSDK support (#176) ([89294cc](https://github.com/rdkcentral/firebolt-openrpc/commit/89294cc37f23a94012621130858e01c946a3a9a6)), closes [#176](https://github.com/rdkcentral/firebolt-openrpc/issues/176) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#127](https://github.com/rdkcentral/firebolt-openrpc/issues/127) [#137](https://github.com/rdkcentral/firebolt-openrpc/issues/137) [#135](https://github.com/rdkcentral/firebolt-openrpc/issues/135) [#134](https://github.com/rdkcentral/firebolt-openrpc/issues/134) [#136](https://github.com/rdkcentral/firebolt-openrpc/issues/136) [#139](https://github.com/rdkcentral/firebolt-openrpc/issues/139) [#138](https://github.com/rdkcentral/firebolt-openrpc/issues/138) [#140](https://github.com/rdkcentral/firebolt-openrpc/issues/140) [#142](https://github.com/rdkcentral/firebolt-openrpc/issues/142) [#144](https://github.com/rdkcentral/firebolt-openrpc/issues/144) [#145](https://github.com/rdkcentral/firebolt-openrpc/issues/145) [#141](https://github.com/rdkcentral/firebolt-openrpc/issues/141) [#149](https://github.com/rdkcentral/firebolt-openrpc/issues/149) [#150](https://github.com/rdkcentral/firebolt-openrpc/issues/150) [#152](https://github.com/rdkcentral/firebolt-openrpc/issues/152) [#151](https://github.com/rdkcentral/firebolt-openrpc/issues/151) [#153](https://github.com/rdkcentral/firebolt-openrpc/issues/153) [#154](https://github.com/rdkcentral/firebolt-openrpc/issues/154) [#156](https://github.com/rdkcentral/firebolt-openrpc/issues/156) [#157](https://github.com/rdkcentral/firebolt-openrpc/issues/157) [#158](https://github.com/rdkcentral/firebolt-openrpc/issues/158) [#160](https://github.com/rdkcentral/firebolt-openrpc/issues/160) [#159](https://github.com/rdkcentral/firebolt-openrpc/issues/159) [#161](https://github.com/rdkcentral/firebolt-openrpc/issues/161) [#163](https://github.com/rdkcentral/firebolt-openrpc/issues/163) [#164](https://github.com/rdkcentral/firebolt-openrpc/issues/164) [#165](https://github.com/rdkcentral/firebolt-openrpc/issues/165) [#167](https://github.com/rdkcentral/firebolt-openrpc/issues/167) [#169](https://github.com/rdkcentral/firebolt-openrpc/issues/169) [#171](https://github.com/rdkcentral/firebolt-openrpc/issues/171) [#173](https://github.com/rdkcentral/firebolt-openrpc/issues/173) [#172](https://github.com/rdkcentral/firebolt-openrpc/issues/172) [#170](https://github.com/rdkcentral/firebolt-openrpc/issues/170) + + +### Features + +* App Pass-through ([#188](https://github.com/rdkcentral/firebolt-openrpc/issues/188)) ([83fa0fc](https://github.com/rdkcentral/firebolt-openrpc/commit/83fa0fcb62cade7ed3b527de6b3fe1ebb42b54e0)) +* CI/CD Merging from next ([#183](https://github.com/rdkcentral/firebolt-openrpc/issues/183)) ([14476a9](https://github.com/rdkcentral/firebolt-openrpc/commit/14476a908f2c10d907417187c41ce255ac2ea6a6)) +* CPP App-Passthrough ([#196](https://github.com/rdkcentral/firebolt-openrpc/issues/196)) ([eeabccb](https://github.com/rdkcentral/firebolt-openrpc/commit/eeabccb8c65761e06447bf7be460d61f47992161)) + + +### BREAKING CHANGES + +* Generalized templating engine to support both JavaScript and CPP (and other languages). + +* chore: Copy JS templates to C and create language.config.json + +* feat(languages): Add support for a distinct JSON-type for each schema + +Also started tweaking C templates and adding a few useful macros. + +* chore: Dropped debug logs + +* fix: Stop passing non-schemas in to getSchemaType + +* feat(accessors): New macro section for schema property accessors + +# [3.0.0](https://github.com/rdkcentral/firebolt-openrpc/compare/v2.3.0...v3.0.0) (2024-08-08) + + +### Bug Fixes + +* Account for new OpenRPC spec URL contents ([#186](https://github.com/rdkcentral/firebolt-openrpc/issues/186)) ([66bd6ac](https://github.com/rdkcentral/firebolt-openrpc/commit/66bd6acc1ffdaefadcb46d78864d615a116b5a85)) +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) +* Added x-response-name in EventTag ([#200](https://github.com/rdkcentral/firebolt-openrpc/issues/200)) ([d2130a8](https://github.com/rdkcentral/firebolt-openrpc/commit/d2130a8bfa88a4a43c033596c9a8aa4d7b1864fa)) +* Build issues with CPP Manage SDK ([#203](https://github.com/rdkcentral/firebolt-openrpc/issues/203)) ([e06f6e2](https://github.com/rdkcentral/firebolt-openrpc/commit/e06f6e2b8c103d44c177351eaa05f9d965b61518)) +* Manually create 3.1.0-next.2 ([f9c2c3c](https://github.com/rdkcentral/firebolt-openrpc/commit/f9c2c3c987fc61ebdac8dc54b707338527723d2f)) +* Manually update version to 3.1.0-next.1 ([#204](https://github.com/rdkcentral/firebolt-openrpc/issues/204)) ([699fd65](https://github.com/rdkcentral/firebolt-openrpc/commit/699fd653999e42b6ba1bee977fcfb75241adf123)) +* Resolve conflicts ([adf6762](https://github.com/rdkcentral/firebolt-openrpc/commit/adf6762c02e1ccd6e7cd708d5249630252bd7c44)) +* SchemasMatch handling null ([#199](https://github.com/rdkcentral/firebolt-openrpc/issues/199)) ([07c47db](https://github.com/rdkcentral/firebolt-openrpc/commit/07c47db16ca2a533ee29e6586703834658928bc4)) + + +* Integration of CPPSDK support (#176) ([89294cc](https://github.com/rdkcentral/firebolt-openrpc/commit/89294cc37f23a94012621130858e01c946a3a9a6)), closes [#176](https://github.com/rdkcentral/firebolt-openrpc/issues/176) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#127](https://github.com/rdkcentral/firebolt-openrpc/issues/127) [#137](https://github.com/rdkcentral/firebolt-openrpc/issues/137) [#135](https://github.com/rdkcentral/firebolt-openrpc/issues/135) [#134](https://github.com/rdkcentral/firebolt-openrpc/issues/134) [#136](https://github.com/rdkcentral/firebolt-openrpc/issues/136) [#139](https://github.com/rdkcentral/firebolt-openrpc/issues/139) [#138](https://github.com/rdkcentral/firebolt-openrpc/issues/138) [#140](https://github.com/rdkcentral/firebolt-openrpc/issues/140) [#142](https://github.com/rdkcentral/firebolt-openrpc/issues/142) [#144](https://github.com/rdkcentral/firebolt-openrpc/issues/144) [#145](https://github.com/rdkcentral/firebolt-openrpc/issues/145) [#141](https://github.com/rdkcentral/firebolt-openrpc/issues/141) [#149](https://github.com/rdkcentral/firebolt-openrpc/issues/149) [#150](https://github.com/rdkcentral/firebolt-openrpc/issues/150) [#152](https://github.com/rdkcentral/firebolt-openrpc/issues/152) [#151](https://github.com/rdkcentral/firebolt-openrpc/issues/151) [#153](https://github.com/rdkcentral/firebolt-openrpc/issues/153) [#154](https://github.com/rdkcentral/firebolt-openrpc/issues/154) [#156](https://github.com/rdkcentral/firebolt-openrpc/issues/156) [#157](https://github.com/rdkcentral/firebolt-openrpc/issues/157) [#158](https://github.com/rdkcentral/firebolt-openrpc/issues/158) [#160](https://github.com/rdkcentral/firebolt-openrpc/issues/160) [#159](https://github.com/rdkcentral/firebolt-openrpc/issues/159) [#161](https://github.com/rdkcentral/firebolt-openrpc/issues/161) [#163](https://github.com/rdkcentral/firebolt-openrpc/issues/163) [#164](https://github.com/rdkcentral/firebolt-openrpc/issues/164) [#165](https://github.com/rdkcentral/firebolt-openrpc/issues/165) [#167](https://github.com/rdkcentral/firebolt-openrpc/issues/167) [#169](https://github.com/rdkcentral/firebolt-openrpc/issues/169) [#171](https://github.com/rdkcentral/firebolt-openrpc/issues/171) [#173](https://github.com/rdkcentral/firebolt-openrpc/issues/173) [#172](https://github.com/rdkcentral/firebolt-openrpc/issues/172) [#170](https://github.com/rdkcentral/firebolt-openrpc/issues/170) + + +### Features + +* App Pass-through ([#188](https://github.com/rdkcentral/firebolt-openrpc/issues/188)) ([83fa0fc](https://github.com/rdkcentral/firebolt-openrpc/commit/83fa0fcb62cade7ed3b527de6b3fe1ebb42b54e0)) +* CI/CD Merging from next ([#183](https://github.com/rdkcentral/firebolt-openrpc/issues/183)) ([14476a9](https://github.com/rdkcentral/firebolt-openrpc/commit/14476a908f2c10d907417187c41ce255ac2ea6a6)) +* CPP App-Passthrough ([#196](https://github.com/rdkcentral/firebolt-openrpc/issues/196)) ([eeabccb](https://github.com/rdkcentral/firebolt-openrpc/commit/eeabccb8c65761e06447bf7be460d61f47992161)) + + +### BREAKING CHANGES + +* Generalized templating engine to support both JavaScript and CPP (and other languages). + +* chore: Copy JS templates to C and create language.config.json + +* feat(languages): Add support for a distinct JSON-type for each schema + +Also started tweaking C templates and adding a few useful macros. + +* chore: Dropped debug logs + +* fix: Stop passing non-schemas in to getSchemaType + +* feat(accessors): New macro section for schema property accessors + +# [3.0.0](https://github.com/rdkcentral/firebolt-openrpc/compare/v2.3.0...v3.0.0) (2024-08-08) + + +### Bug Fixes + +* Account for new OpenRPC spec URL contents ([#186](https://github.com/rdkcentral/firebolt-openrpc/issues/186)) ([66bd6ac](https://github.com/rdkcentral/firebolt-openrpc/commit/66bd6acc1ffdaefadcb46d78864d615a116b5a85)) +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) +* Added x-response-name in EventTag ([#200](https://github.com/rdkcentral/firebolt-openrpc/issues/200)) ([d2130a8](https://github.com/rdkcentral/firebolt-openrpc/commit/d2130a8bfa88a4a43c033596c9a8aa4d7b1864fa)) +* Build issues with CPP Manage SDK ([#203](https://github.com/rdkcentral/firebolt-openrpc/issues/203)) ([e06f6e2](https://github.com/rdkcentral/firebolt-openrpc/commit/e06f6e2b8c103d44c177351eaa05f9d965b61518)) +* Manually update version to 3.1.0-next.1 ([#204](https://github.com/rdkcentral/firebolt-openrpc/issues/204)) ([699fd65](https://github.com/rdkcentral/firebolt-openrpc/commit/699fd653999e42b6ba1bee977fcfb75241adf123)) +* Resolve conflicts ([adf6762](https://github.com/rdkcentral/firebolt-openrpc/commit/adf6762c02e1ccd6e7cd708d5249630252bd7c44)) +* SchemasMatch handling null ([#199](https://github.com/rdkcentral/firebolt-openrpc/issues/199)) ([07c47db](https://github.com/rdkcentral/firebolt-openrpc/commit/07c47db16ca2a533ee29e6586703834658928bc4)) + + +* Integration of CPPSDK support (#176) ([89294cc](https://github.com/rdkcentral/firebolt-openrpc/commit/89294cc37f23a94012621130858e01c946a3a9a6)), closes [#176](https://github.com/rdkcentral/firebolt-openrpc/issues/176) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#90](https://github.com/rdkcentral/firebolt-openrpc/issues/90) [#93](https://github.com/rdkcentral/firebolt-openrpc/issues/93) [#94](https://github.com/rdkcentral/firebolt-openrpc/issues/94) [#96](https://github.com/rdkcentral/firebolt-openrpc/issues/96) [#97](https://github.com/rdkcentral/firebolt-openrpc/issues/97) [#100](https://github.com/rdkcentral/firebolt-openrpc/issues/100) [#99](https://github.com/rdkcentral/firebolt-openrpc/issues/99) [#101](https://github.com/rdkcentral/firebolt-openrpc/issues/101) [#102](https://github.com/rdkcentral/firebolt-openrpc/issues/102) [#107](https://github.com/rdkcentral/firebolt-openrpc/issues/107) [#106](https://github.com/rdkcentral/firebolt-openrpc/issues/106) [#105](https://github.com/rdkcentral/firebolt-openrpc/issues/105) [#103](https://github.com/rdkcentral/firebolt-openrpc/issues/103) [#109](https://github.com/rdkcentral/firebolt-openrpc/issues/109) [#112](https://github.com/rdkcentral/firebolt-openrpc/issues/112) [#111](https://github.com/rdkcentral/firebolt-openrpc/issues/111) [#113](https://github.com/rdkcentral/firebolt-openrpc/issues/113) [#114](https://github.com/rdkcentral/firebolt-openrpc/issues/114) [#115](https://github.com/rdkcentral/firebolt-openrpc/issues/115) [#110](https://github.com/rdkcentral/firebolt-openrpc/issues/110) [#117](https://github.com/rdkcentral/firebolt-openrpc/issues/117) [#116](https://github.com/rdkcentral/firebolt-openrpc/issues/116) [#118](https://github.com/rdkcentral/firebolt-openrpc/issues/118) [#121](https://github.com/rdkcentral/firebolt-openrpc/issues/121) [#119](https://github.com/rdkcentral/firebolt-openrpc/issues/119) [#127](https://github.com/rdkcentral/firebolt-openrpc/issues/127) [#137](https://github.com/rdkcentral/firebolt-openrpc/issues/137) [#135](https://github.com/rdkcentral/firebolt-openrpc/issues/135) [#134](https://github.com/rdkcentral/firebolt-openrpc/issues/134) [#136](https://github.com/rdkcentral/firebolt-openrpc/issues/136) [#139](https://github.com/rdkcentral/firebolt-openrpc/issues/139) [#138](https://github.com/rdkcentral/firebolt-openrpc/issues/138) [#140](https://github.com/rdkcentral/firebolt-openrpc/issues/140) [#142](https://github.com/rdkcentral/firebolt-openrpc/issues/142) [#144](https://github.com/rdkcentral/firebolt-openrpc/issues/144) [#145](https://github.com/rdkcentral/firebolt-openrpc/issues/145) [#141](https://github.com/rdkcentral/firebolt-openrpc/issues/141) [#149](https://github.com/rdkcentral/firebolt-openrpc/issues/149) [#150](https://github.com/rdkcentral/firebolt-openrpc/issues/150) [#152](https://github.com/rdkcentral/firebolt-openrpc/issues/152) [#151](https://github.com/rdkcentral/firebolt-openrpc/issues/151) [#153](https://github.com/rdkcentral/firebolt-openrpc/issues/153) [#154](https://github.com/rdkcentral/firebolt-openrpc/issues/154) [#156](https://github.com/rdkcentral/firebolt-openrpc/issues/156) [#157](https://github.com/rdkcentral/firebolt-openrpc/issues/157) [#158](https://github.com/rdkcentral/firebolt-openrpc/issues/158) [#160](https://github.com/rdkcentral/firebolt-openrpc/issues/160) [#159](https://github.com/rdkcentral/firebolt-openrpc/issues/159) [#161](https://github.com/rdkcentral/firebolt-openrpc/issues/161) [#163](https://github.com/rdkcentral/firebolt-openrpc/issues/163) [#164](https://github.com/rdkcentral/firebolt-openrpc/issues/164) [#165](https://github.com/rdkcentral/firebolt-openrpc/issues/165) [#167](https://github.com/rdkcentral/firebolt-openrpc/issues/167) [#169](https://github.com/rdkcentral/firebolt-openrpc/issues/169) [#171](https://github.com/rdkcentral/firebolt-openrpc/issues/171) [#173](https://github.com/rdkcentral/firebolt-openrpc/issues/173) [#172](https://github.com/rdkcentral/firebolt-openrpc/issues/172) [#170](https://github.com/rdkcentral/firebolt-openrpc/issues/170) + + +### Features + +* App Pass-through ([#188](https://github.com/rdkcentral/firebolt-openrpc/issues/188)) ([83fa0fc](https://github.com/rdkcentral/firebolt-openrpc/commit/83fa0fcb62cade7ed3b527de6b3fe1ebb42b54e0)) +* CI/CD Merging from next ([#183](https://github.com/rdkcentral/firebolt-openrpc/issues/183)) ([14476a9](https://github.com/rdkcentral/firebolt-openrpc/commit/14476a908f2c10d907417187c41ce255ac2ea6a6)) +* CPP App-Passthrough ([#196](https://github.com/rdkcentral/firebolt-openrpc/issues/196)) ([eeabccb](https://github.com/rdkcentral/firebolt-openrpc/commit/eeabccb8c65761e06447bf7be460d61f47992161)) + + +### BREAKING CHANGES + +* Generalized templating engine to support both JavaScript and CPP (and other languages). + +* chore: Copy JS templates to C and create language.config.json + +* feat(languages): Add support for a distinct JSON-type for each schema + +Also started tweaking C templates and adding a few useful macros. + +* chore: Dropped debug logs + +* fix: Stop passing non-schemas in to getSchemaType + +* feat(accessors): New macro section for schema property accessors + +# [3.0.0-next.11](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.10...v3.0.0-next.11) (2024-08-08) + + +### Bug Fixes + +* Build issues with CPP Manage SDK ([#203](https://github.com/rdkcentral/firebolt-openrpc/issues/203)) ([e06f6e2](https://github.com/rdkcentral/firebolt-openrpc/commit/e06f6e2b8c103d44c177351eaa05f9d965b61518)) + +# [3.0.0-next.10](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.9...v3.0.0-next.10) (2024-07-29) + + +### Features + +* CPP App-Passthrough ([#196](https://github.com/rdkcentral/firebolt-openrpc/issues/196)) ([eeabccb](https://github.com/rdkcentral/firebolt-openrpc/commit/eeabccb8c65761e06447bf7be460d61f47992161)) + +# [3.0.0-next.9](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.8...v3.0.0-next.9) (2024-07-29) + + +### Bug Fixes + +* Added CPP Event prioritization ([#197](https://github.com/rdkcentral/firebolt-openrpc/issues/197)) ([11d25e9](https://github.com/rdkcentral/firebolt-openrpc/commit/11d25e9a9784cea105c1de832179e776956b893a)) + +# [3.0.0-next.8](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.7...v3.0.0-next.8) (2024-07-29) + + +### Bug Fixes + +* Added firebolt header to the call-metrics ([#201](https://github.com/rdkcentral/firebolt-openrpc/issues/201)) ([1b3f261](https://github.com/rdkcentral/firebolt-openrpc/commit/1b3f2619c8da9d560b37e48dc5ca78709b453d6e)) + +# [3.0.0-next.7](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.6...v3.0.0-next.7) (2024-07-10) + + +### Bug Fixes + +* Added x-response-name in EventTag ([#200](https://github.com/rdkcentral/firebolt-openrpc/issues/200)) ([d2130a8](https://github.com/rdkcentral/firebolt-openrpc/commit/d2130a8bfa88a4a43c033596c9a8aa4d7b1864fa)) + +# [3.0.0-next.6](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.5...v3.0.0-next.6) (2024-07-10) + + +### Bug Fixes + +* SchemasMatch handling null ([#199](https://github.com/rdkcentral/firebolt-openrpc/issues/199)) ([07c47db](https://github.com/rdkcentral/firebolt-openrpc/commit/07c47db16ca2a533ee29e6586703834658928bc4)) + # [3.0.0-next.5](https://github.com/rdkcentral/firebolt-openrpc/compare/v3.0.0-next.4...v3.0.0-next.5) (2024-06-13) diff --git a/languages/cpp/language.config.json b/languages/cpp/language.config.json index 724a1359..a1ed5f8b 100644 --- a/languages/cpp/language.config.json +++ b/languages/cpp/language.config.json @@ -7,6 +7,7 @@ "createPolymorphicMethods": true, "excludeDeclarations": true, "extractProviderSchema": true, + "enableUnionTypes": false, "aggregateFiles": [ "/include/firebolt.h", "/src/firebolt.cpp" diff --git a/languages/cpp/src/shared/CMakeLists.txt b/languages/cpp/src/shared/CMakeLists.txt index fe7a0085..a60211ec 100644 --- a/languages/cpp/src/shared/CMakeLists.txt +++ b/languages/cpp/src/shared/CMakeLists.txt @@ -18,10 +18,15 @@ cmake_minimum_required(VERSION 3.3) project(Firebolt) +# set(CMAKE_VERBOSE_MAKEFILE ON) set(FIREBOLT_TRANSPORT_WAITTIME 1000 CACHE STRING "Maximum time to wait for Transport layer to get response") set(FIREBOLT_LOGLEVEL "Info" CACHE STRING "Log level to be enabled") + +# Default options option(FIREBOLT_ENABLE_STATIC_LIB "Create Firebolt library as Static library" OFF) -option(ENABLE_TESTS "Build openrpc native test" OFF) +option(ENABLE_TESTS "Build openrpc native test" ON) +option(ENABLE_UNIT_TESTS "Enable unit test" ON) +option(ENABLE_COVERAGE "Enable code coverage build." OFF) if (FIREBOLT_ENABLE_STATIC_LIB) set(FIREBOLT_LIBRARY_TYPE STATIC) @@ -29,10 +34,59 @@ else () set(FIREBOLT_LIBRARY_TYPE SHARED) endif () -if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${SYSROOT_PATH}/usr" CACHE INTERNAL "" FORCE) - set(CMAKE_PREFIX_PATH ${SYSROOT_PATH}/usr/lib/cmake CACHE INTERNAL "" FORCE) +include(FetchContent) + +message("Fetching nlohmann json... ") +set(nlohmann_json_VERSION v3.11.3 CACHE STRING "Fetch nlohmann::json version") +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json + GIT_TAG ${nlohmann_json_VERSION} +) +FetchContent_GetProperties(nlohmann_json) +if(NOT nlohmann_json) + FetchContent_Populate(nlohmann_json) + add_subdirectory(${nlohmann_json_SOURCE_DIR} ${nlohmann_json_BUILD_DIR}) +endif() +FetchContent_MakeAvailable(nlohmann_json) + +message("Fetching nlohmann json-schema-validator... ") +FetchContent_Declare( + nlohmann_json_schema_validator + GIT_REPOSITORY https://github.com/pboettch/json-schema-validator.git + GIT_TAG 2.3.0 +) +FetchContent_GetProperties(nlohmann_json_schema_validator) +if(NOT nlohmann_json_schema_validator) + FetchContent_Populate(nlohmann_json_schema_validator) + add_subdirectory(${nlohmann_json_schema_validator_SOURCE_DIR} ${nlohmann_json_schema_validator_BUILD_DIR}) +endif() +FetchContent_MakeAvailable(nlohmann_json_schema_validator) + +message("Fetching googletest... ") +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest + GIT_TAG v1.15.2 +) +FetchContent_GetProperties(googletest) +if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + add_subdirectory(${googletest_SOURCE_DIR} ${google_BUILD_DIR}) endif() +FetchContent_MakeAvailable(googletest) + +include_directories( + ${nlohmann_json_SOURCE_DIR}/include + ${nlohmann_json_schema_validator_SOURCE_DIR}/src + ${googletest_SOURCE_DIR}/googletest/include + ${googletest_SOURCE_DIR}/googlemock/include +) + +# if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX ${SYSROOT_PATH}/usr CACHE INTERNAL "" FORCE) + set(CMAKE_PREFIX_PATH ${SYSROOT_PATH}/usr/lib/cmake CACHE INTERNAL "" FORCE) +# endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" @@ -42,15 +96,25 @@ include(HelperFunctions) set(FIREBOLT_NAMESPACE ${PROJECT_NAME} CACHE STRING "Namespace of the project") +message("CMAKE_PREFIX_PATH: " ${CMAKE_PREFIX_PATH}) + find_package(WPEFramework CONFIG REQUIRED) +if (ENABLE_TESTS AND ENABLE_COVERAGE) + include(CodeCoverage) + append_coverage_compiler_flags() +endif() + add_subdirectory(src) if (ENABLE_TESTS) - add_subdirectory(test) + enable_testing() + add_subdirectory(test) endif() + + # make sure others can make use cmake settings of Firebolt OpenRPC configure_file( "${CMAKE_SOURCE_DIR}/cmake/project.cmake.in" "${CMAKE_BINARY_DIR}/${FIREBOLT_NAMESPACE}Config.cmake" - @ONLY) + @ONLY) \ No newline at end of file diff --git a/languages/cpp/src/shared/include/json_engine.h b/languages/cpp/src/shared/include/json_engine.h new file mode 100644 index 00000000..d2e2b308 --- /dev/null +++ b/languages/cpp/src/shared/include/json_engine.h @@ -0,0 +1,191 @@ +#include +#include + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include +#include + +using nlohmann::json; +using nlohmann::json_schema::json_validator; +using namespace ::testing; + +#define REMOVE_QUOTES(s) (s.substr(1, s.length() - 2)) +#define STRING_TO_BOOL(s) (s == "true" ? true : false) + + +inline std::string capitalizeFirstChar(std::string str) { + if (!str.empty()) { + str[0] = std::toupper(str[0]); + } + return str; +} + + +class JsonEngine +{ + private: + std::ifstream _file; + nlohmann::json _data; + + public: + + JsonEngine() + { + _data = read_json_from_file("../../firebolt-core-open-rpc.json"); + } + + ~JsonEngine(){ + if (_file.is_open()) + _file.close(); + } + + std::string get_value(const std::string& method_name) + { + for (const auto &method : _data["methods"]) + { + if (method.contains("name") && (method["name"] == method_name)) + { + auto value = method["examples"][0]["result"]["value"]; + return value.dump(); + } + } + return ""; + } + + json read_json_from_file(const std::string &filename) + { + std::ifstream file(filename); + if (!file.is_open()) + { + throw std::runtime_error("Could not open file: " + filename); + } + + json j; + file >> j; + return j; + } + + json resolve_reference(const json &full_schema, const std::string &ref) + { + if (ref.find("#/") != 0) + { + throw std::invalid_argument("Only internal references supported"); + } + + std::string path = ref.substr(2); + std::istringstream ss(path); + std::string token; + json current = full_schema; + + while (std::getline(ss, token, '/')) + { + if (current.contains(token)) + { + current = current[token]; + } + else + { + throw std::invalid_argument("Invalid reference path: " + ref); + } + } + + return current; + } + + json process_schema(json schema, const json &full_schema) + { + if (schema.is_object()) + { + if (schema.contains("$ref")) + { + std::string ref = schema["$ref"]; + schema = resolve_reference(full_schema, ref); + } + + for (auto &el : schema.items()) + { + el.value() = process_schema(el.value(), full_schema); + } + } + else if (schema.is_array()) + { + for (auto &el : schema) + { + el = process_schema(el, full_schema); + } + } + + return schema; + } + + + #ifdef UNIT_TEST + + // template + void MockRequest(const WPEFramework::Core::JSONRPC::Message* message) + { + std::string methodName = capitalizeFirstChar(message->Designator.Value().c_str()); + + /* TODO: Add a flag here that will be set to true if the method name is found in the rpc block, u + Use the flag to validate "Method not found" or other errors from SDK if applicable */ + for (const auto &method : _data["methods"]) + { + if (method.contains("name") && (method["name"] == methodName)) + { + // Method name validation + EXPECT_EQ(methodName, method["name"]); + + // ID Validation + // TODO: Check if id gets incremented by 1 for each request + EXPECT_THAT(message->Id, AllOf(Ge(1),Le(std::numeric_limits::max()))); + + // Schema validation + const json requestParams = json::parse(message->Parameters.Value()); + if(method["params"].empty()) { + std::cout << "Schema validation for empty parameters" << std::endl; + EXPECT_EQ(requestParams, "{}"_json); + } + else { + json_validator validator(nullptr, nlohmann::json_schema::default_string_format_check); + const json openRPCParams = method["params"]; + for (auto& item : openRPCParams.items()) { + std::string key = item.key(); + json currentSchema = item.value(); + std::string paramName = currentSchema["name"]; + if (requestParams.contains(paramName)) { + json dereferenced_schema = process_schema(currentSchema, _data); + try{ + validator.set_root_schema(dereferenced_schema["schema"]); + validator.validate(requestParams[paramName]); + std::cout << "Schema validation succeeded" << std::endl; + } + catch (const std::exception &e){ + FAIL() << "Schema validation error: " << e.what() << std::endl; + } + } + } + } + } + } + } + + template + Firebolt::Error MockResponse(WPEFramework::Core::JSONRPC::Message &message, RESPONSE &response) + { + std::string methodName = capitalizeFirstChar(message.Designator.Value().c_str()); + + // Loop through the methods to find the one with the given name + for (const auto &method : _data["methods"]) + { + if (method.contains("name") && (method["name"] == methodName)) + { + message.Result = method["examples"][0]["result"]["value"].dump(); + } + } + return Firebolt::Error::None; + } +#endif +}; + diff --git a/languages/cpp/src/shared/src/CMakeLists.txt b/languages/cpp/src/shared/src/CMakeLists.txt index 222ba35f..1f116522 100644 --- a/languages/cpp/src/shared/src/CMakeLists.txt +++ b/languages/cpp/src/shared/src/CMakeLists.txt @@ -31,17 +31,23 @@ add_library(${TARGET} ${FIREBOLT_LIBRARY_TYPE} Async/Async.cpp ) +if(ENABLE_UNIT_TESTS) + target_compile_definitions(FireboltSDK PRIVATE UNIT_TEST) +endif() + set(CMAKE_POSITION_INDEPENDENT_CODE ON) find_package(${NAMESPACE}WebSocket CONFIG REQUIRED) find_package(${NAMESPACE}WebSocket CONFIG REQUIRED) find_package(${NAMESPACE}Core CONFIG REQUIRED) +find_package(${NAMESPACE}Cryptalgo CONFIG REQUIRED) target_link_libraries(${TARGET} PUBLIC ${NAMESPACE}WebSocket::${NAMESPACE}WebSocket ${NAMESPACE}Core::${NAMESPACE}Core ${NAMESPACE}WebSocket::${NAMESPACE}WebSocket + ${NAMESPACE}Cryptalgo::${NAMESPACE}Cryptalgo ) target_include_directories(${TARGET} @@ -76,4 +82,4 @@ install( InstallHeaders(TARGET ${TARGET} HEADERS . NAMESPACE ${FIREBOLT_NAMESPACE} DESTINATION ${FIREBOLT_NAMESPACE}SDK) InstallCMakeConfig(TARGETS ${TARGET}) -InstallPackageConfig(TARGETS ${TARGET} DESCRIPTION "Firebolt SDK Library") +InstallPackageConfig(TARGETS ${TARGET} DESCRIPTION "Firebolt SDK Library") \ No newline at end of file diff --git a/languages/cpp/src/shared/src/Event/Event.cpp b/languages/cpp/src/shared/src/Event/Event.cpp index 5d739d70..6f771462 100644 --- a/languages/cpp/src/shared/src/Event/Event.cpp +++ b/languages/cpp/src/shared/src/Event/Event.cpp @@ -22,7 +22,8 @@ namespace FireboltSDK { Event* Event::_singleton = nullptr; Event::Event() - : _eventMap() + : _internalEventMap() + , _externalEventMap() , _adminLock() , _transport(nullptr) { @@ -87,77 +88,111 @@ namespace FireboltSDK { } return result; } - + + + /* This function combines both internal and external event maps, and iterates over them to find the specified event. + If the event is found, it iterates over its associated callbacks, updating their states and executing them if applicable. + Callbacks in the REVOKED state are removed. + */ Firebolt::Error Event::Dispatch(const string& eventName, const WPEFramework::Core::ProxyType& jsonResponse) /* override */ { string response = jsonResponse->Result.Value(); - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.find(eventName); - if (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.begin(); - while(callbackIndex != eventIndex->second.end()) { - State state; - if (callbackIndex->second.state != State::REVOKED) { - callbackIndex->second.state = State::EXECUTING; - } - state = callbackIndex->second.state; - _adminLock.Unlock(); - if (state == State::EXECUTING) { - callbackIndex->second.lambda(callbackIndex->first, callbackIndex->second.userdata, (jsonResponse->Result.Value())); - } - _adminLock.Lock(); - if (callbackIndex->second.state == State::REVOKED) { - callbackIndex = eventIndex->second.erase(callbackIndex); - if (eventIndex->second.size() == 0) { - _eventMap.erase(eventIndex); + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + // Combine both _internalEventMap and _externalEventMap into a single loop + for (auto eventMap : eventMaps) { + _adminLock.Lock(); + EventMap::iterator eventIndex = eventMap->find(eventName); + if (eventIndex != eventMap->end()) { + CallbackMap& callbacks = eventIndex->second; + for (CallbackMap::iterator callbackIndex = callbacks.begin(); callbackIndex != callbacks.end();) { + State state; + if (callbackIndex->second.state != State::REVOKED) { + callbackIndex->second.state = State::EXECUTING; + } + state = callbackIndex->second.state; + _adminLock.Unlock(); + if (state == State::EXECUTING) { + callbackIndex->second.lambda(callbackIndex->first, callbackIndex->second.userdata, response); + } + _adminLock.Lock(); + if (callbackIndex->second.state == State::REVOKED) { + callbackIndex = callbacks.erase(callbackIndex); + if (callbacks.empty()) { + eventMap->erase(eventIndex); // Erase from the correct eventMap + break; // No need to continue iterating if map is empty + } + } else { + callbackIndex->second.state = State::IDLE; + ++callbackIndex; } - } else { - callbackIndex->second.state = State::IDLE; - callbackIndex++; } } + _adminLock.Unlock(); } - _adminLock.Unlock(); - - return Firebolt::Error::None;; + return Firebolt::Error::None; } + Firebolt::Error Event::Revoke(const string& eventName, void* usercb) { Firebolt::Error status = Firebolt::Error::None; - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.begin(); - if (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); - if (callbackIndex->second.state != State::EXECUTING) { + + // Combine both _internalEventMap and _externalEventMap into a single loop + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + for (auto eventMap : eventMaps) { + _adminLock.Lock(); // Lock inside the loop + + // Find the eventIndex for eventName in the current eventMap + EventMap::iterator eventIndex = eventMap->find(eventName); + if (eventIndex != eventMap->end()) { + // Find the callbackIndex for usercb in the current CallbackMap + CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); if (callbackIndex != eventIndex->second.end()) { - eventIndex->second.erase(callbackIndex); + // Check if callback is not executing, then erase it + if (callbackIndex->second.state != State::EXECUTING) { + eventIndex->second.erase(callbackIndex); + } else { + // Mark the callback as revoked + callbackIndex->second.state = State::REVOKED; + } + + // Check if the CallbackMap is empty after potential erasure + if (eventIndex->second.empty()) { + eventMap->erase(eventIndex); + } else { + // Set status to General error if CallbackMap is not empty + status = Firebolt::Error::General; + } } - } else { - callbackIndex->second.state = State::REVOKED; - } - if (eventIndex->second.size() == 0) { - _eventMap.erase(eventIndex); - } else { - status = Firebolt::Error::General; } + + _adminLock.Unlock(); // Unlock after processing each eventMap } - _adminLock.Unlock(); return status; } void Event::Clear() { - EventMap::iterator eventIndex = _eventMap.begin(); - while (eventIndex != _eventMap.end()) { - CallbackMap::iterator callbackIndex = eventIndex->second.begin(); - while (callbackIndex != eventIndex->second.end()) { - callbackIndex = eventIndex->second.erase(callbackIndex); + // Clear both _internalEventMap and _externalEventMap + std::vector eventMaps = {&_internalEventMap, &_externalEventMap}; + + for (auto eventMap : eventMaps) { + _adminLock.Lock(); // Lock before clearing + + EventMap::iterator eventIndex = eventMap->begin(); + while (eventIndex != eventMap->end()) { + CallbackMap::iterator callbackIndex = eventIndex->second.begin(); + while (callbackIndex != eventIndex->second.end()) { + callbackIndex = eventIndex->second.erase(callbackIndex); + } + eventIndex = eventMap->erase(eventIndex); } - eventIndex = _eventMap.erase(eventIndex); + + _adminLock.Unlock(); // Unlock after clearing } - _adminLock.Unlock(); } -} +} \ No newline at end of file diff --git a/languages/cpp/src/shared/src/Event/Event.h b/languages/cpp/src/shared/src/Event/Event.h index 7299fde0..6e599716 100644 --- a/languages/cpp/src/shared/src/Event/Event.h +++ b/languages/cpp/src/shared/src/Event/Event.h @@ -80,44 +80,55 @@ namespace FireboltSDK { } template - Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata) + Firebolt::Error Subscribe(const string& eventName, JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata, bool prioritize = false) { Firebolt::Error status = Firebolt::Error::General; + if (_transport != nullptr) { + EventMap& eventMap = prioritize ? _internalEventMap : _externalEventMap; + + status = Assign(eventMap, eventName, callback, usercb, userdata); - status = Assign(eventName, callback, usercb, userdata); if (status == Firebolt::Error::None) { Response response; - WPEFramework::Core::JSON::Variant Listen = true; jsonParameters.Set(_T("listen"), Listen); string parameters; jsonParameters.ToString(parameters); - status = _transport->Subscribe(eventName, parameters, response); + status = _transport->Subscribe(eventName, parameters, response, prioritize); if (status != Firebolt::Error::None) { Revoke(eventName, usercb); - } else if ((response.Listening.IsSet() == true) && - (response.Listening.Value() == true)) { + } else if (response.Listening.IsSet() && response.Listening.Value()) { status = Firebolt::Error::None; } } } + return status; + } + // To prioritize internal and external events and its corresponding callbacks + template + Firebolt::Error Prioritize(const string& eventName,JsonObject& jsonParameters, const CALLBACK& callback, void* usercb, const void* userdata) + { + Firebolt::Error status = Firebolt::Error::General; + // Assuming prioritized events also need subscription via transport + status = Subscribe(eventName, jsonParameters, callback, usercb, userdata, true); return status; } + Firebolt::Error Unsubscribe(const string& eventName, void* usercb); private: template - Firebolt::Error Assign(const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) + Firebolt::Error Assign(EventMap& eventMap, const string& eventName, const CALLBACK& callback, void* usercb, const void* userdata) { + Firebolt::Error status = Firebolt::Error::General; std::function actualCallback = callback; DispatchFunction implementation = [actualCallback](void* usercb, const void* userdata, const string& parameters) -> Firebolt::Error { - WPEFramework::Core::ProxyType* inbound = new WPEFramework::Core::ProxyType(); *inbound = WPEFramework::Core::ProxyType::Create(); (*inbound)->FromString(parameters); @@ -125,12 +136,13 @@ namespace FireboltSDK { return (Firebolt::Error::None); }; CallbackData callbackData = {implementation, userdata, State::IDLE}; - _adminLock.Lock(); - EventMap::iterator eventIndex = _eventMap.find(eventName); - if (eventIndex != _eventMap.end()) { + EventMap::iterator eventIndex = eventMap.find(eventName); + if (eventIndex != eventMap.end()) { CallbackMap::iterator callbackIndex = eventIndex->second.find(usercb); + if (callbackIndex == eventIndex->second.end()) { + std::cout << "Registering new callback for event: " << eventName << std::endl; eventIndex->second.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData)); status = Firebolt::Error::None; } @@ -138,7 +150,7 @@ namespace FireboltSDK { CallbackMap callbackMap; callbackMap.emplace(std::piecewise_construct, std::forward_as_tuple(usercb), std::forward_as_tuple(callbackData)); - _eventMap.emplace(std::piecewise_construct, std::forward_as_tuple(eventName), std::forward_as_tuple(callbackMap)); + eventMap.emplace(std::piecewise_construct, std::forward_as_tuple(eventName), std::forward_as_tuple(callbackMap)); status = Firebolt::Error::None; } @@ -153,11 +165,12 @@ namespace FireboltSDK { Firebolt::Error ValidateResponse(const WPEFramework::Core::ProxyType& jsonResponse, bool& enabled) override; Firebolt::Error Dispatch(const string& eventName, const WPEFramework::Core::ProxyType& jsonResponse) override; - private: - EventMap _eventMap; + private: + EventMap _internalEventMap; + EventMap _externalEventMap; WPEFramework::Core::CriticalSection _adminLock; Transport* _transport; static Event* _singleton; }; -} +} \ No newline at end of file diff --git a/languages/cpp/src/shared/src/Logger/Logger.cpp b/languages/cpp/src/shared/src/Logger/Logger.cpp index c66c6b68..35ffdc29 100644 --- a/languages/cpp/src/shared/src/Logger/Logger.cpp +++ b/languages/cpp/src/shared/src/Logger/Logger.cpp @@ -37,6 +37,8 @@ ENUM_CONVERSION_BEGIN(FireboltSDK::Logger::Category) { FireboltSDK::Logger::Category::Core, _TXT("FireboltSDK::Core") }, { FireboltSDK::Logger::Category::Manage, _TXT("FireboltSDK::Manage") }, { FireboltSDK::Logger::Category::Discovery, _TXT("FireboltSDK::Discovery") }, + { FireboltSDK::Logger::Category::PlayerProvider, _TXT("FireboltSDK::PlayerProvider") }, + { FireboltSDK::Logger::Category::PlayerProvider, _TXT("FireboltSDK::PlayerManager") }, ENUM_CONVERSION_END(FireboltSDK::Logger::Category) diff --git a/languages/cpp/src/shared/src/Logger/Logger.h b/languages/cpp/src/shared/src/Logger/Logger.h index c88b87e8..e8b6946a 100644 --- a/languages/cpp/src/shared/src/Logger/Logger.h +++ b/languages/cpp/src/shared/src/Logger/Logger.h @@ -39,7 +39,9 @@ namespace FireboltSDK { OpenRPC, Core, Manage, - Discovery + Discovery, + PlayerProvider, + PlayerManager, }; public: diff --git a/languages/cpp/src/shared/src/Transport/Transport.h b/languages/cpp/src/shared/src/Transport/Transport.h index 0caa7603..f7a77b23 100644 --- a/languages/cpp/src/shared/src/Transport/Transport.h +++ b/languages/cpp/src/shared/src/Transport/Transport.h @@ -18,104 +18,117 @@ #pragma once +#include #include "Module.h" #include "error.h" +#include "json_engine.h" -namespace FireboltSDK { +namespace FireboltSDK +{ using namespace WPEFramework::Core::TypeTraits; - template - class CommunicationChannel { + template + class CommunicationChannel + { public: - typedef std::function Callback; - class Entry { + typedef std::function Callback; + class Entry + { private: - Entry(const Entry&) = delete; - Entry& operator=(const Entry& rhs) = delete; - struct Synchronous { + Entry(const Entry &) = delete; + Entry &operator=(const Entry &rhs) = delete; + struct Synchronous + { Synchronous() - : _signal(false, true) - , _response() + : _signal(false, true), _response() { } WPEFramework::Core::Event _signal; std::list> _response; }; - struct ASynchronous { - ASynchronous(const uint32_t waitTime, const Callback& completed) - : _waitTime(WPEFramework::Core::Time::Now().Add(waitTime).Ticks()) - , _completed(completed) + struct ASynchronous + { + ASynchronous(const uint32_t waitTime, const Callback &completed) + : _waitTime(WPEFramework::Core::Time::Now().Add(waitTime).Ticks()), _completed(completed) { } uint64_t _waitTime; Callback _completed; - }; + }; public: Entry() - : _synchronous(true) - , _info() + : _synchronous(true), _info() { } - Entry(const uint32_t waitTime, const Callback& completed) - : _synchronous(false) - , _info(waitTime, completed) + Entry(const uint32_t waitTime, const Callback &completed) + : _synchronous(false), _info(waitTime, completed) { } ~Entry() { - if (_synchronous == true) { + if (_synchronous == true) + { _info.sync.~Synchronous(); } - else { + else + { _info.async.~ASynchronous(); } } public: - const WPEFramework::Core::ProxyType& Response() const + const WPEFramework::Core::ProxyType &Response() const { return (*(_info.sync._response.begin())); } - bool Signal(const WPEFramework::Core::ProxyType& response) + bool Signal(const WPEFramework::Core::ProxyType &response) { - if (_synchronous == true) { + if (_synchronous == true) + { _info.sync._response.push_back(response); _info.sync._signal.SetEvent(); } - else { + else + { _info.async._completed(*response); } return (_synchronous == false); } - const uint64_t& Expiry() const + const uint64_t &Expiry() const { return (_info.async._waitTime); } void Abort(const uint32_t id) { - if (_synchronous == true) { + if (_synchronous == true) + { _info.sync._signal.SetEvent(); } - else { + else + { MESSAGETYPE message; ToMessage(id, message, WPEFramework::Core::ERROR_ASYNC_ABORTED); _info.async._completed(message); } } - bool Expired(const uint32_t id, const uint64_t& currentTime, uint64_t& nextTime) + bool Expired(const uint32_t id, const uint64_t ¤tTime, uint64_t &nextTime) { bool expired = false; - if (_synchronous == false) { - if (_info.async._waitTime > currentTime) { - if (_info.async._waitTime < nextTime) { + if (_synchronous == false) + { + if (_info.async._waitTime > currentTime) + { + if (_info.async._waitTime < nextTime) + { nextTime = _info.async._waitTime; } } - else { + else + { MESSAGETYPE message; ToMessage(id, message, WPEFramework::Core::ERROR_TIMEDOUT); _info.async._completed(message); @@ -130,30 +143,34 @@ namespace FireboltSDK { } private: - void ToMessage(const uint32_t id, WPEFramework::Core::JSONRPC::Message& message, uint32_t error) - { - message.Id = id; - message.Error.Code = error; - switch (error) { - case WPEFramework::Core::ERROR_ASYNC_ABORTED: { - message.Error.Text = _T("Pending a-sync call has been aborted"); - break; - } - case WPEFramework::Core::ERROR_TIMEDOUT: { - message.Error.Text = _T("Pending a-sync call has timed out"); - break; - } - } + void ToMessage(const uint32_t id, WPEFramework::Core::JSONRPC::Message &message, uint32_t error) + { + message.Id = id; + message.Error.Code = error; + switch (error) + { + case WPEFramework::Core::ERROR_ASYNC_ABORTED: + { + message.Error.Text = _T("Pending a-sync call has been aborted"); + break; + } + case WPEFramework::Core::ERROR_TIMEDOUT: + { + message.Error.Text = _T("Pending a-sync call has timed out"); + break; + } + } } bool _synchronous; - union Info { + union Info + { public: Info() : sync() { } - Info(const uint32_t waitTime, const Callback& completed) + Info(const uint32_t waitTime, const Callback &completed) : async(waitTime, completed) { } @@ -165,25 +182,25 @@ namespace FireboltSDK { } _info; }; - - private: - class FactoryImpl { + class FactoryImpl + { private: - FactoryImpl(const FactoryImpl&) = delete; - FactoryImpl& operator=(const FactoryImpl&) = delete; + FactoryImpl(const FactoryImpl &) = delete; + FactoryImpl &operator=(const FactoryImpl &) = delete; - class WatchDog { + class WatchDog + { private: WatchDog() = delete; - WatchDog& operator=(const WatchDog&) = delete; + WatchDog &operator=(const WatchDog &) = delete; public: - WatchDog(CLIENT* client) + WatchDog(CLIENT *client) : _client(client) { } - WatchDog(const WatchDog& copy) + WatchDog(const WatchDog ©) : _client(copy._client) { } @@ -191,34 +208,34 @@ namespace FireboltSDK { { } - bool operator==(const WatchDog& rhs) const + bool operator==(const WatchDog &rhs) const { return (rhs._client == _client); } - bool operator!=(const WatchDog& rhs) const + bool operator!=(const WatchDog &rhs) const { return (!operator==(rhs)); } public: - uint64_t Timed(const uint64_t scheduledTime) { + uint64_t Timed(const uint64_t scheduledTime) + { return (_client->Timed()); } private: - CLIENT* _client; + CLIENT *_client; }; friend WPEFramework::Core::SingletonType; FactoryImpl() - : _messageFactory(2) - , _watchDog(WPEFramework::Core::Thread::DefaultStackSize(), _T("TransportCleaner")) + : _messageFactory(2), _watchDog(WPEFramework::Core::Thread::DefaultStackSize(), _T("TransportCleaner")) { } public: - static FactoryImpl& Instance() + static FactoryImpl &Instance() { return (WPEFramework::Core::SingletonType::Instance()); } @@ -228,49 +245,51 @@ namespace FireboltSDK { } public: - WPEFramework::Core::ProxyType Element(const string&) + WPEFramework::Core::ProxyType Element(const string &) { return (_messageFactory.Element()); } - void Trigger(const uint64_t& time, CLIENT* client) + void Trigger(const uint64_t &time, CLIENT *client) { _watchDog.Trigger(time, client); } - void Revoke(CLIENT* client) + void Revoke(CLIENT *client) { _watchDog.Revoke(client); } + private: WPEFramework::Core::ProxyPoolType _messageFactory; WPEFramework::Core::TimerType _watchDog; }; - class ChannelImpl : public WPEFramework::Core::StreamJSONType, FactoryImpl&, INTERFACE> { + class ChannelImpl : public WPEFramework::Core::StreamJSONType, FactoryImpl &, INTERFACE> + { private: - ChannelImpl(const ChannelImpl&) = delete; - ChannelImpl& operator=(const ChannelImpl&) = delete; + ChannelImpl(const ChannelImpl &) = delete; + ChannelImpl &operator=(const ChannelImpl &) = delete; - typedef WPEFramework::Core::StreamJSONType, FactoryImpl&, INTERFACE> BaseClass; + typedef WPEFramework::Core::StreamJSONType, FactoryImpl &, INTERFACE> BaseClass; public: - ChannelImpl(CommunicationChannel* parent, const WPEFramework::Core::NodeId& remoteNode, const string& path, const string& query, const bool mask) - : BaseClass(5, FactoryImpl::Instance(), path, _T("JSON"), query, "", false, mask, false, remoteNode.AnyInterface(), remoteNode, 512, 512) - , _parent(*parent) + ChannelImpl(CommunicationChannel *parent, const WPEFramework::Core::NodeId &remoteNode, const string &path, const string &query, const bool mask) + : BaseClass(5, FactoryImpl::Instance(), path, _T("JSON"), query, "", false, mask, false, remoteNode.AnyInterface(), remoteNode, 512, 512), _parent(*parent) { } ~ChannelImpl() override = default; public: - void Received(WPEFramework::Core::ProxyType& response) override + void Received(WPEFramework::Core::ProxyType &response) override { WPEFramework::Core::ProxyType inbound(response); ASSERT(inbound.IsValid() == true); - if (inbound.IsValid() == true) { + if (inbound.IsValid() == true) + { _parent.Inbound(inbound); } } - void Send(WPEFramework::Core::ProxyType& msg) override + void Send(WPEFramework::Core::ProxyType &msg) override { #ifdef __DEBUG__ string message; @@ -288,43 +307,45 @@ namespace FireboltSDK { } private: - void ToMessage(const WPEFramework::Core::ProxyType& jsonObject, string& message) const + void ToMessage(const WPEFramework::Core::ProxyType &jsonObject, string &message) const { WPEFramework::Core::ProxyType inbound(jsonObject); ASSERT(inbound.IsValid() == true); - if (inbound.IsValid() == true) { + if (inbound.IsValid() == true) + { inbound->ToString(message); } } - void ToMessage(const WPEFramework::Core::ProxyType& jsonObject, string& message) const + void ToMessage(const WPEFramework::Core::ProxyType &jsonObject, string &message) const { WPEFramework::Core::ProxyType inbound(jsonObject); ASSERT(inbound.IsValid() == true); - if (inbound.IsValid() == true) { + if (inbound.IsValid() == true) + { std::vector values; inbound->ToBuffer(values); - if (values.empty() != true) { + if (values.empty() != true) + { WPEFramework::Core::ToString(values.data(), static_cast(values.size()), false, message); } } } private: - CommunicationChannel& _parent; + CommunicationChannel &_parent; }; protected: - CommunicationChannel(const WPEFramework::Core::NodeId& remoteNode, const string& path, const string& query, const bool mask) - : _channel(this, remoteNode, path, query, mask) - , _sequence(0) + CommunicationChannel(const WPEFramework::Core::NodeId &remoteNode, const string &path, const string &query, const bool mask) + : _channel(this, remoteNode, path, query, mask), _sequence(0) { } public: ~CommunicationChannel() = default; - static WPEFramework::Core::ProxyType Instance(const WPEFramework::Core::NodeId& remoteNode, const string& path, const string& query, const bool mask = true) + static WPEFramework::Core::ProxyType Instance(const WPEFramework::Core::NodeId &remoteNode, const string &path, const string &query, const bool mask = true) { static WPEFramework::Core::ProxyMapType channelMap; @@ -334,7 +355,7 @@ namespace FireboltSDK { } public: - static void Trigger(const uint64_t& time, CLIENT* client) + static void Trigger(const uint64_t &time, CLIENT *client) { FactoryImpl::Instance().Trigger(time, client); } @@ -346,31 +367,44 @@ namespace FireboltSDK { { return (++_sequence); } - void Register(CLIENT& client) + void Register(CLIENT &client) { _adminLock.Lock(); ASSERT(std::find(_observers.begin(), _observers.end(), &client) == _observers.end()); _observers.push_back(&client); - if (_channel.IsOpen() == true) { + if (true) + { client.Opened(); } _adminLock.Unlock(); } - void Unregister(CLIENT& client) + void Unregister(CLIENT &client) { _adminLock.Lock(); - typename std::list::iterator index(std::find(_observers.begin(), _observers.end(), &client)); - if (index != _observers.end()) { - _observers.erase(index); + typename std::list::iterator index(std::find(_observers.begin(), _observers.end(), &client)); + if (index != _observers.end()) + { + _observers.erase(index); } FactoryImpl::Instance().Revoke(&client); _adminLock.Unlock(); } - void Submit(const WPEFramework::Core::ProxyType& message) +// Send requests to JSON engine's mockRequest method for unit testing instead of channel's submit method +#ifdef UNIT_TEST + void Submit(const WPEFramework::Core::ProxyType &message) + { + const WPEFramework::Core::JSONRPC::Message *jsonRpcMessage = dynamic_cast(message.operator->()); + std::unique_ptr jsonEngine = std::make_unique(); + jsonEngine->MockRequest(jsonRpcMessage); + } +#else + + void Submit(const WPEFramework::Core::ProxyType &message) { _channel.Submit(message); } +#endif bool IsSuspended() const { return (_channel.IsSuspended()); @@ -383,27 +417,48 @@ namespace FireboltSDK { { Close(); } + +// Always return true for unit testing +#ifdef UNIT_TEST + bool IsOpen() + { + return true; + } + +#else bool IsOpen() { return (_channel.IsOpen() == true); } - +#endif + protected: void StateChange() { _adminLock.Lock(); - typename std::list::iterator index(_observers.begin()); - while (index != _observers.end()) { - if (_channel.IsOpen() == true) { + typename std::list::iterator index(_observers.begin()); + while (index != _observers.end()) + { + if (_channel.IsOpen() == true) + { (*index)->Opened(); } - else { + else + { (*index)->Closed(); } index++; } _adminLock.Unlock(); } + +// Always return true for unit testing +#ifdef UNIT_TEST + bool Open(const uint32_t waitTime) + { + return true; + } +#else bool Open(const uint32_t waitTime) { bool result = true; @@ -412,18 +467,21 @@ namespace FireboltSDK { } return (result); } + +#endif void Close() { _channel.Close(WPEFramework::Core::infinite); } private: - int32_t Inbound(const WPEFramework::Core::ProxyType& inbound) + int32_t Inbound(const WPEFramework::Core::ProxyType &inbound) { int32_t result = WPEFramework::Core::ERROR_UNAVAILABLE; _adminLock.Lock(); - typename std::list::iterator index(_observers.begin()); - while ((result != WPEFramework::Core::ERROR_NONE) && (index != _observers.end())) { + typename std::list::iterator index(_observers.begin()); + while ((result != WPEFramework::Core::ERROR_NONE) && (index != _observers.end())) + { result = (*index)->Submit(inbound); index++; } @@ -436,42 +494,44 @@ namespace FireboltSDK { WPEFramework::Core::CriticalSection _adminLock; ChannelImpl _channel; mutable std::atomic _sequence; - std::list _observers; + std::list _observers; }; - class IEventHandler { + class IEventHandler + { public: - virtual Firebolt::Error ValidateResponse(const WPEFramework::Core::ProxyType& jsonResponse, bool& enabled) = 0; - virtual Firebolt::Error Dispatch(const string& eventName, const WPEFramework::Core::ProxyType& jsonResponse) = 0; + virtual Firebolt::Error ValidateResponse(const WPEFramework::Core::ProxyType &jsonResponse, bool &enabled) = 0; + virtual Firebolt::Error Dispatch(const string &eventName, const WPEFramework::Core::ProxyType &jsonResponse) = 0; virtual ~IEventHandler() = default; }; - template - class Transport { + template + class Transport + { private: using Channel = CommunicationChannel; using Entry = typename CommunicationChannel::Entry; using PendingMap = std::unordered_map; using EventMap = std::map; - typedef std::function& jsonResponse, bool& enabled)> EventResponseValidatioionFunction; + typedef std::function &jsonResponse, bool &enabled)> EventResponseValidatioionFunction; - class CommunicationJob : public WPEFramework::Core::IDispatch { + class CommunicationJob : public WPEFramework::Core::IDispatch + { protected: - CommunicationJob(const WPEFramework::Core::ProxyType& inbound, class Transport* parent) - : _inbound(inbound) - , _parent(parent) + CommunicationJob(const WPEFramework::Core::ProxyType &inbound, class Transport *parent) + : _inbound(inbound), _parent(parent) { } - public: + public: CommunicationJob() = delete; - CommunicationJob(const CommunicationJob&) = delete; - CommunicationJob& operator=(const CommunicationJob&) = delete; + CommunicationJob(const CommunicationJob &) = delete; + CommunicationJob &operator=(const CommunicationJob &) = delete; ~CommunicationJob() = default; public: - static WPEFramework::Core::ProxyType Create(const WPEFramework::Core::ProxyType& inbound, class Transport* parent); + static WPEFramework::Core::ProxyType Create(const WPEFramework::Core::ProxyType &inbound, class Transport *parent); void Dispatch() override { @@ -480,67 +540,60 @@ namespace FireboltSDK { private: const WPEFramework::Core::ProxyType _inbound; - class Transport* _parent; + class Transport *_parent; }; - class ConnectionJob : public WPEFramework::Core::IDispatch { + class ConnectionJob : public WPEFramework::Core::IDispatch + { protected: - ConnectionJob(class Transport* parent) + ConnectionJob(class Transport *parent) : _parent(parent) { } - public: + public: ConnectionJob() = delete; - ConnectionJob(const ConnectionJob&) = delete; - ConnectionJob& operator=(const ConnectionJob&) = delete; + ConnectionJob(const ConnectionJob &) = delete; + ConnectionJob &operator=(const ConnectionJob &) = delete; ~ConnectionJob() = default; public: - static WPEFramework::Core::ProxyType Create(class Transport* parent); + static WPEFramework::Core::ProxyType Create(class Transport *parent); void Dispatch() override { - if (Firebolt::Error::None != _parent->WaitForLinkReady()) { + if (Firebolt::Error::None != _parent->WaitForLinkReady()) + { _parent->NotifyStatus(Firebolt::Error::Timedout); } } private: const WPEFramework::Core::ProxyType _inbound; - class Transport* _parent; + class Transport *_parent; }; - protected: static constexpr uint32_t DefaultWaitTime = 10000; - inline void Announce() { + inline void Announce() + { _channel->Register(*this); } private: - static constexpr const TCHAR* PathPrefix = _T("/"); + static constexpr const TCHAR *PathPrefix = _T("/"); public: typedef std::function Listener; public: Transport() = delete; - Transport(const Transport&) = delete; - Transport& operator=(Transport&) = delete; - Transport(const WPEFramework::Core::URL& url, const uint32_t waitTime, const Listener listener) - : _adminLock() - , _connectId(WPEFramework::Core::NodeId(url.Host().Value().c_str(), url.Port().Value())) - , _channel(Channel::Instance(_connectId, ((url.Path().Value().rfind(PathPrefix, 0) == 0) ? url.Path().Value() : string(PathPrefix + url.Path().Value())), url.Query().Value(), true)) - , _eventHandler(nullptr) - , _pendingQueue() - , _scheduledTime(0) - , _waitTime(waitTime) - , _listener(listener) - , _connected(false) - , _status(Firebolt::Error::NotConnected) + Transport(const Transport &) = delete; + Transport &operator=(Transport &) = delete; + Transport(const WPEFramework::Core::URL &url, const uint32_t waitTime, const Listener listener) + : _adminLock(), _connectId(WPEFramework::Core::NodeId(url.Host().Value().c_str(), url.Port().Value())), _channel(Channel::Instance(_connectId, ((url.Path().Value().rfind(PathPrefix, 0) == 0) ? url.Path().Value() : string(PathPrefix + url.Path().Value())), url.Query().Value(), true)), _eventHandler(nullptr), _pendingQueue(), _scheduledTime(0), _waitTime(waitTime), _listener(listener), _connected(false), _status(Firebolt::Error::NotConnected) { _channel->Register(*this); WPEFramework::Core::ProxyType job = WPEFramework::Core::ProxyType(WPEFramework::Core::ProxyType::Create(this)); @@ -551,29 +604,60 @@ namespace FireboltSDK { { _channel->Unregister(*this); - for (auto& element : _pendingQueue) { + for (auto &element : _pendingQueue) + { element.second.Abort(element.first); } } public: + +// Always return true for unit testing +#ifdef UNIT_TEST inline bool IsOpen() { - return _channel->IsOpen(); + return true; } +#else + inline bool IsOpen() + { + return _channel->IsOpen(); + } +#endif - void Revoke(const string& eventName) + void Revoke(const string &eventName) { _adminLock.Lock(); - _eventMap.erase(eventName); + // Remove from internal event map + _internalEventMap.erase(eventName); + + // Remove from external event map + _externalEventMap.erase(eventName); _adminLock.Unlock(); } - void SetEventHandler(IEventHandler* eventHandler) + void SetEventHandler(IEventHandler *eventHandler) { _eventHandler = eventHandler; } +// Invoke method is overriden for unit testing to call MockResponse method from JSON engine +#ifdef UNIT_TEST + template + Firebolt::Error Invoke(const string &method, const PARAMETERS ¶meters, RESPONSE &response) + { + Entry slot; + uint32_t id = _channel->Sequence(); + Firebolt::Error result = Send(method, parameters, id); + + WPEFramework::Core::JSONRPC::Message message; + message.Designator = method; + std::unique_ptr jsonEngine = std::make_unique(); + result = jsonEngine->MockResponse(message, response); + FromMessage((INTERFACE *)&response, message); + return (result); + } +#else template Firebolt::Error Invoke(const string& method, const PARAMETERS& parameters, RESPONSE& response) { @@ -586,9 +670,10 @@ namespace FireboltSDK { return (result); } +#endif template - Firebolt::Error InvokeAsync(const string& method, const PARAMETERS& parameters, uint32_t& id) + Firebolt::Error InvokeAsync(const string &method, const PARAMETERS ¶meters, uint32_t &id) { Entry slot; id = _channel->Sequence(); @@ -634,31 +719,39 @@ namespace FireboltSDK { { _adminLock.Lock(); typename PendingMap::iterator index = _pendingQueue.find(id); - Entry& slot(index->second); + Entry &slot(index->second); _adminLock.Unlock(); slot.Abort(id); } template - Firebolt::Error Subscribe(const string& eventName, const string& parameters, RESPONSE& response) + Firebolt::Error Subscribe(const string& eventName, const string& parameters, RESPONSE& response, bool updateInternal = false) { Entry slot; uint32_t id = _channel->Sequence(); Firebolt::Error result = Send(eventName, parameters, id); + if (result == Firebolt::Error::None) { _adminLock.Lock(); - _eventMap.emplace(std::piecewise_construct, - std::forward_as_tuple(eventName), - std::forward_as_tuple(~0)); + + // Choose the map based on updateInternal flag + EventMap& eventMap = updateInternal ? _internalEventMap : _externalEventMap; + + // Add to the selected event map + eventMap.emplace(std::piecewise_construct, + std::forward_as_tuple(eventName), + std::forward_as_tuple(id)); + _adminLock.Unlock(); - result = WaitForEventResponse(id, eventName, response, _waitTime); + result = WaitForEventResponse(id, eventName, response, _waitTime, eventMap); + } - return (result); + return result; } - Firebolt::Error Unsubscribe(const string& eventName, const string& parameters) + Firebolt::Error Unsubscribe(const string &eventName, const string ¶meters) { Revoke(eventName); Entry slot; @@ -678,7 +771,8 @@ namespace FireboltSDK { static constexpr uint32_t SLEEPSLOT_TIME = 100; // Right, a wait till connection is closed is requested.. - while ((waiting > 0) && (IsOpen() == false) && (_status == Firebolt::Error::NotConnected)) { + while ((waiting > 0) && (IsOpen() == false) && (_status == Firebolt::Error::NotConnected)) + { uint32_t sleepSlot = (waiting > SLEEPSLOT_TIME ? SLEEPSLOT_TIME : waiting); @@ -695,14 +789,28 @@ namespace FireboltSDK { inline bool IsEvent(const uint32_t id, string& eventName) { _adminLock.Lock(); - for (auto& event : _eventMap) { - if (event.second == id) { - eventName = event.first; - break; + + bool eventExist = false; + + // List of maps to search + std::vector maps = {&_internalEventMap, &_externalEventMap}; + + // Loop through each map + for (const auto* map : maps) { + for (const auto& event : *map) { + if (event.second == id) { + eventName = event.first; + eventExist = true; + break; // Break the inner loop + } + } + if (eventExist) { + break; // Break the outer loop } } + _adminLock.Unlock(); - return (eventName.empty() != true); + return eventExist; } uint64_t Timed() { @@ -714,12 +822,15 @@ namespace FireboltSDK { typename PendingMap::iterator index = _pendingQueue.begin(); - while (index != _pendingQueue.end()) { + while (index != _pendingQueue.end()) + { - if (index->second.Expired(index->first, currentTime, result) == true) { + if (index->second.Expired(index->first, currentTime, result) == true) + { index = _pendingQueue.erase(index); } - else { + else + { index++; } } @@ -733,7 +844,8 @@ namespace FireboltSDK { virtual void Opened() { _status = Firebolt::Error::None; - if (_connected != true) { + if (_connected != true) + { _connected = true; _listener(_connected, _status); } @@ -745,34 +857,37 @@ namespace FireboltSDK { _adminLock.Lock(); // See if we issued anything, if so abort it.. - while (_pendingQueue.size() != 0) { + while (_pendingQueue.size() != 0) + { _pendingQueue.begin()->second.Abort(_pendingQueue.begin()->first); _pendingQueue.erase(_pendingQueue.begin()); } _adminLock.Unlock(); - if (_connected != false) { + if (_connected != false) + { _connected = false; _listener(_connected, _status); } } - int32_t Submit(const WPEFramework::Core::ProxyType& inbound) + int32_t Submit(const WPEFramework::Core::ProxyType &inbound) { int32_t result = WPEFramework::Core::ERROR_UNAVAILABLE; WPEFramework::Core::ProxyType job = WPEFramework::Core::ProxyType(WPEFramework::Core::ProxyType::Create(inbound, this)); WPEFramework::Core::IWorkerPool::Instance().Submit(job); - return result; + return 0; } - int32_t Inbound(const WPEFramework::Core::ProxyType& inbound) + int32_t Inbound(const WPEFramework::Core::ProxyType &inbound) { int32_t result = WPEFramework::Core::ERROR_INVALID_SIGNATURE; ASSERT(inbound.IsValid() == true); - if ((inbound->Id.IsSet() == true) && (inbound->Result.IsSet() || inbound->Error.IsSet())) { + if ((inbound->Id.IsSet() == true) && (inbound->Result.IsSet() || inbound->Error.IsSet())) + { // Looks like this is a response.. ASSERT(inbound->Parameters.IsSet() == false); ASSERT(inbound->Designator.IsSet() == false); @@ -782,37 +897,42 @@ namespace FireboltSDK { // See if we issued this.. typename PendingMap::iterator index = _pendingQueue.find(inbound->Id.Value()); - if (index != _pendingQueue.end()) { + if (index != _pendingQueue.end()) + { - if (index->second.Signal(inbound) == true) { + if (index->second.Signal(inbound) == true) + { _pendingQueue.erase(index); } - result = WPEFramework::Core::ERROR_NONE; + result = WPEFramework::Core::ERROR_NONE; _adminLock.Unlock(); - } else { + } + else + { _adminLock.Unlock(); string eventName; - if (IsEvent(inbound->Id.Value(), eventName)) { + if (IsEvent(inbound->Id.Value(), eventName)) + { _eventHandler->Dispatch(eventName, inbound); } - } } return (result); } - template - Firebolt::Error Send(const string& method, const PARAMETERS& parameters, const uint32_t& id) + Firebolt::Error Send(const string &method, const PARAMETERS ¶meters, const uint32_t &id) { int32_t result = WPEFramework::Core::ERROR_UNAVAILABLE; - if ((_channel.IsValid() == true) && (_channel->IsSuspended() == true)) { + if ((_channel.IsValid() == true) && (_channel->IsSuspended() == true)) + { result = WPEFramework::Core::ERROR_ASYNC_FAILED; } - else if (_channel.IsValid() == true) { + else if (_channel.IsValid() == true) + { result = WPEFramework::Core::ERROR_ASYNC_FAILED; @@ -823,13 +943,14 @@ namespace FireboltSDK { _adminLock.Lock(); - typename std::pair< typename PendingMap::iterator, bool> newElement = - _pendingQueue.emplace(std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple()); + typename std::pair newElement = + _pendingQueue.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple()); ASSERT(newElement.second == true); - if (newElement.second == true) { + if (newElement.second == true) + { _adminLock.Unlock(); @@ -841,39 +962,62 @@ namespace FireboltSDK { } return FireboltErrorValue(result); } - +#ifdef UNIT_TEST +template + Firebolt::Error WaitForEventResponse(const uint32_t &id, const string &eventName, RESPONSE &response, const uint32_t waitTime, EventMap& _eventMap) + { + std::cout << "Inside Mock Transport WaitForEventResponse function" << std::endl; + std::cout << "Mock Transport WaitForEventResponse eventName: " << eventName << std::endl; + /* Since there is no return value for event subscription, error would be the only validation for now. + Returning a mock event response from open rpc would mean that the logic in WaitForEventResponse to check a queue is not used. + At which point, the function would no longer be validating the SDK functionality. + If the queue find functionality is to be tested, the _pendingQueue could be mocked in upcoming iterations. + */ + return Firebolt::Error::None; + } +#else static constexpr uint32_t WAITSLOT_TIME = 100; template - Firebolt::Error WaitForEventResponse(const uint32_t& id, const string& eventName, RESPONSE& response, const uint32_t waitTime) + Firebolt::Error WaitForEventResponse(const uint32_t &id, const string &eventName, RESPONSE &response, const uint32_t waitTime, EventMap& _eventMap) { + std::cout << "Inside Transport WaitForEventResponse function" << std::endl; Firebolt::Error result = Firebolt::Error::Timedout; _adminLock.Lock(); typename PendingMap::iterator index = _pendingQueue.find(id); - Entry& slot(index->second); + Entry &slot(index->second); _adminLock.Unlock(); uint8_t waiting = waitTime; - do { + do + { uint32_t waitSlot = (waiting > WAITSLOT_TIME ? WAITSLOT_TIME : waiting); - if (slot.WaitForResponse(waitSlot) == true) { - WPEFramework::Core::ProxyType jsonResponse = slot.Response(); + if (slot.WaitForResponse(waitSlot) == true) + { + WPEFramework::Core::ProxyType jsonResponse = slot.Response(); // See if we have a jsonResponse, maybe it was just the connection // that closed? - if (jsonResponse.IsValid() == true) { - if (jsonResponse->Error.IsSet() == true) { + if (jsonResponse.IsValid() == true) + { + if (jsonResponse->Error.IsSet() == true) + { result = FireboltErrorValue(jsonResponse->Error.Code.Value()); - } else { - if ((jsonResponse->Result.IsSet() == true) - && (jsonResponse->Result.Value().empty() == false)) { + } + else + { + if ((jsonResponse->Result.IsSet() == true) && (jsonResponse->Result.Value().empty() == false)) + { bool enabled; result = _eventHandler->ValidateResponse(jsonResponse, enabled); - if (result == Firebolt::Error::None) { - FromMessage((INTERFACE*)&response, *jsonResponse); - if (enabled) { + if (result == Firebolt::Error::None) + { + FromMessage((INTERFACE *)&response, *jsonResponse); + if (enabled) + { _adminLock.Lock(); typename EventMap::iterator index = _eventMap.find(eventName); - if (index != _eventMap.end()) { + if (index != _eventMap.end()) + { index->second = id; } _adminLock.Unlock(); @@ -882,64 +1026,67 @@ namespace FireboltSDK { } } } - } else { + } + else + { result = Firebolt::Error::Timedout; } waiting -= (waiting == WPEFramework::Core::infinite ? 0 : waitSlot); - } while ((result != Firebolt::Error::None) && (waiting > 0 )); + } while ((result != Firebolt::Error::None) && (waiting > 0)); _adminLock.Lock(); _pendingQueue.erase(id); _adminLock.Unlock(); return result; } - +#endif public: - void FromMessage(WPEFramework::Core::JSON::IElement* response, const WPEFramework::Core::JSONRPC::Message& message) const + void FromMessage(WPEFramework::Core::JSON::IElement *response, const WPEFramework::Core::JSONRPC::Message &message) const { response->FromString(message.Result.Value()); } - void FromMessage(WPEFramework::Core::JSON::IMessagePack* response, const WPEFramework::Core::JSONRPC::Message& message) const + void FromMessage(WPEFramework::Core::JSON::IMessagePack *response, const WPEFramework::Core::JSONRPC::Message &message) const { string value = message.Result.Value(); std::vector result(value.begin(), value.end()); response->FromBuffer(result); } - private: - - void ToMessage(const string& parameters, WPEFramework::Core::ProxyType& message) const + void ToMessage(const string ¶meters, WPEFramework::Core::ProxyType &message) const { - if (parameters.empty() != true) { + if (parameters.empty() != true) + { message->Parameters = parameters; } } template - void ToMessage(PARAMETERS& parameters, WPEFramework::Core::ProxyType& message) const + void ToMessage(PARAMETERS ¶meters, WPEFramework::Core::ProxyType &message) const { - ToMessage((INTERFACE*)(¶meters), message); + ToMessage((INTERFACE *)(¶meters), message); return; } - void ToMessage(WPEFramework::Core::JSON::IMessagePack* parameters, WPEFramework::Core::ProxyType& message) const + void ToMessage(WPEFramework::Core::JSON::IMessagePack *parameters, WPEFramework::Core::ProxyType &message) const { std::vector values; parameters->ToBuffer(values); - if (values.empty() != true) { + if (values.empty() != true) + { string strValues(values.begin(), values.end()); message->Parameters = strValues; } return; } - void ToMessage(WPEFramework::Core::JSON::IElement* parameters, WPEFramework::Core::ProxyType& message) const + void ToMessage(WPEFramework::Core::JSON::IElement *parameters, WPEFramework::Core::ProxyType &message) const { string values; parameters->ToString(values); - if (values.empty() != true) { + if (values.empty() != true) + { message->Parameters = values; } return; @@ -947,9 +1094,9 @@ namespace FireboltSDK { Firebolt::Error FireboltErrorValue(const uint32_t error) { - Firebolt::Error fireboltError = static_cast(error); - switch (error) { + switch (error) + { case WPEFramework::Core::ERROR_NONE: fireboltError = Firebolt::Error::None; break; @@ -971,8 +1118,10 @@ namespace FireboltSDK { WPEFramework::Core::CriticalSection _adminLock; WPEFramework::Core::NodeId _connectId; WPEFramework::Core::ProxyType _channel; - IEventHandler* _eventHandler; + IEventHandler *_eventHandler; PendingMap _pendingQueue; + EventMap _internalEventMap; + EventMap _externalEventMap; EventMap _eventMap; uint64_t _scheduledTime; uint32_t _waitTime; @@ -980,4 +1129,4 @@ namespace FireboltSDK { bool _connected; Firebolt::Error _status; }; -} +} \ No newline at end of file diff --git a/languages/cpp/src/shared/test/CMakeLists.txt b/languages/cpp/src/shared/test/CMakeLists.txt index 012f1a6d..94923a79 100644 --- a/languages/cpp/src/shared/test/CMakeLists.txt +++ b/languages/cpp/src/shared/test/CMakeLists.txt @@ -16,64 +16,58 @@ cmake_minimum_required(VERSION 3.3) -project(FireboltSDKTests) -project_version(1.0.0) - -set(TESTLIB ${PROJECT_NAME}) - -message("Setup ${TESTLIB} v${PROJECT_VERSION}") - -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +project(FireboltCoreSDKTests) + +if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${SYSROOT_PATH}/usr" CACHE INTERNAL "" FORCE) + set(CMAKE_PREFIX_PATH ${SYSROOT_PATH}/usr/lib/cmake CACHE INTERNAL "" FORCE) +endif() + +list(APPEND CMAKE_MODULE_PATH + "${SYSROOT_PATH}/usr/lib/cmake" + "${SYSROOT_PATH}/tools/cmake") +message("FIREBOLT_PATH inside cmake " ${FIREBOLT_PATH}) +if (FIREBOLT_PATH) + set(CMAKE_FIREBOLT_PATH + "${FIREBOLT_PATH}/usr/lib/cmake/Firebolt" + "${FIREBOLT_PATH}/usr/lib/cmake/FireboltSDK") + list(APPEND CMAKE_PREFIX_PATH ${CMAKE_FIREBOLT_PATH}) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_FIREBOLT_PATH}) +else () + set(FIREBOLT_PATH "${SYSROOT_PATH}" CACHE INTERNAL "" FORCE) +endif () + +find_package(WPEFramework CONFIG REQUIRED) find_package(${NAMESPACE}Core CONFIG REQUIRED) -add_library(${TESTLIB} STATIC OpenRPCTests.cpp) - -target_link_libraries(${TESTLIB} - PUBLIC - ${NAMESPACE}Core::${NAMESPACE}Core - ${FIREBOLT_NAMESPACE}SDK -) - -target_include_directories(${TESTLIB} - PRIVATE - $ - $ -) - -set_target_properties(${TESTLIB} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES - LINK_WHAT_YOU_USE TRUE - FRAMEWORK FALSE -) - -install( - TARGETS ${TESTLIB} EXPORT ${TESTLIB}Targets - LIBRARY DESTINATION lib COMPONENT libs - PUBLIC_HEADER DESTINATION include/${FIREBOLT_NAMESPACE}Test COMPONENT devel # headers for mac (note the different component -> different package) - INCLUDES DESTINATION include/${FIREBOLT_NAMESPACE}Test # headers -) - -InstallCMakeConfig(TARGETS ${TESTLIB}) -InstallCMakeConfigs(TARGET ${TESTLIB} DESTINATION ${FIREBOLT_NAMESPACE}) -InstallHeaders(TARGET ${TESTLIB} HEADERS . NAMESPACE ${FIREBOLT_NAMESPACE} DESTINATION FireboltTest) -InstallLibraries(TARGET ${TESTLIB} STATIC LIBRARIES ${TESTLIB} DESTINATION ${FIREBOLT_NAMESPACE}) - -set(TESTAPP "FireboltSDKTestApp") +set(TESTAPP TestFireboltCore) message("Setup ${TESTAPP}") -add_executable(${TESTAPP} Main.cpp) +add_executable(${TESTAPP} CoreSDKTest.cpp Main.cpp) target_link_libraries(${TESTAPP} PRIVATE - ${TESTLIB} + ${NAMESPACE}Core::${NAMESPACE}Core + ${FIREBOLT_NAMESPACE}SDK::${FIREBOLT_NAMESPACE}SDK + nlohmann_json_schema_validator + gtest_main ) target_include_directories(${TESTAPP} PRIVATE - $ - $ + $ +) + +if (POLYMORPHICS_REDUCER_METHODS) + target_compile_definitions(${TESTAPP} + PUBLIC + POLYMORPHICS_REDUCER_METHODS=1) +endif() + +set_target_properties(${TESTAPP} PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED YES ) add_custom_command( @@ -84,3 +78,35 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/${TESTAPP} ${CMAKE_BINARY_DIR}/${FIREBOLT_NAMESPACE}/usr/bin ) +if(ENABLE_UNIT_TESTS) + set(UNIT_TESTS_APP FireboltCoreUnitTests) + + message("Setup ${UNIT_TESTS_APP}") + + add_definitions(-DUNIT_TEST) + + file(GLOB UNIT_TESTS "unit/*") + + add_executable(${UNIT_TESTS_APP} + CoreSDKTest.cpp + Unit.cpp + ${UNIT_TESTS} + ) + + link_directories(${CMAKE_SOURCE_DIR}/../../Thunder/install/usr/lib/) + target_link_libraries(${UNIT_TESTS_APP} + PRIVATE + ${NAMESPACE}Core::${NAMESPACE}Core + ${FIREBOLT_NAMESPACE}SDK::${FIREBOLT_NAMESPACE}SDK + nlohmann_json_schema_validator + gtest_main + ) + + target_include_directories(${UNIT_TESTS_APP} + PRIVATE + $ + ) + + include(GoogleTest) + gtest_discover_tests(${UNIT_TESTS_APP}) +endif() \ No newline at end of file diff --git a/languages/cpp/templates/callback-initialization/anyOf.cpp b/languages/cpp/templates/callback-initialization/anyOf.cpp index 30f233a7..92a17554 100644 --- a/languages/cpp/templates/callback-initialization/anyOf.cpp +++ b/languages/cpp/templates/callback-initialization/anyOf.cpp @@ -1 +1 @@ -{property}; + std::string ${property}; diff --git a/languages/cpp/templates/callback-initialization/tuple.cpp b/languages/cpp/templates/callback-initialization/tuple.cpp new file mode 100644 index 00000000..5cc23aca --- /dev/null +++ b/languages/cpp/templates/callback-initialization/tuple.cpp @@ -0,0 +1 @@ +${if.namespace.notsame}${parent.Title}::${end.if.namespace.notsame}${title} ${property}; \ No newline at end of file diff --git a/languages/cpp/templates/callback-result-instantiation/anyOf.cpp b/languages/cpp/templates/callback-result-instantiation/anyOf.cpp index 120561dd..6d8fa873 100644 --- a/languages/cpp/templates/callback-result-instantiation/anyOf.cpp +++ b/languages/cpp/templates/callback-result-instantiation/anyOf.cpp @@ -1 +1 @@ - ${property}; \ No newline at end of file + ${property} = proxyResponse->Value(); \ No newline at end of file diff --git a/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp b/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp index c9775b99..f3049436 100644 --- a/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp +++ b/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp @@ -6,5 +6,4 @@ } }${end.if.optional}${if.non.optional}auto index((*proxyResponse)${Property.dependency}.${Property}.Elements()); while (index.Next() == true) { -${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.value().push_back(index.Current().Value());${end.if.non.object} - }${end.if.non.optional} +${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.push_back(index.Current().Value());${end.if.non.object} }${end.if.non.optional} diff --git a/languages/cpp/templates/codeblocks/interface-focusable.cpp b/languages/cpp/templates/codeblocks/interface-focusable.cpp new file mode 100644 index 00000000..b62df483 --- /dev/null +++ b/languages/cpp/templates/codeblocks/interface-focusable.cpp @@ -0,0 +1,47 @@ + static void ProviderInvokeSession(std::string& methodName, JsonObject& jsonParameters, Firebolt::Error *err = nullptr) + { + Firebolt::Error status = Firebolt::Error::NotConnected; + FireboltSDK::Transport* transport = FireboltSDK::Accessor::Instance().GetTransport(); + if (transport != nullptr) { + + JsonObject jsonResult; + status = transport->Invoke(methodName, jsonParameters, jsonResult); + if (status == Firebolt::Error::None) { + FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "%s is successfully invoked", methodName.c_str()); + } + + } else { + FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", status); + } + if (err != nullptr) { + *err = status; + } + } + static void ProviderFocusSession(std::string methodName, std::string& correlationId, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + + ProviderInvokeSession(methodName, jsonParameters, err); + } + static void ProviderResultSession(std::string methodName, std::string& correlationId, ${provider.xresponse.name} result, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + +${provider.xresponse.serialization} + ProviderInvokeSession(methodName, jsonParameters, err); + } + static void ProviderErrorSession(std::string methodName, std::string& correlationId, ${provider.xerror.name} result, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + +${provider.xerror.serialization} + ProviderInvokeSession(methodName, jsonParameters, err); + } + +${methods} diff --git a/languages/cpp/templates/codeblocks/interface-focusable.h b/languages/cpp/templates/codeblocks/interface-focusable.h new file mode 100644 index 00000000..5a6032f0 --- /dev/null +++ b/languages/cpp/templates/codeblocks/interface-focusable.h @@ -0,0 +1,12 @@ +struct I${info.Title}Session : virtual public IFocussableProviderSession { + virtual ~I${info.Title}Session() override = default; + + virtual void error( ${provider.xerror.name} error, Firebolt::Error *err = nullptr ) = 0; + virtual void result( ${provider.xresponse.name} result, Firebolt::Error *err = nullptr ) = 0; +}; + +struct I${info.Title}Provider { + virtual ~I${info.Title}Provider() = default; + +${methods} +}; diff --git a/languages/cpp/templates/codeblocks/interface.cpp b/languages/cpp/templates/codeblocks/interface.cpp index b62df483..abab1e57 100644 --- a/languages/cpp/templates/codeblocks/interface.cpp +++ b/languages/cpp/templates/codeblocks/interface.cpp @@ -17,31 +17,5 @@ *err = status; } } - static void ProviderFocusSession(std::string methodName, std::string& correlationId, Firebolt::Error *err = nullptr) - { - JsonObject jsonParameters; - WPEFramework::Core::JSON::Variant CorrelationId(correlationId); - jsonParameters.Set(_T("correlationId"), CorrelationId); - - ProviderInvokeSession(methodName, jsonParameters, err); - } - static void ProviderResultSession(std::string methodName, std::string& correlationId, ${provider.xresponse.name} result, Firebolt::Error *err = nullptr) - { - JsonObject jsonParameters; - WPEFramework::Core::JSON::Variant CorrelationId(correlationId); - jsonParameters.Set(_T("correlationId"), CorrelationId); - -${provider.xresponse.serialization} - ProviderInvokeSession(methodName, jsonParameters, err); - } - static void ProviderErrorSession(std::string methodName, std::string& correlationId, ${provider.xerror.name} result, Firebolt::Error *err = nullptr) - { - JsonObject jsonParameters; - WPEFramework::Core::JSON::Variant CorrelationId(correlationId); - jsonParameters.Set(_T("correlationId"), CorrelationId); - -${provider.xerror.serialization} - ProviderInvokeSession(methodName, jsonParameters, err); - } ${methods} diff --git a/languages/cpp/templates/codeblocks/interface.h b/languages/cpp/templates/codeblocks/interface.h index eb299a9c..5d4f4056 100644 --- a/languages/cpp/templates/codeblocks/interface.h +++ b/languages/cpp/templates/codeblocks/interface.h @@ -1,12 +1,5 @@ -struct I${info.Title}Session : virtual public IFocussableProviderSession { - virtual ~I${info.Title}Session() override = default; - - virtual void error( ${provider.xerror.name} error, Firebolt::Error *err = nullptr ) = 0; - virtual void result( ${provider.xresponse.name} result, Firebolt::Error *err = nullptr ) = 0; -}; - struct I${info.Title}Provider { virtual ~I${info.Title}Provider() = default; ${methods} -}; \ No newline at end of file +}; diff --git a/languages/cpp/templates/declarations-override/event.h b/languages/cpp/templates/declarations-override/event.h index 25fd5887..63654969 100644 --- a/languages/cpp/templates/declarations-override/event.h +++ b/languages/cpp/templates/declarations-override/event.h @@ -2,3 +2,7 @@ // method result properties : ${method.result.properties} void subscribe( ${event.signature.params}${if.event.params}, ${end.if.event.params}I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) override; void unsubscribe( I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) override; +${if.globalsubscriber} + void globalSubscribe( I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) override; + void globalUnsubscribe( I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) override; +${end.if.globalsubscriber} \ No newline at end of file diff --git a/languages/cpp/templates/declarations/event.h b/languages/cpp/templates/declarations/event.h index 29803793..711ecf55 100644 --- a/languages/cpp/templates/declarations/event.h +++ b/languages/cpp/templates/declarations/event.h @@ -6,3 +6,7 @@ // method result properties : ${method.result.properties} virtual void subscribe( ${event.signature.params}${if.event.params}, ${end.if.event.params}I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) = 0; virtual void unsubscribe( I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) = 0; +${if.globalsubscriber} + virtual void globalSubscribe( I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) = 0; + virtual void globalUnsubscribe( I${method.Name}Notification& notification, Firebolt::Error *err = nullptr ) = 0; +${end.if.globalsubscriber} \ No newline at end of file diff --git a/languages/cpp/templates/imports/calls-metrics.impl b/languages/cpp/templates/imports/calls-metrics.impl index 75fd87c6..693dc63a 100644 --- a/languages/cpp/templates/imports/calls-metrics.impl +++ b/languages/cpp/templates/imports/calls-metrics.impl @@ -1 +1,2 @@ -#include "metrics_impl.h" +#include "firebolt.h" + diff --git a/languages/cpp/templates/interfaces/default.cpp b/languages/cpp/templates/interfaces/default.cpp index 4cba2764..055c8feb 100644 --- a/languages/cpp/templates/interfaces/default.cpp +++ b/languages/cpp/templates/interfaces/default.cpp @@ -10,8 +10,17 @@ }; static void ${info.Title}${method.Name}SessionInnerCallback( void* provider, const void* userData, void* jsonResponse ) { - //TODO: code to convert jsonResponse to ${method.name} session - I${info.Title}Provider& ${info.title.lowercase}Provider = *(reinterpret_cast(provider)); - ${info.title.lowercase}Provider.${method.name}( parameters, session ); - } +${event.callback.serialization} + ASSERT(proxyResponse.IsValid() == true); + + if (proxyResponse.IsValid() == true) { +${event.callback.initialization} +${event.callback.instantiation} + proxyResponse.Release(); + + std::unique_ptr ${info.title.lowercase}${method.Name}Session = std::make_unique<${info.Title}${method.Name}Session>(); + I${info.Title}Provider& ${info.title.lowercase}Provider = *(reinterpret_cast(provider)); + ${info.title.lowercase}Provider.${method.name}(${method.result.name}.parameters, std::move(${info.title.lowercase}${method.Name}Session)); + } + } diff --git a/languages/cpp/templates/interfaces/default.h b/languages/cpp/templates/interfaces/default.h index 05ebc463..072c0c63 100644 --- a/languages/cpp/templates/interfaces/default.h +++ b/languages/cpp/templates/interfaces/default.h @@ -1 +1 @@ - virtual void ${method.name}( ${method.signature.params}, IProviderSession& session ) = 0; \ No newline at end of file + virtual void ${method.name}( ${method.signature.params}, std::unique_ptr session ) = 0; \ No newline at end of file diff --git a/languages/cpp/templates/json-types/anyOf.h b/languages/cpp/templates/json-types/anyOf.h index fc121f63..2d60a3c8 100644 --- a/languages/cpp/templates/json-types/anyOf.h +++ b/languages/cpp/templates/json-types/anyOf.h @@ -1 +1 @@ -WPEFramework::Core::JSON::VariantContainer \ No newline at end of file +FireboltSDK::JSON::String \ No newline at end of file diff --git a/languages/cpp/templates/json-types/property-assign.cpp b/languages/cpp/templates/json-types/property-assign.cpp index 36bdbf83..ffdad03d 100644 --- a/languages/cpp/templates/json-types/property-assign.cpp +++ b/languages/cpp/templates/json-types/property-assign.cpp @@ -1,2 +1,2 @@ - Add(_T("${property}"), &${Property}); + Add(_T("${property.raw}"), &${Property}); ${Property} = other.${Property}; diff --git a/languages/cpp/templates/json-types/property-register.cpp b/languages/cpp/templates/json-types/property-register.cpp index 01e2a7e0..e4f9a2b2 100644 --- a/languages/cpp/templates/json-types/property-register.cpp +++ b/languages/cpp/templates/json-types/property-register.cpp @@ -1 +1 @@ - Add(_T("${property}"), &${Property}); \ No newline at end of file + Add(_T("${property.raw}"), &${Property}); \ No newline at end of file diff --git a/languages/cpp/templates/methods/calls-metrics.cpp b/languages/cpp/templates/methods/calls-metrics.cpp index 1b6765c6..9c508c55 100644 --- a/languages/cpp/templates/methods/calls-metrics.cpp +++ b/languages/cpp/templates/methods/calls-metrics.cpp @@ -1,6 +1,7 @@ /* ${method.name} - ${method.description} */ - static void ${method.name}Dispatcher(const void* result) { - Metrics::MetricsImpl::${method.name}(${if.result.nonboolean}${if.result.nonvoid}(static_cast<${method.result.json.type}>(const_cast(result)))${end.if.result.nonvoid}${end.if.result.nonboolean}); + static void ${method.name}Dispatcher(const void* result) { + // Accessing Metrics methods using singleton Instance + Firebolt::IFireboltAccessor::Instance().MetricsInterface().${method.name}(${if.result.nonboolean}${if.result.nonvoid}(static_cast<${method.result.json.type}>(const_cast(result)))${end.if.result.nonvoid}${end.if.result.nonboolean}); } /* ${method.name} - ${method.description} */ ${method.signature.result} ${info.Title}Impl::${method.name}( ${method.signature.params}${if.params}, ${end.if.params}Firebolt::Error *err ) ${if.result.nonvoid}${if.params.empty} const${end.if.params.empty}${end.if.result.nonvoid} diff --git a/languages/cpp/templates/methods/default.cpp b/languages/cpp/templates/methods/default.cpp index 0b5b31bf..533c914e 100644 --- a/languages/cpp/templates/methods/default.cpp +++ b/languages/cpp/templates/methods/default.cpp @@ -1,7 +1,7 @@ /* ${method.name} - ${method.description} */ ${method.signature.result} ${info.Title}Impl::${method.name}( ${method.signature.params}${if.params}, ${end.if.params}Firebolt::Error *err ) ${if.result.nonvoid}${if.params.empty} const${end.if.params.empty}${end.if.result.nonvoid} { - Firebolt::Error status = Firebolt::Error::NotConnected; + Firebolt::Error statusError = Firebolt::Error::NotConnected; ${if.result.nonvoid}${method.result.initialization}${end.if.result.nonvoid} FireboltSDK::Transport* transport = FireboltSDK::Accessor::Instance().GetTransport(); if (transport != nullptr) { @@ -9,17 +9,17 @@ JsonObject jsonParameters; ${method.params.serialization.with.indent} ${method.result.json.type} jsonResult; - status = transport->Invoke("${info.title.lowercase}.${method.name}", jsonParameters, jsonResult); - if (status == Firebolt::Error::None) { + statusError = transport->Invoke("${info.title.lowercase}.${method.name}", jsonParameters, jsonResult); + if (statusError == Firebolt::Error::None) { FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "${info.Title}.${method.name} is successfully invoked"); ${if.result.nonvoid}${method.result.instantiation.with.indent}${end.if.result.nonvoid} } } else { - FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", status); + FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", statusError); } if (err != nullptr) { - *err = status; + *err = statusError; } return${if.result.nonvoid} ${method.result.name}${end.if.result.nonvoid}; diff --git a/languages/cpp/templates/methods/event.cpp b/languages/cpp/templates/methods/event.cpp index ec3ba93f..8f21e9d7 100644 --- a/languages/cpp/templates/methods/event.cpp +++ b/languages/cpp/templates/methods/event.cpp @@ -35,3 +35,41 @@ *err = status; } } + +${if.globalsubscriber} + static void ${method.name}GlobalCallback( void* notification, const void* userData, void* jsonResponse) + { +${event.callback.serialization} + ASSERT(proxyResponse.IsValid() == true); + + if (proxyResponse.IsValid() == true) { +${event.callback.initialization} + +${event.callback.instantiation} + proxyResponse.Release(); + + I${info.Title}::I${method.Name}Notification& notifier = *(reinterpret_cast(notification)); + notifier.${method.rpc.name}(${event.callback.response.instantiation}); + } + } + void ${info.Title}Impl::globalSubscribe( I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err ) + { + const string eventName = _T("${info.title.lowercase}.${method.rpc.name}"); + Firebolt::Error status = Firebolt::Error::None; + + JsonObject jsonParameters; + status = FireboltSDK::Event::Instance().Subscribe<${event.result.json.type}>(eventName, jsonParameters, ${method.name}GlobalCallback, reinterpret_cast(¬ification), nullptr); + + if (err != nullptr) { + *err = status; + } + } + void ${info.Title}Impl::globalUnsubscribe( I${info.Title}::I${method.Name}Notification& notification, Firebolt::Error *err ) + { + Firebolt::Error status = FireboltSDK::Event::Instance().Unsubscribe(_T("${info.title.lowercase}.${method.rpc.name}"), reinterpret_cast(¬ification)); + + if (err != nullptr) { + *err = status; + } + } +${end.if.globalsubscriber} diff --git a/languages/cpp/templates/parameter-serialization/enum.cpp b/languages/cpp/templates/parameter-serialization/enum.cpp index 478e1d8e..c8a82f9c 100644 --- a/languages/cpp/templates/parameter-serialization/enum.cpp +++ b/languages/cpp/templates/parameter-serialization/enum.cpp @@ -1,7 +1,7 @@ ${if.optional}if (${property}.has_value()) { - ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonValue = ${property}.value(); - WPEFramework::Core::JSON::Variant ${property}Variant(jsonValue.Data()); + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} json${Property} = ${property}.value(); + WPEFramework::Core::JSON::Variant ${property}Variant(json${Property}.Data()); jsonParameters.Set(_T("${property}"), ${property}Variant); - }${end.if.optional}${if.non.optional}${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonValue = ${property}; - WPEFramework::Core::JSON::Variant ${property}Variant(jsonValue.Data()); + }${end.if.optional}${if.non.optional}${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} json${Property} = ${property}; + WPEFramework::Core::JSON::Variant ${property}Variant(json${Property}.Data()); jsonParameters.Set(_T("${property}"), ${property}Variant);${end.if.non.optional} \ No newline at end of file diff --git a/languages/cpp/templates/result-instantiation/sub-property/array.cpp b/languages/cpp/templates/result-instantiation/sub-property/array.cpp index a9badd14..0404dc8c 100644 --- a/languages/cpp/templates/result-instantiation/sub-property/array.cpp +++ b/languages/cpp/templates/result-instantiation/sub-property/array.cpp @@ -1,10 +1,10 @@ - ${if.optional}if (jsonResult.${Property}.IsSet()) { - ${base.title}Result${level}.${property} = std::make_optional<${type}>(); - auto index(jsonResult.${Property}.Elements()); - while (index.Next() == true) { - ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}Result${level}.${property}.value().push_back(index.Current().Value());${end.if.non.object} + ${if.optional}if (jsonResult${Property.dependency}.${Property}.IsSet()) { + ${base.title}Result${level}${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property} = std::make_optional<${type}>(); + auto ${property}Index(jsonResult${Property.dependency}.${Property}.Elements()); + while (${property}Index.Next() == true) { + ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}Result${level}.${property}.value().push_back(${property}Index.Current().Value());${end.if.non.object} } - }${end.if.optional}${if.non.optional}auto index(jsonResult.${Property}.Elements()); - while (index.Next() == true) { - ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}Result${level}.${property}.push_back(index.Current().Value());${end.if.non.object} + }${end.if.optional}${if.non.optional}auto ${property}Index(jsonResult.${Property}.Elements()); + while (${property}Index.Next() == true) { + ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}Result${level}.${property}.push_back(${property}Index.Current().Value());${end.if.non.object} }${end.if.non.optional} diff --git a/languages/cpp/templates/result-instantiation/sub-property/object-array.cpp b/languages/cpp/templates/result-instantiation/sub-property/object-array.cpp index 1274a0da..5a99765d 100644 --- a/languages/cpp/templates/result-instantiation/sub-property/object-array.cpp +++ b/languages/cpp/templates/result-instantiation/sub-property/object-array.cpp @@ -1,6 +1,6 @@ ${type} ${property}Result${level}; - ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonResult = index.Current(); + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonResult = ${property}Index.Current(); { ${properties} } - ${property}Result.${property}${if.impl.array.optional}.value()${end.if.impl.array.optional}.push_back(${property}Result${level}); \ No newline at end of file + ${base.title}Result${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}${if.optional}.value()${end.if.optional}.push_back(${property}Result${level}); \ No newline at end of file diff --git a/languages/cpp/templates/sdk/scripts/build.sh b/languages/cpp/templates/sdk/scripts/build.sh index 8f2142df..415225a1 100755 --- a/languages/cpp/templates/sdk/scripts/build.sh +++ b/languages/cpp/templates/sdk/scripts/build.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e usage() { echo "options:" diff --git a/languages/cpp/templates/sdk/scripts/install.sh b/languages/cpp/templates/sdk/scripts/install.sh index b31556a2..46429bc3 100755 --- a/languages/cpp/templates/sdk/scripts/install.sh +++ b/languages/cpp/templates/sdk/scripts/install.sh @@ -5,6 +5,7 @@ usage() echo " -i install path" echo " -s sdk path" echo " -m module name. i.e, core/manage" + echo " -v sdk version. i.e, 1.3.0" echo echo "usage: " echo " ./install.sh -i path -s sdk path -m core" @@ -13,12 +14,15 @@ usage() SdkPath=".." InstallPath=".." ModuleName="core" -while getopts i:s:m:h flag +Version=1.3.0-next.1 + +while getopts i:s:m:v:h flag do case "${flag}" in i) InstallPath="${OPTARG}";; s) SdkPath="${OPTARG}";; m) ModuleName="${OPTARG}";; + v) Version="${OPTARG}";; h) usage && exit 1;; esac done @@ -40,8 +44,7 @@ GetVersion() Version=${array[2]} } -Version=0.0 -GetVersion +#GetVersion ReleaseName=firebolt-${ModuleName}-native-sdk-${Version} ReleasePath=${InstallPath}/${ReleaseName} @@ -52,6 +55,7 @@ cp -aR ${SdkPath}/include ${ReleasePath} cp -aR ${SdkPath}/cmake ${ReleasePath} cp -aR ${SdkPath}/scripts/build.sh ${ReleasePath} cp -aR ${SdkPath}/CMakeLists.txt ${ReleasePath} +mv ${SdkPath}/firebolt-*open-rpc.json ${ReleasePath} cp -aR ${SdkPath}/cpptest ${ReleasePath}/test sed -i'' -e '/EnableTest="ON";;/d' ${ReleasePath}/build.sh diff --git a/languages/cpp/templates/sdk/src/firebolt.cpp b/languages/cpp/templates/sdk/src/firebolt.cpp index a864c2c4..c426f127 100644 --- a/languages/cpp/templates/sdk/src/firebolt.cpp +++ b/languages/cpp/templates/sdk/src/firebolt.cpp @@ -18,6 +18,7 @@ #include #include "FireboltSDK.h" +#include "IModule.h" ${module.includes.private} namespace Firebolt { diff --git a/languages/javascript/language.config.json b/languages/javascript/language.config.json index 19b4659d..6c5452f5 100644 --- a/languages/javascript/language.config.json +++ b/languages/javascript/language.config.json @@ -5,6 +5,7 @@ "/index.mjs", "/defaults.mjs" ], + "enableStringPropertyKeys": true, "createModuleDirectories": true, "copySchemasIntoModules": true, "aggregateFiles": [ diff --git a/languages/javascript/src/shared/Events/index.mjs b/languages/javascript/src/shared/Events/index.mjs index 18c2092a..bc458934 100644 --- a/languages/javascript/src/shared/Events/index.mjs +++ b/languages/javascript/src/shared/Events/index.mjs @@ -177,6 +177,9 @@ const doListen = function(module, event, callback, context, once, internal=false resolve(listenerId) } else { + // Remove the listener from external list on failure to subscribe + // TODO: Instead of removing, the failed subscription shouldn't be put into the external list + listeners.remove(listenerId) reject(error) } }) @@ -184,7 +187,6 @@ const doListen = function(module, event, callback, context, once, internal=false else { resolve(listenerId) } - return p } } diff --git a/languages/javascript/src/shared/ProvideManager/index.mjs b/languages/javascript/src/shared/ProvideManager/index.mjs index 68ce6e9c..5da44cfa 100644 --- a/languages/javascript/src/shared/ProvideManager/index.mjs +++ b/languages/javascript/src/shared/ProvideManager/index.mjs @@ -115,7 +115,8 @@ const provide = function(capability, provider) { result.then(result => { if (imethod.response) { - response.result = result + // void results should be null in the JSONRPC message + response.result = result == null ? null : result } Transport.send(module, `${method}Response`, response) diff --git a/languages/javascript/templates/codeblocks/interface-focusable.mjs b/languages/javascript/templates/codeblocks/interface-focusable.mjs new file mode 100644 index 00000000..8d1fcfbc --- /dev/null +++ b/languages/javascript/templates/codeblocks/interface-focusable.mjs @@ -0,0 +1,3 @@ +interface ${name} { + ${methods} +} diff --git a/languages/markdown/templates/codeblocks/provider.md b/languages/markdown/templates/codeblocks/provider.md index e30d3a19..6865d717 100644 --- a/languages/markdown/templates/codeblocks/provider.md +++ b/languages/markdown/templates/codeblocks/provider.md @@ -23,7 +23,7 @@ import { ${info.title} } from '${package.name}' class My${provider} { ${provider.interface.start} async ${provider.interface.name}(parameters, session) { - return ${provider.interface.example.result} + ${if.provider.interface.example.result}return ${provider.interface.example.result}${end.if.provider.interface.example.result} } ${provider.interface.end} } diff --git a/languages/markdown/templates/methods/rpc-only.md b/languages/markdown/templates/methods/rpc-only.md index fdca6d05..e23ff102 100644 --- a/languages/markdown/templates/methods/rpc-only.md +++ b/languages/markdown/templates/methods/rpc-only.md @@ -1,6 +1,6 @@ ### ${method.name} -*This is an private RPC method.* +*This is a private RPC method.* ${method.summary} diff --git a/languages/markdown/templates/modules/index.md b/languages/markdown/templates/modules/index.md index 152cde30..5ef99353 100644 --- a/languages/markdown/templates/modules/index.md +++ b/languages/markdown/templates/modules/index.md @@ -23,8 +23,12 @@ ${end.if.public} /* ${METHODS} */ +/* ${PRIVATE_METHODS} */ + /* ${EVENTS} */ +/* ${PRIVATE_EVENTS} */ + /* ${PROVIDERS} */ /* ${SCHEMAS} */ diff --git a/languages/markdown/templates/sections/private-events.md b/languages/markdown/templates/sections/private-events.md new file mode 100644 index 00000000..677c317e --- /dev/null +++ b/languages/markdown/templates/sections/private-events.md @@ -0,0 +1,6 @@ +## Private Events +
+ View + + ${event.list} +
diff --git a/languages/markdown/templates/sections/private-methods.md b/languages/markdown/templates/sections/private-methods.md new file mode 100644 index 00000000..3da04445 --- /dev/null +++ b/languages/markdown/templates/sections/private-methods.md @@ -0,0 +1,6 @@ +## Private Methods +
+ View + + ${method.list} +
diff --git a/package-lock.json b/package-lock.json index de926ccc..2d50bf71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.5", + "version": "3.2.0-next.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.5", + "version": "3.2.0-next.4", "license": "Apache-2.0", "dependencies": { "ajv": "^8.12.0", diff --git a/package.json b/package.json index cc528173..b1cb253f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@firebolt-js/openrpc", - "version": "3.0.0-next.5", + "version": "3.2.0-next.4", "description": "The Firebolt SDK Code & Doc Generator", "main": "languages/javascript/src/sdk.mjs", "type": "module", diff --git a/src/firebolt-openrpc.json b/src/firebolt-openrpc.json index e2c2abc8..aac66665 100644 --- a/src/firebolt-openrpc.json +++ b/src/firebolt-openrpc.json @@ -696,6 +696,7 @@ "enum": [ "name", "x-response", + "x-response-name", "x-alternative", "x-since", "x-pulls-for", @@ -1010,6 +1011,13 @@ }, "x-provided-by": { "type": "string" + }, + "x-provider-selection": { + "type": "string", + "enum": [ + "focus", + "appId" + ] } }, "if": { diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 9a7823fc..b23f5d05 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -269,6 +269,10 @@ const eventHasOptionalParam = (event) => { return event.params.length && event.params.find(param => !(param.required && param.required === true)) } +const isGlobalSubscriber = (method) => { + return method.tags && method.tags.some(tag => tag['x-subscriber-type'] === 'global'); +} + const isOptionalParam = (param) => { return (!(param.required && param.required === true)) } @@ -347,6 +351,12 @@ const deprecatedOrEmptyArray = compose( getMethods ) +const getGlobalSubscribers = compose( + option([]), + map(filter(isGlobalSubscriber)), + getMethods +) + const props = compose( option([]), map(filter(m => isPropertyMethod(m))), @@ -535,21 +545,28 @@ const generateMacros = (obj, templates, languages, options = {}) => { const allMethodsArray = generateMethods(obj, examples, templates, languages, options.type) Array.from(new Set(['methods'].concat(config.additionalMethodTemplates))).filter(dir => dir).forEach(dir => { - if (dir.includes('declarations')) { const declarationsArray = allMethodsArray.filter(m => m.declaration[dir] && (!config.excludeDeclarations || (!options.hideExcluded || !m.excluded))) macros.methods[dir] = declarationsArray.length ? getTemplate('/sections/declarations', templates).replace(/\$\{declaration\.list\}/g, declarationsArray.map(m => m.declaration[dir]).join('\n')) : '' } else if (dir.includes('methods')) { - const methodsArray = allMethodsArray.filter(m => m.body[dir] && !m.event && (!options.hideExcluded || !m.excluded)) - macros.methods[dir] = methodsArray.length ? getTemplate('/sections/methods', templates).replace(/\$\{method.list\}/g, methodsArray.map(m => m.body[dir]).join('\n')) : '' + const publicMethodsArray = allMethodsArray.filter(m => m.body[dir] && !m.event && (!options.hideExcluded || !m.excluded) && !m.private) + const privateMethodsArray = allMethodsArray.filter(m => m.body[dir] && !m.event && (!options.hideExcluded || !m.excluded) && m.private) + const methodSection = (template, arr) => { + const regex = template.endsWith('events') ? /\$\{event.list\}/g : /\$\{method.list\}/g + return arr.length ? getTemplate('/sections/' + template, templates).replace(regex, arr.map(m => m.body[dir]).join('\n')) : '' + } + macros.methods.methods = methodSection('methods', publicMethodsArray) + macros.methods.private = methodSection('private-methods', privateMethodsArray) - const eventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded)) - macros.events[dir] = eventsArray.length ? getTemplate('/sections/events', templates).replace(/\$\{event.list\}/g, eventsArray.map(m => m.body[dir]).join('\n')) : '' + const publicEventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded) && !m.private) + const privateEventsArray = allMethodsArray.filter(m => m.body[dir] && m.event && (!options.hideExcluded || !m.excluded && m.private)) + macros.events.methods = methodSection('events', publicEventsArray) + macros.events.private = methodSection('private-events', privateEventsArray) if (dir === 'methods') { - macros.methodList = methodsArray.filter(m => m.body).map(m => m.name) - macros.eventList = eventsArray.map(m => makeEventName(m)) + macros.methodList = publicMethodsArray.filter(m => m.body).map(m => m.name) + macros.eventList = publicEventsArray.map(m => makeEventName(m)) } } }) @@ -601,7 +618,7 @@ const insertAggregateMacros = (fContents = '', aggregateMacros = {}) => { fContents = fContents.replace(/[ \t]*\/\* \$\{MOCK_OBJECTS\} \*\/[ \t]*\n/, aggregateMacros.mockObjects) fContents = fContents.replace(/\$\{readable\}/g, aggregateMacros.version.readable) fContents = fContents.replace(/\$\{package.name\}/g, aggregateMacros.library) - + return fContents } @@ -640,8 +657,10 @@ const insertMacros = (fContents = '', macros = {}) => { // Output the originally supported non-configurable methods & events macros fContents = fContents.replace(/[ \t]*\/\* \$\{METHODS\} \*\/[ \t]*\n/, macros.methods.methods) + fContents = fContents.replace(/[ \t]*\/\* \$\{PRIVATE_METHODS\} \*\/[ \t]*\n/, macros.methods.private) fContents = fContents.replace(/[ \t]*\/\* \$\{METHOD_LIST\} \*\/[ \t]*\n/, macros.methodList.join(',\n')) fContents = fContents.replace(/[ \t]*\/\* \$\{EVENTS\} \*\/[ \t]*\n/, macros.events.methods) + fContents = fContents.replace(/[ \t]*\/\* \$\{PRIVATE_EVENTS\} \*\/[ \t]*\n/, macros.events.private) fContents = fContents.replace(/[ \t]*\/\* \$\{EVENT_LIST\} \*\/[ \t]*\n/, macros.eventList.join(',')) fContents = fContents.replace(/[ \t]*\/\* \$\{EVENTS_ENUM\} \*\/[ \t]*\n/, macros.eventsEnum) @@ -713,12 +732,18 @@ function insertTableofContents(content) { let toc = '' const count = {} const slugger = title => title.toLowerCase().replace(/ /g, '-').replace(/-+/g, '-').replace(/[^a-zA-Z-]/g, '') + let collapsedContentLevel = null content.split('\n').filter(line => line.match(/^\#/)).map(line => { const match = line.match(/^(\#+) (.*)/) if (match) { const level = match[1].length if (level > 1 && level < 4) { + if (collapsedContentLevel === level) { + // we are back to the level we started the collapsed content, end the collapse + toc += ' ' + ' '.repeat(collapsedContentLevel) + '\n' + collapsedContentLevel = null + } const title = match[2] const slug = slugger(title) if (count.hasOwnProperty(slug)) { @@ -728,7 +753,14 @@ function insertTableofContents(content) { count[slug] = 0 } const link = '#' + slug + (count[slug] ? `-${count[slug]}` : '') - toc += ' ' + ' '.repeat(level - 1) + `- [${title}](${link})\n` + toc += ' ' + ' '.repeat(level - 1) + `- [${title}](${link})` + if (title === 'Private Methods' || title === 'Private Events') { + let anchor = title === 'Private Methods' ? 'private-methods-details' : 'private-events-details' + toc += '
Show\n' + collapsedContentLevel = level + } else { + toc += '\n' + } } } }).join('\n') @@ -1158,10 +1190,37 @@ function generateMethods(json = {}, examples = {}, templates = {}, languages = [ body: {}, declaration: {}, excluded: methodObj.tags.find(t => t.name === 'exclude-from-sdk'), - event: isEventMethod(methodObj) + event: isEventMethod(methodObj), + private: isRPCOnlyMethod(methodObj) } - const suffix = state.destination && config.templateExtensionMap ? state.destination.split(state.destination.includes('_') ? '_' : '.').pop() : '' + + /** + * Extracts the suffix from a given file path. + * + * The suffix is determined by the last underscore or period in the filename. + * If the filename contains an underscore, the portion after the last underscore + * is considered the suffix. If no underscore is found but there is a period, + * the portion after the last period (typically the file extension) is considered the suffix. + * If neither an underscore nor a period is found, an empty string is returned. + * + * @param {string} path - The full file path from which to extract the suffix. + * @returns {string} - The extracted suffix or an empty string if no suffix is found. + */ + const getSuffix = (path) => { + // Extract the last part of the path (the filename) + const filename = path.split('/').pop() // Get the last part of the path + // Check for underscores or periods in the filename and handle accordingly + if (filename.includes('_')) { + return filename.split('_').pop() // Return the last part after the last underscore + } else if (filename.includes('.')) { + return filename.split('.').pop() // Return the extension after the last period + } else { + return '' // Return empty if no suffix can be determined + } + } + + const suffix = state.destination && config.templateExtensionMap ? getSuffix(state.destination) : '' // Generate implementation of methods/events for both dynamic and static configured templates Array.from(new Set(['methods'].concat(config.additionalMethodTemplates))).filter(dir => dir).forEach(dir => { @@ -1250,7 +1309,17 @@ function insertMethodMacros(template, methodObj, json, templates, type = '', exa const result = JSON.parse(JSON.stringify(methodObj.result)) const event = isEventMethod(methodObj) ? JSON.parse(JSON.stringify(methodObj)) : '' + // Keep track of any global subscribers to insert into templates + const globalSubscribersArr = getGlobalSubscribers(json); + let isGlobalSubscriberEvent = false + if (event) { + isGlobalSubscriberEvent = globalSubscribersArr.some(subscriber => { + const strippedEventName = event.name.replace(/^on/, '').replace(/Changed$/, '').toLowerCase(); + const subscriberName = subscriber.name.toLowerCase(); + return subscriberName && strippedEventName === subscriberName; + }) + result.schema = JSON.parse(JSON.stringify(getPayloadFromEvent(methodObj))) event.result.schema = getPayloadFromEvent(event) event.params = event.params.filter(p => p.name !== 'listen') @@ -1391,6 +1460,7 @@ function insertMethodMacros(template, methodObj, json, templates, type = '', exa .replace(/\$\{event\.params\}/g, eventParams) .replace(/\$\{event\.params\.table\.rows\}/g, eventParamsRows) .replace(/\$\{if\.event\.params\}(.*?)\$\{end\.if\.event\.params\}/gms, event && event.params.length ? '$1' : '') + .replace(/\$\{if\.globalsubscriber\}(.*?)\$\{end\.if\.globalsubscriber\}/gms, (isGlobalSubscriberEvent) ? '$1' : '') .replace(/\$\{if\.event\.callback\.params\}(.*?)\$\{end\.if\.event\.callback\.params\}/gms, event && eventHasOptionalParam(event) ? '$1' : '') .replace(/\$\{event\.signature\.params\}/g, event ? types.getMethodSignatureParams(event, json, { destination: state.destination, section: state.section }) : '') .replace(/\$\{event\.signature\.callback\.params\}/g, event ? types.getMethodSignatureParams(event, json, { destination: state.destination, section: state.section, callback: true }) : '') @@ -1775,16 +1845,24 @@ function getProviderXValues(method) { return xValues } -function insertProviderXValues(template, moduleJson, xValues) { +function insertProviderXValues(template, module, xValues) { if (xValues['x-response']) { - const xResponseInst = types.getSchemaShape(xValues['x-response'], moduleJson, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + let schema = localizeDependencies(xValues['x-response'], module) + const moduleTitle = types.getXSchemaGroup(schema, module) + const xResponseInst = types.getSchemaShape(schema, module, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + const type = types.getSchemaType(schema, module, { moduleTitle: moduleTitle, result: true, namespace: true}) template = template.replace(/\$\{provider\.xresponse\.serialization\}/gms, xResponseInst) - .replace(/\$\{provider\.xresponse\.name\}/gms, xValues['x-response'].title) + .replace(/\$\{provider\.xresponse\.name\}/gms, type) + .replace(/\$\{parent\.Title\}/g, capitalize(moduleTitle)) } if (xValues['x-error']) { - const xErrorInst = types.getSchemaShape(xValues['x-error'], moduleJson, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + let schema = localizeDependencies(xValues['x-error'], module) + const moduleTitle = types.getXSchemaGroup(schema, module) + const xErrorInst = types.getSchemaShape(schema, module, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + const type = types.getSchemaType(schema, module, { moduleTitle: moduleTitle, result: true, namespace: true}) template = template.replace(/\$\{provider\.xerror\.serialization\}/gms, xErrorInst) - .replace(/\$\{provider\.xerror\.name\}/gms, xValues['x-error'].title) + .replace(/\$\{provider\.xerror\.name\}/gms, type) + .replace(/\$\{parent\.Title\}/g, capitalize(moduleTitle)) } return template } @@ -1805,9 +1883,24 @@ function insertProviderInterfaceMacros(template, capability, moduleJson = {}, te let name = getProviderInterfaceName(iface, capability, moduleJson) let xValues const suffix = state.destination ? state.destination.split('.').pop() : '' - let interfaceShape = getTemplate(suffix ? `/codeblocks/interface.${suffix}` : '/codeblocks/interface', templates) - if (!interfaceShape) { - interfaceShape = getTemplate('/codeblocks/interface', templates) + + // Determine if any method has the 'x-allow-focus' tag set to true + const hasFocusableMethods = iface.some(method => + method.tags.some(tag => tag['x-allow-focus'] === true) + ) + + // Determine the appropriate template based on hasFocusableMethods and suffix + let interfaceShape; + if (hasFocusableMethods) { + interfaceShape = getTemplate(suffix ? `/codeblocks/interface-focusable.${suffix}` : '/codeblocks/interface-focusable', templates); + if (!interfaceShape) { + interfaceShape = getTemplate('/codeblocks/interface-focusable', templates); + } + } else { + interfaceShape = getTemplate(suffix ? `/codeblocks/interface.${suffix}` : '/codeblocks/interface', templates); + if (!interfaceShape) { + interfaceShape = getTemplate('/codeblocks/interface', templates); + } } interfaceShape = interfaceShape.replace(/\$\{name\}/g, name) @@ -1882,9 +1975,9 @@ function insertProviderInterfaceMacros(template, capability, moduleJson = {}, te let i = 1 iface.forEach(method => { - methodsBlock += match[0].replace(/\$\{provider\.interface\.name\}/g, method.name) .replace(/\$\{provider\.interface\.Name\}/g, method.name.charAt(0).toUpperCase() + method.name.substr(1)) + .replace(/\$\{if\.provider\.interface\.example\.result\}(.*?)\$\{end\.if\.provider\.interface\.example\.result\}/gms, method.examples[0].result.value == null ? '' : '$1') // first check for indented lines, and do the fancy indented replacement .replace(/^([ \t]+)(.*?)\$\{provider\.interface\.example\.result\}/gm, '$1$2' + indent(JSON.stringify(method.examples[0].result.value, null, ' '), '$1')) @@ -1899,7 +1992,6 @@ function insertProviderInterfaceMacros(template, capability, moduleJson = {}, te .replace(/\$\{provider\.interface\.i\}/g, i) .replace(/\$\{provider\.interface\.j\}/g, (i + iface.length)) .replace(/\$\{provider\.interface\.k\}/g, (i + 2 * iface.length)) - i++ }) methodsBlock = methodsBlock.replace(/\$\{provider\.interface\.[a-zA-Z]+\}/g, '') diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 298241f6..9ff30291 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -196,14 +196,14 @@ const macrofy = async ( templatesPerModule.forEach(t => { const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, createPolymorphicMethods: createPolymorphicMethods, destination: t, type: 'methods'}) let content = getTemplateForModule(module.info.title, t, templates) - + // NOTE: whichever insert is called first also needs to be called again last, so each phase can insert recursive macros from the other content = engine.insertAggregateMacros(content, aggregateMacros) content = engine.insertMacros(content, macros) content = engine.insertAggregateMacros(content, aggregateMacros) const location = createModuleDirectories ? path.join(output, module.info.title, t) : path.join(output, t.replace(/module/, module.info.title.toLowerCase()).replace(/index/, module.info.title)) - + outputFiles[location] = content logSuccess(`Generated macros for module ${path.relative(output, location)}`) }) diff --git a/src/macrofier/types.mjs b/src/macrofier/types.mjs index 6e854d15..5fa445f5 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -17,9 +17,11 @@ */ import deepmerge from 'deepmerge' -import { getPath, localizeDependencies, getSafeEnumKeyName } from '../shared/json-schema.mjs' +import { getPath, localizeDependencies, getSafeEnumKeyName, getSafeKeyName } from '../shared/json-schema.mjs' import path from "path" +import { getConfig } from '../shared/configLoader.mjs' +const config = getConfig() let convertTuplesToArraysOrObjects = false const templates = {} const state = {} @@ -315,6 +317,8 @@ const insertObjectPatternPropertiesMacros = (content, schema, module, title, opt } const getIndents = level => level ? ' ' : '' +const wrapProp = name => name.match(/[/\.\+]/) ? `"${name}"` : name +const safePropName = name => config.enableStringPropertyKeys ? wrapProp(name) : getSafeKeyName(name) const insertObjectMacros = (content, schema, module, title, property, options) => { const options2 = options ? JSON.parse(JSON.stringify(options)) : {} options2.parent = title @@ -346,8 +350,10 @@ const insertObjectMacros = (content, schema, module, title, property, options) = const description = getSchemaDescription(prop, module) let replacedTemplate = template .replace(/(^\s+)/g, '$1'.repeat(options2.level)) - .replace(/\$\{property\}/g, name) - .replace(/\$\{Property\}/g, capitalize(name)) + .replace(/\$\{property.raw\}/g, name) //Gives the raw RPC propery name, even if it's unsafe + .replace(/\$\{Property.raw\}/g, capitalize(name)) + .replace(/\$\{property\}/g, safePropName(name)) + .replace(/\$\{Property\}/g, capitalize(safePropName(name))) .replace(/\$\{parent\.title\}/g, title) .replace(/\$\{title\}/g, type) .replace(/\$\{shape\}/g, schemaShape) @@ -360,7 +366,7 @@ const insertObjectMacros = (content, schema, module, title, property, options) = .replace(/\$\{if\.base\.optional\}(.*?)\$\{end\.if\.base\.optional\}/gms, options.required ? '' : '$1') .replace(/\$\{if\.non\.object\}(.*?)\$\{end\.if\.non\.object\}/gms, isObject(localizedProp) ? '' : '$1') .replace(/\$\{if\.non\.array\}(.*?)\$\{end\.if\.non\.array\}/gms, (localizedProp.type === 'array') ? '' : '$1') - .replace(/\$\{if\.non\.anyOf\}(.*?)\$\{end\.if\.non\.anyOf\}/gms, (localizedProp.anyOf || localizedProp.anyOneOf) ? '' : '$1') + .replace(/\$\{if\.non\.anyOf\}(.*?)\$\{end\.if\.non\.anyOf\}/gms, (localizedProp.anyOf || localizedProp.oneOf) ? '' : '$1') .replace(/\$\{if\.non\.const\}(.*?)\$\{end\.if\.non\.const\}/gms, (typeof localizedProp.const === 'string') ? '' : '$1') let baseTitle = options.property @@ -724,7 +730,11 @@ function getSchemaType(schema, module, { destination, templateDir = 'types', lin const theTitle = insertSchemaMacros(namespaceStr + getTemplate(path.join(templateDir, 'title' + suffix)), schema, module, { name: schema.title, parent: getXSchemaGroup(schema, module), recursive: false }) const allocatedProxy = event || result - const title = schema.type === "object" || schema.anyOf || schema.oneOf || Array.isArray(schema.type) && schema.type.includes("object") || schema.enum ? true : false + let title = schema.type === "object" || schema.anyOf || schema.oneOf || Array.isArray(schema.type) && schema.type.includes("object") || schema.enum ? true : false + + if (config?.enableUnionTypes === false) { + title = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.enum ? true : false + } if (schema['$ref']) { if (schema['$ref'][0] === '#') { @@ -929,5 +939,6 @@ export default { getMethodSignatureResult, getSchemaShape, getSchemaType, - getSchemaInstantiation + getSchemaInstantiation, + getXSchemaGroup } diff --git a/src/sdk/index.mjs b/src/sdk/index.mjs index f6fd0f5e..2a0c6da4 100755 --- a/src/sdk/index.mjs +++ b/src/sdk/index.mjs @@ -21,6 +21,7 @@ import path from 'path' import { readJson } from '../shared/filesystem.mjs' import macrofy from '../macrofier/index.mjs' +import { loadConfig, getConfig } from '../shared/configLoader.mjs'; /************************************************************************************************/ /******************************************** MAIN **********************************************/ @@ -48,7 +49,9 @@ const run = async ({ // fail silently } - const config = await readJson(path.join(language, 'language.config.json')) + // Load in config + await loadConfig(language) + const config = getConfig() return macrofy(input, template, output, { headline: 'SDK code', diff --git a/src/shared/configLoader.mjs b/src/shared/configLoader.mjs new file mode 100644 index 00000000..ca9f8fb5 --- /dev/null +++ b/src/shared/configLoader.mjs @@ -0,0 +1,18 @@ +import path from 'path' +import { readJson } from './filesystem.mjs' + +let config = null + +export const loadConfig = async (language) => { + if (!config) { + config = await readJson(path.join(language, 'language.config.json')) + } + return config +} + +export const getConfig = () => { + if (!config) { + return {}; + } + return config +} diff --git a/src/shared/json-schema.mjs b/src/shared/json-schema.mjs index 98fdeaba..db13a833 100644 --- a/src/shared/json-schema.mjs +++ b/src/shared/json-schema.mjs @@ -282,126 +282,152 @@ const schemaReferencesItself = (schema, path) => { return false } -// TODO: get rid of schemas param, after updating the validate task to use addExternalSchemas -const localizeDependencies = (json, document, schemas = {}, options = defaultLocalizeOptions) => { - if (typeof options === 'boolean') { - // if we got a boolean, then inject it into the default options for the externalOnly value (for backwards compatibility) - options = Object.assign(JSON.parse(JSON.stringify(defaultLocalizeOptions)), { externalOnly: options }) - } +/** + * Deep clones an object to avoid mutating the original. + * @param {Object} obj - The object to clone. + * @returns {Object} - The cloned object. + */ +const cloneDeep = (obj) => JSON.parse(JSON.stringify(obj)) + +/** + * Dereferences schema paths and resolves references. + * @param {Array} refs - Array of schema paths to dereference. + * @param {Object} definition - The schema definition. + * @param {Object} document - The document containing schemas. + * @param {Array} unresolvedRefs - Array to collect unresolved references. + * @param {boolean} [externalOnly=false] - Whether to only dereference external schemas. + * @param {boolean} [keepRefsAndLocalizeAsComponent=false] - Whether to keep references and localize as components. + * @returns {Object} - The updated schema definition. + */ +const dereferenceSchema = (refs, definition, document, unresolvedRefs, externalOnly = false, keepRefsAndLocalizeAsComponent = false) => { + while (refs.length > 0) { + for (let i = 0; i < refs.length; i++) { + let path = refs[i] + const ref = getPathOr(null, path, definition) + path.pop() // drop ref - let definition = JSON.parse(JSON.stringify(json)) - let refs = getLocalSchemaPaths(definition) - let unresolvedRefs = [] + let resolvedSchema = cloneDeep(getPathOr(null, refToPath(ref), document)) - if (!options.externalOnly) { - while (refs.length > 0) { - for (let i=0; i 1) { - let resolvedSchema = JSON.parse(JSON.stringify(getPathOr(null, refToPath(ref), document))) - if (schemaReferencesItself(resolvedSchema, refToPath(ref))) { - resolvedSchema = null - } - - if (!resolvedSchema) { - resolvedSchema = { "$REF": ref} - unresolvedRefs.push([...path]) - } - - if (path.length) { - // don't loose examples from original object w/ $ref - // todo: should we preserve other things, like title? - const examples = getPathOr(null, [...path, 'examples'], definition) - resolvedSchema.examples = examples || resolvedSchema.examples - definition = setPath(path, resolvedSchema, definition) - } - else { - delete definition['$ref'] - Object.assign(definition, resolvedSchema) - } - } + if (schemaReferencesItself(resolvedSchema, refToPath(ref))) { + resolvedSchema = null } - refs = getLocalSchemaPaths(definition) - } - } - - refs = getExternalSchemaPaths(definition) - while (refs.length > 0) { - for (let i=0; i { + let allOfFound = false; + + const mergeAllOfs = (obj) => { + if (Array.isArray(obj) && obj.length === 0) { + return obj; + } + + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (key === 'allOf' && Array.isArray(obj[key])) { + const union = deepmerge.all(obj.allOf.reverse()); + const title = obj.title; + Object.assign(obj, union); + if (title) { + obj.title = title; + } + delete obj.allOf; + allOfFound = true; + } else if (typeof obj[key] === 'object') { + mergeAllOfs(obj[key]); + } + } + } + }; - unresolvedRefs.forEach(ref => { + mergeAllOfs(pointer); + return allOfFound; +}; + +/** + * Dereferences and merges allOf entries in a method schema. + * @param {Object} method - The method schema to dereference and merge. + * @param {Object} module - The module containing schemas. + * @returns {Object} - The dereferenced and merged schema. + */ +const dereferenceAndMergeAllOfs = (method, module) => { + let definition = cloneDeep(method) + let unresolvedRefs = [] + const originalDefinition = cloneDeep(definition) + + definition = dereferenceSchema(getLocalSchemaPaths(definition), definition, module, unresolvedRefs) + definition = dereferenceSchema(getExternalSchemaPaths(definition), definition, module, unresolvedRefs, true) + + const allOfFound = findAndMergeAllOfs(definition) + + if (!allOfFound) { + return originalDefinition + } + + unresolvedRefs.forEach((ref) => { let node = getPathOr({}, ref, definition) node['$ref'] = node['$REF'] delete node['$REF'] }) - if (options.mergeAllOfs) { - const findAndMergeAllOfs = pointer => { - if ((typeof pointer) !== 'object' || !pointer) { - return - } + return definition +} - Object.keys(pointer).forEach( key => { +/** + * Localizes dependencies in a JSON schema, dereferencing references and optionally merging allOf entries. + * @param {Object} json - The JSON schema to localize. + * @param {Object} document - The document containing schemas. + * @param {Object} [schemas={}] - Additional schemas to use for dereferencing. + * @param {Object|boolean} [options=defaultLocalizeOptions] - Options for localization, or a boolean for externalOnly. + * @returns {Object} - The localized schema. + */ +const localizeDependencies = (json, document, schemas = {}, options = defaultLocalizeOptions) => { + if (typeof options === 'boolean') { + options = { ...defaultLocalizeOptions, externalOnly: options } + } - if (Array.isArray(pointer) && key === 'length') { - return - } - // do a depth-first search for `allOfs` to reduce complexity of merges - if ((key !== 'allOf') && (typeof pointer[key] === 'object')) { - findAndMergeAllOfs(pointer[key]) - } - else if (key === 'allOf' && Array.isArray(pointer[key])) { - const union = deepmerge.all(pointer.allOf.reverse()) // reversing so lower `title` attributes will win - const title = pointer.title - Object.assign(pointer, union) - if (title) { - pointer.title = title - } - delete pointer.allOf - } - }) - } + let definition = cloneDeep(json) + let unresolvedRefs = [] + + if (!options.externalOnly) { + definition = dereferenceSchema(getLocalSchemaPaths(definition), definition, document, unresolvedRefs) + } + + definition = dereferenceSchema(getExternalSchemaPaths(definition), definition, document, unresolvedRefs, true, options.keepRefsAndLocalizeAsComponent) + unresolvedRefs.forEach((ref) => { + let node = getPathOr({}, ref, definition) + node['$ref'] = node['$REF'] + delete node['$REF'] + }) + + if (options.mergeAllOfs) { findAndMergeAllOfs(definition) } @@ -494,6 +520,10 @@ function mergeOneOf(schema) { return union(schema.oneOf) } +const getSafeKeyName = (value) => value.split(':').pop() + .replace(/[\.\-]/g, '_') // replace dots and dashes + .replace(/\+/g, '_plus') // change + to _plus + const getSafeEnumKeyName = (value) => value.split(':').pop() // use last portion of urn:style:values .replace(/[\.\-]/g, '_') // replace dots and dashes .replace(/\+/g, '_plus') // change + to _plus @@ -503,6 +533,7 @@ const getSafeEnumKeyName = (value) => value.split(':').pop() export { getSchemaConstraints, + getSafeKeyName, getSafeEnumKeyName, getExternalSchemaPaths, getLocalSchemas, @@ -519,5 +550,6 @@ export { replaceRef, removeIgnoredAdditionalItems, mergeAnyOf, - mergeOneOf + mergeOneOf, + dereferenceAndMergeAllOfs } diff --git a/src/shared/modules.mjs b/src/shared/modules.mjs index 5fa64c6a..097bd7c5 100644 --- a/src/shared/modules.mjs +++ b/src/shared/modules.mjs @@ -28,7 +28,7 @@ import isEmpty from 'crocks/core/isEmpty.js' const { and, not } = logic import isString from 'crocks/core/isString.js' import predicates from 'crocks/predicates/index.js' -import { getExternalSchemaPaths, isDefinitionReferencedBySchema, isNull, localizeDependencies, isSchema, getLocalSchemaPaths, replaceRef, getPropertySchema } from './json-schema.mjs' +import { getExternalSchemaPaths, isDefinitionReferencedBySchema, isNull, localizeDependencies, isSchema, getLocalSchemaPaths, replaceRef, getPropertySchema, dereferenceAndMergeAllOfs } from './json-schema.mjs' import { getPath as getRefDefinition } from './json-schema.mjs' const { isObject, isArray, propEq, pathSatisfies, hasProp, propSatisfies } = predicates @@ -91,8 +91,8 @@ const getProviderInterfaceMethods = (capability, json) => { function getProviderInterface(capability, module, extractProviderSchema = false) { module = JSON.parse(JSON.stringify(module)) - const iface = getProviderInterfaceMethods(capability, module)//.map(method => localizeDependencies(method, module, null, { mergeAllOfs: true })) - + const iface = getProviderInterfaceMethods(capability, module).map(method => dereferenceAndMergeAllOfs(method, module)) + iface.forEach(method => { const payload = getPayloadFromEvent(method) const focusable = method.tags.find(t => t['x-allow-focus']) @@ -157,7 +157,7 @@ function getProviderInterface(capability, module, extractProviderSchema = false) method.tags = method.tags.filter(tag => tag.name !== 'event') } }) - + return iface } diff --git a/src/validate/validator/index.mjs b/src/validate/validator/index.mjs index 687aaada..6c7b83f4 100644 --- a/src/validate/validator/index.mjs +++ b/src/validate/validator/index.mjs @@ -48,8 +48,8 @@ const addFailingMethodSchema = (error, json, schema) => { const i = parseInt(error.schemaPath.split("/")[2]) error.params.failingSchema = schema.definitions.Method.allOf[i].then.$ref } - - } + + } } } @@ -61,7 +61,7 @@ export const pruneErrors = (errors = []) => { Object.values(groups).forEach( group => { const paths = [] - pruned.push(group.sort( (a, b) => b.schemaPath.split('/').length - a.schemaPath.split('/').length ).pop()) + pruned.push(group.sort( (a, b) => b.schemaPath.split('/').length - a.schemaPath.split('/').length ).pop()) }) return pruned @@ -163,12 +163,18 @@ export const validate = (json = {}, schemas = {}, ajv, validator, additionalPack validator.errors.forEach(error => error.source = 'OpenRPC') errors.push(...pruneErrors(validator.errors)) - } + } return { valid: valid, title: json.title || json.info.title, errors: errors } } const schemasMatch = (a, b) => { + if (a == null) { + return b == null + } + if (b == null) { + return a == null + } const aKeys = Object.keys(a) const bKeys = Object.keys(b) const keysMatch = (aKeys.length == bKeys.length) && aKeys.every(key => bKeys.includes(key)) @@ -229,7 +235,7 @@ export const validatePasshtroughs = (json) => { if (!schemasMatch(source, destination)) { const properties = getPropertiesInSchema(destination, json) - + // follow $refs so we can see the schemas source = getPropertySchema(source, '.', json) destination = getPropertySchema(destination, '.', json) @@ -270,4 +276,4 @@ export const validatePasshtroughs = (json) => { return result -} \ No newline at end of file +}