In this tutorial, you will create an application with ZetaPush, from the initialization to the deployment. You will learn to:

  • Add business logic with ZetaPush

  • Use cloud services provided by ZetaPush

  • Run your code locally

  • Deploy your application

Use case

You will create a realtime chat application, but it will be particular: This will be an Avengers Chat !

At the beginning, the user of the chat can choose an Avenger. Each character has many skills and they can use them on the chat to attack the others Avengers.

Table 1. List of skills by Avenger
Avenger Skill

Captain America

Shoot of shield / Cure

Falcon

Archery / Super vision

Iron Man

Flight / Missile launcher

Hulk

Punch / Regeneration

Thor

Hammer hit / Lightning strike

Spider Man

Shoot of cobweb / Jump with cobweb

Wolverine

Scratch / Regeneration

You will create this application in few steps:

We recommend to use TypeScript so in this tutorial all of your code will be in this language.

Initialize your application

In the first step, you need to create your application. To do this you can run:

1
npm init @zetapush myApp

This command will ask you your developer login and password.

This command will create you an account on the ZetaPush platform and will create your first application in the myApp directory. An email will be sent to confirm your account.

To use your application, you need to validate your account. To do this, click on the link in the received email

In this tutorial, we are focusing on the ZetaPush development. So, to begin, get all resources and add them to your application (css, assets, …​):

1
2
3
4
$ cd myApp/front/
$ rm -r ./*
$ curl -X GET 'http://github-download-subfolder.zpush.io/?owner=zetapush&repository=zetapush-tutorials&path=avengersChat/front' --output front.zip
$ unzip front.zip && rm front.zip
If you are using Windows, you can download the file with all resources and unzip it in the front directory. Link: http://github-download-subfolder.zpush.io/?owner=zetapush&repository=zetapush-tutorials&path=avengersChat/front

So you already have the style and the frontend logic in the folders assets and utils. You can browse these files to understand this code.

In this tutorial, you need to:

  1. Create the business logic with a custom cloud service

  2. Implement the interaction with the custom cloud service (front side)

  3. Deploy your application

Create your business logic

Now, you will create the business logic of your application. To do this, you will use a custom cloud service.

A custom cloud service is a class where you develop a business logic. You can create several custom cloud services inside one application. Each custom cloud service can use the cloud services provided by ZetaPush.

In your existing application you already have a custom cloud service on the file worker/index.ts (The entry point of the service is defined in the package.json with the property main).

To use your custom cloud services you need to export them. To do this, the property main in your package.json define the path of the file where you export all of your custom cloud services.

You can delete the content of the file worker/index.ts and fill it with the following content step by step.

Import cloud services and define constants

First, you need to import the cloud services provided by ZetaPush, used in this application:

  • Stack (Save data in a stack)

  • Messaging (Send and receive messages)

  • Groups (Manage group of users)

You also need to import Injectable that is useful for the dependencies injection.

Imports and constants
1
2
3
4
5
import { Injectable } from '@zetapush/core';
import { Stack, Messaging, Groups } from '@zetapush/platform-legacy';

const CONVERSATION_ID = 'avengersChat';
const CHANNEL_MESSAGING = 'avengersChannel'; (1)
1 Channel on which the users send and listen to the messages

Create the class with its constructor

A custom cloud service is a class, so you need to create it.

Class and constructor
1
2
3
4
5
6
7
8
9
10
11
12
@Injectable() (1)
export default class AvengersApi {
  /**
   * Constructor of our API
   */
  constructor(
    private stack: Stack,
    private messaging: Messaging,
    private groups: Groups
  ) {
  }
}
1 We expose our custom cloud service with only one annotation
The dependencies injection of ZetaPush use injection-js.

Create the chat

To create our chat, we use the Groups cloud service provided by ZetaPush. The created group includes all users of the conversation. So we add a method to our class to create this conversation.

Create conversation
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Create the conversation of the chat, if doesn't already exists
 */
async createConversation() {
  const { exists } = await this.groups.exists({
    group: CONVERSATION_ID
  });
  if (!exists) {
    await this.groups.createGroup({
      group: CONVERSATION_ID
    });
  }
}

Add user to the conversation

When an user comes to the chat, we need to add it to the conversation. So we create a method in our class to add the current user to the conversation.

1
2
3
4
5
6
7
8
9
/**
* Add the current user to the conversation
*/
addMeToConversation(parameters: any, context: any) { (1)
  return this.groups.addUser({
    group: CONVERSATION_ID,
      user: context.owner (2)
  });
}
1 Each custom cloud function takes only one (client-provided) parameter. The second is the context, injected by the SDK
2 We get the caller (owner) of the cloud function from the context.

