diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0f8d1a02b78b4a96d79bf37230c5b49d2408fe78 --- /dev/null +++ b/.gitignore @@ -0,0 +1,90 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj +build/ + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Visual Studio files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.vcxproj* +*.user +*.user.* +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* +x64/ +.vs/ +*.bat +*remakeninfo.txt +Debug/ +Release/ +*-packagedependencies.* +*-packagedependencies-win.* +*-packagedependencies-linux.* +*-packagedependencies-unix.* +*-packagedependencies-android.* +*.pc +*-Debug +*-Release + +# Executables +*.exe +*.out +*.app + +# Generated documentation +doc/ +doxygen/ + +# Tests builds +tests/bin + +# Others +*.*pre1 +*.rej +*.stash +*.rc +*.res +*.exp +*.ilk +*.pdb +*.autosave +*.project +*.props +*.log +*.tlog +*.TMP +*.tmp +.git Merge \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..31202e8762d5399f02ba3fce5c0f5d788a76aa84 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# SolARWorldStorage +## Server implementation using the SolAR world storage module + +[![License](https://img.shields.io/github/license/SolARFramework/SolARModuleOpencv?style=flat-square&label=License)](https://www.apache.org/licenses/LICENSE-2.0) + +The goal of the world storage server is to be able to store and fetch online all the elements needed to design and execute AR apps. +This server implements a [server partially generated by OpenAPI generator](https://labs.etsi.org/rep/arf/world-storage-api-helpers/world-storage-cpp-server.git), based on the ETSI specification and handles REST requests designed in the same ETSI specification file, [available on the ETSI forge](https://forge.etsi.org/rep/arf/arf005/-/blob/develop/API/openapi.yaml). +It uses the ETSIWorldStorage component of the Solar world storage module ([SolARModuleWorldStorage]((https://github.com/SolarFramework/SolARModuleWorldStorage/tree/develop))) as an implementation for SolAR framework's [IWorldGraphManager](https://github.com/SolarFramework/SolARFramework/blob/feature/WorldGraph/interfaces/api/storage/IWorldGraphManager.h). + + +![All the project's architecture](images/SchemaWrapper.png) + +For each Tag that we explicitly define in our API specification, OpenAPI will generate a corresponding interface able to handle all the requests specific to that tag. All that is left to do is to implement them and define the desired behavior as a response in the methods. +All the classes in this project (except for the main and UnitSysConversion) are implementation of the interfaces generated by OpenAPI. + +![All the project's architecture](images/WorldStorageServer.png) + +Except for the `DefaultSolARImpl` class, that only has usages for when you want to check if the server is up and check the version, all of the request handling classes have the world storage singleton as an attribute. On which they will be able to call methods in response to requests. +The module is passsed down through the constructor to ensure the uniqueness of it. + +## How to + +To be able to compile and run this server, you need to: +- clone [the OpenAPI world storage](https://labs.etsi.org/rep/arf/world-storage-api-helpers/world-storage-cpp-server.git) project and then generate the code and export it as a library (follow the git's instructions) +- have [remaken](https://github.com/b-com-software-basis/remaken) installed +- clone [SolAR framework](https://github.com/SolarFramework/SolARFramework) (for now, as the work is not released yet, you will have to clone the [feature/WorldGraph](https://github.com/SolarFramework/SolARFramework/tree/feature/WorldGraph) branch), perform a `remaken install` in the source directory and finally build the project +- clone [the world storage module](https://github.com/SolarFramework/SolARModuleWorldStorage) (for now, as the work is not released yet, you will have to clone the [develop](https://github.com/SolarFramework/SolARModuleWorldStorage/tree/develop) branch) and build it + +Once all those requirements are met, you should be able to compile your server and run it, you can try and send requests to http://localhost:8080 to try and see if it's working (e.g. POST request to see if the server is up : http://localhost:8080/ping) \ No newline at end of file diff --git a/SolARSample_World_Storage_conf.xml b/SolARSample_World_Storage_conf.xml new file mode 100644 index 0000000000000000000000000000000000000000..802e84a6e8220023824cc361ad018d6ecd2d1005 --- /dev/null +++ b/SolARSample_World_Storage_conf.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Solar-Wrapper/README.md b/Solar-Wrapper/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dcfe53c34d5d95f4112f14d25bd01b8da8bc2aab --- /dev/null +++ b/Solar-Wrapper/README.md @@ -0,0 +1,139 @@ +# SolARWorldStorage +## Server implementation using the SolAR world storage module + +[![License](https://img.shields.io/github/license/SolARFramework/SolARModuleOpencv?style=flat-square&label=License)](https://www.apache.org/licenses/LICENSE-2.0) + +This server handles REST requests designed in the ETSI specification file, [available on the ETSI forge](https://forge.etsi.org/rep/arf/arf005/-/blob/develop/API/openapi.yaml). + +It relies on two libraries: +- The library generated by the OpenAPI generator project. ([git repository](https://labs.etsi.org/rep/arf/world-storage-api-helpers/world-storage-cpp-server.git)) +- The world storage, a SolAR module used to store the different items needed to create an AR app ([git repository](https://github.com/SolarFramework/SolARModuleWorldStorage/tree/develop)) + + + +## I - OpenAPI project + +This project is the direct implementation of the server classes generated by the [OpenAPI generator ETSI project](https://labs.etsi.org/rep/arf/world-storage-api-helpers/world-storage-cpp-server.git) from the [API specification file](https://forge.etsi.org/rep/arf/arf005/-/blob/develop/API/openapi.yaml). +For each tag attribute that we defined in our specification (i.e "default", "trackable", "world anchor" and "world link"), OpenAPI generates classes handling the requests specific to that tag (one method generated per request specified). + +![OpenAPI generated classes](images/serverClasses.png) + +The OpenAPI project also generates model classes for our specified objects (e.g Trackables, WorldAnchors...). + +All of this project is exported as a library for us to use and augment in our wrapper. More info can be found in the project's git. + +Although we won't be using them, OpenAPI also generates basic implementation of the API endpoints classes and a main class to run your server instantly. + +## II - SolAR module + +**SolAR architecture** + +By SolAR standards, a module is a collection of components. Components are implementations of SolAR interfaces. +Our wrapper uses the world storage module, a singleton instantiated by the XPCF component manager, a SolAR tool. + +![XPCF component manager instantiation](images/XPCFComponentManager.png) + +It has a component that dynamically stores `Trackables`, `Anchors` and `Links` and implements the methods of the world graph manager, a SolAR interface. These methods allow for interaction with the stored elements. These elements are specified in the SolAR framework itself in the datastrucutre folder. +| **datastructure** | **description** | +|:-------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------:| +| `StorageWorldLink` | A Link between two `StorageWorldElement`, it holds the information of both elements and the transform between them | +| `StorageWorldElement` | The abstract type used to describe the elements that we want to store in our world storage. It holds all the common attributes to those elements. | +| `StorageTrackable` | (inherits `StorageWorldELement`) A trackable that will be stored in the world storage | +| `StorageWorldAnchor` | (inherits `StorageWorldELement`) A world anchor that will be stored in the world storage | + +Each datastructure is described in detail in the [SolAR git repository](https://github.com/SolarFramework/SolARFramework). + +**Module world storage** + +The module in itself has three attributes used to store information: + +- **m_nodes** : `map>` + - The map that holds all of the elements in the world storage, it stores their id as keys for performance purposes. +- **m_tags** : `multimap, shared_ptr>` + - A multimap that allows for research by the `tag`, a `StorageWorldElement` attribute that widens the capacity of customisation. It consists of a pair of string {key;value}. +- **m_links** : `map>` + - The map that holds all of the information regarding relations between each element. + +Each datastructure is stored dynamically with the usage of `shared_ptr`. + +**Method calls** + +All the methods of the world storage return a `FRAMEWORK_RETURN_CODE`, a SolAR enum to standardize and store responses from methods. most of them will return +- `FRAMEWORK_RETURN_CODE::_SUCCESS` when the method executes succesfuly +- `FRAMEWORK_RETURN_CODE::_ERROR__` when an error is raised +- `FRAMEWORK_RETURN_CODE::_NOT_FOUND_` when ressources that need to be fetched are not available. + +Most of the methods implemented by the module are described in the [project README](https://github.com/SolarFramework/SolARModuleWorldStorage/tree/develop#readme) + +## III - Wrapper architecture + +**OpenAPI inheritance** + +For the endpoints, we have to make new classes that inherit those generated by OpenAPI and override their handle methods in order to be able to correcly answer REST requests. +For now we have four child classes : +- `DefaultSolARImpl` +- `TrackablesSolARImpl` +- `WolrdAnchorsSolARImpl` +- `WorldLinksSolARImpl` + +Here are the methods associated to each endpoint : + +| Class | Methods | +|:------------:|:--------------------------------------------------:| +| `DefaultApi.h` | ![Default methods](images/DefaultMethods.png) | +| `TrackableApi.h` | ![Trackable methods](images/TrackableMethods.png) | +| `WorldAnchorApi.h` | ![Anchor methods](images/AnchorMethods.png) | +| `WorldLinkApi.h` | ![Link methods](images/LinkMethods.png) | + + +For all those methods, the `Pistache::Http::ResponseWriter` is a [out] param that allows the user to give the response back to the REST request. + + +Except for the `DefaultSolARImpl` class, that only has usages for when you want to check if the server is up and check the version, all of those classes have the world storage singleton as an attribute. On which they will be able to call methods in response to requests. +The module is passsed down through the constructor to ensure the uniqueness of it. + +**Default methods** + **`get_ping` | `get_version`** +These two methods are associated to the "Default" endpoint and serve the purpose of indicating the server's state. + +**add_X** + **`add_trackable` | `add_world_anchor` | `add_world_link`** +These methods are used for all the models that we want to preserve in our storage. As an argument, you receive the object you want to add. Its type is of the model type defined in the API specification. The verification of the object's integrity is already done in the OpenAPI generated library. +In our SolAR wrapper we perform a conversion between the two types that we use (OpenAPI model and SolAR datastructure) and then call the module's add method corresponding to the element in question to add it to the world storage. +For the `add_world_link`, we also added a verification that the two elements it connects are present in the world storage prior to the request reception. +When the user performs a REST request to add an element, he gets as a response the ID of the newly added element. + +**delete_X** + **`delete_trackable` | `delete_world_anchor` | `delete_world_link`** +Those are the methods you call when you want to delete an element from the world storage. The methods receive a UUID (unique identifier) as a `String` argument, convert it to the `UUID` type (from the boost library) and pass it to the module's delete method. +When the user performs a REST request to remove an element, he gets as a response a confirmation that the element is deleted (or not). + +**get_X_by_id** + **`get_trackable_by_id` | `get_world_anchor_by_id` | `get_world_link_by_id`** +The logic is the same as the delete methods: we get a `String` UUID, convert it to `UUID` type and pass it to the module's get method. +The module's method returns a SolAR datastructure on which we call the `from_storage` method to convert it to the OpenAPI model. Then we can translate it into a JSON thanks to the `to_json` method generated by OpenAPI. We return this JSON to the user who sent the request. + + +**get_Xs** + **`get_trackables` | `get_world_anchors` | `get_world_links`** +These methods return all the elements (of a given type) present in the world storage. We call the module's get_Xs method that returns a vector. For each element of this vector we add it to a JSON array that will be sent back to the user. + + +**get_attached_objects_from_uuid** + **`get_attached_objects_from_uuid`** +This method receives as an argument a link Id, fetches it from the world storage via the module's `getWorldLink` method. Then we look at the two elements it connects and put their info into a JSON that we send back to the user. + +**Utility methods** + **`from_storage` | `to_bytes`** +These methods do not override methods from the OpenAPI generated library, they are here to help handle models/datastructures. `from_storage` converts a SolAR datastructure into an OpenAPI model, `to_bytes` is only used to convert the `Trackable`'s payload attribute from a `String` into a vector of bytes. + +## Main + +The main.cpp class being already generated by OpenAPI, we just have to modify it to match what we want for our server. After setting up the world storage module, we need to set up our endpoints classes. + +![XPCF component manager instantiation](images/HandleSetUp.png) + +Once it's done, the rest of the generated code sets up everything up and waits for REST requests on http://localhost:8080. + + + diff --git a/Solar-Wrapper/interfaces/DefaultSolARImpl.h b/Solar-Wrapper/interfaces/DefaultSolARImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..a65921aa387feccde3b6311fb7e0cf2f5fb87abe --- /dev/null +++ b/Solar-Wrapper/interfaces/DefaultSolARImpl.h @@ -0,0 +1,58 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DEFAULTSOLARIMPL_H +#define DEFAULTSOLARIMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace org::openapitools::server::implem +{ + + using namespace org::openapitools::server::model; + + /** + * @class + * @brief implementation of (class generated by OpenAPI-Generator), implements all the method defined with no tags in the API specification + * + */ + + class DefaultSolARImpl : public org::openapitools::server::api::DefaultApi { + + public: + explicit DefaultSolARImpl(const std::shared_ptr& rtr); + ~DefaultSolARImpl() override = default; + + void get_version(Pistache::Http::ResponseWriter &response) override; + void get_ping(Pistache::Http::ResponseWriter &response) override; + void get_admin(Pistache::Http::ResponseWriter &response) override; + + // DefaultApi interface + private: + }; + +} + +#endif // DEFAULTSOLARIMPL_H diff --git a/Solar-Wrapper/interfaces/TrackablesSolARImpl.h b/Solar-Wrapper/interfaces/TrackablesSolARImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..986c0c95fdc267fe89d2b3e4f5ff74799c4238c0 --- /dev/null +++ b/Solar-Wrapper/interfaces/TrackablesSolARImpl.h @@ -0,0 +1,93 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TRACKABLES_SOLAR_IMPL_H_ +#define TRACKABLES_SOLAR_IMPL_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace org::openapitools::server::implem +{ + +/** + * @class TrackablesSolARImpl + * @brief implementation of TrackableAPI (class generated by OpenAPI-Generator), implements all the methods defined with the tag 'trackable' in the API specification + * + */ + +class TrackablesSolARImpl : public org::openapitools::server::api::TrackablesApi { + public: + explicit TrackablesSolARImpl(const std::shared_ptr& rtr, SRef worldStorage); + ~TrackablesSolARImpl() override = default; + + + /// @brief API method to add a trackable to the world storage. It converts the Trackable into a StorageTrackable and stores it in the worldGraph manager + /// @param trackable: trackable to be added + /// @param response: the response to be sent: if it succeeds, the UUID of the newly created StorageTrackable + void add_trackable(const org::openapitools::server::model::Trackable &trackable, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to delete a trackable, it fetches the StorageTrackable in the world storage Manager and removes it + /// @param trackableUUID: the ID of the StorageTrackable to be removed + /// @param response: the response to be sent: if it succeeds, a confirmation of the deletion of the StorageTrackable + void delete_trackable(const std::string &trackableUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get a single StorageTrackable from the world storage + /// @param trackableUUID: the ID of the trackable to be fetched + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from the StorageTrackable + void get_trackable_by_id(const std::string &trackableUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get all the trackables currently stored in the world storage + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from all the StorageTrackables + void get_trackables(Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to modify an existing trackable in the world storage. + /// @param trackable: trackable to be modified + /// @param response: the response to be sent: if it succeeds, the UUID of the modified StorageTrackable + void modify_trackable(const org::openapitools::server::model::Trackable &trackable, Pistache::Http::ResponseWriter &response) override; + + /// @brief static method to convert StorageTrackable (defined by the SolAR framework) to a Trackable (defined by OpenAPI generator) + /// @param trackable: the StorageTrackable to be converted + /// @return the converted trackable + static org::openapitools::server::model::Trackable from_storage(const SolAR::datastructure::StorageTrackable &trackable); + + /// @brief static method to transform a string into a vector of bytes. Used to transform a Trackable into a StorageTrackable (attribute payload) + /// @return a vector of byte + static std::vector to_bytes(const std::string &s); + + /// @brief initialize the API handler, creates the singleton m_worldStorage if it is not already done + void init(); + + private: + /// @brief the instance of the world storage manager that will be used to handle the queries + SRef m_worldStorage; +}; + +} // namespace org::openapitools::server::api + + + +#endif diff --git a/Solar-Wrapper/interfaces/UnitSysConversion.h b/Solar-Wrapper/interfaces/UnitSysConversion.h new file mode 100644 index 0000000000000000000000000000000000000000..3f9baeddf9275dc1f1bda7c097f07a7dfbbadc9b --- /dev/null +++ b/Solar-Wrapper/interfaces/UnitSysConversion.h @@ -0,0 +1,172 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UNITSYSCONVERSION_H +#define UNITSYSCONVERSION_H + + +#include +#include +#include +#include +#include + +#include "TrackablesSolARImpl.h" + +namespace xpcf = org::bcom::xpcf; +namespace org::openapitools::server::implem +{ + + /// @brief method to swap between UnitSystem enums (SolAR & OPenAPI) + /// @param the UnitSystem in openAPI format + /// @return the UnitSystem in SolAR format + static SolAR::datastructure::UnitSystem resolve_unitSystem(org::openapitools::server::model::UnitSystem input){ + switch(input.getValue()){ + case org::openapitools::server::model::UnitSystem::eUnitSystem::MM: + { + return SolAR::datastructure::UnitSystem::MM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::CM: + { + return SolAR::datastructure::UnitSystem::CM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::DM: + { + return SolAR::datastructure::UnitSystem::DM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::M: + { + return SolAR::datastructure::UnitSystem::M; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::DAM: + { + return SolAR::datastructure::UnitSystem::DAM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::HM: + { + return SolAR::datastructure::UnitSystem::HM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::KM: + { + return SolAR::datastructure::UnitSystem::KM; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::INCH: + { + return SolAR::datastructure::UnitSystem::INCH; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::FOOT: + { + return SolAR::datastructure::UnitSystem::FOOT; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::YARD: + { + return SolAR::datastructure::UnitSystem::YARD; + break; + } + case org::openapitools::server::model::UnitSystem::eUnitSystem::MILE: + { + return SolAR::datastructure::UnitSystem::MILE; + break; + } + default: + { + return SolAR::datastructure::UnitSystem::INVALID; + } + } + } + + /// @brief method to swap between UnitSystem enums (OPenAPI & SolAR) + /// @param the UnitSystem in SolAR format + /// @return the UnitSystem in openAPI format + static org::openapitools::server::model::UnitSystem resolve_unitSystem(SolAR::datastructure::UnitSystem input){ + + org::openapitools::server::model::UnitSystem ret; + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::INVALID_VALUE_OPENAPI_GENERATED); + switch(input){ + case SolAR::datastructure::UnitSystem::MM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::MM); + break; + } + case SolAR::datastructure::UnitSystem::CM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::CM); + break; + } + case SolAR::datastructure::UnitSystem::DM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::DM); + break; + } + case SolAR::datastructure::UnitSystem::M: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::M); + break; + } + case SolAR::datastructure::UnitSystem::DAM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::DAM); + break; + } + case SolAR::datastructure::UnitSystem::HM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::HM); + break; + } + case SolAR::datastructure::UnitSystem::KM: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::KM); + break; + } + case SolAR::datastructure::UnitSystem::INCH: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::INCH); + break; + } + case SolAR::datastructure::UnitSystem::FOOT: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::FOOT); + break; + } + case SolAR::datastructure::UnitSystem::YARD: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::YARD); + break; + } + case SolAR::datastructure::UnitSystem::MILE: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::MILE); + break; + } + default: + { + ret.setValue(org::openapitools::server::model::UnitSystem::eUnitSystem::INVALID_VALUE_OPENAPI_GENERATED); + } + } + return ret; + } + +} +#endif // UNITSYSCONVERSION_H diff --git a/Solar-Wrapper/interfaces/WorldAnchorsSolARImpl.h b/Solar-Wrapper/interfaces/WorldAnchorsSolARImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..bc8fb74ca89f4ef03a123d6c1124f03f8440260d --- /dev/null +++ b/Solar-Wrapper/interfaces/WorldAnchorsSolARImpl.h @@ -0,0 +1,87 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WORLDANCHORSSOLARIMPL_H +#define WORLDANCHORSSOLARIMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace org::openapitools::server::implem +{ + + +/** + * @class WorldAnchorsSolARImpl + * @brief implementation of WorldAnchorsAPI (class generated by OpenAPI-Generator), implements all the method defined with the tag 'world anchors' in the API specification + * + */ + +class WorldAnchorsSolARImpl : public org::openapitools::server::api::WorldAnchorsApi { + public: + explicit WorldAnchorsSolARImpl(const std::shared_ptr& rtr, SRef worldStorage); + ~WorldAnchorsSolARImpl() override = default; + + + /// @brief API method to add a world anchor to the world storage. It converts the World anchor into a StorageWorldAnchor and stores it in the worldGraph manager + /// @param worldAnchor: worldAnchor to be added + /// @param response: the response to be sent: if it succeeds, the UUID of the newly created StorageWorldAnchor + void add_world_anchor(const org::openapitools::server::model::WorldAnchor &worldAnchor, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to delete a world anchor, it fetches the StorageWorldAnchor in the world storage Manager and removes it + /// @param worldAnchorUUID: the ID of the StorageWorldAnchor to be removed + /// @param response: the response to be sent: if it succeeds, a confirmation of the deletion of the StorageWorldAnchor + void delete_world_anchor(const std::string &worldAnchorUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get a single StorageWorldAnchor from the world storage + /// @param worldAnchorUUID: the ID of the world anchor to be fetched + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from the StorageWorldAnchor + void get_world_anchor_by_id(const std::string &worldAnchorUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get all the world anchors currently stored in the world storage + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from all the StorageWorldAnchor + void get_world_anchors(Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to modify an existing world anchor in the world storage. + /// @param worldAnchor: worldAnchor to be modified + /// @param response: the response to be sent: if it succeeds, the UUID of the modified worldAnchor + void modify_world_anchor(const org::openapitools::server::model::WorldAnchor &worldAnchor, Pistache::Http::ResponseWriter &response) override; + + /// @brief static method to convert StorageWorldAnchor (defined by the SolAR framework) to a world anchors (defined by OpenAPI generator) + /// @param worldAnchor: the StorageWorldAnchor to be converted + /// @return the converted world anchor + static org::openapitools::server::model::WorldAnchor from_storage(const SolAR::datastructure::StorageWorldAnchor &worldAnchor); + + /// @brief initialize the API handler, creates the singleton m_worldStorage if it is not already done + void init(); + + private: + /// @brief the instance of the world storage manager that will be used to handle the queries + SRef m_worldStorage; + +}; + +} // namespace org::openapitools::server::api + + +#endif // WORLDANCHORSSOLARIMPL_H diff --git a/Solar-Wrapper/interfaces/WorldLinksSolARImpl.h b/Solar-Wrapper/interfaces/WorldLinksSolARImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..583e56be476974dde21e66f189cf84b5c1ecc51e --- /dev/null +++ b/Solar-Wrapper/interfaces/WorldLinksSolARImpl.h @@ -0,0 +1,94 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef WORLDLINKSSOLARIMPL_H + +#define WORLDLINKSSOLARIMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace org::openapitools::server::implem +{ + +/** + * @class WorldLinksSolARImpl + * @brief implementation of WorldLinksAPI (class generated by OpenAPI-Generator), implements all the method defined with the tag 'world links' in the API specification + * + */ + +class WorldLinksSolARImpl : public org::openapitools::server::api::WorldLinksApi { + public: + explicit WorldLinksSolARImpl(const std::shared_ptr& rtr, SRef worldStorage); + ~WorldLinksSolARImpl() override = default; + + + /// @brief API method to add a world link to the world storage. It converts the World link into a StorageWorldLink and stores it in the worldGraph manager + /// @param worldLink: worldLink to be added + /// @param response: the response to be sent: if it succeeds, the UUID of the newly created StorageWorldLink + void add_world_link(const org::openapitools::server::model::WorldLink &worldLink, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to delete a world link, it fetches the StorageWorldLink in the world storage Manager and removes it + /// @param worldLinkUUID: the ID of the StorageWorldLink to be removed + /// @param response: the response to be sent: if it succeeds, a confirmation of the deletion of the StorageWorldLink + void delete_world_link(const std::string &worldLinkUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get a single StorageWorldLink from the world storage + /// @param worldLinkUUID: the ID of the world link to be fetched + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from the StorageWorldLink + void get_world_link_by_id(const std::string &worldLinkUUID, Pistache::Http::ResponseWriter &response) override; + + /// @brief API method to get all the world links currently stored in the world storage + /// @param response: the response to be sent: if it succeeds, a JSON containing all the informations from all the StorageWorldLink + void get_world_links(Pistache::Http::ResponseWriter &response) override; + + virtual void modify_world_link(const org::openapitools::server::model::WorldLink &worldLink, Pistache::Http::ResponseWriter &response) override; + + /// @brief static method that returns a worldlink Json object from the informations contaiend in the worldStorage (before implementing a solution taht complies with the world link api description) + /// @param worldLink: the StorageWorldLink to be converted + /// @return A Json containing the id of the link, the id of both attached elements and the transform between them + static org::openapitools::server::model::WorldLink from_storage(SolAR::datastructure::StorageWorldLink worldLink); + + /// @brief method to get the world elements currently linked to the given world link + /// @param response: A pair containing shared pointers of the two elements connected to by the link + std::pair,SRef> get_attached_objects_from_uuid(const std::string &worldLinkUUID); + + /// @brief initialize the API handler, creates the singleton m_worldStorage if it is not already done + void init(); + + /// @brief method to convert ElementKind(SolAR) to ObjectType(OpenAPI spec) + static model::ObjectType resolve_element_kind(SolAR::datastructure::ElementKind kind); + + /// @brief method to convert ObjectType(OpenAPI spec) to ElementKind(SolAR) + static SolAR::datastructure::ElementKind resolve_element_kind(model::ObjectType kind); + + private: + /// @brief the instance of the world storage manager that will be used to handle the queries + SRef m_worldStorage; + +}; + +} // namespace org::openapitools::server::api + +#endif // WORLDLINKSSOLARIMPL_H diff --git a/Solar-Wrapper/openapitools.json b/Solar-Wrapper/openapitools.json new file mode 100644 index 0000000000000000000000000000000000000000..2774f4541b6dc8afc9786080258ce73cf28cb845 --- /dev/null +++ b/Solar-Wrapper/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "5.3.1" + } +} diff --git a/Solar-Wrapper/src/DefaultSolARImpl.cpp b/Solar-Wrapper/src/DefaultSolARImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f64144aa4851b9bd4312c82969791887a79265c2 --- /dev/null +++ b/Solar-Wrapper/src/DefaultSolARImpl.cpp @@ -0,0 +1,44 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DefaultSolARImpl.h" + +namespace org::openapitools::server::implem +{ + + DefaultSolARImpl::DefaultSolARImpl(const std::shared_ptr& rtr) + : DefaultApi(rtr) + { + } + + void DefaultSolARImpl::get_version(Pistache::Http::ResponseWriter &response){ + response.headers().add(MIME(Text, Plain)); + //TODO put it in a variable + response.send(Pistache::Http::Code::Ok, "Version 1.0.0"); + } + + void DefaultSolARImpl::get_ping(Pistache::Http::ResponseWriter &response) { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, "Pong"); + } + + void DefaultSolARImpl::get_admin(Pistache::Http::ResponseWriter &response) { + response.headers().add(MIME(Text, Plain)); + //TODO add verif on the module side + response.send(Pistache::Http::Code::Ok, "Server running and ready!"); + } + +} diff --git a/Solar-Wrapper/src/TrackablesSolARImpl.cpp b/Solar-Wrapper/src/TrackablesSolARImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ab6a5899ede6bdc75855b6ed14390795331cb9e --- /dev/null +++ b/Solar-Wrapper/src/TrackablesSolARImpl.cpp @@ -0,0 +1,389 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xpcf = org::bcom::xpcf; + +namespace org::openapitools::server::implem +{ + + + TrackablesSolARImpl::TrackablesSolARImpl(const std::shared_ptr& rtr, SRef worldStorage) + : TrackablesApi(rtr) + { + m_worldStorage = worldStorage; + } + + void TrackablesSolARImpl::add_trackable(const org::openapitools::server::model::Trackable &trackable, Pistache::Http::ResponseWriter &response) + { + //convert all the Trackable attributes into StorageTrackable attributes to create one and store it in the world storage + + //creator uuid + xpcf::uuids::uuid creatorId = xpcf::toUUID(trackable.getCreatorUUID()); + + //localCRS + for (float i: trackable.getLocalCRS()){ + std::cout << std::to_string(i) << std::endl; + } + std::vector vector = trackable.getLocalCRS(); + float* data = vector.data(); + Eigen::Matrix matrix = Eigen::Map>(data); + SolAR::datastructure::Transform3Df localCRS(matrix); + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(trackable.getUnit()); + + //dimension + Eigen::Vector3d dimension = Eigen::Vector3d(trackable.getTrackableSize().data()); + + //taglist + std::multimap keyvalueTagList; + for (const auto &tag : trackable.getKeyvalueTags()){ + for(const auto &value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //trackable type + SolAR::datastructure::StorageTrackableType type = SolAR::datastructure::resolveTrackableType(trackable.getTrackableType()); + + //encoding info + SolAR::datastructure::EncodingInfo encodingInfo(trackable.getTrackableEncodingInformation().getDataFormat(), trackable.getTrackableEncodingInformation().getVersion()); + + //payload + std::vector payload = TrackablesSolARImpl::to_bytes(trackable.getTrackablePayload()); + + //name + std::string name = trackable.getName(); + + //create the trackable + SRef storageTrackable = xpcf::utils::make_shared(creatorId, localCRS, unitSystem, dimension, keyvalueTagList, type, encodingInfo, payload, name); + + //adding the newly created StorageTrackable to the worldgraph + xpcf::uuids::uuid trackableId; + if(m_worldStorage->addTrackable(trackableId, storageTrackable) != SolAR::FrameworkReturnCode::_SUCCESS) + { + //if something went wrong + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "something went wrong when adding the trackable to the world storage"); + return; + } + + //initialize the json object that we will send back to the client (the trackable's id) + std::string trackableIdString = xpcf::uuids::to_string(trackableId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, trackableIdString); + + //send the ID to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + + void TrackablesSolARImpl::delete_trackable(const std::string &trackableUUID, Pistache::Http::ResponseWriter &response) + { + //trackable uuid + xpcf::uuids::uuid id = xpcf::toUUID(trackableUUID); + switch(m_worldStorage->removeTrackable(id)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, "Trackable removed\n"); + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "Trackable not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void TrackablesSolARImpl::get_trackable_by_id(const std::string &trackableUUID, Pistache::Http::ResponseWriter &response) + { + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //look for the trackable with given id + xpcf::uuids::uuid id = xpcf::toUUID(trackableUUID); + SRef storageTrackable; + + switch(m_worldStorage->getTrackable(id, storageTrackable)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //StorageTrackable found, we convert it into a Trackable + org::openapitools::server::model::Trackable trackable = from_storage(*storageTrackable); + + //add the Trackable to our JSON object + to_json(jsonObjects, trackable); + + //send the Trackable to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "Trackable not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + + + } + + void TrackablesSolARImpl::get_trackables(Pistache::Http::ResponseWriter &response) + { + + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //declaration of all the objects that will be changed at each iteration of the loop + nlohmann::json toAdd; + org::openapitools::server::model::Trackable track; + + std::vector> vector; + if(m_worldStorage->getTrackables(vector) != SolAR::FrameworkReturnCode::_SUCCESS) + { + //Exception raised in getTrackables + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong when fetching the trackables from the world storage"); + } + else + { + //iteration over the content of the world storage + for (const SRef &t : vector){ + //add the current trackable to the JSON object + track = from_storage(*t); + to_json(toAdd, track); + jsonObjects.push_back(toAdd); + } + + //send the JSON object to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + } + + void TrackablesSolARImpl::modify_trackable(const model::Trackable &trackable, Pistache::Http::ResponseWriter &response) + { + //convert all the Trackable attributes into StorageTrackable attributes to create one and store it in the world storage + + //creator uuid + xpcf::uuids::uuid creatorId = xpcf::toUUID(trackable.getCreatorUUID()); + + //localCRS + std::vector vector = trackable.getLocalCRS(); + Eigen::Matrix matrix = Eigen::Map>(vector.data()); + SolAR::datastructure::Transform3Df localCRS(matrix); + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(trackable.getUnit()); + + //dimension + Eigen::Vector3d dimension = Eigen::Vector3d(trackable.getTrackableSize().data()); + + //taglist + std::multimap keyvalueTagList; + for (const auto &tag : trackable.getKeyvalueTags()){ + for(const auto &value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //trackable type + SolAR::datastructure::StorageTrackableType type = SolAR::datastructure::resolveTrackableType(trackable.getTrackableType()); + + //encoding info + SolAR::datastructure::EncodingInfo encodingInfo(trackable.getTrackableEncodingInformation().getDataFormat(), trackable.getTrackableEncodingInformation().getVersion()); + + //payload + std::vector payload = TrackablesSolARImpl::to_bytes(trackable.getTrackablePayload()); + + //name + std::string name = trackable.getName(); + + //id + boost::uuids::uuid id = xpcf::toUUID(trackable.getUUID()); + + //create the trackable + SRef storageTrackable = xpcf::utils::make_shared(id, creatorId, localCRS, unitSystem, dimension, keyvalueTagList, type, encodingInfo, payload, name); + + //adding the newly created StorageTrackable to the worldgraph + xpcf::uuids::uuid trackableId; + switch(m_worldStorage->modifyTrackable(trackableId, storageTrackable)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //initialize the json object that we will send back to the client (the trackable's id) + std::string trackableIdString = xpcf::uuids::to_string(trackableId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, trackableIdString); + + //send the ID to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "Trackable not found\n"); + + break; + } + + default : + { + //if something went wrong + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "something went wrong when modifying the trackable to the world storage\n"); + + } + } + + return; + } + + org::openapitools::server::model::Trackable TrackablesSolARImpl::from_storage(const SolAR::datastructure::StorageTrackable &trackable){ + //the object to be returned + org::openapitools::server::model::Trackable ret; + + //convert all the StorageTrackable attributes into Trackable attibutes + + //trackable UUID + std::string id = xpcf::uuids::to_string(trackable.getID()); + ret.setUUID(id); + + //creator UUID + std::string creatorUid = xpcf::uuids::to_string(trackable.getCreatorID()); + ret.setCreatorUUID(creatorUid); + + //name + ret.setName(trackable.getName()); + + //Trackable type + std::string type = resolveTrackableType(trackable.getType()); + ret.setTrackableType(type); + + //EncodingInfo struct + org::openapitools::server::model::EncodingInformationStructure encodingInfo; + SolAR::datastructure::EncodingInfo storageEncodingInfo(trackable.getEncodingInfo()); + encodingInfo.setDataFormat(storageEncodingInfo.getDataFormat()); + encodingInfo.setVersion(storageEncodingInfo.getVersion()); + ret.setTrackableEncodingInformation(encodingInfo); + + //Payload + std::vector storagePayload = trackable.getPayload(); + std::string payload(reinterpret_cast(&storagePayload[0]), storagePayload.size()); + ret.setTrackablePayload(payload); + + //Transform3Df (localCRS) + SolAR::datastructure::Transform3Df transform3d = trackable.getLocalCrs(); + Eigen::Matrix4f matrix = transform3d.matrix(); + std::vector localCRS; + for (size_t i = 0; i < (size_t) matrix.rows(); i++) + { + for (size_t j = 0; j < (size_t) matrix.cols(); j++) + { + localCRS.push_back(matrix(i, j)); + } + } + ret.setLocalCRS(localCRS); + + //Unit system + org::openapitools::server::model::UnitSystem unit = resolve_unitSystem(trackable.getUnitSystem()); + ret.setUnit(unit); + + //Dimension (scale) + Eigen::Vector3d dimension = trackable.getSize(); + std::vector vector(3); + for(int i = 0; i < 3; i++) + { + vector[i] = dimension[0,i]; + } + ret.setTrackableSize(vector); + + //keyvalue taglist (multimap to map>) + std::map> tagList; + auto storageMap = trackable.getTags(); + for (const auto &tag : storageMap) + { + if (tagList.count(tag.first) != 0){ + std::vector& vector = tagList.at(tag.first); + vector.push_back(tag.second); + }else { + std::vector vector; + vector.push_back(tag.second); + tagList.insert(std::pair>(tag.first, vector)); + } + } + ret.setKeyvalueTags(tagList); + + return ret; + } + + std::vector TrackablesSolARImpl::to_bytes(const std::string &s) + { + std::vector bytes; + bytes.reserve(std::size(s)); + std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c){ + return std::byte(c); + }); + + return bytes; + } + + void TrackablesSolARImpl::init(){ + try { + TrackablesApi::init(); + } + catch (xpcf::Exception e) + { + std::cout << e.what() << std::endl; + } + } + +} + diff --git a/Solar-Wrapper/src/WorldAnchorsSolARImpl.cpp b/Solar-Wrapper/src/WorldAnchorsSolARImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58ecba2b16b3924122396481a0437489bd796741 --- /dev/null +++ b/Solar-Wrapper/src/WorldAnchorsSolARImpl.cpp @@ -0,0 +1,327 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +namespace org::openapitools::server::implem +{ + + + WorldAnchorsSolARImpl::WorldAnchorsSolARImpl(const std::shared_ptr& rtr, SRef worldStorage) + : WorldAnchorsApi(rtr) + { + m_worldStorage = worldStorage; + } + + void WorldAnchorsSolARImpl::add_world_anchor(const org::openapitools::server::model::WorldAnchor &worldAnchor, Pistache::Http::ResponseWriter &response) + { + //convert all the WorldAnchor attributes into StorageWorldAnchor attributes to create one and store it in the world storage + + //creator uuid + xpcf::uuids::uuid creatorId = xpcf::toUUID(worldAnchor.getCreatorUUID()); + + //localCRS + std::vector vector = worldAnchor.getLocalCRS(); + Eigen::Matrix matrix = Eigen::Map>(vector.data()); + SolAR::datastructure::Transform3Df localCRS(matrix); + + //size + Eigen::Vector3d size = Eigen::Vector3d(worldAnchor.getWorldAnchorSize().data()); + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(worldAnchor.getUnit()); + + //taglist + std::multimap keyvalueTagList; + for (std::pair> tag : worldAnchor.getKeyvalueTags()){ + for(std::string value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //name + std::string name = worldAnchor.getName(); + + //create a world anchor + SRef storageWorldAnchor = xpcf::utils::make_shared(creatorId, localCRS, unitSystem, size, keyvalueTagList, name); + + //adding the newly created StorageWorldAnchor to the worldgraph + xpcf::uuids::uuid worldAnchorId; + if(m_worldStorage->addWorldAnchor(worldAnchorId, storageWorldAnchor) != SolAR::FrameworkReturnCode::_SUCCESS) + { + //if something went wrong + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "something went wrong when adding the anchor to the world storage"); + return; + } + + //initialize the json object that we will send back to the client (the WorldAnchor's id) + std::string worldAnchorIdString = xpcf::uuids::to_string(worldAnchorId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, worldAnchorIdString); + + //send the ID to the client + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + + void WorldAnchorsSolARImpl::delete_world_anchor(const std::string &worldAnchorUUID, Pistache::Http::ResponseWriter &response) + { + //world anchor uuid + xpcf::uuids::uuid id = xpcf::toUUID(worldAnchorUUID); + switch(m_worldStorage->removeWorldAnchor(id)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, "WorldAnchor removed\n"); + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "WorldAnchor not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldAnchorsSolARImpl::get_world_anchor_by_id(const std::string &worldAnchorUUID, Pistache::Http::ResponseWriter &response) + { + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //look for the world anchor with given id + xpcf::uuids::uuid id = xpcf::toUUID(worldAnchorUUID); + SRef storageWorldAnchor; + + switch(m_worldStorage->getWorldAnchor(id, storageWorldAnchor)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //StorageWorldAnchor found, we convert it into a WorldAnchor + org::openapitools::server::model::WorldAnchor worldAnchor = from_storage(*storageWorldAnchor); + + //add the WorldAnchor to our JSON object + to_json(jsonObjects, worldAnchor); + + //send the WorldAnchor to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "WorldAnchor not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldAnchorsSolARImpl::get_world_anchors(Pistache::Http::ResponseWriter &response) + { + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //declaration of all the objects that will be changed at each iteration of the loop + nlohmann::json toAdd; + org::openapitools::server::model::WorldAnchor worldAnchor; + + std::vector> vector; + if(m_worldStorage->getWorldAnchors(vector) != SolAR::FrameworkReturnCode::_SUCCESS) + { + //Exception raised in getWorldAnchor + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong when fetching the world storage"); + } + else + { + //iteration over the content of the world storage + for (const SRef &w : vector){ + //add the current worldAnchor to the JSON object + worldAnchor = from_storage(*w); + to_json(toAdd, worldAnchor); + jsonObjects.push_back(toAdd); + } + + //send the JSON object to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + } + + void WorldAnchorsSolARImpl::modify_world_anchor(const model::WorldAnchor &worldAnchor, Pistache::Http::ResponseWriter &response) + { + //convert all the WorldAnchor attributes into StorageWorldAnchor attributes to create one and store it in the world storage + + //creator uuid + xpcf::uuids::uuid creatorId = xpcf::toUUID(worldAnchor.getCreatorUUID()); + + //localCRS + std::vector vector = worldAnchor.getLocalCRS(); + Eigen::Matrix matrix = Eigen::Map>(vector.data()); + SolAR::datastructure::Transform3Df localCRS(matrix); + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(worldAnchor.getUnit()); + + //size + Eigen::Vector3d size = Eigen::Vector3d(worldAnchor.getWorldAnchorSize().data()); + + //taglist + std::multimap keyvalueTagList; + for (std::pair> tag : worldAnchor.getKeyvalueTags()){ + for(std::string value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //name + std::string name = worldAnchor.getName(); + + //id + xpcf::uuids::uuid id = xpcf::toUUID(worldAnchor.getUUID()); + + //create a world anchor + SRef storageWorldAnchor = xpcf::utils::make_shared(id, creatorId, localCRS, unitSystem, size, keyvalueTagList, name); + + //adding the newly created StorageWorldAnchor to the worldgraph + xpcf::uuids::uuid worldAnchorId; + switch(m_worldStorage->modifyWorldAnchor(worldAnchorId, storageWorldAnchor)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //initialize the json object that we will send back to the client (the WorldAnchor's id) + std::string worldAnchorIdString = xpcf::uuids::to_string(worldAnchorId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, worldAnchorIdString); + + //send the ID to the client + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "WorldAnchor not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + return; + } + + void WorldAnchorsSolARImpl::init() + { + try + { + WorldAnchorsApi::init(); + } + catch (xpcf::Exception e) + { + std::cout << e.what() << std::endl; + } + } + + org::openapitools::server::model::WorldAnchor WorldAnchorsSolARImpl::from_storage(const SolAR::datastructure::StorageWorldAnchor &worldAnchor) + { + //the object to be returned + org::openapitools::server::model::WorldAnchor ret; + + //convert all the StorageWorldAnchor attributes into WorldAnchor attibutes + + //world anchor UUID + std::string id = xpcf::uuids::to_string(worldAnchor.getID()); + ret.setUUID(id); + + //name + ret.setName(worldAnchor.getName()); + + //creator UUID + std::string creatorUid = xpcf::uuids::to_string(worldAnchor.getCreatorID()); + ret.setCreatorUUID(creatorUid); + + //Transform3Df (localCRS) + SolAR::datastructure::Transform3Df transform3d = worldAnchor.getLocalCrs(); + Eigen::Matrix matrix = transform3d.matrix(); + std::vector localCRS; + for (size_t i = 0; i < (size_t) matrix.rows(); i++) + { + for (size_t j = 0; j < (size_t) matrix.cols(); j++) + { + localCRS.push_back(matrix(i, j)); + } + } + ret.setLocalCRS(localCRS); + + //Unit system + org::openapitools::server::model::UnitSystem unit = resolve_unitSystem(worldAnchor.getUnitSystem()); + ret.setUnit(unit); + + //Dimension (scale) + Eigen::Vector3d dimension = worldAnchor.getSize(); + std::vector vector(3); + for(int i = 0; i < 3; i++){ + vector[i] = dimension[0,i]; + } + ret.setWorldAnchorSize(vector); + + //keyvalue taglist (multimap to map>) + std::map> tagList; + auto storageMap = worldAnchor.getTags(); + for (const auto &tag : storageMap){ + if (tagList.count(tag.first) != 0){ + std::vector& vector = tagList.at(tag.first); + vector.push_back(tag.second); + }else { + std::vector vector; + vector.push_back(tag.second); + tagList.insert(std::pair>(tag.first, vector)); + } + } + ret.setKeyvalueTags(tagList); + + return ret; + } +} diff --git a/Solar-Wrapper/src/WorldLinksSolARImpl.cpp b/Solar-Wrapper/src/WorldLinksSolARImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e045bfd013d610ed894f2d679016169cdb2a8b1 --- /dev/null +++ b/Solar-Wrapper/src/WorldLinksSolARImpl.cpp @@ -0,0 +1,411 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "TrackablesSolARImpl.h" +#include "UnitSysConversion.h" +#include "WorldAnchorsSolARImpl.h" +#include "WorldLinksSolARImpl.h" + +namespace xpcf = org::bcom::xpcf; + +namespace org::openapitools::server::implem { + + + WorldLinksSolARImpl::WorldLinksSolARImpl(const std::shared_ptr& rtr, SRef worldStorage) + : WorldLinksApi(rtr) + { + m_worldStorage = worldStorage; + } + + void WorldLinksSolARImpl::add_world_link(const org::openapitools::server::model::WorldLink &worldLink, Pistache::Http::ResponseWriter &response) + { + //convert all the WorldLink attributes into StorageWorldLink attributes to create one and store it in the world storage + + //authorId + xpcf::uuids::uuid authorId = xpcf::toUUID(worldLink.getCreatorUUID()); + + //transform 3d + std::vector vector = worldLink.getTransform(); + Eigen::Matrix matrix = Eigen::Map>(vector.data()); + SolAR::datastructure::Transform3Df transfo(matrix); + + //world element from ID + xpcf::uuids::uuid fromElementId = xpcf::toUUID(worldLink.getUUIDFrom()); + + //world element to ID + xpcf::uuids::uuid toElementId = xpcf::toUUID(worldLink.getUUIDTo()); + + //check if the link connects a single element + if(fromElementId == toElementId) + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Bad_Request, "An element can not be connected to himself\n"); + return; + } + + //world element from type + SolAR::datastructure::ElementKind fromElementType = resolve_element_kind(worldLink.getTypeFrom()); + + //world element to type + SolAR::datastructure::ElementKind toElementType = resolve_element_kind(worldLink.getTypeTo()); + + //adding the link to the storage by calling the world storage method + xpcf::uuids::uuid linkId; + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(worldLink.getUnit()); + + //taglist + std::multimap keyvalueTagList; + for (std::pair> tag : worldLink.getKeyvalueTags()){ + for(std::string value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //build the worldLink + xpcf::utils::shared_ptr storageWorldLink = xpcf::utils::make_shared(authorId, fromElementId, toElementId, fromElementType, toElementType, transfo, unitSystem, keyvalueTagList); + switch(m_worldStorage->addWorldLink(linkId, storageWorldLink)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //initialize the json object that we will send back to the client (the WorldAnchor's id) + std::string worldLinkIdString = xpcf::uuids::to_string(linkId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, worldLinkIdString); + + //send the ID to the client + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "The connected elements were not found in the world storage\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldLinksSolARImpl::delete_world_link(const std::string &worldLinkUUID, Pistache::Http::ResponseWriter &response) + { + auto linkId = xpcf::toUUID(worldLinkUUID); + switch(m_worldStorage->removeWorldLink(linkId)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, "WorldLink removed\n"); + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "WorldLink not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldLinksSolARImpl::get_world_link_by_id(const std::string &worldLinkUUID, Pistache::Http::ResponseWriter &response) + { + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //look for the world anchor with given id + xpcf::uuids::uuid id = xpcf::toUUID(worldLinkUUID); + SRef storageWorldLink; + + switch(m_worldStorage->getWorldLink(id, storageWorldLink)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //StorageWorldLink found, we convert it into a WorldLink + org::openapitools::server::model::WorldLink worldLink = from_storage(*storageWorldLink); + + //add the WorldLink to our JSON object + to_json(jsonObjects, worldLink); + + //send the link to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "WorldLink not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldLinksSolARImpl::get_world_links(Pistache::Http::ResponseWriter &response) + { + //initialize the json object that we will send back to the client + auto jsonObjects = nlohmann::json::array(); + + //declaration of all the objects that will be changed at each iteration of the loop + nlohmann::json toAdd; + org::openapitools::server::model::WorldLink worldLink; + + std::vector> vector; + if(m_worldStorage->getWorldLinks(vector) != SolAR::FrameworkReturnCode::_SUCCESS) + { + //Exception raised in getWorldLinks + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong when fetching the world storage"); + } + else + { + //for all the worldLinks in the worldStorage + for(const SRef &l : vector){ + //add the current world link to the JSON object + worldLink = from_storage(*l); + to_json(toAdd, worldLink); + jsonObjects.push_back(toAdd); + } + + //send the JSON object to the client + response.headers().add(MIME(Application, Json)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + } + } + + void WorldLinksSolARImpl::modify_world_link(const model::WorldLink &worldLink, Pistache::Http::ResponseWriter &response) + { + //convert all the WorldLink attributes into StorageWorldLink attributes to create one and store it in the world storage + + //authorId + xpcf::uuids::uuid authorId = xpcf::toUUID(worldLink.getCreatorUUID()); + + //transform 3d + std::vector vector = worldLink.getTransform(); + Eigen::Matrix matrix = Eigen::Map>(vector.data()); + SolAR::datastructure::Transform3Df transfo(matrix); + + //world element from ID + xpcf::uuids::uuid fromElementId = xpcf::toUUID(worldLink.getUUIDFrom()); + + //world element to ID + xpcf::uuids::uuid toElementId = xpcf::toUUID(worldLink.getUUIDTo()); + + //check if the link connects a single element + if(fromElementId == toElementId) + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Bad_Request, "An element can not be connected to himself\n"); + } + + //world element from type + SolAR::datastructure::ElementKind fromElementType = resolve_element_kind(worldLink.getTypeFrom()); + + //world element to type + SolAR::datastructure::ElementKind toElementType = resolve_element_kind(worldLink.getTypeTo()); + + //unitsystem + SolAR::datastructure::UnitSystem unitSystem = resolve_unitSystem(worldLink.getUnit()); + + //taglist + std::multimap keyvalueTagList; + for (std::pair> tag : worldLink.getKeyvalueTags()){ + for(std::string value : tag.second){ + keyvalueTagList.insert({tag.first,value}); + } + } + + //id + xpcf::uuids::uuid id = xpcf::toUUID(worldLink.getUUID()); + + + //build the worldLink + xpcf::utils::shared_ptr storageWorldLink = xpcf::utils::make_shared(id, authorId, fromElementId, toElementId, fromElementType, toElementType, transfo, unitSystem, keyvalueTagList); + + + //adding the link to the storage by calling the world storage method + xpcf::uuids::uuid linkId; + switch(m_worldStorage->modifyWorldLink(linkId, storageWorldLink)) + { + case SolAR::FrameworkReturnCode::_SUCCESS : + { + //initialize the json object that we will send back to the client (the WorldAnchor's id) + std::string worldLinkIdString = xpcf::uuids::to_string(linkId); + auto jsonObjects = nlohmann::json::array(); + nlohmann::to_json(jsonObjects, worldLinkIdString); + + //send the ID to the client + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Ok, jsonObjects.dump()); + break; + } + + case SolAR::FrameworkReturnCode::_NOT_FOUND : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Not_Found, "Either the WorldLink was not found, or the elements it should connect were not found\n"); + break; + } + + default : + { + response.headers().add(MIME(Text, Plain)); + response.send(Pistache::Http::Code::Internal_Server_Error, "Something went wrong\n"); + } + } + } + + void WorldLinksSolARImpl::init() + { + try + { + WorldLinksApi::init(); + } + catch (xpcf::Exception e) + { + std::cout << e.what() << std::endl; + } + } + + org::openapitools::server::model::WorldLink WorldLinksSolARImpl::from_storage(SolAR::datastructure::StorageWorldLink worldLink) + { + //the object to be returned + org::openapitools::server::model::WorldLink ret; + + //convert all the StorageWorldLink attributes into WorldLink attibutes + + //world link UUID + std::string id = xpcf::uuids::to_string(worldLink.getId()); + ret.setUUID(id); + + //creator UUID + std::string creatorUid = xpcf::uuids::to_string(worldLink.getAuthor()); + ret.setCreatorUUID(creatorUid); + + //element from UUID + std::string elementTo = xpcf::uuids::to_string(worldLink.getUuidFrom()); + ret.setUUIDFrom(elementTo); + + //element to UUID + std::string elementFrom = xpcf::uuids::to_string(worldLink.getUuidTo()); + ret.setUUIDTo(elementFrom); + + //element from Type + model::ObjectType typeFrom = resolve_element_kind(worldLink.getTypeFrom()); + ret.setTypeFrom(typeFrom); + + //element to Type + model::ObjectType typeTo = resolve_element_kind(worldLink.getTypeTo()); + ret.setTypeTo(typeTo); + + //transform + SolAR::datastructure::Transform3Df transform3d = worldLink.getTransform(); + Eigen::Matrix matrix = transform3d.matrix(); + std::vector localCRS; + for (size_t i = 0; i < (size_t) matrix.rows(); i++) + { + for (size_t j = 0; j < (size_t) matrix.cols(); j++) + { + localCRS.push_back(matrix(i, j)); + } + } + ret.setTransform(localCRS); + + //Unit system + org::openapitools::server::model::UnitSystem unit = resolve_unitSystem(worldLink.getUnitSystem()); + ret.setUnit(unit); + + //keyvalue taglist (multimap to map>) + std::map> tagList; + auto storageMap = worldLink.getTags(); + for (const auto &tag : storageMap){ + if (tagList.count(tag.first) != 0){ + std::vector& vector = tagList.at(tag.first); + vector.push_back(tag.second); + }else { + std::vector vector; + vector.push_back(tag.second); + tagList.insert(std::pair>(tag.first, vector)); + } + } + ret.setKeyvalueTags(tagList); + + return ret; + } + + model::ObjectType WorldLinksSolARImpl::resolve_element_kind(SolAR::datastructure::ElementKind kind) + { + model::ObjectType ret; + switch(kind) + { + case SolAR::datastructure::ElementKind::ANCHOR : + ret.setValue(model::ObjectType::eObjectType::WORLDANCHOR); + return ret; + break; + case SolAR::datastructure::ElementKind::TRACKABLE : + ret.setValue(model::ObjectType::eObjectType::TRACKABLE); + return ret; + break; + default : + ret.setValue(model::ObjectType::eObjectType::NOTIDENTIFIED); + return ret; + } + } + + SolAR::datastructure::ElementKind WorldLinksSolARImpl::resolve_element_kind(model::ObjectType kind) + { + switch(kind.getValue()) + { + case model::ObjectType::eObjectType::WORLDANCHOR : + return SolAR::datastructure::ElementKind::ANCHOR; + break; + case model::ObjectType::eObjectType::TRACKABLE : + return SolAR::datastructure::ElementKind::TRACKABLE; + break; + default : + return SolAR::datastructure::ElementKind::INVALID; + } + } +} diff --git a/Solar-Wrapper/src/main.cpp b/Solar-Wrapper/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3abce4cd6293bdf2eccbfc15df50f42f4a24ca51 --- /dev/null +++ b/Solar-Wrapper/src/main.cpp @@ -0,0 +1,150 @@ +/** + * Copyright 2022 ETSI + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* World Storage API +* API ensuring interoperability between an authoring tool and a World Storage service +* +* The version of the OpenAPI document: 0.0.1 +* +* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ + +#ifdef __linux__ +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "TrackablesSolARImpl.h" +#include "WorldAnchorsSolARImpl.h" +#include "WorldLinksSolARImpl.h" +#include "DefaultSolARImpl.h" + +#define PISTACHE_SERVER_THREADS 2 +#define PISTACHE_SERVER_MAX_REQUEST_SIZE 32768 +#define PISTACHE_SERVER_MAX_RESPONSE_SIZE 32768 + + +namespace xpcf = org::bcom::xpcf; + +static Pistache::Http::Endpoint *httpEndpoint; +#ifdef __linux__ +static void sigHandler [[noreturn]] (int sig){ + switch(sig){ + case SIGINT: + case SIGQUIT: + case SIGTERM: + case SIGHUP: + default: + httpEndpoint->shutdown(); + break; + } + exit(0); +} + +static void setUpUnixSignals(std::vector quitSignals) { + sigset_t blocking_mask; + sigemptyset(&blocking_mask); + for (auto sig : quitSignals) + sigaddset(&blocking_mask, sig); + + struct sigaction sa; + sa.sa_handler = sigHandler; + sa.sa_mask = blocking_mask; + sa.sa_flags = 0; + + for (auto sig : quitSignals) + sigaction(sig, &sa, nullptr); +} +#endif + +using namespace org::openapitools::server::implem; +using namespace SolAR; + +int main() { + + #ifdef __linux__ + std::vector sigs{SIGQUIT, SIGINT, SIGTERM, SIGHUP}; + setUpUnixSignals(sigs); + #endif + + try { + + #if NDEBUG + boost::log::core::get()->set_logging_enabled(false); + #endif + + //init the logger + LOG_ADD_LOG_TO_CONSOLE(); + LOG_INFO("program is running"); + + /* instantiate component manager*/ + /* this is needed in dynamic mode */ + SRef xpcfComponentManager = xpcf::getComponentManagerInstance(); + + if(xpcfComponentManager->load("SolARSample_World_Storage_conf.xml")!=org::bcom::xpcf::_SUCCESS) + { + LOG_ERROR("Failed to load the configuration file SolARSample_World_Storage_conf.xml"); + return -1; + } + auto worldStorage = xpcfComponentManager->resolve(); + + Pistache::Address addr(Pistache::Ipv4::any(), Pistache::Port(8080)); + + httpEndpoint = new Pistache::Http::Endpoint((addr)); + auto router = std::make_shared(); + + auto opts = Pistache::Http::Endpoint::options().threads(PISTACHE_SERVER_THREADS); + opts.flags(Pistache::Tcp::Options::ReuseAddr); + opts.maxRequestSize(PISTACHE_SERVER_MAX_REQUEST_SIZE); + opts.maxResponseSize(PISTACHE_SERVER_MAX_RESPONSE_SIZE); + httpEndpoint->init(opts); + + + DefaultSolARImpl DefaultApiserver(router); + DefaultApiserver.init(); + TrackablesSolARImpl TrackablesApiserver(router, worldStorage); + TrackablesApiserver.init(); + WorldAnchorsSolARImpl WorldAnchorsApiserver(router, worldStorage); + WorldAnchorsApiserver.init(); + WorldLinksSolARImpl WorldLinksApiserver(router, worldStorage); + WorldLinksApiserver.init(); + + httpEndpoint->setHandler(router->handler()); + httpEndpoint->serve(); + + httpEndpoint->shutdown(); + + } + + catch (xpcf::Exception e) + { + LOG_ERROR("Exception raised : \n {}", e.what()) + return -1; + } + return 0; + +} diff --git a/Solar-pistache-server-localbuild.pro b/Solar-pistache-server-localbuild.pro new file mode 100644 index 0000000000000000000000000000000000000000..fb39657d5f66ba08741a56a23d7f886e04c6105e --- /dev/null +++ b/Solar-pistache-server-localbuild.pro @@ -0,0 +1,62 @@ +## global defintions : target lib name, version +TARGET = SolARService_WorldStorage +VERSION = 0.11.0 + +QMAKE_PROJECT_DEPTH = 0 + +## remove Qt dependencies +QT -= core gui +CONFIG -= qt +CONFIG += c++1z +CONFIG += console +CONFIG += verbose + +DEFINES += MYVERSION=$${VERSION} + +include(findremakenrules.pri) + +LIBS += -L"/usr/local" -l"PistacheGen" + +# Default rules for deployment. +qnx: target.path = $${PWD}/bin/Debug# /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + + +unix: CONFIG += link_pkgconfig +unix: PKGCONFIG += libpistache + +DEPENDENCIESCONFIG = sharedlib install_recurse + +#NOTE : CONFIG as staticlib or sharedlib, DEPENDENCIESCONFIG as staticlib or sharedlib, QMAKE_TARGET.arch and PROJECTDEPLOYDIR MUST BE DEFINED BEFORE templatelibconfig.pri inclusion +include ($$shell_quote($$shell_path($${QMAKE_REMAKEN_RULES_ROOT}/templateappconfig.pri))) # Shell_quote & shell_path required for visual on windows + +INCLUDEPATH += \ + Solar-Wrapper/ \ + Solar-Wrapper/interfaces/ + +HEADERS += \ + Solar-Wrapper/interfaces/DefaultSolARImpl.h \ + Solar-Wrapper/interfaces/TrackablesSolARImpl.h \ + Solar-Wrapper/interfaces/UnitSysConversion.h \ + Solar-Wrapper/interfaces/WorldAnchorsSolARImpl.h \ + Solar-Wrapper/interfaces/WorldLinksSolARImpl.h + +SOURCES += \ + Solar-Wrapper/src/DefaultSolARImpl.cpp \ + Solar-Wrapper/src/TrackablesSolARImpl.cpp \ + Solar-Wrapper/src/WorldAnchorsSolARImpl.cpp \ + Solar-Wrapper/src/WorldLinksSolARImpl.cpp \ + Solar-Wrapper/src/main.cpp + +DISTFILES += \ + build/SolARSample_World_Storage_conf.xml \ + packagedependencies.txt + +config_files.path = target.path +config_files.files= $$files($${PWD}/SolARSample_World_Storage_conf.xml) +INSTALLS += config_files + + +#NOTE : Must be placed at the end of the .pro +include ($$shell_quote($$shell_path($${QMAKE_REMAKEN_RULES_ROOT}/remaken_install_target.pri)))) # Shell_quote & shell_path required for visual on windows diff --git a/bundle_system_install.sh b/bundle_system_install.sh new file mode 100755 index 0000000000000000000000000000000000000000..a9bf588e2f88457fdf73ac7361ef1d596fb81453 --- /dev/null +++ b/bundle_system_install.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/findremakenrules.pri b/findremakenrules.pri new file mode 100644 index 0000000000000000000000000000000000000000..3a13c891778ebec4719f7d8565c0a6cb92855050 --- /dev/null +++ b/findremakenrules.pri @@ -0,0 +1,43 @@ +# Author(s) : Loic Touraine, Stephane Leduc + +android { + # unix path + USERHOMEFOLDER = $$clean_path($$(HOME)) + isEmpty(USERHOMEFOLDER) { + # windows path + USERHOMEFOLDER = $$clean_path($$(USERPROFILE)) + isEmpty(USERHOMEFOLDER) { + USERHOMEFOLDER = $$clean_path($$(HOMEDRIVE)$$(HOMEPATH)) + } + } +} + +unix:!android { + USERHOMEFOLDER = $$clean_path($$(HOME)) +} + +win32 { + USERHOMEFOLDER = $$clean_path($$(USERPROFILE)) + isEmpty(USERHOMEFOLDER) { + USERHOMEFOLDER = $$clean_path($$(HOMEDRIVE)$$(HOMEPATH)) + } +} + +exists(builddefs/qmake) { + QMAKE_REMAKEN_RULES_ROOT=builddefs/qmake +} +else { + QMAKE_REMAKEN_RULES_ROOT = $$clean_path($$(REMAKEN_RULES_ROOT)) + !isEmpty(QMAKE_REMAKEN_RULES_ROOT) { + QMAKE_REMAKEN_RULES_ROOT = $$clean_path($$(REMAKEN_RULES_ROOT)/qmake) + } + else { + QMAKE_REMAKEN_RULES_ROOT=$${USERHOMEFOLDER}/.remaken/rules/qmake + } +} + +!exists($${QMAKE_REMAKEN_RULES_ROOT}) { + error("Unable to locate remaken rules in " $${QMAKE_REMAKEN_RULES_ROOT} ". Either check your remaken installation, or provide the path to your remaken qmake root folder rules in REMAKEN_RULES_ROOT environment variable.") +} + +message("Remaken qmake build rules used : " $$QMAKE_REMAKEN_RULES_ROOT) \ No newline at end of file diff --git a/images/AnchorMethods.png b/images/AnchorMethods.png new file mode 100644 index 0000000000000000000000000000000000000000..14c16be461e2daeb321fc8ad972c34c54d98a62d Binary files /dev/null and b/images/AnchorMethods.png differ diff --git a/images/DefaultMethods.png b/images/DefaultMethods.png new file mode 100644 index 0000000000000000000000000000000000000000..97316f382bd351bbe197de2bec56bc9c13ce06f1 Binary files /dev/null and b/images/DefaultMethods.png differ diff --git a/images/HandleSetUp.png b/images/HandleSetUp.png new file mode 100644 index 0000000000000000000000000000000000000000..e431f5d8642543baa6fa499c27bb8f92cb649ad4 Binary files /dev/null and b/images/HandleSetUp.png differ diff --git a/images/LinkMethods.png b/images/LinkMethods.png new file mode 100644 index 0000000000000000000000000000000000000000..1d064d7b0ac55ff760ef0a7eb71dc6a5228fab0d Binary files /dev/null and b/images/LinkMethods.png differ diff --git a/images/SchemaWrapper.png b/images/SchemaWrapper.png new file mode 100644 index 0000000000000000000000000000000000000000..b562c46c54fbb09ffa22f4eb334c9290f6b918f4 Binary files /dev/null and b/images/SchemaWrapper.png differ diff --git a/images/ToUUID.png b/images/ToUUID.png new file mode 100644 index 0000000000000000000000000000000000000000..b4bd982790dc02e075e479f7ea368d769b36d947 Binary files /dev/null and b/images/ToUUID.png differ diff --git a/images/TrackableMethods.png b/images/TrackableMethods.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad5285add7dab5018dd6872933587f32a280c18 Binary files /dev/null and b/images/TrackableMethods.png differ diff --git a/images/WorldStorageServer.png b/images/WorldStorageServer.png new file mode 100644 index 0000000000000000000000000000000000000000..904b8767ee6e29fdc7c3274f6edd5f7046936b1b Binary files /dev/null and b/images/WorldStorageServer.png differ diff --git a/images/XPCFComponentManager.png b/images/XPCFComponentManager.png new file mode 100644 index 0000000000000000000000000000000000000000..b290307312a1c9db1e56370184e5f6613881ac90 Binary files /dev/null and b/images/XPCFComponentManager.png differ diff --git a/images/serverClasses.png b/images/serverClasses.png new file mode 100644 index 0000000000000000000000000000000000000000..73c0e3c45134f46052f41d78921f7d3eb6df2586 Binary files /dev/null and b/images/serverClasses.png differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..e77ee76ca26a16736757c4cfc9dcf74ec0614ad6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "Solar-pistache-server-localbuild", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/packagedependencies.txt b/packagedependencies.txt new file mode 100644 index 0000000000000000000000000000000000000000..62ba3137b51b9fc75d74c0ddfe51a48d5080a31b --- /dev/null +++ b/packagedependencies.txt @@ -0,0 +1,2 @@ +SolARFramework|0.11.0|SolARFramework|SolARBuild@github|https://github.com/SolarFramework/SolarFramework/releases/download +xpcf|2.5.0|xpcf|github|https://github.com/ diff --git a/target.path/SolARSample_World_Storage_conf.xml b/target.path/SolARSample_World_Storage_conf.xml new file mode 100644 index 0000000000000000000000000000000000000000..802e84a6e8220023824cc361ad018d6ecd2d1005 --- /dev/null +++ b/target.path/SolARSample_World_Storage_conf.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +