Skip to content

Commit

Permalink
Merge pull request #256 from XavierGeerinck/issue_223
Browse files Browse the repository at this point in the history
Rename dapr-client to @dapr/dapr
  • Loading branch information
XavierGeerinck authored May 10, 2022
2 parents b827da6 + 2da4bd8 commit e4f8245
Show file tree
Hide file tree
Showing 40 changed files with 11,439 additions and 11,296 deletions.
38 changes: 25 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Node.js CI
name: Build

on:
push:
Expand All @@ -20,30 +19,27 @@ on:
- release-*
tags:
- v*
pull_request:
branches:
- master
- release-*

jobs:
build:
runs-on: ubuntu-latest
environment: production
env:
NODE_VER: 16.14.0
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

# Setup .npmrc file to publish to npm
# https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
- name: Use Node.js
uses: actions/setup-node@v2
- name: Configure .npmrc for NPM publish to @dapr
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VER }}
registry-url: 'https://registry.npmjs.org'

- name: Build Package
run: ./scripts/build.sh

# @TODO: add a depend on the test-e2e pipeline?
- name: Run unit tests
id: tests
run: npm run test:unit:all
Expand All @@ -54,9 +50,25 @@ jobs:
- name: Is Release?
if: startswith(github.ref, 'refs/tags/v')
run: echo "DEPLOY_PACKAGE=true" >> $GITHUB_ENV

- name: Publish to npm

# note: package.json gets updated here for the new package name
- name: Publish to npm (@dapr/dapr)
if: env.DEPLOY_PACKAGE == 'true'
run: npm run build && npm pack && npm publish build/ --access public
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: "[dapr-client] Configure to publish to dapr-client for deprecation notice reasons"
if: env.DEPLOY_PACKAGE == 'true'
run: sed -i s#"@dapr/dapr"#"dapr-client"# package.json

- name: "[dapr-client] Build Package"
if: env.DEPLOY_PACKAGE == 'true'
run: ./scripts/build.sh

