Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/build/
/docs/
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"rules": {
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/strict-boolean-expressions": "warn",
"@typescript-eslint/no-non-null-assertion": "off",
"simple-import-sort/sort": "error"
}
}
14 changes: 14 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Push Server CRD API
## Overview
Clients can interact with the push server through a CRD API that allows for the creation, reading and deletion of `Task` documents.


## Routers
As a REST API, the following routers implement HTTP methods:

|Router Name| HTTP Method | Description |
|-----------| ----------- | ----------- |
|`getTaskRoute`| GET | Expect to get an array of `taskIds`. If the array is empty, it will get all tasks for the given `userId`. |
|`createTaskRoute`| POST | Construct a body and returns it as an HttpResponse. The body will include a payload that conforms to the `Task` type. It will write to the CouchDB database to create such task. |
|`deleteTaskRoute`| DELETE | Remove tasks from the database. If the `taskIds` array is empty, it will remove all tasks under the `userId`. |

Binary file added docs/assets/Action-Server.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/push-publisher-pseudocode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/push-publisher-views.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions docs/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Push Server Overview

## Introduction
The push server handles all the push notifications for end users.

The server itself consists of an API interface and a number of publishers/listeners. Below you can find documentation for the API inteface and specific publishers/listeners.

* [API](./api.md)
* [Push Publisher](./publishers/push-publisher.md)


## Architecture
The push server is constructed as a number of independent microservices:

<img src='assets/Action-Server.jpg'>

The core component of the server is the CouchDB database, with which publishers and listeners perform their operations based on the changes in the database.
42 changes: 42 additions & 0 deletions docs/publishers/push-publisher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Push Publisher
## Overview

The push publisher is responsible for pushing notifications to end users.

The new version of the push server is designed to accommodate the "action-queue" feature of the Edge app. Users will have the ability to configure an arbitrary number of transactional actions and to "chain" them all together with predefined sequences.

Some servers will then process these actions. The push publisher's job, then, is to handle push notifications once tasks are done.

## Architecture
The publisher directly interacts with a CouchDB database, named 'db_tasks'. However, for performance reasons, we create two "views" for the database. A view is simply an interface that displays a set of documents based on certain query conditions.

### Views

Since the push publisher only pushes notifications for completed tasks, it is best to have a view that shows all completed tasks, and another view to show all incompleted tasks.

<img src='../assets/push-publisher-views.png'>

`Task` is a data type modeled as below:
```js
taskId: string
userId: string
actionEffects: ActionEffect[]
action: Action
```

The `task_publishing` view contains all `Task`s that have every `ActionEffect` marked as completed. This is the view that the push publisher is listening for changes.

Similarly, the `task_listening` view contains `Task`s that have at least one incomplete `ActionEffect`.

## Publisher Logics
The push publisher gets a stream of `Task` documents from the `task_publishing` view. For each eligible document, the publisher pushes a notfication to devices.

<img src='../assets/push-publisher-pseudocode.png'>

Depending on the `Action` of each task, the publisher may delete a task document if the `Action`'s `repeat` flag is marked as false.

Otherwise, the publisher loops through the array of `ActionEffect`s, and set the `completed` flag to false for each one. Upon updating the document, the `task_listening` view will automatically pick up the `Task`, thereby allowing the `Task` to be processed repeatedly.

To prevent race conditions, the push publisher also manipulate the `inProgress` flag in the `Action` property.

The mutex implementaion coupled with the dual-view design abstractly reap the benefits of a message queue where each task can only be picked up by one service.
1 change: 1 addition & 0 deletions docs/references/.nojekyll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
36 changes: 36 additions & 0 deletions docs/references/assets/highlight.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
:root {
--light-hl-0: #000000;
--dark-hl-0: #D4D4D4;
--light-hl-1: #008000;
--dark-hl-1: #6A9955;
--light-code-background: #FFFFFF;
--dark-code-background: #1E1E1E;
}

@media (prefers-color-scheme: light) { :root {
--hl-0: var(--light-hl-0);
--hl-1: var(--light-hl-1);
--code-background: var(--light-code-background);
} }

@media (prefers-color-scheme: dark) { :root {
--hl-0: var(--dark-hl-0);
--hl-1: var(--dark-hl-1);
--code-background: var(--dark-code-background);
} }

:root[data-theme='light'] {
--hl-0: var(--light-hl-0);
--hl-1: var(--light-hl-1);
--code-background: var(--light-code-background);
}

:root[data-theme='dark'] {
--hl-0: var(--dark-hl-0);
--hl-1: var(--dark-hl-1);
--code-background: var(--dark-code-background);
}

.hl-0 { color: var(--hl-0); }
.hl-1 { color: var(--hl-1); }
pre, code { background: var(--code-background); }
54 changes: 54 additions & 0 deletions docs/references/assets/main.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/references/assets/search.js

Large diffs are not rendered by default.

Loading