@microsoft/servicehub-framework
TypeScript icon, indicating that this package has built-in type declarations

4.2.102 • Public • Published

NodeJS ServiceHub Framework

This NPM package provides a way to proffer and consume brokered services. It is used in Visual Studio-related products to exchange services within and across processes and even across machines.

Learn about the brokered services essentials, how to provide a brokered service, and how to consume a brokered service.

Usage

Given an instance of IServiceBroker, you can request a service (such as a simple calculator service) like this:

const proxy = await serviceBroker.getProxy<ICalculatorService>(CalculatorDescriptor);
try {
    if (proxy) {
        const sum = await proxy.add(3, 5);
        assert(sum == 8);
    }
} finally {
    proxy?.dispose();
}

Important points to remember:

  1. Always be defensive by checking for an null result from the call for a service.
  2. Always dispose the proxy when you're done with it to avoid leaking resources. These proxies do not get garbage collected automatically on account of the I/O resource they require.

Let's do something real. Visual Studio 16.6 includes a VersionInfoService that exposes the VS and Live Share versions on the host. You can call that service from VS Code like this:

import * as isb from '@microsoft/servicehub-framework';
import * as vsls from 'vsls';

const VersionInfoService = new isb.ServiceJsonRpcDescriptor(
    isb.ServiceMoniker.create('Microsoft.VisualStudio.Shell.VersionInfoService', '1.0'),
    isb.Formatters.Utf8,
    isb.MessageDelimiters.HttpLikeHeaders);

interface IVersionInfoService {
    GetVersionInformationAsync(cancellationToken?: vscode.CancellationToken): Promise<VersionInformation>;
}

interface VersionInformation {
    visualStudioVersion: string;
    liveShareVersion: string;
}

const ls = await vsls.getApi();
const serviceBroker = await ls.services.getRemoteServiceBroker();
const proxy = await serviceBroker?.getProxy<IVersionInfoService>(VersionInfoService);
try {
    if (proxy) {
        const versionInfo = await proxy.GetVersionInformationAsync();
        console.log(`VS version: ${versionInfo.visualStudioVersion}`);
    }
} finally {
    proxy?.dispose();
}

Brokered Service Container

A process that wishes to offer its own brokered services need a container. If your javascript process does not already have a container, the following is for you.

Here is the simplest possible, self-contained executable sample (in TypeScript). The sample demonstrates definition and implementation of a service, registers it and proffers it with a ServiceRpcDescriptor and service factory into the container, and finally consumes it via an IServiceBroker.

import assert from 'assert'
import CancellationToken from 'cancellationtoken'
import {
    Formatters,
    MessageDelimiters,
    ServiceJsonRpcDescriptor,
    ServiceMoniker,
    ServiceRpcDescriptor,
    GlobalBrokeredServiceContainer,
    ServiceAudience,
    ServiceRegistration,
} from '@microsoft/servicehub-framework'

interface IService {
    readonly moniker: ServiceMoniker
    readonly descriptor: ServiceRpcDescriptor
    readonly registration: ServiceRegistration
}

class Services {
    static calculator: Readonly<IService> = Services.defineLocal('calc')

    private static defineLocal(
        name: string,
        version?: string
    ): Readonly<IService> {
        const moniker = { name, version }
        const descriptor = new ServiceJsonRpcDescriptor(
            moniker,
            Formatters.MessagePack,
            MessageDelimiters.BigEndianInt32LengthHeader
        )
        const registration = new ServiceRegistration(
            ServiceAudience.local,
            false
        )
        return Object.freeze({ moniker, descriptor, registration })
    }
}

interface ICalculator {
    add(
        a: number,
        b: number,
        cancellationToken?: CancellationToken
    ): Promise<number>
}

class Calculator implements ICalculator {
    public add(
        a: number,
        b: number,
        cancellationToken?: CancellationToken
    ): Promise<number> {
        return Promise.resolve(a + b)
    }
}

let container: GlobalBrokeredServiceContainer
beforeAll(function () {
    container = new GlobalBrokeredServiceContainer()
    container.register([Services.calculator])
    container.profferServiceFactory(
        Services.calculator.descriptor,
        (mk, options, sb, ct) => Promise.resolve(new Calculator())
    )
})

it('self-contained sample', async function () {
    const sb = container.getFullAccessServiceBroker()
    const calc = await sb.getProxy<ICalculator>(Services.calculator.descriptor)
    assert(calc)
    const sum = await calc.add(3, 5)
    assert(sum === 8)
})

Note that in a real world application, the preceding code would typically be divided into many files, and may even span packages and processes.

Contributing

Check out our CONTRIBUTING.md file.

Readme

Keywords

none

Package Sidebar

Install

npm i @microsoft/servicehub-framework

Weekly Downloads

48

Version

4.2.102

License

LICENSE.txt

Unpacked Size

1.13 MB

Total Files

181

Last publish

Collaborators

  • andrewarnott
  • jepetty
  • rytoth
  • microsoft1es