# note: package.json gets updated here for the new package name
- name: "[dapr-client] Publish to npm (dapr-client)"
if: env.DEPLOY_PACKAGE == 'true'
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ spec:
**example.ts**
```javascript
import { DaprClient, DaprServer } from "dapr-client";
import { DaprClient, DaprServer } from "@dapr/dapr";

const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "50000"; // Dapr Sidecar Port
Expand Down
246 changes: 188 additions & 58 deletions daprdocs/content/en/js-sdk-docs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,198 @@ type: docs
title: "JavaScript SDK"
linkTitle: "JavaScript"
weight: 1000
description: JavaScript SDK packages for developing Dapr applications
no_list: true
description: How to get up and running with Actors using the Dapr JavaScript SDK
---

The Dapr JS SDK will allow you to interface with the Dapr process that abstracts several commonly used functionalities such as Service-to-Service invocation, State Management, PubSub, and more.
The Dapr actors package allows you to interact with Dapr virtual actors from a JavaScript application. The examples below demonstrate how to use the JavaScript SDK for interacting with virtual actors.

## Installation
For a more in-depth overview of Dapr actors, visit the [actors overview page]({{< ref actors-overview >}}).

To get started with the Javascript SDK, you can download the Dapr Javascript SDK package from [NPM](https://npmjs.org/package/dapr-client) by running the following:
## Pre-requisites
- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed
- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}})
- [Latest LTS version of Node or greater](https://nodejs.org/en/)
- [JavaScript NPM package installed](https://www.npmjs.com/package/@dapr/dapr)

```bash
npm install --save dapr-client
## Scenario
The below code examples loosely describe the scenario of a Parking Garage Spot Monitoring System, which can be seen in this [video](https://www.youtube.com/watch?v=eJCu6a-x9uo&t=3785) by Mark Russinovich.

A parking garage consists of hundreds of parking spaces, where each parking space includes a sensor that provides updates to a centralized monitoring system. The parking space sensors (our actors) detect if a parking space is occupied or available.

To jump in and run this example yourself, clone the source code, which can be found in the [JavaScript SDK examples directory](https://github.com/dapr/js-sdk/tree/master/examples/http/actor-parking-sensor).

## Actor Interface
The actor interface defines the contract that is shared between the actor implementation and the clients calling the actor. In the example below, we have created an interace for a parking garage sensor. Each sensor has 2 methods: `carEnter` and `carLeave`, which defines the state of the parking space:

```ts
export default interface ParkingSensorInterface {
carEnter(): Promise<void>;
carLeave(): Promise<void>;
}
```

## Actor Implementation
An actor implementation defines a class by extending the base type `AbstractActor` and implementing the actor interface (`ParkingSensorInterface` in this case).

The following code describes an actor implementation along with a few helper methods.

```ts
import { AbstractActor } from "@dapr/dapr";
import ParkingSensorInterface from "./ParkingSensorInterface";

export default class ParkingSensorImpl extends AbstractActor implements ParkingSensorInterface {
async carEnter(): Promise<void> {
// Implementation that updates state that this parking spaces is occupied.
}

async carLeave(): Promise<void> {
// Implementation that updates state that this parking spaces is available.
}

private async getInfo(): Promise<object> {
// Implementation of requesting an update from the parking space sensor.
}

/**
* @override
*/
async onActivate(): Promise<void> {
// Initialization logic called by AbstractActor.
}
}
```

## Registering Actors
Initialize and register your actors by using the `DaprServer` package:

```javascript
import { DaprServer } from "@dapr/dapr";
import ParkingSensorImpl from "./ParkingSensorImpl";

const daprHost = "127.0.0.1";
const daprPort = "50000";
const serverHost = "127.0.0.1";
const serverPort = "50001";

const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);

await server.actor.init(); // Let the server know we need actors
server.actor.registerActor(ParkingSensorImpl); // Register the actor
await server.start(); // Start the server

// To get the registered actors, you can invoke `getRegisteredActors`:
const resRegisteredActors = await server.actor.getRegisteredActors();
console.log(`Registered Actors: ${JSON.stringify(resRegisteredActors)}`);
```

## Invoking Actor Methods
After Actors are registered, create a Proxy object that implements `ParkingSensorInterface` using the `ActorProxyBuilder`. You can invoke the actor methods by directly calling methods on the Proxy object. Internally, it translates to making a network call to the Actor API and fetches the result back.

```javascript
import { DaprClient, ActorId } from "@dapr/dapr";
import ParkingSensorImpl from "./ParkingSensorImpl";
import ParkingSensorInterface from "./ParkingSensorInterface";

const daprHost = "127.0.0.1";
const daprPort = "50000";

const client = new DaprClient(daprHost, daprPort);

// Create a new actor builder. It can be used to create multiple actors of a type.
const builder = new ActorProxyBuilder<ParkingSensorInterface>(ParkingSensorImpl, client);

// Create a new actor instance.
const actor = builder.build(new ActorId("my-actor"));
// Or alternatively, use a random ID
// const actor = builder.build(ActorId.createRandomId());

// Invoke the method.
await actor.carEnter();
```

## Using states with Actor

```ts
// ...

const PARKING_SENSOR_PARKED_STATE_NAME = "parking-sensor-parked"

const actor = builder.build(new ActorId("my-actor"))

// SET state
await actor.getStateManager().setState(PARKING_SENSOR_PARKED_STATE_NAME, true);

// GET state
const value = await actor.getStateManager().getState(PARKING_SENSOR_PARKED_STATE_NAME);
if (!value) {
console.log(`Received: ${value}!`);
}

// DELETE state
await actor.removeState(PARKING_SENSOR_PARKED_STATE_NAME);
...
```

## Actor Timers and Reminders
The JS SDK supports actors that can schedule periodic work on themselves by registering either timers or reminders. The main difference between timers and reminders is that the Dapr actor runtime does not retain any information about timers after deactivation, but persists reminders information using the Dapr actor state provider.

This distinction allows users to trade off between light-weight but stateless timers versus more resource-demanding but stateful reminders.

The scheduling interface of timers and reminders is identical. For an more in-depth look at the scheduling configurations see the [actors timers and reminders docs]({{< ref "howto-actors.md#actor-timers-and-reminders" >}}).

### Actor Timers
```javascript
// ...

const actor = builder.build(new ActorId("my-actor"));

// Register a timer
await actor.registerActorTimer(
"timer-id", // Unique name of the timer.
"cb-method", // Callback method to execute when timer is fired.
Temporal.Duration.from({ seconds: 2 }), // DueTime
Temporal.Duration.from({ seconds: 1 }), // Period
Temporal.Duration.from({ seconds: 1 }), // TTL
50 // State to be sent to timer callback.
);

// Delete the timer
await actor.unregisterActorTimer("timer-id");
```

### Actor Reminders
```javascript
// ...

const actor = builder.build(new ActorId("my-actor"));

// Register a reminder, it has a default callback: `receiveReminder`
await actor.registerActorReminder(
"reminder-id", // Unique name of the reminder.
Temporal.Duration.from({ seconds: 2 }), // DueTime
Temporal.Duration.from({ seconds: 1 }), // Period
Temporal.Duration.from({ seconds: 1 }), // TTL
100 // State to be sent to reminder callback.
);

// Delete the reminder
await actor.unregisterActorReminder("reminder-id");
```

To handle the callback, you need to override the default `receiveReminder` implementation in your actor. For example, from our original actor implementation:
```ts
export default class ParkingSensorImpl extends AbstractActor implements ParkingSensorInterface {
// ...

/**
* @override
*/
async receiveReminder(state: any): Promise<void> {
// handle stuff here
}

// ...
}
```

## Structure

The Dapr Javascript SDK contains two major components:

* **DaprServer:** The Dapr Server manages all communication from the Dapr Sidecar to your application
* **DaprClient:** The Dapr Client manages all communication from your application to the Dapr Sidecar

The above communication can be configured to use either of the gRPC or HTTP protocols.

![Dapr Server](./js-server/dapr-server.jpg)
![Dapr Client](./js-client/dapr-client.jpg)

## Get Started

To help you get started, check out the resources below:

<div class="card-deck">
<div class="card">
<div class="card-body">
<h5 class="card-title"><b>Client</b></h5>
<p class="card-text">Create a JavaScript client and interact with a Dapr sidecar and other Dapr applications. (e.g., publishing events, output binding support, etc.)</p>
<a href="{{< ref js-client >}}" class="stretched-link"></a>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><b>Server</b></h5>
<p class="card-text">Create a JavaScript server and let the Dapr sidecar interact with your application. (e.g., subscribing to events, input binding support, etc.)</p>
<a href="{{< ref js-server >}}" class="stretched-link"></a>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><b>Actors</b></h5>
<p class="card-text">Create virtual actors with state, reminders/timers, and methods in JavaScript.</p>
<a href="{{< ref js-actors >}}" class="stretched-link"></a>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><b>Examples</b></h5>
<p class="card-text">Clone the JavaScript SDK repo and try out some of the examples and get started quickly.</p>
<a href="https://github.com/dapr/js-sdk/blob/master/documentation/examples.md" class="stretched-link"></a>
</div>
</div>
</div>

### Available packages
- [DaprClient]({{< ref "js-client#installing-and-importing-daprs-js-sdk" >}}) is a package that for how your application interacts with the Dapr sidecar, or other Dapr powered applications.

- [DaprServer]({{< ref "js-client#installing-and-importing-daprs-js-sdk" >}}) is a package for how the Dapr sidecar interacts with your application, forwarding event subscriptions, invokes and more.
For a full guide on actors, visit [How-To: Use virtual actors in Dapr]({{< ref howto-actors.md >}}).
8 changes: 4 additions & 4 deletions daprdocs/content/en/js-sdk-docs/js-actors/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ For a more in-depth overview of Dapr actors, visit the [actors overview page]({{
- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed
- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}})
- [Latest LTS version of Node or greater](https://nodejs.org/en/)
- [JavaScript NPM package installed](https://www.npmjs.com/package/dapr-client)
- [JavaScript NPM package installed](https://www.npmjs.com/package/@dapr/dapr)

## Scenario
The below code examples loosely describe the scenario of a Parking Garage Spot Monitoring System, which can be seen in this [video](https://www.youtube.com/watch?v=eJCu6a-x9uo&t=3785) by Mark Russinovich.
Expand All @@ -39,7 +39,7 @@ An actor implementation defines a class by extending the base type `AbstractActo
The following code describes an actor implementation along with a few helper methods.

```ts
import { AbstractActor } from "dapr-client";
import { AbstractActor } from "@dapr/dapr";
import ParkingSensorInterface from "./ParkingSensorInterface";

export default class ParkingSensorImpl extends AbstractActor implements ParkingSensorInterface {
Expand Down Expand Up @@ -68,7 +68,7 @@ export default class ParkingSensorImpl extends AbstractActor implements ParkingS
Initialize and register your actors by using the `DaprServer` package:

```javascript
import { DaprServer } from "dapr-client";
import { DaprServer } from "@dapr/dapr";
import ParkingSensorImpl from "./ParkingSensorImpl";

const daprHost = "127.0.0.1";
Expand All @@ -91,7 +91,7 @@ console.log(`Registered Actors: ${JSON.stringify(resRegisteredActors)}`);
After Actors are registered, create a Proxy object that implements `ParkingSensorInterface` using the `ActorProxyBuilder`. You can invoke the actor methods by directly calling methods on the Proxy object. Internally, it translates to making a network call to the Actor API and fetches the result back.

```javascript
import { DaprClient, ActorId } from "dapr-client";
import { DaprClient, ActorId } from "@dapr/dapr";
import ParkingSensorImpl from "./ParkingSensorImpl";
import ParkingSensorInterface from "./ParkingSensorInterface";

Expand Down
Loading

0 comments on commit e4f8245

Please sign in to comment.