tturn 0.1.1 → 0.1.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 +34 -5
- package/README.zh-CN.md +32 -4
- package/dist/app.js +9 -6
- package/dist/cli.js +39 -9
- package/dist/native-binding.js +2 -2
- package/dist/service.js +7 -2
- package/dist/types.d.ts +3 -1
- package/index.node +0 -0
- package/package.json +1 -1
- package/tturn.win32-x64-msvc.node +0 -0
package/README.md
CHANGED
|
@@ -29,11 +29,11 @@ import { Tturn } from "tturn";
|
|
|
29
29
|
|
|
30
30
|
const turn = new Tturn({
|
|
31
31
|
realm: "turn.example.com",
|
|
32
|
-
|
|
32
|
+
password: "replace-with-your-password",
|
|
33
33
|
publicIp: "1.2.3.4",
|
|
34
34
|
listenPort: 3478,
|
|
35
35
|
username: "user-1001",
|
|
36
|
-
|
|
36
|
+
disableCredentialExpiry: true
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
const ice = await turn.start();
|
|
@@ -44,6 +44,13 @@ await turn.stop();
|
|
|
44
44
|
|
|
45
45
|
`start()` now returns one ICE payload directly, so bootstrap can be only `new Tturn(...)` + `start()`.
|
|
46
46
|
|
|
47
|
+
For long-running sessions, set `disableCredentialExpiry: true` to issue non-expiring credentials.
|
|
48
|
+
|
|
49
|
+
With static password mode (`password` + `username`), what you set is what clients use:
|
|
50
|
+
|
|
51
|
+
- output `username` is exactly your configured username
|
|
52
|
+
- output `credential` is exactly your configured password
|
|
53
|
+
|
|
47
54
|
## Credential options
|
|
48
55
|
|
|
49
56
|
`issueCredential(options)` supports:
|
|
@@ -69,12 +76,18 @@ TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn credentia
|
|
|
69
76
|
|
|
70
77
|
# Optional: provide custom username
|
|
71
78
|
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret TTURN_USERNAME=alice tturn credential
|
|
79
|
+
|
|
80
|
+
# Optional: disable credential expiry (long-lived credentials)
|
|
81
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret TTURN_USERNAME=alice TTURN_DISABLE_CREDENTIAL_EXPIRY=1 tturn credential
|
|
82
|
+
|
|
83
|
+
# Static account/password (exact value, no rewrite)
|
|
84
|
+
TURN_REALM=turn.example.com TURN_USERNAME=alice TURN_PASSWORD=alice-pass TTURN_DISABLE_CREDENTIAL_EXPIRY=1 tturn start
|
|
72
85
|
```
|
|
73
86
|
|
|
74
87
|
Required env:
|
|
75
88
|
|
|
76
89
|
- `TURN_REALM`
|
|
77
|
-
- `TURN_SECRET`
|
|
90
|
+
- `TURN_SECRET` or `TURN_PASSWORD`
|
|
78
91
|
|
|
79
92
|
Optional env:
|
|
80
93
|
|
|
@@ -82,19 +95,35 @@ Optional env:
|
|
|
82
95
|
- `TURN_PORT`
|
|
83
96
|
- `TTURN_TTL_SEC`
|
|
84
97
|
- `TTURN_USER_ID`
|
|
85
|
-
- `TTURN_USERNAME`
|
|
98
|
+
- `TTURN_USERNAME` (or `TURN_USERNAME`)
|
|
99
|
+
- `TTURN_DISABLE_CREDENTIAL_EXPIRY` (`1` or `true`)
|
|
86
100
|
|
|
87
101
|
## API options
|
|
88
102
|
|
|
89
103
|
- `realm` (required): TURN realm/domain.
|
|
90
|
-
- `authSecret` (
|
|
104
|
+
- `authSecret` (optional): shared secret for dynamic credentials.
|
|
105
|
+
- `password` (optional): static TURN password (when set, returned credential stays fixed).
|
|
91
106
|
- `listenPort` (default `3478`): TURN listening port.
|
|
92
107
|
- `publicIp` (optional, recommended): public relay IP exposed to clients.
|
|
93
108
|
- `listeningIp` (default `0.0.0.0`): bind address.
|
|
94
109
|
- `username` / `userId` (optional): default credential username seed. `username` has higher priority.
|
|
95
110
|
- `ttlSec` (optional): default credential TTL used by `start()` and `issueCredential()`.
|
|
111
|
+
- `disableCredentialExpiry` (optional): disable timestamp expiry check and issue non-expiring credentials.
|
|
96
112
|
- `minPort` / `maxPort`: reserved for relay port range control in next iterations.
|
|
97
113
|
|
|
114
|
+
At least one of `authSecret` or `password` must be provided.
|
|
115
|
+
|
|
116
|
+
## Quick verify
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npm install
|
|
120
|
+
npm run build
|
|
121
|
+
|
|
122
|
+
TURN_REALM=turn.example.com TURN_PUBLIC_IP=1.2.3.4 TURN_USERNAME=alice TURN_PASSWORD=alice-pass TTURN_DISABLE_CREDENTIAL_EXPIRY=1 node dist/cli.js credential
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The returned JSON should keep `username = "alice"` and `credential = "alice-pass"`.
|
|
126
|
+
|
|
98
127
|
## Build from source
|
|
99
128
|
|
|
100
129
|
Requirements:
|
package/README.zh-CN.md
CHANGED
|
@@ -32,11 +32,11 @@ import { Tturn } from "tturn";
|
|
|
32
32
|
|
|
33
33
|
const turn = new Tturn({
|
|
34
34
|
realm: "turn.example.com",
|
|
35
|
-
|
|
35
|
+
password: "replace-with-your-password",
|
|
36
36
|
publicIp: "1.2.3.4",
|
|
37
37
|
listenPort: 3478,
|
|
38
38
|
username: "user-1001",
|
|
39
|
-
|
|
39
|
+
disableCredentialExpiry: true
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
const ice = await turn.start();
|
|
@@ -46,6 +46,13 @@ await turn.stop();
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
`start()` 会直接返回一组 ICE,因此最简流程只需要 `new Tturn(...)` 和 `start()`。
|
|
49
|
+
|
|
50
|
+
如果你需要长时间持续连接,可设置 `disableCredentialExpiry: true`,生成不过期凭证。
|
|
51
|
+
|
|
52
|
+
在静态账号密码模式(`password` + `username`)下:
|
|
53
|
+
|
|
54
|
+
- 输出的 `username` 就是你配置的账号
|
|
55
|
+
- 输出的 `credential` 就是你配置的密码
|
|
49
56
|
|
|
50
57
|
## 5)CLI 用法
|
|
51
58
|
|
|
@@ -58,6 +65,12 @@ TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret tturn credentia
|
|
|
58
65
|
|
|
59
66
|
# 可选:传入自定义 username
|
|
60
67
|
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret TTURN_USERNAME=alice tturn credential
|
|
68
|
+
|
|
69
|
+
# 可选:禁用凭证过期(长期凭证)
|
|
70
|
+
TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret TTURN_USERNAME=alice TTURN_DISABLE_CREDENTIAL_EXPIRY=1 tturn credential
|
|
71
|
+
|
|
72
|
+
# 静态账号密码(原样输出,不改写)
|
|
73
|
+
TURN_REALM=turn.example.com TURN_USERNAME=alice TURN_PASSWORD=alice-pass TTURN_DISABLE_CREDENTIAL_EXPIRY=1 tturn start
|
|
61
74
|
```
|
|
62
75
|
|
|
63
76
|
## 5.1)凭证参数补充(username)
|
|
@@ -70,14 +83,29 @@ TURN_REALM=turn.example.com TURN_SECRET=replace-with-your-secret TTURN_USERNAME=
|
|
|
70
83
|
|
|
71
84
|
## 6)配置参数说明
|
|
72
85
|
|
|
73
|
-
- `realm`(必填):TURN realm / 域名。
|
|
74
|
-
- `authSecret
|
|
86
|
+
- `realm`(必填):TURN realm / 域名。
|
|
87
|
+
- `authSecret`(可选):动态凭证签名密钥。
|
|
88
|
+
- `password`(可选):静态 TURN 密码(设置后返回值保持固定)。
|
|
75
89
|
- `listenPort`(默认 `3478`):TURN 监听端口。
|
|
76
90
|
- `publicIp`(建议配置):客户端访问的公网 IP。
|
|
77
91
|
- `listeningIp`(默认 `0.0.0.0`):本地绑定地址。
|
|
78
92
|
- `username` / `userId`(可选):默认凭证用户名种子,`username` 优先级更高。
|
|
79
93
|
- `ttlSec`(可选):`start()` 与 `issueCredential()` 的默认凭证时效。
|
|
94
|
+
- `disableCredentialExpiry`(可选):禁用时间戳过期校验,生成不过期凭证。
|
|
80
95
|
- `minPort` / `maxPort`:预留给后续中继端口范围控制。
|
|
96
|
+
|
|
97
|
+
`authSecret` 和 `password` 至少需要提供一个。
|
|
98
|
+
|
|
99
|
+
## 6.1)快速验证
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install
|
|
103
|
+
npm run build
|
|
104
|
+
|
|
105
|
+
TURN_REALM=turn.example.com TURN_PUBLIC_IP=1.2.3.4 TURN_USERNAME=alice TURN_PASSWORD=alice-pass TTURN_DISABLE_CREDENTIAL_EXPIRY=1 node dist/cli.js credential
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
返回 JSON 中应保持 `username = "alice"`、`credential = "alice-pass"`。
|
|
81
109
|
|
|
82
110
|
## 7)源码构建
|
|
83
111
|
|
package/dist/app.js
CHANGED
|
@@ -3,20 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const index_1 = require("./index");
|
|
4
4
|
const APP_CONFIG = {
|
|
5
5
|
realm: "turn.example.com",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
ttlSec: 600
|
|
6
|
+
publicIp: "192.168.3.66",
|
|
7
|
+
listenPort: 22224,
|
|
8
|
+
username: "metadigiee",
|
|
9
|
+
password: "22222",
|
|
10
|
+
ttlSec: 600,
|
|
11
|
+
disableCredentialExpiry: true
|
|
11
12
|
};
|
|
12
13
|
async function main() {
|
|
13
14
|
const service = new index_1.Tturn({
|
|
14
15
|
realm: APP_CONFIG.realm,
|
|
15
16
|
authSecret: APP_CONFIG.authSecret,
|
|
17
|
+
password: APP_CONFIG.password,
|
|
16
18
|
publicIp: APP_CONFIG.publicIp,
|
|
17
19
|
listenPort: APP_CONFIG.listenPort,
|
|
18
20
|
username: APP_CONFIG.username,
|
|
19
|
-
ttlSec: APP_CONFIG.ttlSec
|
|
21
|
+
ttlSec: APP_CONFIG.ttlSec,
|
|
22
|
+
disableCredentialExpiry: APP_CONFIG.disableCredentialExpiry
|
|
20
23
|
});
|
|
21
24
|
const ice = await service.start();
|
|
22
25
|
console.log("[tturn] started.");
|
package/dist/cli.js
CHANGED
|
@@ -5,28 +5,36 @@ const index_1 = require("./index");
|
|
|
5
5
|
async function run() {
|
|
6
6
|
const command = process.argv[2];
|
|
7
7
|
if (command === "credential") {
|
|
8
|
-
const secret = mustGetEnv("TURN_SECRET");
|
|
9
8
|
const realm = mustGetEnv("TURN_REALM");
|
|
10
|
-
const
|
|
9
|
+
const authOptions = resolveAuthOptions();
|
|
10
|
+
const service = (0, index_1.createTurnService)({
|
|
11
|
+
realm,
|
|
12
|
+
authSecret: authOptions.authSecret,
|
|
13
|
+
password: authOptions.password,
|
|
14
|
+
publicIp: process.env.TURN_PUBLIC_IP,
|
|
15
|
+
disableCredentialExpiry: readBoolEnv("TTURN_DISABLE_CREDENTIAL_EXPIRY") ?? Boolean(authOptions.password)
|
|
16
|
+
});
|
|
11
17
|
const ice = service.issueCredential({
|
|
12
18
|
ttlSec: process.env.TTURN_TTL_SEC ? Number(process.env.TTURN_TTL_SEC) : 3600,
|
|
13
19
|
userId: process.env.TTURN_USER_ID,
|
|
14
|
-
username:
|
|
20
|
+
username: readUsernameEnv()
|
|
15
21
|
});
|
|
16
22
|
process.stdout.write(`${JSON.stringify(ice, null, 2)}\n`);
|
|
17
23
|
return;
|
|
18
24
|
}
|
|
19
25
|
if (command === "start") {
|
|
20
|
-
const secret = mustGetEnv("TURN_SECRET");
|
|
21
26
|
const realm = mustGetEnv("TURN_REALM");
|
|
27
|
+
const authOptions = resolveAuthOptions();
|
|
22
28
|
const service = (0, index_1.createTurnService)({
|
|
23
29
|
realm,
|
|
24
|
-
authSecret:
|
|
30
|
+
authSecret: authOptions.authSecret,
|
|
31
|
+
password: authOptions.password,
|
|
25
32
|
publicIp: process.env.TURN_PUBLIC_IP,
|
|
26
33
|
listenPort: process.env.TURN_PORT ? Number(process.env.TURN_PORT) : 3478,
|
|
27
34
|
ttlSec: process.env.TTURN_TTL_SEC ? Number(process.env.TTURN_TTL_SEC) : 3600,
|
|
28
|
-
username:
|
|
29
|
-
userId: process.env.TTURN_USER_ID
|
|
35
|
+
username: readUsernameEnv(),
|
|
36
|
+
userId: process.env.TTURN_USER_ID,
|
|
37
|
+
disableCredentialExpiry: readBoolEnv("TTURN_DISABLE_CREDENTIAL_EXPIRY") ?? Boolean(authOptions.password)
|
|
30
38
|
});
|
|
31
39
|
const ice = await service.start();
|
|
32
40
|
process.stdout.write("tturn started\n");
|
|
@@ -53,11 +61,33 @@ function printUsage() {
|
|
|
53
61
|
" tturn credential # prints one ICE server credential JSON",
|
|
54
62
|
"",
|
|
55
63
|
"required env:",
|
|
56
|
-
" TURN_REALM
|
|
64
|
+
" TURN_REALM",
|
|
65
|
+
" TURN_SECRET or TURN_PASSWORD",
|
|
57
66
|
"optional env:",
|
|
58
|
-
" TURN_PUBLIC_IP, TURN_PORT, TTURN_TTL_SEC, TTURN_USER_ID, TTURN_USERNAME"
|
|
67
|
+
" TURN_PUBLIC_IP, TURN_PORT, TTURN_TTL_SEC, TTURN_USER_ID, TTURN_USERNAME (or TURN_USERNAME), TTURN_DISABLE_CREDENTIAL_EXPIRY"
|
|
59
68
|
].join("\n") + "\n");
|
|
60
69
|
}
|
|
70
|
+
function readUsernameEnv() {
|
|
71
|
+
return process.env.TTURN_USERNAME ?? process.env.TURN_USERNAME;
|
|
72
|
+
}
|
|
73
|
+
function resolveAuthOptions() {
|
|
74
|
+
const authSecret = process.env.TURN_SECRET;
|
|
75
|
+
const password = process.env.TURN_PASSWORD;
|
|
76
|
+
if (!authSecret && !password) {
|
|
77
|
+
throw new Error("Missing required env: TURN_SECRET or TURN_PASSWORD");
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
authSecret: authSecret ?? "",
|
|
81
|
+
password
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function readBoolEnv(name) {
|
|
85
|
+
const value = process.env[name];
|
|
86
|
+
if (!value) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
90
|
+
}
|
|
61
91
|
function waitForSignal() {
|
|
62
92
|
return new Promise((resolve) => {
|
|
63
93
|
const keepAlive = setInterval(() => {
|
package/dist/native-binding.js
CHANGED
|
@@ -6,9 +6,9 @@ const node_path_1 = require("node:path");
|
|
|
6
6
|
function loadNativeBinding() {
|
|
7
7
|
const root = (0, node_path_1.join)(__dirname, "..");
|
|
8
8
|
const candidates = [
|
|
9
|
+
(0, node_path_1.join)(root, binaryName()),
|
|
9
10
|
(0, node_path_1.join)(root, "index.node"),
|
|
10
|
-
(0, node_path_1.join)(root, "native", "index.node")
|
|
11
|
-
(0, node_path_1.join)(root, binaryName())
|
|
11
|
+
(0, node_path_1.join)(root, "native", "index.node")
|
|
12
12
|
];
|
|
13
13
|
for (const filePath of candidates) {
|
|
14
14
|
if (!(0, node_fs_1.existsSync)(filePath)) {
|
package/dist/service.js
CHANGED
|
@@ -4,14 +4,19 @@ exports.TurnService = void 0;
|
|
|
4
4
|
const native_binding_1 = require("./native-binding");
|
|
5
5
|
class TurnService {
|
|
6
6
|
constructor(options) {
|
|
7
|
-
const { username, userId, ttlSec, ...nativeOptions } = options;
|
|
7
|
+
const { username, password, userId, ttlSec, ...nativeOptions } = options;
|
|
8
|
+
const disableCredentialExpiry = options.disableCredentialExpiry ?? Boolean(password);
|
|
8
9
|
this.native = new native_binding_1.binding.NativeTurnService({
|
|
9
10
|
...nativeOptions,
|
|
11
|
+
authSecret: nativeOptions.authSecret ?? "",
|
|
10
12
|
listenPort: nativeOptions.listenPort ?? 3478,
|
|
11
13
|
minPort: nativeOptions.minPort ?? 49152,
|
|
12
14
|
maxPort: nativeOptions.maxPort ?? 65535,
|
|
13
15
|
publicIp: nativeOptions.publicIp ?? nativeOptions.realm,
|
|
14
|
-
listeningIp: nativeOptions.listeningIp ?? "0.0.0.0"
|
|
16
|
+
listeningIp: nativeOptions.listeningIp ?? "0.0.0.0",
|
|
17
|
+
username,
|
|
18
|
+
password,
|
|
19
|
+
disableCredentialExpiry
|
|
15
20
|
});
|
|
16
21
|
this.defaultIssueOptions = {
|
|
17
22
|
ttlSec,
|
package/dist/types.d.ts
CHANGED
|
@@ -16,15 +16,17 @@ export interface IssueCredentialOptions {
|
|
|
16
16
|
}
|
|
17
17
|
export interface TurnServiceOptions {
|
|
18
18
|
realm: string;
|
|
19
|
-
authSecret
|
|
19
|
+
authSecret?: string;
|
|
20
20
|
listenPort?: number;
|
|
21
21
|
minPort?: number;
|
|
22
22
|
maxPort?: number;
|
|
23
23
|
publicIp?: string;
|
|
24
24
|
listeningIp?: string;
|
|
25
25
|
username?: string;
|
|
26
|
+
password?: string;
|
|
26
27
|
userId?: string;
|
|
27
28
|
ttlSec?: number;
|
|
29
|
+
disableCredentialExpiry?: boolean;
|
|
28
30
|
}
|
|
29
31
|
export interface StartOptions {
|
|
30
32
|
detached?: boolean;
|
package/index.node
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|