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
18 changes: 18 additions & 0 deletions deltachat-jsonrpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ We also include a JavaScript and TypeScript client for the JSON-RPC API. The sou
The package includes a JavaScript/TypeScript client which is partially auto-generated through the JSON-RPC library used by this crate ([yerpc](https://github.com/chatmail/yerpc)). Find the source in the [`typescript`](typescript) folder.

To use it locally, first install the dependencies and compile the TypeScript code to JavaScript:

```sh
cd typescript
npm install
Expand All @@ -24,11 +25,28 @@ npm run build

The JavaScript client is [published on NPM](https://www.npmjs.com/package/@deltachat/jsonrpc-client).

###### Usage

```typescript
import { startDeltaChat } from "@deltachat/stdio-rpc-server";
import { C } from "@deltachat/jsonrpc-client";

const dc = await startDeltaChat("deltachat-data");
console.log(await dc.rpc.getSystemInfo());
const accounts = await dc.rpc.getAllAccounts();
console.log("accounts", accounts);
dc.close();
```

##### Generate TypeScript/JavaScript documentation

A script is included to build autogenerated documentation, which includes all RPC methods:

```sh
cd typescript
npm run docs
```

Then open the [`typescript/docs`](typescript/docs) folder in a web browser.

## Development
Expand Down
206 changes: 206 additions & 0 deletions deltachat-jsonrpc/typescript/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# @deltachat/jsonrpc-client

This package is a client for the jsonrpc server.

> If you are looking for the functions in the documentation, they are under [`RawClient`](https://js.jsonrpc.delta.chat/classes/RawClient.html).

### Important Terms

- [chat mail core (formerly delta chat core)](https://github.com/deltachat/deltachat-core-rust/) is heart of all Delta Chat clients. Handels all the heavy lifting (email, encryption, ...) and provides an easy api for bots and clients (`getChatlist`, `getChat`, `getContact`, ...).
- [jsonrpc](https://www.jsonrpc.org/specification) is a JSON based protocol
for applications to speak to each other by [remote procedure calls](https://en.wikipedia.org/wiki/Remote_procedure_call) (short RPC),
which basically means that the client can call methods on the server by sending a JSON messages.
- [`deltachat-rpc-server`](https://github.com/deltachat/deltachat-core-rust/tree/main/deltachat-rpc-server) provides the jsonrpc api over stdio (stdin/stdout)
- [`@deltachat/stdio-rpc-server`](https://www.npmjs.com/package/@deltachat/stdio-rpc-server) is an easy way to install `deltachat-rpc-server` from npm and use it from nodejs.

#### Transport

You need to connect this client to an instance of chatmail-core via a transport.

For this you can use the `StdioTransport`, which you can use by importing `StdioDeltaChat`.

You can also make your own transport, for example deltachat desktop uses a custom transport that sends the json messages over electron ipc.
Just implement your transport based on the `Transport` interface - look at how the [stdio transport is implemented](https://github.com/deltachat/deltachat-core-rust/blob/7121675d226e69fd85d0194d4b9c4442e4dd8299/deltachat-jsonrpc/typescript/src/client.ts#L113) for an example, it's not hard.

The other transports that exist (but note that those are not standalone, they list here only serves as reference on how to implement those.):

- Electron IPC (from Delta Chat Desktop)
- [transport](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-electron/runtime-electron/runtime.ts#L49-L123), [request handling](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-electron/src/deltachat/controller.ts#L199-L201), [responses](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-electron/src/deltachat/controller.ts#L93-L113)
- Tauri IPC (from DC Desktop Tauri edition)
- [transport](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-tauri/runtime-tauri/runtime.ts#L86-L118), backend: [request handling](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-tauri/src-tauri/src/lib.rs#L85-L94), [responses](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-tauri/src-tauri/src/state/deltachat.rs#L43-L95)
- Authenticated Websocket (from DC Desktop Browser edition)
- [transport](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-browser/runtime-browser/runtime.ts#L37-L80), backend: [authentication](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-browser/src/index.ts#L258-L275), [web socket server](https://github.com/deltachat/deltachat-desktop/blob/0a4fdb2065c7b14fa097769181afd05e3f552f54/packages/target-browser/src/deltachat-rpc.ts#L93) (this also contains some unrelated code, it's easier than it looks at first glance)

## Usage

> The **minimum** nodejs version for `@deltachat/stdio-rpc-server` is `16`

```
npm i @deltachat/stdio-rpc-server @deltachat/jsonrpc-client
```

```js
import { startDeltaChat } from "@deltachat/stdio-rpc-server";
// Import constants you might need later
import { C } from "@deltachat/jsonrpc-client";

async function main() {
const dc = await startDeltaChat("deltachat-data");
console.log(await dc.rpc.getSystemInfo());
dc.close();
}
main();
```

For a more complete example refer to <https://github.com/deltachat-bot/echo/tree/master/nodejs_stdio_jsonrpc>.

### Listening for events

```ts
dc.on("Info", (accountId, { msg }) =>
console.info(accountId, "[core:info]", msg),
);
// Or get an event emitter for only one account
const emitter = dc.getContextEvents(accountId);
emitter.on("IncomingMsg", async ({ chatId, msgId }) => {
const message = await dc.rpc.getMessage(accountId, msgId);
console.log("got message in chat " + chatId + " : ", message.text);
});
```

### Getting Started

This section describes how to handle the Delta Chat core library over the jsonrpc bindings.
For general information about Delta Chat itself,
see <https://delta.chat> and <https://github.com/deltachat>.

Let's start.

First of all, you have to start the deltachat-rpc-server process.

```js
import { startDeltaChat } from "@deltachat/stdio-rpc-server";
const dc = await startDeltaChat("deltachat-data");
```

Then we have to create an Account (also called Context or profile) that is bound to a database.
The database is a normal SQLite file with a "blob directory" beside it.
But these details are handled by deltachat's account manager.
So you just have to tell the account manager to create a new account:

```js
const accountId = await dc.rpc.addAccount();
```

After that, register event listeners so you can see what core is doing:
Intenally `@deltachat/jsonrpc-client` implments a loop that waits for new events and then emits them to javascript land.

```js
dc.on("Info", (accountId, { msg }) =>
console.info(accountId, "[core:info]", msg),
);
```

Now you can **configure the account:**

```js
// use some real test credentials here
await dc.rpc.setConfig(accountId, "addr", "alice@example.org");
await dc.rpc.setConfig(accountId, "mail_pw", "***");
// you can also set multiple config options in one call
await dc.rpc.batchSetConfig(accountId, {
addr: "alice@example.org",
mail_pw: "***",
});

// after setting the credentials attempt to login
await dc.rpc.configure(accountId);
```

`configure()` returns a promise that is rejected on error (with await is is thrown).
The configuration itself may take a while. You can monitor it's progress like this:

```js
dc.on("ConfigureProgress", (accountId, { progress, comment }) => {
console.log(accountId, "ConfigureProgress", progress, comment);
});
// make sure to register this event handler before calling `dc.rpc.configure()`
```

The configuration result is saved in the database.
On subsequent starts it is not needed to call `dc.rpc.configure(accountId)`
(you can check this using `dc.rpc.isConfigured(accountId)`).

On a successfully configuration delta chat core automatically connects to the server, however subsequent starts you **need to do that manually** by calling `dc.rpc.startIo(accountId)` or `dc.rpc.startIoForAllAccounts()`.

```js
if (!(await dc.rpc.isConfigured(accountId))) {
// use some real test credentials here
await dc.rpc.batchSetConfig(accountId, {
addr: "alice@example.org",
mail_pw: "***",
});
await dc.rpc.configure(accountId);
} else {
await dc.rpc.startIo(accountId);
}
```

Now you can **send the first message:**

```js
const contactId = await dc.rpc.createContact(
accountId,
"bob@example.org",
null /* optional name */,
);
const chatId = await dc.rpc.createChatByContactId(accountId, contactId);

await dc.rpc.miscSendTextMessage(
accountId,
chatId,
"Hi, here is my first message!",
);
```

`dc.rpc.miscSendTextMessage()` returns immediately;
the sending itself is done in the background.
If you check the testing address (bob),
you should receive a normal e-mail.
Answer this e-mail in any e-mail program with "Got it!",
and the IO you started above will **receive the message**.

You can then **list all messages** of a chat as follows:

```js
let i = 0;
for (const msgId of await exp.rpc.getMessageIds(120, 12, false, false)) {
i++;
console.log(`Message: ${i}`, (await dc.rpc.getMessage(120, msgId)).text);
}
```

This will output the following two lines:

```
Message 1: Hi, here is my first message!
Message 2: Got it!
```

<!-- TODO: ### Clean shutdown? - seems to be more advanced to call async functions on exit, also is this needed in this usecase? -->

## Further information

- `@deltachat/stdio-rpc-server`
- [package on npm](https://www.npmjs.com/package/@deltachat/stdio-rpc-server)
- [source code on github](https://github.com/deltachat/deltachat-core-rust/tree/main/deltachat-rpc-server/npm-package)
- [use `@deltachat/stdio-rpc-server` on an usuported platform](https://github.com/deltachat/deltachat-core-rust/tree/main/deltachat-rpc-server/npm-package#how-to-use-on-an-unsupported-platform)
- The issue-tracker for the core library is here: <https://github.com/deltachat/deltachat-core-rust/issues>

If you need further assistance,
please do not hesitate to contact us
through the channels shown at https://delta.chat/en/contribute

Please keep in mind, that your derived work
must respect the Mozilla Public License 2.0 of deltachat-rpc-server
and the respective licenses of the libraries deltachat-rpc-server links with.
4 changes: 2 additions & 2 deletions deltachat-jsonrpc/typescript/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { RawClient } from "../generated/client.js";
import { BaseTransport, Request } from "yerpc";
import { TinyEmitter } from "@deltachat/tiny-emitter";

type Events = { ALL: (accountId: number, event: EventType) => void } & {
export type Events = { ALL: (accountId: number, event: EventType) => void } & {
[Property in EventType["kind"]]: (
accountId: number,
event: Extract<EventType, { kind: Property }>,
) => void;
};

type ContextEvents = { ALL: (event: EventType) => void } & {
export type ContextEvents = { ALL: (event: EventType) => void } & {
[Property in EventType["kind"]]: (
event: Extract<EventType, { kind: Property }>,
) => void;
Expand Down
45 changes: 37 additions & 8 deletions deltachat-rpc-server/npm-package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ it does not use NAPI bindings but instead uses stdio executables
to let you talk to core over jsonrpc over stdio.
This simplifies cross-compilation and even reduces binary size (no CFFI layer and no NAPI layer).

📚 Docs: <https://js.jsonrpc.delta.chat/>

## Usage

> The **minimum** nodejs version for this package is `16`
Expand All @@ -18,20 +20,47 @@ import { startDeltaChat } from "@deltachat/stdio-rpc-server";
import { C } from "@deltachat/jsonrpc-client";

async function main() {
const dc = await startDeltaChat("deltachat-data");
console.log(await dc.rpc.getSystemInfo());
dc.close()
const dc = await startDeltaChat("deltachat-data");
console.log(await dc.rpc.getSystemInfo());
dc.close();
}
main()
main();
```

For a more complete example refer to https://github.com/deltachat-bot/echo/pull/69/files (TODO change link when pr is merged).
For a more complete example refer to <https://github.com/deltachat-bot/echo/tree/master/nodejs_stdio_jsonrpc>.

## How to use on an unsupported platform

<!-- todo instructions, will uses an env var for pointing to `deltachat-rpc-server` binary -->
You need to have rust installed to compile deltachat core for your platform and cpu architecture.
<https://rustup.rs/> is the recommended way to install rust.
Also your system probably needs more than 4GB RAM to compile core, alternatively your could try to build the debug build, which might take less RAM to build.

1. clone the core repo, right next to your project folder: `git clone git@github.com:deltachat/deltachat-core-rust.git`
2. go into your core checkout and run `git pull` and `git checkout <version>` to point it to the correct version (needs to be the same version the `@deltachat/jsonrpc-client` package has)
3. run `cargo build --release --package deltachat-rpc-server --bin deltachat-rpc-server`

Then you have 2 options:

### point to deltachat-rpc-server via direct path:

```sh
# start your app with the DELTA_CHAT_RPC_SERVER env var
DELTA_CHAT_RPC_SERVER="../deltachat-core-rust/target/release/deltachat-rpc-server" node myapp.js
```

<!-- todo copy parts from https://github.com/deltachat/deltachat-desktop/blob/7045c6f549e4b9d5caa0709d5bd314bbd9fd53db/docs/UPDATE_CORE.md -->
### install deltachat-rpc-server in your $PATH:

```sh
# use this to install to ~/.cargo/bin
cargo install --release --package deltachat-rpc-server --bin deltachat-rpc-server
# or manually move deltachat-core-rust/target/release/deltachat-rpc-server
# to a location that is included in your $PATH Environment variable.
```

And make sure to enable the `takeVersionFromPATH` option:
```js
startDeltaChat("data-dir", { takeVersionFromPATH: true });
```

## How does it work when you install it

Expand All @@ -46,7 +75,7 @@ references:
When you import this package it searches for the rpc server in the following locations and order:

1. `DELTA_CHAT_RPC_SERVER` environment variable
2. use the PATH when `{takeVersionFromPATH: true}` is supplied in the options.
2. use the PATH when `{takeVersionFromPATH: true}` is supplied in the options.
3. prebuilds in npm packages

so by default it uses the prebuilds.
Expand Down