trimbledesktopclient
v2.0.10
Published
Trimble Desktop Web Client
Downloads
61
Readme
Trimble Desktop is a local service that allows communication between a local browser page and desktop product. It consists for a client that runs on the browser and a windows service that should exist/be installed in the local machine.
Npm package
Run "npm run package"
bundle.js
Requisites: have browsify installed: npm install -g browserify browserify -r ./index.js:tbonewebclient > bundle.js
Available npm targets
npm run "target"
test => run jest unit tests : be sure a service is launched
build => build the client
lint => fixes/checks codes for format. Run always before commit
version => creates a new version. U need to append the version number: ex npm run version 1.2.3
bundle => creates a bundle.js with all client side libraries...
package => creates a npm package Run Jest Tests
To run tests against debug session in VS. Run the server in debug F5 Run tests in VS code
Run backend Unit tests
Use visual studio.
Service Ports
Tests will connect to port 44325, in Visual studio when pressing debug, before, set additonal command arguments on you debug to --urls=http://localhost:44325/ Alternatively you can run from command line in "dotnet run --urls=http://localhost:44325/" in the TeklaTBone folder
TeklaTBone Components
Backend Service
Asp.net core .net 6 + sqlite db (entity framework) + rest api Runs as admin in system account TrimbleDesktopConsole => .net full framework component to access windows 32 apis
TBone Client
Typescript: npm or bundle.js library that runs on users browser and communicate to service via rest api
The next examples show some of the components for the client and some examples how to use them
Service Manager
Singleton service, that is interacts with backed service. Following supported features are available
- Management of the service, download and check versions
- Install module - Creation of install jobs on the backed
- Discovery module - Checking what products are installed
In your app, initialization is required before accessing further functionality. Service manager is a sigleton to avoid multiple queries
Examples Initialization
Using Azure Blob Storage
<script>
var tBoneWebClient = require('tbonewebclient');
tBoneWebClient.ServiceManager.InitInstance(new tBoneWebClient.TBoneRestHelpers("http://localhost:5000/"), new tBoneWebClient.AzureBlobBackedRestHelpers())
</script>Using Tekla Downloads
<script>
var tBoneWebClient = require('tbonewebclient');
tBoneWebClient.ServiceManager.InitInstance(new tBoneWebClient.TBoneRestHelpers("http://localhost:5000/"), ew TeklaDownloadsRestHelpers('https://download.dev.tekla.com/'))
</script>Using TypeScript and npm packges - vue.js
<script lang="ts">
import { AzureBlobBackedRestHelpers, ServiceManager, TBoneRestHelpers } from 'tbonewebclient';
export default class App extends Vue {
private tboneService : ServiceManager = ServiceManager.InitService(new TBoneRestHelpers('http://localhost:5000/'), new AzureBlobBackedRestHelpers())
}
</script> Example Monitor Service Status
Assumes Initialization is done
<script lang="ts">
import { AzureBlobBackedRestHelpers, ServiceManager, TBoneRestHelpers } from 'tbonewebclient';
export default class App extends Vue {
private tboneService : ServiceManager = ServiceManager.InitService(new TBoneRestHelpers('http://localhost:5000/'), new AzureBlobBackedRestHelpers());
private async created() {
this.serviceManager.RegisterOnServiceHandler(async () => this.HandleServiceOnEvent());
this.serviceManager.RegisterOffServiceHandler(async () => this.HandleServiceOffEvent());
}
private async HandleServiceOnEvent(){
console.log("Service off");
}
private async HandleServiceOffEvent(){
console.log("Service on");
}
}
</script> Examples Download Service/Check Service
Assumes Initialization is done
<script>
var tBoneWebClient = require('tbonewebclient');
console.log("Latest Version", tBoneWebClient.ServiceManager.Instance().LastVersion())
console.log("Installed Version", tBoneWebClient.ServiceManager.Instance().CurrentInstalledVersion())
</script>Product Manager
Helper class that allows management of installs/execution/discovery at higher level. Extendable, clients using the library can create new products by inheriting GenericProduct interface
Available features
- Discovery - searchs for a product in local machine
- Installation - installs a product
- Execution - Runs a product
At the moment the client ships with the following product definitions, TrimbleConnectDesktop, TeklaStructuresMsi and TeklaStructuresDailyMsi
Discovery
Discovery responsibility is from the product definition itself. This approachs allow more easily support different products that have different ways of install.
Example
<script lang="ts">
import { AzureBlobBackedRestHelpers, ServiceManager, TBoneRestHelpers } from 'tbonewebclient';
export default class App extends Vue {
private TEKLADOWNLOADURLDEV = 'https://download.dev.tekla.com/';
// creates manager
private productManager: ProductManager = new ProductManager(new TeklaDownloadsRestHelpers(this.TEKLADOWNLOADURLDEV));
// define a product
private tcdProduct: GenericProduct = new TrimbleConnectDesktopMsi();
private async created() {
if (ServiceManager.Instance().IsLocalServiceRunning()) {
await this.productManager.DiscoverProduct(this.tcdProduct);
console.log("Last Version", this.tcdProduct.ProductLastVersion);
console.log("Installed Version", this.tcdProduct.ProductInstalledVersion);
}
}
}
</script> Typically discovery for example means checking some registries on local machines. However registry might not be involved at all if the product itself doesnt have a registry to check.
Install Instructions and Install
The manager expects a certain set of install instructions to be sent to the ServiceManager, again the instructions should be defined by the product to allow more flexibily. Typical instructions for example involve run a installer.
Example
<script lang="ts">
import { AzureBlobBackedRestHelpers, ServiceManager, TBoneRestHelpers } from 'tbonewebclient';
export default class App extends Vue {
private TEKLADOWNLOADURLDEV = 'https://download.dev.tekla.com/';
// creates manager
private productManager: ProductManager = new ProductManager(new TeklaDownloadsRestHelpers(this.TEKLADOWNLOADURLDEV));
// define a product
private tcdProduct: GenericProduct = new TrimbleConnectDesktopMsi();
private async InstallJob() {
if (ServiceManager.Instance().IsLocalServiceRunning()) {
const installId = await this.productManager.InstallProduct(
this.tcdProduct.ProductName,
this.LatestVersion,
async (_: any, job: InstallJob | undefined) => {
console.log("Job Completed Ok");
},
async (_: any, job: InstallJob | undefined) => {
console.log("Job Completed Failed");
},
false,
);
}
}
}
</script> Product Start
Client use custom protocol, it requires the product the provide the app path. and the protocol will be created in the local machine. Should be possible to pass arguments to the product when execution
Example
<script lang="ts">
import { AzureBlobBackedRestHelpers, ServiceManager, TBoneRestHelpers } from 'tbonewebclient';
export default class App extends Vue {
private TEKLADOWNLOADURLDEV = 'https://download.dev.tekla.com/';
// creates manager
private productManager: ProductManager = new ProductManager(new TeklaDownloadsRestHelpers(this.TEKLADOWNLOADURLDEV));
// define a product
private tcdProduct: GenericProduct = new TrimbleConnectDesktopMsi();
private async StartApplication() {
if (ServiceManager.Instance().IsLocalServiceRunning()) {
await this.productManager.RunProduct(this.tcdProduct.ProductName);
}
}
}
</script> Products Definition
Clients can construct products based on GenericProduct.
export interface GenericProduct {
DiscoverProduct(): Promise<void>;
RunProduct(): Promise<void>;
InstallInstructions(
backendService: TBoneBackedRestHelpersI,
versionToInstall: string,
autoUpdate: boolean,
): Promise<InstallJob>;
ProductState: ProductInstallState;
ProductLastVersion: string;
ProductInstalledVersion: string;
ProductId: string;
ProductName: string;
}Discovery Examples
In the next example we use GetRegistryValues and GetAppPath to check if a version has registry settings and exist on disk.
It also figures out whats the version from the registry.
async DiscoverProduct(): Promise<void> {
const handlers = new LocalMachineRegistryDiscoveryHandler();
handlers.searchRegistries = [];
handlers.searchRegistries.push(
new RegistryKeyPair('SOFTWARE\\Trimble\\Trimble Connect\\Installer', 'InstallDir', ''),
);
handlers.searchRegistries.push(
new RegistryKeyPair('SOFTWARE\\Trimble\\Trimble Connect\\Installer', 'ProductVersion', ''),
);
const registryKeysToCheck = (await ServiceManager.Instance().GetRegistryValues(handlers)) as LocalMachineRegistryDiscoveryHandler;
if (registryKeysToCheck !== undefined && registryKeysToCheck.searchRegistries !== undefined) {
if (registryKeysToCheck.searchRegistries[0].value !== '') {
const folderSearchPath = new FolderDiscoveryHandler();
folderSearchPath.pathsToSearch = [];
folderSearchPath.pathsToSearch.push(registryKeysToCheck.searchRegistries[0].value! + '\\TrimbleConnect.exe');
this.appPath = await ServiceManager.Instance().GetAppPath(folderSearchPath);
if (this.appPath !== '') {
this.productState = ProductInstallState.INSTALLED;
this.productInstalledVersion = registryKeysToCheck.searchRegistries[1].value!;
const elems = this.productInstalledVersion.split(".");
if (elems.length === 4) { // 123.23.2.23
// we support only sem version
this.productInstalledVersion = elems[0] + "." + elems[1] + "." + elems[2];
}
} else {
this.productState = ProductInstallState.INVALID;
}
} else {
// check if installation is running
const jobState = await ServiceManager.Instance().GetJobState(this.productName);
if (jobState === InstallInstructionState.Processing) {
this.productState = ProductInstallState.INSTALLING;
} else {
this.productState = ProductInstallState.NOTAVAILABLE;
}
}
}
}Install Instructions Examples
In the next example we set the type of installer, how binaries are retrieved and additional command line argumets the installer will perform.
async InstallInstructions(
backendService: TBoneBackedRestHelpersI,
versionToInstall: string,
autoUpdateSet: boolean,
): Promise<InstallJob> {
// define install instructions
const installInstruction = new InstallJob(this.productName);
installInstruction.downloadType = ProductDownloadType.Download;
installInstruction.productType = ProductInstallType.Msi;
installInstruction.versionToInstall = versionToInstall;
installInstruction.installOrder = 0;
installInstruction.installState = InstallInstructionState.Planned;
installInstruction.automaticUpgradeSet = autoUpdateSet;
installInstruction.additionalCommandLineArguments = '/s /debuglog"%LOGFOLDER%\\SetupLogExe.log" /v"/qnb REBOOT=ReallySuppress" /V"/lv %LOGFOLDER%\\SetupLogMis.log"';
installInstruction.downloadLocation = await backendService.GetDownloadLinkForProduct(
this.productName,
versionToInstall,
GetOsInfo(),
);
return installInstruction;
}
Product bundles
Should be possible to define a set of product bundles. Each install job can have sub jobs or dependent jobs that are installed at given order provided by user.
TBone Service
Reseting Database
Remove all migrations, then
Drop-Database -Verbose Add-Migration Initial Update-Database
