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:276
std::unordered_map< std::string, std::string > tags
Definition MTConnectorSDK.h:292
Definition MTConnectorSDK.h:473
std::vector< LocalTagRecord > tags
Definition MTConnectorSDK.h:485
std::string localFilePath
Definition MTConnectorSDK.h:493
Definition MTConnectorSDK.h:452
std::string name
Definition MTConnectorSDK.h:456
std::string value
Definition MTConnectorSDK.h:460
Definition MTConnectorSDK.h:500
LogEvent eventId
Definition MTConnectorSDK.h:505
std::string message
Definition MTConnectorSDK.h:513
std::chrono::system_clock::time_point time
Definition MTConnectorSDK.h:509
Definition MTConnectorSDK.h:305
std::string displayName
Definition MTConnectorSDK.h:326
std::string serverUrl
Definition MTConnectorSDK.h:334
std::vector< IncludeConfiguration > include
Definition MTConnectorSDK.h:353
std::string localRoot
Definition MTConnectorSDK.h:338
static MT_CONNECTOR_EXPORT const std::string SHARED_PACKAGE_VISIBILITY
Definition MTConnectorSDK.h:309
bool enabled
Definition MTConnectorSDK.h:322
std::vector< std::string > exclude
Definition MTConnectorSDK.h:358
std::string visibility
Definition MTConnectorSDK.h:377
std::string packageUID
Definition MTConnectorSDK.h:330