Send a message

No we want to send a message on our chat. To do this, we need to follow 3 steps:

  1. Get all users in the conversation

  2. Send the message of all users in the conversation

  3. Store the message in a stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Send a message on the chat
* @param {Object} message
*/
async sendMessage(message = {}) {
  // Get all users inside the conversation
  const group = await this.groups.groupUsers({
    group: CONVERSATION_ID
  });
  const users = group.users || [];

  // Send the message to each user in the conversation
  this.messaging.send({
    target: users,
    channel: CHANNEL_MESSAGING,
    data: { message }
  });

  // Store the message in a stack
  await this.stack.push({
    stack: CONVERSATION_ID,
    data: message
  });

  return group;
}
There is no specific method to launch an attack, to do this, we only send a specific message throught sendMessage.

Get all messages

To complete our business logic, we need to have an other method in our class to get all messages (when we enter the chat).

1
2
3
4
5
6
7
8
9
/**
* Get all messages in the conversation
*/
async getMessages() {
  const { result } = await this.stack.list({
    stack: CONVERSATION_ID
  });
  return result;
}

Now your custom cloud service is ready with this following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { Injectable } from '@zetapush/core';
import { Stack, Messaging, Groups } from "@zetapush/platform-legacy";

const CONVERSATION_ID = "avengersChat";
const CHANNEL_MESSAGING = "avengersChannel";

@Injectable()
export default class AvengersApi {
  /**
   * Constructor of our API
   */
  constructor(
    private stack: Stack,
    private messaging: Messaging,
    private groups: Groups
  ) {}

  /**
   * Create the conversation of the chat, if doesn't already exists
   */
  async createConversation() {
    const { exists } = await this.groups.exists({
      group: CONVERSATION_ID
    });
    if (!exists) {
      await this.groups.createGroup({
        group: CONVERSATION_ID
      });
    }
  }

  /**
   * Add the current user in the conversation
   */
  addMeToConversation(parameters: any, context: any) {
    return this.groups.addUser({
      group: CONVERSATION_ID,
      user: context.owner
    });
  }

  /**
   * Send a message on the chat
   * @param {Object} message
   */
  async sendMessage(message = {}) {
    // Get all users inside the conversation
    const group = await this.groups.groupUsers({
      group: CONVERSATION_ID
    });
    const users = group.users || [];

    // Send the message to each user in the conversation
    this.messaging.send({
      target: users,
      channel: CHANNEL_MESSAGING,
      data: { message }
    });

    // Store the message in a stack
    await this.stack.push({
      stack: CONVERSATION_ID,
      data: message
    });

    return group;
  }

  /**
   * Get all messages in the conversation
   */
  async getMessages() {
    const { result } = await this.stack.list({
      stack: CONVERSATION_ID
    });
    return result;
  }
}

Use your custom cloud services

Once we have our custom cloud service, we need to create the frontend of our application.

Launch the worker locally

When we work on the frontend part, we often want to test our interaction with the backend logic. With ZetaPush, you can launch your worker locally to test this interaction. To do this you need to use the CLI and run: zeta run. But in this project, the CLI is imported and a script is created with npm, so you just need to launch:

Run worker locally
// In the root of the application
$ npm run start -- --serve-front
If you want to install the ZetaPush CLI you can run npm install -g @zetapush/cli.

Then you have access to your application on http://localhost:3000.

Interaction with worker

Now you just need to add the interaction with the custom cloud service. To do this, fill the file front/index.js:

Interaction with worker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import AvengersController from './utils/controller.js'; (1)

// Create the ZetaPush Client
const client = new ZetaPushClient.WeakClient();
/**
 * Create service to listen incoming messages
 */
const service = client.createService({
  Type: ZetaPushPlatform.Messaging,
  listener: {
    // Listen incoming messages from the channel 'avengersChannel'
    avengersChannel: ({ data }) => controller.onAvengersMessage(data), (2)
  },
});

const controller = new AvengersController(client);

(async function main() {
  // Expose to template
  window.$controller = controller;
  // Connect to ZetaPush
  await client.connect();
  // Notify client connected
  controller.onConnectionEstablished();
})();
1 Import the frontend logic (in the controller)
2 Cloud service provided by ZetaPush to listen to incoming messages

Deploy your application

Your application is working but only locally. To deploy your application you just need to launch zeta push. In this application you already have a npm script so you can run:

Deploy the application
$ npm run deploy

This command deploys all in once (Front and Worker). It will return you an unique URL to access to your application.

Enjoy ! Your Avengers Chat is working and deployed !