simplex-chat 7.1.0-beta.2 → 7.1.0-beta.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/binding.gyp +2 -0
- package/cpp/simplex.cc +265 -29
- package/cpp/simplex.h +2 -0
- package/dist/api.d.ts +9 -6
- package/dist/api.js +37 -19
- package/dist/api.js.map +1 -1
- package/dist/bot.d.ts +6 -2
- package/dist/bot.js +17 -34
- package/dist/bot.js.map +1 -1
- package/dist/core.d.ts +11 -7
- package/dist/core.js +5 -2
- package/dist/core.js.map +1 -1
- package/dist/simplex.d.ts +3 -2
- package/dist/util.js +1 -1
- package/dist/util.js.map +1 -1
- package/docs/Namespace.bot.md +1 -0
- package/docs/api.Class.ChatApi.md +122 -78
- package/docs/api.TypeAlias.EventSubscriberFunc.md +5 -1
- package/docs/bot.Function.run.md +1 -1
- package/docs/bot.Function.subscribeChatItems.md +27 -0
- package/docs/bot.Interface.BotConfig.md +13 -9
- package/docs/bot.Interface.BotOptions.md +10 -10
- package/docs/bot.TypeAlias.BotDbOpts.md +4 -0
- package/docs/core.Class.ChatAPIError.md +4 -4
- package/docs/core.Class.ChatInitError.md +4 -4
- package/docs/core.DBMigrationError.Interface.ErrorMigration.md +4 -4
- package/docs/core.DBMigrationError.Interface.ErrorNotADatabase.md +3 -3
- package/docs/core.DBMigrationError.Interface.ErrorSQL.md +4 -4
- package/docs/core.DBMigrationError.Interface.InvalidConfirmation.md +2 -2
- package/docs/core.DBMigrationError.Interface.InvalidQueueSize.md +25 -0
- package/docs/core.DBMigrationError.TypeAlias.Tag.md +2 -2
- package/docs/core.Enumeration.MigrationConfirmation.md +5 -5
- package/docs/core.Function.chatCloseStore.md +1 -1
- package/docs/core.Function.chatDecryptFile.md +1 -1
- package/docs/core.Function.chatEncryptFile.md +1 -1
- package/docs/core.Function.chatMigrateInit.md +8 -2
- package/docs/core.Function.chatReadFile.md +3 -3
- package/docs/core.Function.chatRecvMsgWait.md +1 -1
- package/docs/core.Function.chatSendCmd.md +1 -1
- package/docs/core.Function.chatWriteFile.md +2 -2
- package/docs/core.Interface.APIResult.md +3 -3
- package/docs/core.Interface.CryptoArgs.md +3 -3
- package/docs/core.Interface.UpMigration.md +3 -3
- package/docs/core.MTRError.Interface.MTREDifferent.md +3 -3
- package/docs/core.MTRError.Interface.MTRENoDown.md +10 -10
- package/docs/core.MTRError.TypeAlias.Tag.md +1 -1
- package/docs/core.MigrationError.Interface.MEDowngrade.md +3 -3
- package/docs/core.MigrationError.Interface.MEUpgrade.md +4 -4
- package/docs/core.MigrationError.Interface.MigrationError.md +3 -3
- package/docs/core.MigrationError.TypeAlias.Tag.md +1 -1
- package/docs/core.Namespace.DBMigrationError.md +1 -0
- package/docs/core.TypeAlias.DBMigrationError.md +2 -2
- package/docs/core.TypeAlias.MTRError.md +1 -1
- package/docs/core.TypeAlias.MigrationError.md +1 -1
- package/examples/squaring-bot-readme.js +2 -2
- package/examples/squaring-bot.ts +4 -4
- package/package.json +2 -2
- package/src/api.ts +54 -25
- package/src/bot.ts +43 -37
- package/src/core.ts +15 -7
- package/src/download-libs.js +28 -1
- package/src/simplex.d.ts +3 -2
- package/src/util.ts +3 -3
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: MTREDifferent
|
|
8
8
|
|
|
9
|
-
Defined in: [src/core.ts:
|
|
9
|
+
Defined in: [src/core.ts:214](../src/core.ts#L214)
|
|
10
10
|
|
|
11
11
|
## Extends
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:206](../src/core.ts#L206)
|
|
|
18
18
|
|
|
19
19
|
> **downMigrations**: `string`[]
|
|
20
20
|
|
|
21
|
-
Defined in: [src/core.ts:
|
|
21
|
+
Defined in: [src/core.ts:216](../src/core.ts#L216)
|
|
22
22
|
|
|
23
23
|
***
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ Defined in: [src/core.ts:208](../src/core.ts#L208)
|
|
|
26
26
|
|
|
27
27
|
> **type**: `"different"`
|
|
28
28
|
|
|
29
|
-
Defined in: [src/core.ts:
|
|
29
|
+
Defined in: [src/core.ts:215](../src/core.ts#L215)
|
|
30
30
|
|
|
31
31
|
#### Overrides
|
|
32
32
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: MTRENoDown
|
|
8
8
|
|
|
9
|
-
Defined in: [src/core.ts:
|
|
9
|
+
Defined in: [src/core.ts:209](../src/core.ts#L209)
|
|
10
10
|
|
|
11
11
|
## Extends
|
|
12
12
|
|
|
@@ -14,20 +14,20 @@ Defined in: [src/core.ts:201](../src/core.ts#L201)
|
|
|
14
14
|
|
|
15
15
|
## Properties
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### dbMigrations
|
|
18
18
|
|
|
19
|
-
> **
|
|
19
|
+
> **dbMigrations**: `string`[]
|
|
20
20
|
|
|
21
|
-
Defined in: [src/core.ts:
|
|
21
|
+
Defined in: [src/core.ts:211](../src/core.ts#L211)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
***
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### type
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
> **type**: `"noDown"`
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Defined in: [src/core.ts:210](../src/core.ts#L210)
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
#### Overrides
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
`Interface.type`
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: MEDowngrade
|
|
8
8
|
|
|
9
|
-
Defined in: [src/core.ts:
|
|
9
|
+
Defined in: [src/core.ts:182](../src/core.ts#L182)
|
|
10
10
|
|
|
11
11
|
## Extends
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:174](../src/core.ts#L174)
|
|
|
18
18
|
|
|
19
19
|
> **downMigrations**: `string`[]
|
|
20
20
|
|
|
21
|
-
Defined in: [src/core.ts:
|
|
21
|
+
Defined in: [src/core.ts:184](../src/core.ts#L184)
|
|
22
22
|
|
|
23
23
|
***
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ Defined in: [src/core.ts:176](../src/core.ts#L176)
|
|
|
26
26
|
|
|
27
27
|
> **type**: `"downgrade"`
|
|
28
28
|
|
|
29
|
-
Defined in: [src/core.ts:
|
|
29
|
+
Defined in: [src/core.ts:183](../src/core.ts#L183)
|
|
30
30
|
|
|
31
31
|
#### Overrides
|
|
32
32
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: MEUpgrade
|
|
8
8
|
|
|
9
|
-
Defined in: [src/core.ts:
|
|
9
|
+
Defined in: [src/core.ts:177](../src/core.ts#L177)
|
|
10
10
|
|
|
11
11
|
## Extends
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:169](../src/core.ts#L169)
|
|
|
18
18
|
|
|
19
19
|
> **type**: `"upgrade"`
|
|
20
20
|
|
|
21
|
-
Defined in: [src/core.ts:
|
|
21
|
+
Defined in: [src/core.ts:178](../src/core.ts#L178)
|
|
22
22
|
|
|
23
23
|
#### Overrides
|
|
24
24
|
|
|
@@ -28,6 +28,6 @@ Defined in: [src/core.ts:170](../src/core.ts#L170)
|
|
|
28
28
|
|
|
29
29
|
### upMigrations
|
|
30
30
|
|
|
31
|
-
> **upMigrations**: [`UpMigration`](core.Interface.UpMigration.md)
|
|
31
|
+
> **upMigrations**: [`UpMigration`](core.Interface.UpMigration.md)[]
|
|
32
32
|
|
|
33
|
-
Defined in: [src/core.ts:
|
|
33
|
+
Defined in: [src/core.ts:179](../src/core.ts#L179)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: MigrationError
|
|
8
8
|
|
|
9
|
-
Defined in: [src/core.ts:
|
|
9
|
+
Defined in: [src/core.ts:187](../src/core.ts#L187)
|
|
10
10
|
|
|
11
11
|
## Extends
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:179](../src/core.ts#L179)
|
|
|
18
18
|
|
|
19
19
|
> **mtrError**: [`MTRError`](core.TypeAlias.MTRError.md)
|
|
20
20
|
|
|
21
|
-
Defined in: [src/core.ts:
|
|
21
|
+
Defined in: [src/core.ts:189](../src/core.ts#L189)
|
|
22
22
|
|
|
23
23
|
***
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ Defined in: [src/core.ts:181](../src/core.ts#L181)
|
|
|
26
26
|
|
|
27
27
|
> **type**: `"migrationError"`
|
|
28
28
|
|
|
29
|
-
Defined in: [src/core.ts:
|
|
29
|
+
Defined in: [src/core.ts:188](../src/core.ts#L188)
|
|
30
30
|
|
|
31
31
|
#### Overrides
|
|
32
32
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
- [ErrorNotADatabase](core.DBMigrationError.Interface.ErrorNotADatabase.md)
|
|
13
13
|
- [ErrorSQL](core.DBMigrationError.Interface.ErrorSQL.md)
|
|
14
14
|
- [InvalidConfirmation](core.DBMigrationError.Interface.InvalidConfirmation.md)
|
|
15
|
+
- [InvalidQueueSize](core.DBMigrationError.Interface.InvalidQueueSize.md)
|
|
15
16
|
|
|
16
17
|
## Type Aliases
|
|
17
18
|
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
# Type Alias: DBMigrationError
|
|
8
8
|
|
|
9
|
-
> **DBMigrationError** = [`InvalidConfirmation`](core.DBMigrationError.Interface.InvalidConfirmation.md) \| [`ErrorNotADatabase`](core.DBMigrationError.Interface.ErrorNotADatabase.md) \| [`ErrorMigration`](core.DBMigrationError.Interface.ErrorMigration.md) \| [`ErrorSQL`](core.DBMigrationError.Interface.ErrorSQL.md)
|
|
9
|
+
> **DBMigrationError** = [`InvalidConfirmation`](core.DBMigrationError.Interface.InvalidConfirmation.md) \| [`InvalidQueueSize`](core.DBMigrationError.Interface.InvalidQueueSize.md) \| [`ErrorNotADatabase`](core.DBMigrationError.Interface.ErrorNotADatabase.md) \| [`ErrorMigration`](core.DBMigrationError.Interface.ErrorMigration.md) \| [`ErrorSQL`](core.DBMigrationError.Interface.ErrorSQL.md)
|
|
10
10
|
|
|
11
|
-
Defined in: [src/core.ts:
|
|
11
|
+
Defined in: [src/core.ts:125](../src/core.ts#L125)
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
|
|
9
9
|
> **MigrationError** = [`MEUpgrade`](core.MigrationError.Interface.MEUpgrade.md) \| [`MEDowngrade`](core.MigrationError.Interface.MEDowngrade.md) \| [`MigrationError`](core.MigrationError.Interface.MigrationError.md)
|
|
10
10
|
|
|
11
|
-
Defined in: [src/core.ts:
|
|
11
|
+
Defined in: [src/core.ts:165](../src/core.ts#L165)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
(async () => {
|
|
2
2
|
const {bot} = await import("../dist/index.js")
|
|
3
|
-
|
|
3
|
+
await bot.run({
|
|
4
4
|
profile: {displayName: "Squaring bot example", fullName: ""},
|
|
5
5
|
dbOpts: {type: "sqlite", filePrefix: "./squaring_bot"},
|
|
6
6
|
options: {
|
|
7
7
|
addressSettings: {welcomeMessage: "Send a number, I will square it."},
|
|
8
8
|
},
|
|
9
|
-
onMessage: async (ci, content) => {
|
|
9
|
+
onMessage: async (ci, content, chat) => {
|
|
10
10
|
const n = +content.text
|
|
11
11
|
const reply = typeof n === "number" && !isNaN(n)
|
|
12
12
|
? `${n} * ${n} = ${n * n}`
|
package/examples/squaring-bot.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {bot, util} from "../dist"
|
|
|
3
3
|
|
|
4
4
|
(async () => {
|
|
5
5
|
const welcomeMessage = "Hello! I am a simple squaring bot.\n\nIf you send me a number, I will calculate its square."
|
|
6
|
-
|
|
6
|
+
await bot.run({
|
|
7
7
|
profile: {displayName: "Squaring bot example", fullName: ""},
|
|
8
8
|
dbOpts: {type: "sqlite", filePrefix: "./squaring_bot"},
|
|
9
9
|
options: {
|
|
@@ -15,7 +15,7 @@ import {bot, util} from "../dist"
|
|
|
15
15
|
logContacts: true,
|
|
16
16
|
logNetwork: false
|
|
17
17
|
},
|
|
18
|
-
onMessage: async (ci, content) => {
|
|
18
|
+
onMessage: async (ci, content, chat) => {
|
|
19
19
|
const n = +content.text
|
|
20
20
|
const reply = typeof n === "number" && !isNaN(n)
|
|
21
21
|
? `${n} * ${n} = ${n * n}`
|
|
@@ -23,11 +23,11 @@ import {bot, util} from "../dist"
|
|
|
23
23
|
await chat.apiSendTextReply(ci, reply)
|
|
24
24
|
},
|
|
25
25
|
onCommands: { // command handlers can be different from commands to be shown in client UI
|
|
26
|
-
"help": async (ci: T.AChatItem, _cmd: util.BotCommand) => {
|
|
26
|
+
"help": async (ci: T.AChatItem, _cmd: util.BotCommand, chat) => {
|
|
27
27
|
await chat.apiSendTextMessage(ci.chatInfo, welcomeMessage)
|
|
28
28
|
},
|
|
29
29
|
// fallback handler that will be called for all other commands
|
|
30
|
-
"": async (ci: T.AChatItem, _cmd: util.BotCommand) => {
|
|
30
|
+
"": async (ci: T.AChatItem, _cmd: util.BotCommand, chat) => {
|
|
31
31
|
await chat.apiSendTextReply(ci, "This command is not supported")
|
|
32
32
|
}
|
|
33
33
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simplex-chat",
|
|
3
|
-
"version": "7.1.0-beta.2",
|
|
3
|
+
"version": "7.1.0-beta.4.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"docs": "typedoc"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@simplex-chat/types": "^0.11.
|
|
27
|
+
"@simplex-chat/types": "^0.11.4",
|
|
28
28
|
"extract-zip": "^2.0.1",
|
|
29
29
|
"fast-deep-equal": "^3.1.3",
|
|
30
30
|
"node-addon-api": "^8.5.0"
|
package/src/api.ts
CHANGED
|
@@ -47,7 +47,7 @@ export const defaultBotAddressSettings: BotAddressSettings = {
|
|
|
47
47
|
businessAddress: false
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export type EventSubscriberFunc<K extends CEvt.Tag> = (event: ChatEvent & {type: K}) => void | Promise<void>
|
|
50
|
+
export type EventSubscriberFunc<K extends CEvt.Tag> = (event: ChatEvent & {type: K}, chat: ChatApi) => void | Promise<void>
|
|
51
51
|
|
|
52
52
|
export type EventSubscribers = {[K in CEvt.Tag]?: EventSubscriberFunc<K>}
|
|
53
53
|
|
|
@@ -106,13 +106,15 @@ export class ChatApi {
|
|
|
106
106
|
* Initializes the ChatApi.
|
|
107
107
|
* @param {DbConfig} db - Database configuration (sqlite or postgres).
|
|
108
108
|
* @param {core.MigrationConfirmation} [confirm=core.MigrationConfirmation.YesUp] - Migration confirmation mode.
|
|
109
|
+
* @param {number} [queueSize] - Size of internal queues, the core default is used when omitted.
|
|
109
110
|
*/
|
|
110
111
|
static async init(
|
|
111
112
|
db: DbConfig,
|
|
112
|
-
confirm = core.MigrationConfirmation.YesUp
|
|
113
|
+
confirm = core.MigrationConfirmation.YesUp,
|
|
114
|
+
queueSize?: number
|
|
113
115
|
): Promise<ChatApi> {
|
|
114
116
|
const [path, key] = dbConfigToMigrateArgs(db)
|
|
115
|
-
const ctrl = await core.chatMigrateInit(path, key, confirm)
|
|
117
|
+
const ctrl = await core.chatMigrateInit(path, key, confirm, queueSize)
|
|
116
118
|
return new ChatApi(ctrl)
|
|
117
119
|
}
|
|
118
120
|
|
|
@@ -120,39 +122,52 @@ export class ChatApi {
|
|
|
120
122
|
* Start chat controller. Must be called with the existing user profile.
|
|
121
123
|
*/
|
|
122
124
|
async startChat(): Promise<void> {
|
|
125
|
+
if (this.eventsLoop) throw new Error("chat already started")
|
|
126
|
+
const ctrl = this.ctrl
|
|
123
127
|
this.receiveEvents = true
|
|
124
128
|
this.eventsLoop = this.runEventsLoop()
|
|
125
|
-
|
|
129
|
+
let r: ChatResponse
|
|
130
|
+
try {
|
|
131
|
+
r = await core.chatSendCmd(ctrl, CC.StartChat.cmdString({mainApp: true, enableSndFiles: true, serviceRequests: false}))
|
|
132
|
+
} catch (e) {
|
|
133
|
+
await this.stopEventsLoop()
|
|
134
|
+
throw e
|
|
135
|
+
}
|
|
126
136
|
if (r.type !== "chatStarted" && r.type !== "chatRunning") {
|
|
137
|
+
await this.stopEventsLoop()
|
|
127
138
|
throw new ChatCommandError("error starting chat", r)
|
|
128
139
|
}
|
|
129
140
|
}
|
|
130
|
-
|
|
141
|
+
|
|
131
142
|
/**
|
|
132
143
|
* Stop chat controller.
|
|
133
|
-
*
|
|
144
|
+
* `close` calls it before closing the database.
|
|
134
145
|
* Usually doesn't need to be called in chat bots.
|
|
135
146
|
*/
|
|
136
147
|
async stopChat(): Promise<void> {
|
|
137
148
|
const r = await this.sendChatCmd("/_stop")
|
|
138
|
-
if (r.type !== "chatStopped") throw new ChatCommandError("error
|
|
139
|
-
this.
|
|
140
|
-
if (this.eventsLoop) await this.eventsLoop
|
|
141
|
-
this.eventsLoop = undefined
|
|
149
|
+
if (r.type !== "chatStopped") throw new ChatCommandError("error stopping chat", r)
|
|
150
|
+
await this.stopEventsLoop()
|
|
142
151
|
}
|
|
143
152
|
|
|
144
153
|
/**
|
|
145
|
-
*
|
|
154
|
+
* Stop chat controller and close chat database.
|
|
155
|
+
* The database is not closed if stopping fails.
|
|
146
156
|
* Usually doesn't need to be called in chat bots.
|
|
147
157
|
*/
|
|
148
158
|
async close(): Promise<void> {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
this.eventsLoop = undefined
|
|
159
|
+
// a running controller keeps using the database connections that closing frees
|
|
160
|
+
await this.stopChat()
|
|
152
161
|
await core.chatCloseStore(this.ctrl)
|
|
153
162
|
this.ctrl_ = undefined
|
|
154
163
|
}
|
|
155
|
-
|
|
164
|
+
|
|
165
|
+
private async stopEventsLoop(): Promise<void> {
|
|
166
|
+
this.receiveEvents = false
|
|
167
|
+
if (this.eventsLoop) await this.eventsLoop
|
|
168
|
+
this.eventsLoop = undefined
|
|
169
|
+
}
|
|
170
|
+
|
|
156
171
|
private async runEventsLoop(): Promise<void> {
|
|
157
172
|
while (this.receiveEvents) {
|
|
158
173
|
try {
|
|
@@ -162,7 +177,7 @@ export class ChatApi {
|
|
|
162
177
|
if (subs) {
|
|
163
178
|
for (const {subscriber, once} of [...subs]) {
|
|
164
179
|
try {
|
|
165
|
-
const p = (subscriber as EventSubscriberFunc<typeof event.type>)(event)
|
|
180
|
+
const p = (subscriber as EventSubscriberFunc<typeof event.type>)(event, this)
|
|
166
181
|
if (p instanceof Promise) await p
|
|
167
182
|
} catch(e) {
|
|
168
183
|
console.log(`${event.type} event processing error`, e)
|
|
@@ -172,7 +187,7 @@ export class ChatApi {
|
|
|
172
187
|
}
|
|
173
188
|
for (const r of [...this.receivers]) {
|
|
174
189
|
try {
|
|
175
|
-
const p = r(event)
|
|
190
|
+
const p = r(event, this)
|
|
176
191
|
if (p instanceof Promise) await p
|
|
177
192
|
} catch(e) {
|
|
178
193
|
console.log(`${event.type} event processing error`, e)
|
|
@@ -335,7 +350,7 @@ export class ChatApi {
|
|
|
335
350
|
return await core.chatSendCmd(this.ctrl, cmd)
|
|
336
351
|
}
|
|
337
352
|
|
|
338
|
-
async recvChatEvent(wait: number =
|
|
353
|
+
async recvChatEvent(wait: number = 500_000): Promise<ChatEvent | undefined> {
|
|
339
354
|
return await core.chatRecvMsgWait(this.ctrl, wait)
|
|
340
355
|
}
|
|
341
356
|
|
|
@@ -386,8 +401,10 @@ export class ChatApi {
|
|
|
386
401
|
switch (r.type) {
|
|
387
402
|
case "userProfileUpdated":
|
|
388
403
|
return r.updateSummary
|
|
404
|
+
case "userProfileNoChange":
|
|
405
|
+
return {updateSuccesses: 0, updateFailures: 0, changedContacts: []}
|
|
389
406
|
default:
|
|
390
|
-
throw new ChatCommandError("error
|
|
407
|
+
throw new ChatCommandError("error setting profile address", r)
|
|
391
408
|
}
|
|
392
409
|
}
|
|
393
410
|
|
|
@@ -405,7 +422,18 @@ export class ChatApi {
|
|
|
405
422
|
const r = await this.sendChatCmd(CC.APISetAddressSettings.cmdString({userId, settings}))
|
|
406
423
|
if (r.type !== "userContactLinkUpdated") {
|
|
407
424
|
throw new ChatCommandError("error changing user contact address settings", r)
|
|
408
|
-
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async apiSetUserDomain(userId: number, simplexDomain?: string): Promise<T.User> {
|
|
429
|
+
const r = await this.sendChatCmd(CC.APISetUserDomain.cmdString({userId, simplexDomain}))
|
|
430
|
+
switch (r.type) {
|
|
431
|
+
case "userProfileUpdated":
|
|
432
|
+
case "userProfileNoChange":
|
|
433
|
+
return r.user
|
|
434
|
+
default:
|
|
435
|
+
throw new ChatCommandError("error setting SimpleX name", r)
|
|
436
|
+
}
|
|
409
437
|
}
|
|
410
438
|
|
|
411
439
|
/**
|
|
@@ -460,7 +488,7 @@ export class ChatApi {
|
|
|
460
488
|
updatedMessage: {msgContent, mentions: {}},
|
|
461
489
|
})
|
|
462
490
|
)
|
|
463
|
-
if (r.type === "chatItemUpdated") return r.chatItem.chatItem
|
|
491
|
+
if (r.type === "chatItemUpdated" || r.type === "chatItemNotChanged") return r.chatItem.chatItem
|
|
464
492
|
throw new ChatCommandError("error updating chat item", r)
|
|
465
493
|
}
|
|
466
494
|
|
|
@@ -499,10 +527,10 @@ export class ChatApi {
|
|
|
499
527
|
chatItemId: number,
|
|
500
528
|
add: boolean,
|
|
501
529
|
reaction: T.MsgReaction
|
|
502
|
-
) {
|
|
530
|
+
): Promise<T.ACIReaction> {
|
|
503
531
|
const r = await this.sendChatCmd(CC.APIChatItemReaction.cmdString({chatRef: {chatType, chatId}, chatItemId, add, reaction}))
|
|
504
|
-
if (r.type === "
|
|
505
|
-
throw new ChatCommandError("error setting item reaction", r)
|
|
532
|
+
if (r.type === "chatItemReaction") return r.reaction
|
|
533
|
+
throw new ChatCommandError("error setting item reaction", r)
|
|
506
534
|
}
|
|
507
535
|
|
|
508
536
|
/**
|
|
@@ -512,6 +540,7 @@ export class ChatApi {
|
|
|
512
540
|
async apiReceiveFile(fileId: number): Promise<T.AChatItem> {
|
|
513
541
|
const r = await this.sendChatCmd(CC.ReceiveFile.cmdString({fileId, userApprovedRelays: true}))
|
|
514
542
|
if (r.type === "rcvFileAccepted") return r.chatItem
|
|
543
|
+
if (r.type === "rcvFileAcceptedSndCancelled") throw new ChatCommandError("file cancelled by sender", r)
|
|
515
544
|
throw new ChatCommandError("error receiving file", r)
|
|
516
545
|
}
|
|
517
546
|
|
|
@@ -698,7 +727,7 @@ export class ChatApi {
|
|
|
698
727
|
* Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link
|
|
699
728
|
* Network usage: interactive.
|
|
700
729
|
*/
|
|
701
|
-
async apiConnect(userId: number, incognito: boolean, preparedLink
|
|
730
|
+
async apiConnect(userId: number, incognito: boolean, preparedLink: T.CreatedConnLink): Promise<ConnReqType> {
|
|
702
731
|
const r = await this.sendChatCmd(CC.APIConnect.cmdString({userId, incognito, preparedLink_: preparedLink}))
|
|
703
732
|
return this.handleConnectResult(r)
|
|
704
733
|
}
|
package/src/bot.ts
CHANGED
|
@@ -6,6 +6,7 @@ import equal = require("fast-deep-equal")
|
|
|
6
6
|
|
|
7
7
|
export type BotDbOpts = api.DbConfig & {
|
|
8
8
|
confirmMigrations?: core.MigrationConfirmation
|
|
9
|
+
queueSize?: number
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface BotOptions {
|
|
@@ -34,21 +35,21 @@ const defaultOpts: Required<BotOptions> = {
|
|
|
34
35
|
|
|
35
36
|
export interface BotConfig {
|
|
36
37
|
profile: T.Profile,
|
|
38
|
+
simplexName?: string,
|
|
37
39
|
dbOpts: BotDbOpts,
|
|
38
40
|
options: BotOptions,
|
|
39
|
-
onMessage?: (chatItem: T.AChatItem, content: T.MsgContent) => void | Promise<void>,
|
|
41
|
+
onMessage?: (chatItem: T.AChatItem, content: T.MsgContent, chat: api.ChatApi) => void | Promise<void>,
|
|
40
42
|
// command handlers can be different from commands to be shown in client UI
|
|
41
|
-
onCommands?: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand) => void | Promise<void>)},
|
|
43
|
+
onCommands?: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand, chat: api.ChatApi) => void | Promise<void>)},
|
|
42
44
|
// If you use `onMessage` and to subscribe "newChatItems" event, exclude content messages from processing
|
|
43
45
|
// If you use `onCommands` and to subscribe "newChatItems" event, exclude commands from processing
|
|
44
46
|
events?: api.EventSubscribers
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
export async function run({profile, dbOpts, options = defaultOpts, onMessage, onCommands = {}, events = {}}: BotConfig): Promise<[api.ChatApi, T.User, T.UserContactLink | undefined]> {
|
|
48
|
-
const bot = await api.ChatApi.init(dbOpts, dbOpts.confirmMigrations || core.MigrationConfirmation.YesUp)
|
|
49
|
+
export async function run({profile, simplexName, dbOpts, options = defaultOpts, onMessage, onCommands = {}, events = {}}: BotConfig): Promise<[api.ChatApi, T.User, T.UserContactLink | undefined]> {
|
|
50
|
+
const bot = await api.ChatApi.init(dbOpts, dbOpts.confirmMigrations || core.MigrationConfirmation.YesUp, dbOpts.queueSize)
|
|
49
51
|
const opts = fullOptions(options)
|
|
50
|
-
if (onMessage)
|
|
51
|
-
if (Object.keys(onCommands).length > 0) subscribeCommands(bot, onCommands)
|
|
52
|
+
if (onMessage || Object.keys(onCommands).length > 0) subscribeChatItems(bot, onMessage, onCommands)
|
|
52
53
|
if (Object.keys(events).length > 0) bot.on(events)
|
|
53
54
|
subscribeLogEvents(bot, opts)
|
|
54
55
|
const botProfile = mkBotProfile(profile, opts)
|
|
@@ -60,7 +61,8 @@ export async function run({profile, dbOpts, options = defaultOpts, onMessage, on
|
|
|
60
61
|
console.log(`Bot address: ${addressLink}`)
|
|
61
62
|
if (opts.useBotProfile) botProfile.contactLink = addressLink
|
|
62
63
|
}
|
|
63
|
-
await
|
|
64
|
+
const namedUser = await updateBotSimplexName(bot, user, simplexName, opts)
|
|
65
|
+
await updateBotUserProfile(bot, namedUser, botProfile, opts)
|
|
64
66
|
return [bot, user, address]
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -105,38 +107,25 @@ function mkBotProfile(profile: T.Profile, opts: Required<BotOptions>): T.Profile
|
|
|
105
107
|
return profile
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
function
|
|
110
|
+
export function subscribeChatItems(
|
|
111
|
+
bot: api.ChatApi,
|
|
112
|
+
onMessage: ((chatItem: T.AChatItem, content: T.MsgContent, chat: api.ChatApi) => void | Promise<void>) | undefined,
|
|
113
|
+
commands: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand, chat: api.ChatApi) => void | Promise<void>)}
|
|
114
|
+
) {
|
|
109
115
|
bot.on("newChatItems", async ({chatItems}) => {
|
|
110
116
|
for (const ci of chatItems) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const p = onMessage(ci, ci.chatItem.content.msgContent)
|
|
114
|
-
if (p instanceof Promise) await p
|
|
115
|
-
} catch (e) {
|
|
116
|
-
console.log("message processing error", e)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function subscribeCommands(bot: api.ChatApi, commands: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand) => void | Promise<void>)}) {
|
|
124
|
-
bot.on("newChatItems", async (evt) => {
|
|
125
|
-
for (const ci of evt.chatItems) {
|
|
117
|
+
const content = ci.chatItem.content
|
|
118
|
+
if (content.type !== "rcvMsgContent") continue
|
|
126
119
|
const cmd = util.ciBotCommand(ci.chatItem)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (cmdFunc)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
} catch(e) {
|
|
134
|
-
console.log(`${cmd} command processing error`, e)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
120
|
+
const cmdFunc = cmd && (commands[cmd.keyword] || commands[""])
|
|
121
|
+
try {
|
|
122
|
+
if (cmd && cmdFunc) await cmdFunc(ci, cmd, bot)
|
|
123
|
+
else if (onMessage) await onMessage(ci, content.msgContent, bot)
|
|
124
|
+
} catch (e) {
|
|
125
|
+
console.log(cmd && cmdFunc ? `${cmd.keyword} command processing error` : "message processing error", e)
|
|
137
126
|
}
|
|
138
127
|
}
|
|
139
|
-
})
|
|
128
|
+
})
|
|
140
129
|
}
|
|
141
130
|
|
|
142
131
|
function subscribeLogEvents(bot: api.ChatApi, opts: Required<BotOptions>) {
|
|
@@ -193,15 +182,32 @@ async function createOrUpdateAddress(bot: api.ChatApi, user: T.User, opts: Requi
|
|
|
193
182
|
}
|
|
194
183
|
}
|
|
195
184
|
|
|
196
|
-
return address
|
|
185
|
+
return address
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function updateBotSimplexName(bot: api.ChatApi, user: T.User, simplexName: string | undefined, opts: Required<BotOptions>): Promise<T.User> {
|
|
189
|
+
const name = simplexName?.toLowerCase()
|
|
190
|
+
if (user.profile.contactDomain?.domain === name) return user
|
|
191
|
+
if (!opts.updateAddress) {
|
|
192
|
+
console.log("Bot SimpleX name changed")
|
|
193
|
+
return user
|
|
194
|
+
}
|
|
195
|
+
console.log("Bot SimpleX name changed, updating...")
|
|
196
|
+
try {
|
|
197
|
+
return await bot.apiSetUserDomain(user.userId, name)
|
|
198
|
+
} catch (e) {
|
|
199
|
+
console.log("Error updating bot SimpleX name", e)
|
|
200
|
+
return user
|
|
201
|
+
}
|
|
197
202
|
}
|
|
198
203
|
|
|
199
204
|
async function updateBotUserProfile(bot: api.ChatApi, user: T.User, profile: T.Profile, opts: Required<BotOptions>): Promise<void> {
|
|
200
205
|
const {userId} = user
|
|
201
|
-
|
|
206
|
+
const {contactDomain, ...currentProfile} = util.fromLocalProfile(user.profile)
|
|
207
|
+
if (!equal(currentProfile, profile)) {
|
|
202
208
|
if (opts.updateProfile) {
|
|
203
209
|
console.log("Bot profile changed, updating...")
|
|
204
|
-
const summary = await bot.apiUpdateProfile(userId, profile)
|
|
210
|
+
const summary = await bot.apiUpdateProfile(userId, {...profile, contactDomain})
|
|
205
211
|
console.log(
|
|
206
212
|
summary
|
|
207
213
|
? `Bot profile updated: ${summary.updateSuccesses} updated contact(s), ${summary.updateFailures} failed contact update(s).`
|
package/src/core.ts
CHANGED
|
@@ -3,9 +3,12 @@ import * as simplex from "./simplex"
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Initialize chat controller
|
|
6
|
+
* @param {number} [queueSize] - Size of internal queues, the core default is used when omitted.
|
|
6
7
|
*/
|
|
7
|
-
export async function chatMigrateInit(dbPath: string, dbKey: string, confirm: MigrationConfirmation): Promise<bigint> {
|
|
8
|
-
const [ctrl, res] =
|
|
8
|
+
export async function chatMigrateInit(dbPath: string, dbKey: string, confirm: MigrationConfirmation, queueSize?: number): Promise<bigint> {
|
|
9
|
+
const [ctrl, res] = queueSize === undefined
|
|
10
|
+
? await simplex.chat_migrate_init(dbPath, dbKey, confirm)
|
|
11
|
+
: await simplex.chat_migrate_init_queue(dbPath, dbKey, confirm, queueSize)
|
|
9
12
|
const json = JSON.parse(res)
|
|
10
13
|
if (json.type === 'ok') return ctrl
|
|
11
14
|
throw new ChatInitError("Database or migration error (see dbMigrationError property)", json as DBMigrationError)
|
|
@@ -47,7 +50,7 @@ export async function chatRecvMsgWait(ctrl: bigint, wait: number): Promise<ChatE
|
|
|
47
50
|
/**
|
|
48
51
|
* Write buffer to encrypted file
|
|
49
52
|
*/
|
|
50
|
-
export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuffer): Promise<CryptoArgs> {
|
|
53
|
+
export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuffer | Uint8Array): Promise<CryptoArgs> {
|
|
51
54
|
const res = await simplex.chat_write_file(ctrl, path, buffer)
|
|
52
55
|
return cryptoArgsResult(res)
|
|
53
56
|
}
|
|
@@ -55,7 +58,7 @@ export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuf
|
|
|
55
58
|
/**
|
|
56
59
|
* Read buffer from encrypted file
|
|
57
60
|
*/
|
|
58
|
-
export async function chatReadFile(path: string, {fileKey, fileNonce}: CryptoArgs): Promise<
|
|
61
|
+
export async function chatReadFile(path: string, {fileKey, fileNonce}: CryptoArgs): Promise<Buffer> {
|
|
59
62
|
return await simplex.chat_read_file(path, fileKey, fileNonce)
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -121,12 +124,13 @@ export class ChatInitError extends Error {
|
|
|
121
124
|
|
|
122
125
|
export type DBMigrationError =
|
|
123
126
|
| DBMigrationError.InvalidConfirmation
|
|
127
|
+
| DBMigrationError.InvalidQueueSize
|
|
124
128
|
| DBMigrationError.ErrorNotADatabase // invalid/corrupt database file or incorrect encryption key
|
|
125
129
|
| DBMigrationError.ErrorMigration
|
|
126
130
|
| DBMigrationError.ErrorSQL
|
|
127
131
|
|
|
128
132
|
export namespace DBMigrationError {
|
|
129
|
-
export type Tag = "invalidConfirmation" | "errorNotADatabase" | "errorMigration" | "errorSQL"
|
|
133
|
+
export type Tag = "invalidConfirmation" | "invalidQueueSize" | "errorNotADatabase" | "errorMigration" | "errorSQL"
|
|
130
134
|
|
|
131
135
|
interface Interface {
|
|
132
136
|
type: Tag
|
|
@@ -136,6 +140,10 @@ export namespace DBMigrationError {
|
|
|
136
140
|
type: "invalidConfirmation"
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
export interface InvalidQueueSize extends Interface {
|
|
144
|
+
type: "invalidQueueSize"
|
|
145
|
+
}
|
|
146
|
+
|
|
139
147
|
export interface ErrorNotADatabase extends Interface {
|
|
140
148
|
type: "errorNotADatabase"
|
|
141
149
|
dbFile: string
|
|
@@ -168,7 +176,7 @@ export namespace MigrationError {
|
|
|
168
176
|
|
|
169
177
|
export interface MEUpgrade extends Interface {
|
|
170
178
|
type: "upgrade"
|
|
171
|
-
upMigrations: UpMigration
|
|
179
|
+
upMigrations: UpMigration[]
|
|
172
180
|
}
|
|
173
181
|
|
|
174
182
|
export interface MEDowngrade extends Interface {
|
|
@@ -200,7 +208,7 @@ export namespace MTRError {
|
|
|
200
208
|
|
|
201
209
|
export interface MTRENoDown extends Interface {
|
|
202
210
|
type: "noDown"
|
|
203
|
-
|
|
211
|
+
dbMigrations: string[]
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
export interface MTREDifferent extends Interface {
|