Exposes MineTrustConnector SDK functionality to a native C++ application via a C++/CLI wrapper. This allows the native application to interact with the MineTrust Connector service, enabling features such as loading and saving package configurations, finding tags and files, evaluating filters, and receiving events from the service.
#include "../../CppCliInterop/MTConnectorSDK.h"
#include <magic_enum.hpp>
#include <chrono>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <process.h>
#include <random>
#include <thread>
using namespace std::chrono_literals;
namespace fs = std::filesystem;
template <>
struct magic_enum::customize::enum_range<MTConnectorSDK::LogEvent> {
static constexpr int min = 1000;
static constexpr int max = 5000;
};
static std::string random_string(std::string::size_type length)
{
static auto& chrs = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
thread_local static std::mt19937 rg{ std::random_device{}() };
thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);
std::string s;
s.reserve(length);
while (length--)
s += chrs[pick(rg)];
return s;
}
namespace
{
constexpr bool showUI = false;
{
std::cout << "Package processing in main thread" << std::endl;
MTConnectorSDK::LockPackage(newConfiguration.
packageUID, _getpid(), showUI);
MTConnectorSDK::SyncNow(newConfiguration.
packageUID, showUI);
MTConnectorSDK::UnlockPackage(newConfiguration.
packageUID,
true, showUI);
std::cout << "Finished processing in main thread" << std::endl;
}
{
concurrency::cancellation_token_source cts;
auto token = cts.get_token();
auto t = MTConnectorSDK::SyncNowTask(newConfiguration.
packageUID, showUI, token)
.then([&newConfiguration, token](MTConnectorSDK::SyncNowResultCodes syncReturnCode)
{
return MTConnectorSDK::LockPackageTask(newConfiguration.
packageUID, _getpid(), showUI, token);
}, token)
.then([&newConfiguration, token, &cts](MTConnectorSDK::LockPackageResultCodes lockReturnCode)
{
cts.cancel();
return MTConnectorSDK::SyncNowTask(newConfiguration.
packageUID, showUI, token);
}, token)
.then([&newConfiguration, token](MTConnectorSDK::SyncNowResultCodes syncReturnCode)
{
return MTConnectorSDK::UnlockPackageTask(newConfiguration.
packageUID,
false, showUI, token);
}, token);
std::cout << "Package processing in background" << std::endl;
const concurrency::task_status taskStatus = t.wait();
std::cout << "Finished processing in background being canceled? " <<
std::boolalpha << (concurrency::task_status::canceled == taskStatus) << std::endl;
MTConnectorSDK::UnlockPackage(newConfiguration.
packageUID,
false, showUI);
}
{
bool done = false;
{
std::cout << "Preparing multiple Sync processing in background" << std::endl;
auto t = MTConnectorSDK::SyncNowTask(newConfiguration.
packageUID, showUI)
.then([&done](MTConnectorSDK::SyncNowResultCodes syncReturnCode)
{
std::cout << "Done processing" << std::endl;
done = true;
});
std::cout << "Leave task scope" << std::endl;
}
std::cout << "Out of scope processing in background" << std::endl;
while (!done)
{
std::cout << "Still waiting for task to be done" << std::endl;
std::this_thread::sleep_for(1s);
}
std::cout << "Done waiting" << std::endl;
}
void SubscribeToEvents()
{
std::list<MTConnectorSDK::LogEvent> eventIds;
eventIds.push_back(MTConnectorSDK::LogEvent::AllFilesUpToDate);
eventIds.push_back(MTConnectorSDK::LogEvent::SyncStarted);
eventIds.push_back(MTConnectorSDK::LogEvent::SyncCompleted);
eventIds.push_back(MTConnectorSDK::LogEvent::GeneralSyncError);
{
std::cout << connectorEvent.
time
<<
": Event (" << magic_enum::enum_name(connectorEvent.
eventId) <<
") received: "
<< connectorEvent.
message << std::endl;
}, eventIds);
std::this_thread::sleep_for(10s);
}
auto AddRandomFile(const std::string& baseName, const fs::path& destinationDir)
{
auto rnd_suffix = random_string(6);
auto localFileName = baseName + "_" + rnd_suffix + ".txt";
auto localFilePath = destinationDir / localFileName;
std::ofstream outfile(localFilePath);
outfile.close();
return localFilePath.string();
}
auto SetUpTestPackage(const std::string& baseName, const std::string& serverUrl, int numberTestFiles = 10)
{
auto rnd_suffix = random_string(6);
auto displayName = baseName + "_" + rnd_suffix;
packageConfiguration.
enabled =
true;
packageConfiguration.
localRoot = R
"(C:\temp\test\)" + rnd_suffix;
MTConnectorSDK::SavePackageConfiguration(packageConfiguration);
packageConfiguration = MTConnectorSDK::FindPackageConfigurations("$.DisplayName", displayName)[0];
MTConnectorSDK::SyncNow(packageConfiguration.
packageUID);
for (int i = 0; i < numberTestFiles; ++i)
{
AddRandomFile(std::format(
"dummy {} ({})", i, rnd_suffix), packageConfiguration.
localRoot);
}
if (numberTestFiles > 0)
{
MTConnectorSDK::SyncNow(packageConfiguration.
packageUID);
}
return packageConfiguration;
}
}
int main()
{
try
{
std::cout << MTConnectorSDK::GetShellExtensionName() << std::endl;
std::cout << "Connector is installed: " << std::boolalpha << MTConnectorSDK::IsMineTrustConnectorInstalled() << std::endl;
std::cout << "Connector is running: " << std::boolalpha << MTConnectorSDK::IsMineTrustConnectorRunning() << std::endl;
auto serverConfiguration = MTConnectorSDK::ListServerConfigurations()[0];
std::cout << serverConfiguration.serverUrl << std::endl;
{
std::cout <<
"Package is enabled: " << packageConfiguration.
packageUID << std::endl;
}
{
std::cout << "Tag name: " << tagRecord.name << " / Tag value: " << tagRecord.value << std::endl;
{
std::cout << "File record file found: " << fileRecord.name << std::endl;
}
}
{
std::cout << "Level map file found: " << fileRecord.name << std::endl;
}
{
std::cout << "Located level map file via filter evaluation: " << filterResult.name << std::endl;
}
for (const std::string& packageUID : MTConnectorSDK::GetDeletedPackages())
{
std::cout << "Package has been deleted: " << packageUID << std::endl;
}
for (const std::string& packageUID : MTConnectorSDK::GetArchivedPackages())
{
std::cout << "Package has been archived: " << packageUID << std::endl;
}
auto testPackage1 = SetUpTestPackage("Cpp/CLI Package Test 1", serverConfiguration.serverUrl);
DoSync(testPackage1);
DoAsync(testPackage1);
DoAsyncLeavingScope(testPackage1);
SubscribeToEvents();
for (const std::string& localFile : MTConnectorSDK::EnumerateLocalContents(testPackage1.packageUID))
{
std::cout << "Test package has local file: " << localFile << std::endl;
}
auto packageMetrics = MTConnectorSDK::LoadPackageMetrics(testPackage1.packageUID, serverConfiguration.packageUID);
std::cout << "Test package total files: " << packageMetrics.totalFiles << std::endl;
std::cout << "Test package local files: " << packageMetrics.localFiles << std::endl;
std::cout << "Test package percentage downloaded: " << packageMetrics.percentageDownloaded << std::endl;
auto testEmptyPackage = [&testPackage1](auto&& emptyThePackageFn)
{
std::cout << "Has " << MTConnectorSDK::EnumerateLocalContents(testPackage1.packageUID).size() << " files in scope" << std::endl;
auto packageCopy = testPackage1;
emptyThePackageFn(packageCopy);
MTConnectorSDK::SavePackageConfiguration(packageCopy);
MTConnectorSDK::SyncNow(testPackage1.packageUID);
std::cout << "After being emptied, has " << MTConnectorSDK::EnumerateLocalContents(testPackage1.packageUID).size() << " files in scope" << std::endl;
MTConnectorSDK::LoadPackageConfiguration(testPackage1.packageUID, reloaded);
MTConnectorSDK::SavePackageConfiguration(testPackage1);
MTConnectorSDK::SyncNow(testPackage1.packageUID);
};
{
std::cout << "Emptying the package (add empty include) " << std::endl;
packageConfig.
include.push_back({});
});
{
std::cout << "Emptying the package (exclude everything) " << std::endl;
packageConfig.
exclude.push_back(
"*");
});
auto testFile1a = AddRandomFile("testFile1a", testPackage1.localRoot);
MTConnectorSDK::SyncNow(testPackage1.packageUID);
MTConnectorSDK::TagFile(testPackage1, testFile1a, "Status", "Published");
MTConnectorSDK::SavePackageConfiguration(testPackage1);
MTConnectorSDK::SyncNow(testPackage1.packageUID, showUI);
for (const std::string& localFile : MTConnectorSDK::EnumerateLocalFilesByTag(testPackage1.packageUID, "Status", "Published"))
{
std::cout << "Located the following file by tag in the test package: " << localFile << std::endl;
}
auto testFile1b = AddRandomFile("testFile1b", testPackage1.localRoot);
MTConnectorSDK::SyncNow(testPackage1.packageUID);
{
include.
tags.insert(std::make_pair(
"Status",
"Published"));
});
MTConnectorSDK::SavePackageConfiguration(testPackage1);
MTConnectorSDK::SyncNow(testPackage1.packageUID, showUI);
for (const std::string& localFile : MTConnectorSDK::EnumerateLocalFilesByTag(testPackage1.packageUID, "Status", "Published"))
{
std::cout << "Located the following file by tag in the test package: " << localFile << std::endl;
}
testPackage1.enabled = false;
testPackage1.localRoot = std::string();
MTConnectorSDK::SavePackageConfiguration(testPackage1);
auto testPackage2 = SetUpTestPackage("Cpp/CLI Package Test 2", serverConfiguration.serverUrl);
auto testFile2a = AddRandomFile("testFile2a", testPackage2.localRoot);
auto testFile2b = AddRandomFile("testFile2b", testPackage2.localRoot);
MTConnectorSDK::SyncNow(testPackage2.packageUID);
MTConnectorSDK::TagFile(testPackage2, testFile2a, "Status", "Draft");
MTConnectorSDK::TagFile(testPackage2, testFile2b, "Status", "Draft");
MTConnectorSDK::TagFile(testPackage2, testFile2b, "LocalOnly", "True");
MTConnectorSDK::TagFile(testPackage2, testFile2a, "Hidden", "True");
MTConnectorSDK::SavePackageConfiguration(testPackage2);
MTConnectorSDK::SyncNow(testPackage2.packageUID, showUI);
MTConnectorSDK::RemoveTag(testPackage2, testFile2a, "Hidden");
MTConnectorSDK::SavePackageConfiguration(testPackage2);
MTConnectorSDK::SyncNow(testPackage2.packageUID, showUI);
{
MTConnectorSDK::SyncNow(serverConfiguration.packageUID, showUI);
}
auto publishedFiles = MTConnectorSDK::FindFiles("Status", "Published");
MTConnectorSDK::ReceiveFiles(publishedFiles, [&](const std::vector<MTConnectorSDK::LocalFileRecord>& receivedFiles)
{
{
std::cout << "Received file: " << receivedFile.localFilePath << std::endl;
const fs::path tempDir(testPackage2.localRoot);
if (!fs::exists(tempDir / receivedFile.name))
{
fs::copy_file(receivedFile.localFilePath, tempDir / receivedFile.name);
}
}
}).wait();
auto draftFiles = MTConnectorSDK::FindFiles("Status", "Draft");
{
{
if (tagRecord.
name ==
"LocalOnly" && tagRecord.
value ==
"True")
{
}
}
std::cout <<
"Sending file to package: " << localFileRecord.
localFilePath << std::endl;
return testPackage1;
}).wait();
for (const std::string& permittedValue : MTConnectorSDK::GetPermittedValues("Studio Mapper/Mine"))
{
std::cout << "Permitted value: " << permittedValue << std::endl;
}
}
catch (const std::runtime_error& e)
{
std::cout << "Sample app encountered an error: " << e.what() << std::endl;
}
return 0;
}
Definition MTConnectorSDK.h:280
std::unordered_map< std::string, std::string > tags
Definition MTConnectorSDK.h:296
Definition MTConnectorSDK.h:477
std::vector< LocalTagRecord > tags
Definition MTConnectorSDK.h:489
std::string localFilePath
Definition MTConnectorSDK.h:497
Definition MTConnectorSDK.h:456
std::string name
Definition MTConnectorSDK.h:460
std::string value
Definition MTConnectorSDK.h:464
Definition MTConnectorSDK.h:504
LogEvent eventId
Definition MTConnectorSDK.h:509
std::string message
Definition MTConnectorSDK.h:517
std::chrono::system_clock::time_point time
Definition MTConnectorSDK.h:513
Definition MTConnectorSDK.h:309
std::string displayName
Definition MTConnectorSDK.h:330
std::string serverUrl
Definition MTConnectorSDK.h:338
std::vector< IncludeConfiguration > include
Definition MTConnectorSDK.h:357
std::string localRoot
Definition MTConnectorSDK.h:342
static MT_CONNECTOR_EXPORT const std::string SHARED_PACKAGE_VISIBILITY
Definition MTConnectorSDK.h:313
bool enabled
Definition MTConnectorSDK.h:326
std::vector< std::string > exclude
Definition MTConnectorSDK.h:362
std::string visibility
Definition MTConnectorSDK.h:381
std::string packageUID
Definition MTConnectorSDK.h:334