floating-live 0.17.0-alpha.12 → 0.17.0-alpha.13

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.
@@ -13,8 +13,6 @@ export declare class FloatingLive extends App {
13
13
  /** 获取房间 */
14
14
  get(key: string): LiveRoom | import("./live/index.js").InvalidLiveRoom | undefined;
15
15
  has(key: string): boolean;
16
- /** 获取房间信息 */
17
- data(key: string): import("./live/index.js").LiveRoomData | undefined;
18
16
  /** 更新房间信息 */
19
17
  update(key: string): void;
20
18
  /** 打开房间连接 */
@@ -24,10 +24,6 @@ export class FloatingLive extends App {
24
24
  has(key) {
25
25
  return this.room.has(key);
26
26
  }
27
- /** 获取房间信息 */
28
- data(key) {
29
- return this.room.data(key);
30
- }
31
27
  /** 更新房间信息 */
32
28
  update(key) {
33
29
  return this.room.update(key);
package/dist/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CommandOptions, CommandCallOptions, AppCommandMap, CommandFunction } from "./command/index.js";
1
+ import { CommandOptions, CommandCallOptions, AppCommandMap, CommandFunction, AppCommandAliasMap } from "./command/index.js";
2
2
  import { CommandManager } from "./command/manager.js";
3
3
  import { AppEventDetailMap, AppEventEmitOptions, AppEventListener } from "./event/index.js";
4
4
  import { AppHookMap, HookCallOptions, HookContext, HookFunction, HookUseOptions } from "./hook/index.js";
@@ -31,6 +31,7 @@ export declare class App extends CustomEventEmitter implements PluginContext {
31
31
  getPluginExposes(pluginName: string): any;
32
32
  hasPlugin(pluginName: string): boolean;
33
33
  registerCommand<T extends keyof AppCommandMap>(name: T, func: CommandFunction<AppCommandMap[T]>, options?: CommandOptions): void;
34
+ registerCommandAlias<T extends keyof AppCommandAliasMap>(name: T, targetName: AppCommandAliasMap[T], options?: CommandOptions): void;
34
35
  unregisterCommand(name: string): void;
35
36
  hasCommand(name: string): boolean;
36
37
  call<T extends keyof AppCommandMap>(name: T, ...args: Parameters<AppCommandMap[T]>): ReturnType<AppCommandMap[T]>;
package/dist/app.js CHANGED
@@ -16,7 +16,7 @@ export class App extends CustomEventEmitter {
16
16
  this.valueManager = new ValueManager(this);
17
17
  this.pluginManager = new PluginManager(this);
18
18
  // 初始化命令
19
- this.registerCommand("command.snapshot", () => this.commandManager.toSnapshot());
19
+ this.registerCommand("command.getData", () => this.commandManager.getData());
20
20
  this.registerCommand("get", (e, name) => this.getValue(name));
21
21
  this.registerCommand("set", (e, name, value) => this.setValue(name, value));
22
22
  }
@@ -66,6 +66,9 @@ export class App extends CustomEventEmitter {
66
66
  registerCommand(name, func, options) {
67
67
  this.commandManager.register(name, func, options);
68
68
  }
69
+ registerCommandAlias(name, targetName, options) {
70
+ this.commandManager.registerAlias(name, targetName, options);
71
+ }
69
72
  unregisterCommand(name) {
70
73
  this.commandManager.unregister(name);
71
74
  }
@@ -7,16 +7,20 @@ export declare class CommandManager {
7
7
  constructor(app: App);
8
8
  /** 注册命令 */
9
9
  register(name: string, call: CommandFunction<any>, options?: CommandOptions): void;
10
+ /** 注册命令别名 */
11
+ registerAlias(name: string, targetName: string, options?: CommandOptions): void;
10
12
  /** 注销命令 */
11
13
  unregister(name: string): void;
12
14
  /** 调用命令 */
13
15
  call(name: string, ...args: any[]): any;
14
16
  /** 调用命令(可配置) */
15
17
  callWithOptions(name: string, options: CommandCallOptions, ...args: any[]): any;
18
+ /** 从命令别名调用命令 */
19
+ private _callAliasWithOptions;
16
20
  /** 检测命令是否存在 */
17
21
  has(name: string): boolean;
18
22
  /** 获取数据 */
19
- toSnapshot(): {
23
+ getData(): {
20
24
  name: string;
21
25
  pluginName: string | undefined;
22
26
  }[];
@@ -12,6 +12,12 @@ export class CommandManager {
12
12
  this.list.set(name, { call, pluginName });
13
13
  this.app.emit("command:register", { name });
14
14
  }
15
+ /** 注册命令别名 */
16
+ registerAlias(name, targetName, options) {
17
+ const { pluginName } = options || {};
18
+ this.list.set(name, { targetName, pluginName });
19
+ this.app.emit("command:register", { name });
20
+ }
15
21
  /** 注销命令 */
16
22
  unregister(name) {
17
23
  this.list.delete(name);
@@ -26,12 +32,38 @@ export class CommandManager {
26
32
  const command = this.list.get(name);
27
33
  if (!command) {
28
34
  throw appError("command:call_unexist", {
29
- message: `命令不存在: ${name}`,
35
+ message: `命令不存在[${name}]`,
30
36
  target: `command/${name}`,
31
37
  });
32
38
  }
33
39
  else {
34
- return command.call({ source: options.source, client: options.client }, ...args);
40
+ const { call } = command;
41
+ if (!call) {
42
+ return this._callAliasWithOptions(name, command.targetName, options, ...args);
43
+ }
44
+ else {
45
+ return call({ source: options.source, client: options.client }, ...args);
46
+ }
47
+ }
48
+ }
49
+ /** 从命令别名调用命令 */
50
+ _callAliasWithOptions(name, targetName, options, ...args) {
51
+ const tcommand = this.list.get(targetName);
52
+ if (!tcommand) {
53
+ throw appError("command:alias_unexist", {
54
+ message: `命令别名[${name}]指向的命令不存在[${targetName}]`,
55
+ target: `command/${name}>${targetName}`,
56
+ });
57
+ }
58
+ else {
59
+ const { call } = tcommand;
60
+ if (!call) {
61
+ throw appError("command:alias_target_uncallable", {
62
+ message: `命令别名[${name}]不可指向其他命令别名[${targetName}]`,
63
+ target: `command/${name}>${targetName}>${tcommand.targetName}`,
64
+ });
65
+ }
66
+ return call({ source: options.source, client: options.client }, ...args);
35
67
  }
36
68
  }
37
69
  /** 检测命令是否存在 */
@@ -39,7 +71,7 @@ export class CommandManager {
39
71
  return this.list.has(name);
40
72
  }
41
73
  /** 获取数据 */
42
- toSnapshot() {
74
+ getData() {
43
75
  return [...this.list].map(([name, { pluginName }]) => ({
44
76
  name,
45
77
  pluginName,
@@ -19,27 +19,36 @@ export interface CommandItem {
19
19
  call: CommandFunction<any>;
20
20
  pluginName?: string;
21
21
  }
22
+ export interface CommandAliasItem {
23
+ call?: undefined;
24
+ targetName: string;
25
+ pluginName?: string;
26
+ }
27
+ /** 命令函数类型表 */
22
28
  export interface AppCommandMap {
23
29
  get: <T extends keyof AppValueMap>(name: T) => AppValueMap[T];
24
30
  set: <T extends keyof AppValueMap>(name: T, value: AppValueMap[T]) => boolean;
25
- /** 获取注册值快照 */
26
- "value.snapshot": () => {
31
+ /** 获取注册值数据 */
32
+ "value.getData": () => {
27
33
  name: string;
28
34
  value: any;
29
35
  }[];
30
- /** 获取命令快照 */
31
- "command.snapshot": () => {
36
+ /** 获取命令数据 */
37
+ "command.getData": () => {
32
38
  name: string;
33
39
  }[];
34
- /** 获取插件快照 */
35
- "plugin.snapshot": () => {
40
+ /** 获取插件数据 */
41
+ "plugin.getData": () => {
36
42
  pluginName: string;
37
43
  }[];
38
- /** 获取hook快照 */
39
- "hook.snapshot": () => {
44
+ /** 获取hook数据 */
45
+ "hook.getData": () => {
40
46
  name: string;
41
47
  list: {
42
48
  pluginName?: string;
43
49
  }[];
44
50
  }[];
45
51
  }
52
+ /** 命令别名映射 */
53
+ export interface AppCommandAliasMap {
54
+ }
@@ -2,8 +2,8 @@ export * from "./types.js";
2
2
  export interface AppError extends Error {
3
3
  /** 错误发生信息 */
4
4
  cause: {
5
- /** 错误id */
6
- id: string;
5
+ /** 错误代码 */
6
+ code: string;
7
7
  /** 错误目标对象 */
8
8
  target?: string;
9
9
  /** 错误原因 */
@@ -21,4 +21,4 @@ export interface AppErrorOptions {
21
21
  errorConstructor?: ErrorConstructor;
22
22
  [key: string]: unknown;
23
23
  }
24
- export declare function appError(id: string, { message, target, reason, errorConstructor }: AppErrorOptions): Error;
24
+ export declare function appError(code: string, { message, target, reason, errorConstructor }: AppErrorOptions): AppError;
@@ -1,8 +1,8 @@
1
1
  export * from "./types.js";
2
- export function appError(id, { message, target, reason, errorConstructor = Error }) {
2
+ export function appError(code, { message, target, reason, errorConstructor = Error }) {
3
3
  return new errorConstructor(message, {
4
4
  cause: {
5
- id,
5
+ code,
6
6
  target,
7
7
  reason,
8
8
  },
@@ -13,7 +13,7 @@ export declare class HookManager {
13
13
  call(name: string, ctx: any): Promise<any>;
14
14
  /** 同步调用钩子函数 */
15
15
  callSync(name: string, ctx: any): any;
16
- toSnapshot(): {
16
+ getData(): {
17
17
  name: string;
18
18
  list: {
19
19
  pluginName?: string;
@@ -5,7 +5,7 @@ export class HookManager {
5
5
  app;
6
6
  constructor(app) {
7
7
  this.app = app;
8
- app.registerCommand("hook.snapshot", () => this.toSnapshot());
8
+ app.registerCommand("hook.getData", () => this.getData());
9
9
  }
10
10
  /** 挂载钩子函数 */
11
11
  use(name, call, options) {
@@ -64,7 +64,7 @@ export class HookManager {
64
64
  }
65
65
  return ctx;
66
66
  }
67
- toSnapshot() {
67
+ getData() {
68
68
  return [...this.list].map(([name, fnList]) => ({
69
69
  name,
70
70
  list: fnList.map(({ pluginName }) => ({ pluginName })),
@@ -6,11 +6,12 @@ import { UserInfo } from "./messageInfo.js";
6
6
  export declare abstract class LiveRoom extends CustomEventEmitter implements LiveRoomData {
7
7
  constructor();
8
8
  get valid(): true;
9
- get serviceId(): string;
9
+ get pending(): false;
10
+ get service(): string;
10
11
  /** 平台 */
11
12
  abstract readonly platform: string;
12
13
  /** api服务 */
13
- readonly service: string;
14
+ readonly serviceName: string;
14
15
  /** 房间id */
15
16
  abstract readonly id: string | number;
16
17
  /** 房间详情 */
@@ -60,11 +61,15 @@ export declare abstract class LiveRoom extends CustomEventEmitter implements Liv
60
61
  /** 无效房间 */
61
62
  export declare class InvalidLiveRoom implements LiveRoomData {
62
63
  get valid(): false;
63
- get serviceId(): string;
64
- constructor(serviceId: string, id: string | number);
64
+ get service(): string;
65
+ constructor(service: string, id: string | number, { pending, error }?: {
66
+ pending?: boolean | undefined;
67
+ error?: null | undefined;
68
+ });
65
69
  readonly platform: string;
66
70
  readonly id: string | number;
67
- readonly service: string;
71
+ readonly serviceName: string;
72
+ pending: boolean;
68
73
  detail: LiveRoomDetailInfo;
69
74
  stats?: LiveRoomStatsInfo;
70
75
  anchor: UserInfo;
@@ -73,6 +78,10 @@ export declare class InvalidLiveRoom implements LiveRoomData {
73
78
  connectionStatus: LiveConnectionStatus;
74
79
  openStatus: LiveRoomOpenStatus;
75
80
  liveId?: string;
81
+ error: {
82
+ code: string;
83
+ message: string;
84
+ } | null;
76
85
  get opened(): boolean;
77
86
  available: boolean;
78
87
  /** 生成房间数据 */
@@ -90,14 +99,16 @@ export interface LiveRoom {
90
99
  export interface LiveRoomData {
91
100
  /** 房间有效性 */
92
101
  valid: boolean;
102
+ /** 房间待定状态 */
103
+ pending: boolean;
93
104
  /** 平台id */
94
105
  platform: string;
95
106
  /** API服务 */
96
- service: string;
107
+ serviceName: string;
97
108
  /** 房间id */
98
109
  id: number | string;
99
110
  /** API服务id */
100
- serviceId: string;
111
+ service: string;
101
112
  /** 房间key */
102
113
  key: string;
103
114
  /** 基本信息 */
@@ -120,6 +131,11 @@ export interface LiveRoomData {
120
131
  opened: boolean;
121
132
  /** 房间是否可用 */
122
133
  available: boolean;
134
+ /** 错误信息 */
135
+ error?: {
136
+ code: string;
137
+ message: string;
138
+ } | null;
123
139
  }
124
140
  /** 房间展示信息 */
125
141
  export interface LiveRoomDetailInfo {
@@ -179,6 +195,8 @@ export declare const LiveRoomOpenStatus: {
179
195
  readonly opened: 2;
180
196
  };
181
197
  export type LiveRoomOpenStatus = EnumValue<typeof LiveRoomOpenStatus>;
198
+ export declare const LiveRoomValidStatus: {};
199
+ export type LiveRoomValidStatus = EnumValue<typeof LiveRoomValidStatus>;
182
200
  export interface LiveRoomEventMap {
183
201
  /** */
184
202
  status: {
package/dist/live/room.js CHANGED
@@ -7,11 +7,16 @@ export class LiveRoom extends CustomEventEmitter {
7
7
  get valid() {
8
8
  return true;
9
9
  }
10
- get serviceId() {
11
- return this.service ? `${this.platform}.${this.service}` : this.platform;
10
+ get pending() {
11
+ return false;
12
+ }
13
+ get service() {
14
+ return this.serviceName
15
+ ? `${this.platform}.${this.serviceName}`
16
+ : this.platform;
12
17
  }
13
18
  /** api服务 */
14
- service = "";
19
+ serviceName = "";
15
20
  /** 统计信息 */
16
21
  stats;
17
22
  /** 直播状态 */
@@ -81,8 +86,9 @@ export class LiveRoom extends CustomEventEmitter {
81
86
  toData() {
82
87
  return {
83
88
  valid: this.valid,
89
+ pending: this.pending,
84
90
  platform: this.platform,
85
- service: this.service,
91
+ serviceName: this.serviceName,
86
92
  id: this.id,
87
93
  detail: this.detail,
88
94
  stats: this.stats,
@@ -95,11 +101,11 @@ export class LiveRoom extends CustomEventEmitter {
95
101
  available: this.available,
96
102
  connectionStatus: this.connectionStatus,
97
103
  key: this.key,
98
- serviceId: this.serviceId,
104
+ service: this.service,
99
105
  };
100
106
  }
101
107
  get key() {
102
- return `${this.serviceId}:${this.id}`;
108
+ return `${this.service}:${this.id}`;
103
109
  }
104
110
  }
105
111
  /** 无效房间 */
@@ -107,18 +113,23 @@ export class InvalidLiveRoom {
107
113
  get valid() {
108
114
  return false;
109
115
  }
110
- get serviceId() {
111
- return this.service ? `${this.platform}.${this.service}` : this.platform;
116
+ get service() {
117
+ return this.serviceName
118
+ ? `${this.platform}.${this.serviceName}`
119
+ : this.platform;
112
120
  }
113
- constructor(serviceId, id) {
114
- const [platform, ...serviceIdArr] = serviceId.split(".");
121
+ constructor(service, id, { pending = false, error = null } = {}) {
122
+ const [platform, ...serviceIdArr] = service.split(".");
115
123
  this.platform = platform;
116
124
  this.id = id;
117
- this.service = serviceIdArr.join(".");
125
+ this.serviceName = serviceIdArr.join(".");
126
+ this.pending = pending;
127
+ this.error = error;
118
128
  }
119
129
  platform;
120
130
  id;
121
- service;
131
+ serviceName;
132
+ pending;
122
133
  detail = {};
123
134
  stats;
124
135
  anchor = { name: "", id: 0 };
@@ -127,6 +138,7 @@ export class InvalidLiveRoom {
127
138
  connectionStatus = LiveConnectionStatus.off;
128
139
  openStatus = 0;
129
140
  liveId;
141
+ error;
130
142
  get opened() {
131
143
  return this.openStatus == 2;
132
144
  }
@@ -135,8 +147,9 @@ export class InvalidLiveRoom {
135
147
  toData() {
136
148
  return {
137
149
  valid: this.valid,
150
+ pending: this.pending,
138
151
  platform: this.platform,
139
- service: this.service,
152
+ serviceName: this.serviceName,
140
153
  id: this.id,
141
154
  detail: this.detail,
142
155
  stats: this.stats,
@@ -148,12 +161,12 @@ export class InvalidLiveRoom {
148
161
  opened: this.opened,
149
162
  available: this.available,
150
163
  connectionStatus: this.connectionStatus,
151
- serviceId: this.serviceId,
164
+ service: this.service,
152
165
  key: this.key,
153
166
  };
154
167
  }
155
168
  get key() {
156
- return `${this.serviceId}:${this.id}`;
169
+ return `${this.service}:${this.id}`;
157
170
  }
158
171
  }
159
172
  /** 直播间状态 */
@@ -191,3 +204,4 @@ export const LiveRoomOpenStatus = {
191
204
  /** 已开启 */
192
205
  opened: 2,
193
206
  };
207
+ export const LiveRoomValidStatus = {};
@@ -1,5 +1,5 @@
1
1
  import { App } from "../../app.js";
2
- import type { CommandOptions, CommandCallOptions, CommandFunction, AppCommandMap } from "../../command/index.js";
2
+ import type { CommandOptions, CommandCallOptions, CommandFunction, AppCommandMap, AppCommandAliasMap } from "../../command/index.js";
3
3
  import { AppEventListener, AppEventEmitOptions, AppEventDetailMap } from "../../event/index.js";
4
4
  import { HookUseOptions, HookCallOptions, AppHookMap, HookFunction, HookContext } from "../../hook/index.js";
5
5
  import { AppValueMap, ValueContext, ValueOptions } from "../../value/index.js";
@@ -23,6 +23,7 @@ export declare class CommonPluginContext implements PluginContext {
23
23
  registerValue<K extends keyof AppValueMap>(name: K, options: ValueOptions<AppValueMap[K]>): ValueContext<AppValueMap[K]>;
24
24
  unregisterValue(name: string): void;
25
25
  registerCommand<T extends keyof AppCommandMap>(name: T, func: CommandFunction<AppCommandMap[T]>, options?: CommandOptions): void;
26
+ registerCommandAlias<T extends keyof AppCommandAliasMap>(name: T, targetName: AppCommandAliasMap[T], options?: CommandOptions): void;
26
27
  unregisterCommand(name: string): void;
27
28
  hasCommand(name: string): boolean;
28
29
  on<K extends keyof AppEventDetailMap>(type: K, listener: AppEventListener<AppEventDetailMap[K]>): void;
@@ -78,6 +78,10 @@ export class CommonPluginContext {
78
78
  this.#app.registerCommand(name, func, options);
79
79
  this.#registered.commands.add(name);
80
80
  }
81
+ registerCommandAlias(name, targetName, options) {
82
+ this.#app.registerCommandAlias(name, targetName, options);
83
+ this.#registered.commands.add(name);
84
+ }
81
85
  unregisterCommand(name) {
82
86
  this.#app.unregisterCommand(name);
83
87
  this.#registered.commands.delete(name);
@@ -22,7 +22,7 @@ export declare class PluginManager {
22
22
  whenRegister(pluginName: string, callback: WhenRegisterCallback): void;
23
23
  /** 取消插件已注册时的执行回调 */
24
24
  cancelWhenRegister(pluginName: string, callback: WhenRegisterCallback): void;
25
- toSnapshot(): {
25
+ getData(): {
26
26
  pluginName: string;
27
27
  }[];
28
28
  }
@@ -8,22 +8,20 @@ export class PluginManager {
8
8
  app;
9
9
  constructor(app) {
10
10
  this.app = app;
11
- app.registerCommand("plugin.snapshot", bindCommand(this.toSnapshot, this));
11
+ app.registerCommand("plugin.getData", bindCommand(this.getData, this));
12
12
  }
13
13
  registerSync(pluginConstructor, options = {}, { context, unremovable = false, accessApp = false, pluginType = "", } = {}) {
14
14
  const pluginName = pluginConstructor.pluginName;
15
15
  const role = pluginConstructor.role || "";
16
16
  if (!pluginName) {
17
17
  throw appError("plugin:register_id_missing", {
18
- message: "插件注册失败",
19
- reason: "插件缺少pluginName字段",
18
+ message: "插件注册失败: 插件缺少pluginName字段",
20
19
  target: "plugin/#unnamed",
21
20
  });
22
21
  }
23
22
  if (this.list.has(pluginName)) {
24
23
  throw appError("plugin:register_id_duplicate", {
25
- message: `插件注册失败: ${pluginName}`,
26
- reason: "已存在相同id的插件",
24
+ message: `插件注册失败[${pluginName}]: 已存在相同id的插件`,
27
25
  target: `plugin/${pluginName}`,
28
26
  });
29
27
  }
@@ -33,8 +31,7 @@ export class PluginManager {
33
31
  const ctx = this.app.callHookSync("plugin.register", registerCtx);
34
32
  if (ctx.defaultPrevented)
35
33
  throw appError("plugin:register_hook_prevented", {
36
- message: `插件注册失败: ${pluginName}`,
37
- reason: "插件注册被钩子函数阻止",
34
+ message: `插件注册失败${pluginName}: 插件注册被钩子函数阻止`,
38
35
  target: `plugin/${pluginName}`,
39
36
  });
40
37
  // 执行插件函数
@@ -84,15 +81,13 @@ export class PluginManager {
84
81
  const role = pluginConstructor.role || "";
85
82
  if (!pluginName) {
86
83
  throw appError("plugin:register_id_missing", {
87
- message: "插件注册失败",
88
- reason: "插件缺少pluginName字段",
84
+ message: "插件注册失败: 插件缺少pluginName字段",
89
85
  target: "plugin/#unnamed",
90
86
  });
91
87
  }
92
88
  if (this.list.has(pluginName)) {
93
89
  throw appError("plugin:register_id_duplicate", {
94
- message: `插件注册失败: ${pluginName}`,
95
- reason: "已存在相同id的插件",
90
+ message: `插件注册失败[${pluginName}]: 已存在相同id的插件`,
96
91
  target: `plugin/${pluginName}`,
97
92
  });
98
93
  }
@@ -103,8 +98,7 @@ export class PluginManager {
103
98
  .then(async (ctx) => {
104
99
  if (ctx.defaultPrevented)
105
100
  throw appError("plugin:register_hook_prevented", {
106
- message: `插件注册失败: ${pluginName}`,
107
- reason: "插件注册被钩子函数阻止",
101
+ message: `插件注册失败${pluginName}: 插件注册被钩子函数阻止`,
108
102
  target: `plugin/${pluginName}`,
109
103
  });
110
104
  // 执行插件函数
@@ -153,8 +147,7 @@ export class PluginManager {
153
147
  // 检测插件是否存在
154
148
  if (!pluginData) {
155
149
  throw appError("plugin:unregister_unexist", {
156
- message: `插件移除失败: ${pluginName}`,
157
- reason: "插件不存在",
150
+ message: `插件移除失败[${pluginName}]: 插件不存在`,
158
151
  target: `plugin/${pluginName}`,
159
152
  });
160
153
  }
@@ -162,8 +155,7 @@ export class PluginManager {
162
155
  const { plugin, context, unremovable, role } = pluginData;
163
156
  if (unremovable) {
164
157
  throw appError("plugin:unregister_unremovable", {
165
- message: `插件移除失败: ${pluginName}`,
166
- reason: "不可移除的插件",
158
+ message: `插件移除失败[${pluginName}]: 该插件已配置为不可移除`,
167
159
  target: `plugin/${pluginName}`,
168
160
  });
169
161
  }
@@ -231,7 +223,7 @@ export class PluginManager {
231
223
  callbackMap.delete(callback);
232
224
  }
233
225
  }
234
- toSnapshot() {
226
+ getData() {
235
227
  return [...this.list.keys()].map((n) => ({ pluginName: n }));
236
228
  }
237
229
  }
@@ -1,5 +1,5 @@
1
1
  import { App } from "../app.js";
2
- import { CommandOptions, CommandCallOptions, AppCommandMap, CommandFunction } from "../command/index.js";
2
+ import { CommandOptions, CommandCallOptions, AppCommandMap, CommandFunction, AppCommandAliasMap } from "../command/index.js";
3
3
  import { AppEventListener, AppEventEmitOptions, AppEventDetailMap } from "../event/index.js";
4
4
  import { AppHookMap, HookCallOptions, HookContext, HookFunction, HookUseOptions } from "../hook/index.js";
5
5
  import { AppValueMap, ValueContext, ValueOptions } from "../value/index.js";
@@ -88,9 +88,11 @@ export interface PluginContext {
88
88
  hasPlugin(pluginName: string): boolean;
89
89
  /** 注册指令 */
90
90
  registerCommand<T extends keyof AppCommandMap>(name: T, func: CommandFunction<AppCommandMap[T]>, options?: CommandOptions): void;
91
+ /** 注册指令别名,别名指令通常只作为手动输入指令的简写,不应在代码中直接使用 */
92
+ registerCommandAlias<T extends keyof AppCommandAliasMap>(name: T, targetName: AppCommandAliasMap[T], options?: CommandOptions): void;
91
93
  /** 注销指令 */
92
94
  unregisterCommand(name: string): void;
93
- /** 检测值是否存在 */
95
+ /** 检测指令是否存在 */
94
96
  hasCommand(name: string): boolean;
95
97
  /** 调用指令 */
96
98
  call<T extends keyof AppCommandMap>(name: T, ...args: Parameters<AppCommandMap[T]>): ReturnType<AppCommandMap[T]>;
@@ -1,8 +1,9 @@
1
- import { BasePlugin, LivePlatformInfo } from "../../index.js";
1
+ import { BasePlugin, LivePlatformInfo, PluginContext } from "../../index.js";
2
2
  interface PluginExposes {
3
3
  register(name: string, info: LivePlatformInfo, signal: AbortSignal): void;
4
4
  get(name: string): LivePlatformInfo | undefined;
5
- toSnapshot(): {
5
+ info(name: string): LivePlatformInfo | undefined;
6
+ getData(): {
6
7
  name: string;
7
8
  }[];
8
9
  }
@@ -19,8 +20,12 @@ declare module "../../index.js" {
19
20
  name: string;
20
21
  };
21
22
  }
23
+ interface AppCommandAliasMap {
24
+ platform: "platform.info";
25
+ }
22
26
  interface AppCommandMap {
23
- "platform.snapshot": () => {
27
+ "platform.info": (name: string) => LivePlatformInfo | undefined;
28
+ "platform.getData": () => {
24
29
  name: string;
25
30
  info: LivePlatformInfo;
26
31
  }[];
@@ -35,14 +40,17 @@ declare module "../../index.js" {
35
40
  export declare class Platform extends BasePlugin {
36
41
  static pluginName: string;
37
42
  private list;
43
+ init(ctx: PluginContext): void;
38
44
  /** 注册直播平台信息 */
39
45
  register(name: string, info: LivePlatformInfo, signal?: AbortSignal): void;
40
46
  /** 解除注册直播平台信息 */
41
47
  unregister(name: string): void;
42
- /** 获取直播平台信息 */
48
+ /** 直接获取直播平台信息 */
43
49
  get(name: string): LivePlatformInfo | undefined;
50
+ /** 获取直播平台信息 */
51
+ info(name: string): LivePlatformInfo | undefined;
44
52
  expose(): PluginExposes;
45
- toSnapshot(): {
53
+ getData(): {
46
54
  name: string;
47
55
  info: LivePlatformInfo;
48
56
  }[];
@@ -1,7 +1,13 @@
1
+ import { bindCommand } from "../../utils/index.js";
1
2
  import { appError, BasePlugin } from "../../index.js";
2
3
  export class Platform extends BasePlugin {
3
4
  static pluginName = "platform";
4
5
  list = new Map();
6
+ init(ctx) {
7
+ ctx.registerCommand("platform.getData", this.getData.bind(this));
8
+ ctx.registerCommand("platform.info", bindCommand(this.info, this));
9
+ ctx.registerCommandAlias("platform", "platform.info");
10
+ }
5
11
  /** 注册直播平台信息 */
6
12
  register(name, info, signal) {
7
13
  if (this.list.has(name)) {
@@ -13,7 +19,7 @@ export class Platform extends BasePlugin {
13
19
  if (signal) {
14
20
  signal.addEventListener("abort", () => {
15
21
  this.unregister(name);
16
- }, { once: true });
22
+ }, { once: true, signal: this.ctx.signal });
17
23
  }
18
24
  }
19
25
  /** 解除注册直播平台信息 */
@@ -25,20 +31,25 @@ export class Platform extends BasePlugin {
25
31
  }
26
32
  this.list.delete(name);
27
33
  }
28
- /** 获取直播平台信息 */
34
+ /** 直接获取直播平台信息 */
29
35
  get(name) {
30
36
  return this.list.get(name);
31
37
  }
38
+ /** 获取直播平台信息 */
39
+ info(name) {
40
+ return structuredClone(this.list.get(name));
41
+ }
32
42
  expose() {
33
43
  return {
34
44
  register: (name, info, signal) => {
35
45
  this.register(name, info, signal);
36
46
  },
37
47
  get: (name) => this.get(name),
38
- toSnapshot: () => this.toSnapshot(),
48
+ info: (name) => this.info(name),
49
+ getData: () => this.getData(),
39
50
  };
40
51
  }
41
- toSnapshot() {
52
+ getData() {
42
53
  return [...this.list].map(([name, info]) => ({ name, info }));
43
54
  }
44
55
  }
@@ -3,6 +3,9 @@ import { LiveRoom, LiveRoomDetailInfo, LiveRoomData, LiveRoomStatsInfo, LiveRoom
3
3
  import { BasePlugin } from "../../plugin/index.js";
4
4
  import { PluginContext } from "../../plugin/types.js";
5
5
  export interface RoomCreateOptions {
6
+ /** 允许立即添加房间,如果不能立即添加,则先添加待定状态的房间,以免房间添加顺序混乱或重复执行 */
7
+ allowPending?: boolean;
8
+ /** 允许在创建房间失败后,设置为无效房间 */
6
9
  allowInvalidRoom?: boolean;
7
10
  open?: boolean;
8
11
  [option: string]: any;
@@ -10,27 +13,41 @@ export interface RoomCreateOptions {
10
13
  interface PluginExposes {
11
14
  add(platform: string, id: number, options?: boolean | RoomCreateOptions): Promise<void>;
12
15
  remove(key: string): void;
13
- get(key: string): LiveRoom | InvalidLiveRoom | undefined;
14
- has(key: string): boolean;
15
- data(key: string): LiveRoomData | undefined;
16
- update(key: string): void;
16
+ move: (key: string, position: number) => void;
17
17
  open(key: string): void;
18
18
  close(key: string): void;
19
+ has(key: string): boolean;
20
+ info(key: string): LiveRoomData | null;
21
+ update(key: string): void;
22
+ validate: (key: string, options: RoomCreateOptions) => void;
23
+ invalidate: (key: string) => void;
24
+ getData(): LiveRoomData[];
25
+ get(key: string): LiveRoom | InvalidLiveRoom | undefined;
19
26
  getList(): (LiveRoom | InvalidLiveRoom)[];
20
27
  }
21
28
  declare module "../../index.js" {
29
+ interface AppCommandAliasMap {
30
+ add: "room.add";
31
+ remove: "room.remove";
32
+ move: "room.move";
33
+ open: "room.open";
34
+ close: "room.close";
35
+ update: "room.update";
36
+ room: "room.info";
37
+ }
22
38
  interface AppCommandMap {
23
- add: (platform: string, id: number, options?: boolean | RoomCreateOptions) => void;
24
- remove: (key: string) => void;
25
- move: (key: string, position: number) => void;
26
- open: (key: string) => void;
27
- close: (key: string) => void;
28
- update: (key: string) => void;
29
- "room.snapshot": () => LiveRoomData[];
39
+ "room.add": (platform: string, id: number, options?: boolean | RoomCreateOptions) => void;
40
+ "room.remove": (key: string) => void;
41
+ "room.move": (key: string, position: number) => void;
42
+ "room.open": (key: string) => void;
43
+ "room.close": (key: string) => void;
44
+ "room.update": (key: string) => void;
45
+ "room.info": (key: string) => LiveRoomData | null;
30
46
  "room.validate": (key: string, options: RoomCreateOptions) => void;
31
47
  "room.invalidate": (key: string) => void;
48
+ "room.getData": () => LiveRoomData[];
32
49
  [name: `${string}.room.create`]: (id: string | number, options: RoomCreateOptions) => LiveRoom | Promise<LiveRoom>;
33
- [name: `${string}.room.data`]: (id: string | number) => LiveRoomData | Promise<LiveRoomData>;
50
+ [name: `${string}.room.info`]: (id: string | number) => LiveRoomData | Promise<LiveRoomData>;
34
51
  }
35
52
  interface AppEventDetailMap {
36
53
  "live:message": {
@@ -76,6 +93,15 @@ declare module "../../index.js" {
76
93
  key: string;
77
94
  room: LiveRoomData;
78
95
  };
96
+ "room:replace": {
97
+ key: string;
98
+ room: LiveRoomData;
99
+ };
100
+ "room:changeKey": {
101
+ oldKey: string;
102
+ newKey: string;
103
+ room: LiveRoomData;
104
+ };
79
105
  "room:open": {
80
106
  key: string;
81
107
  room: LiveRoomData;
@@ -111,7 +137,7 @@ declare module "../../index.js" {
111
137
  message: LiveMessage.All;
112
138
  };
113
139
  "room.create": {
114
- serviceId: string;
140
+ service: string;
115
141
  id: string | number;
116
142
  options: RoomCreateOptions;
117
143
  };
@@ -139,9 +165,9 @@ export declare class Room extends BasePlugin {
139
165
  /** 绑定房间事件监听 */
140
166
  private bindEvent;
141
167
  /** 添加房间 */
142
- add(serviceId: string, id: number, options?: boolean | RoomCreateOptions): Promise<void>;
168
+ add(service: string, id: number, options?: boolean | RoomCreateOptions): Promise<void>;
143
169
  /** 创建房间实例 */
144
- create(serviceId: string, id: number | string, options?: RoomCreateOptions): Promise<LiveRoom | InvalidLiveRoom>;
170
+ create(service: string, id: number | string, options?: RoomCreateOptions): Promise<LiveRoom | InvalidLiveRoom>;
145
171
  /** 移除并销毁房间 */
146
172
  remove(key: string): void;
147
173
  /** 使无效房间生效 */
@@ -152,7 +178,7 @@ export declare class Room extends BasePlugin {
152
178
  get(key: string): LiveRoom | InvalidLiveRoom | undefined;
153
179
  has(key: string): boolean;
154
180
  /** 获取房间信息 */
155
- data(key: string): LiveRoomData | undefined;
181
+ info(key: string): LiveRoomData | null;
156
182
  /** 更新房间信息 */
157
183
  update(key: string): void;
158
184
  /** 获取房间key列表 */
@@ -165,7 +191,9 @@ export declare class Room extends BasePlugin {
165
191
  close(key: string): void;
166
192
  /** 更改某个房间的顺序 */
167
193
  move(key: string, position: number): void;
168
- /** 获取快照 */
169
- toSnapshot(): LiveRoomData[];
194
+ /** 在不更改列表排序的情况下更改某个房间的key,目前仅用于处理输入房间key与返回房间key不一致的特殊情况,不提供指令,通常情况下请勿使用该方法 */
195
+ changeKey(oldKey: string, newKey: string): void;
196
+ /** 获取当前数据 */
197
+ getData(): LiveRoomData[];
170
198
  }
171
199
  export default Room;
@@ -10,26 +10,38 @@ export class Room extends BasePlugin {
10
10
  */
11
11
  symbolAbortController = Symbol("room.abortController");
12
12
  init(ctx) {
13
- ctx.registerCommand("add", bindCommand(this.add, this));
14
- ctx.registerCommand("remove", bindCommand(this.remove, this));
15
- ctx.registerCommand("open", bindCommand(this.open, this));
16
- ctx.registerCommand("close", bindCommand(this.close, this));
17
- ctx.registerCommand("update", bindCommand(this.update, this));
18
- ctx.registerCommand("move", bindCommand(this.move, this));
19
- ctx.registerCommand("room.snapshot", bindCommand(this.toSnapshot, this));
13
+ ctx.registerCommand("room.add", bindCommand(this.add, this));
14
+ ctx.registerCommand("room.remove", bindCommand(this.remove, this));
15
+ ctx.registerCommand("room.move", bindCommand(this.move, this));
16
+ ctx.registerCommand("room.open", bindCommand(this.open, this));
17
+ ctx.registerCommand("room.close", bindCommand(this.close, this));
18
+ ctx.registerCommand("room.update", bindCommand(this.update, this));
19
+ ctx.registerCommand("room.info", bindCommand(this.info, this));
20
20
  ctx.registerCommand("room.validate", bindCommand(this.validate, this));
21
21
  ctx.registerCommand("room.invalidate", bindCommand(this.invalidate, this));
22
+ ctx.registerCommand("room.getData", bindCommand(this.getData, this));
23
+ ctx.registerCommandAlias("add", "room.add");
24
+ ctx.registerCommandAlias("remove", "room.remove");
25
+ ctx.registerCommandAlias("move", "room.move");
26
+ ctx.registerCommandAlias("open", "room.open");
27
+ ctx.registerCommandAlias("close", "room.close");
28
+ ctx.registerCommandAlias("update", "room.update");
29
+ ctx.registerCommandAlias("room", "room.info");
22
30
  }
23
31
  expose() {
24
32
  return {
25
33
  add: this.add.bind(this),
26
34
  remove: this.remove.bind(this),
27
- get: this.get.bind(this),
28
- has: this.has.bind(this),
29
- data: this.data.bind(this),
30
- update: this.update.bind(this),
35
+ move: this.move.bind(this),
31
36
  open: this.open.bind(this),
32
37
  close: this.close.bind(this),
38
+ has: this.has.bind(this),
39
+ update: this.update.bind(this),
40
+ info: this.info.bind(this),
41
+ validate: this.validate.bind(this),
42
+ invalidate: this.invalidate.bind(this),
43
+ getData: this.getData.bind(this),
44
+ get: this.get.bind(this),
33
45
  getList: this.getList.bind(this),
34
46
  };
35
47
  }
@@ -139,39 +151,102 @@ export class Room extends BasePlugin {
139
151
  });
140
152
  }
141
153
  /** 添加房间 */
142
- async add(serviceId, id, options) {
154
+ async add(service, id, options) {
143
155
  const opt = typeof options == "boolean" ? { open: options } : options || {};
144
- const room = await this.create(serviceId, id, opt);
145
- this.attach(room);
156
+ if (opt.allowPending) {
157
+ const promiseRoom = this.create(service, id, opt);
158
+ await Promise.race([promiseRoom, 0]).then(async (result) => {
159
+ if (result === 0) {
160
+ // pending: 房间尚未创建完毕
161
+ // 先添加一个待定状态的房间,以免房间添加顺序混乱或重复执行
162
+ const pendingRoom = new InvalidLiveRoom(service, id);
163
+ this.attach(pendingRoom);
164
+ // 等待房间创建完毕后,再用真正的房间实例替换掉待定房间
165
+ const room = await promiseRoom.catch((e) => {
166
+ // 如果创建房间失败且不返回无效房间,则直接移除待定房间,并抛出错误
167
+ this.detach(pendingRoom.key);
168
+ throw e;
169
+ });
170
+ // 如果房间key与待定房间key不一致,则更改房间key(通常是因为输入的房间key与实际返回的房间key不一致的特殊情况),并触发 changeKey 事件
171
+ if (pendingRoom.key != room.key) {
172
+ // 更改房间数据以匹配实际返回的房间key
173
+ pendingRoom.platform = room.platform;
174
+ pendingRoom.id = room.id;
175
+ // 更改列表中的房间key
176
+ this.changeKey(pendingRoom.key, room.key);
177
+ }
178
+ // 用真正的房间实例替换掉待定房间
179
+ this.map.set(pendingRoom.key, room);
180
+ if (room.valid) {
181
+ this.bindEvent(room);
182
+ if (opt.open) {
183
+ room.open();
184
+ }
185
+ // 如果房间有效,则触发 validate 事件
186
+ this.ctx.emit("room:validate", {
187
+ key: room.key,
188
+ room: room.toData(),
189
+ });
190
+ }
191
+ else {
192
+ // 如果房间无效,则触发 invalidate 事件
193
+ this.ctx.emit("room:invalidate", {
194
+ key: room.key,
195
+ room: room.toData(),
196
+ });
197
+ }
198
+ }
199
+ else {
200
+ // fulfilled: 房间已经立即创建完毕
201
+ this.attach(result, opt.open);
202
+ }
203
+ });
204
+ }
205
+ else {
206
+ const room = await this.create(service, id, opt);
207
+ this.attach(room, opt.open);
208
+ }
146
209
  }
147
210
  /** 创建房间实例 */
148
- async create(serviceId, id, options = {}) {
149
- const ctx = { serviceId, id, options };
150
- const res = await this.ctx.callHook("room.create", ctx).catch((reason) => {
151
- throw appError("room:create_hook_error", {
152
- message: `无法创建房间监听实例[${serviceId}:${id}]:调用钩子函数出错`,
153
- target: `room/${serviceId}:${id}`,
154
- });
155
- });
156
- if (res.defaultPrevented) {
157
- throw appError("room:create_hook_prevented", {
158
- message: `无法创建房间监听实例[${serviceId}:${id}]:房间添加被钩子函数阻止`,
159
- target: `room/${serviceId}:${id}`,
211
+ async create(service, id, options = {}) {
212
+ const ctx = { service, id, options };
213
+ try {
214
+ const res = await this.ctx
215
+ .callHook("room.create", ctx)
216
+ .catch((reason) => {
217
+ throw appError("room:create_hook_error", {
218
+ message: `无法创建房间监听实例[${service}:${id}]: 调用钩子函数出错`,
219
+ target: `room/${service}:${id}`,
220
+ });
160
221
  });
222
+ if (res.defaultPrevented) {
223
+ throw appError("room:create_hook_prevented", {
224
+ message: `无法创建房间监听实例[${service}:${id}]: 房间添加被钩子函数阻止`,
225
+ target: `room/${service}:${id}`,
226
+ });
227
+ }
228
+ }
229
+ catch (e) {
230
+ if (options.allowInvalidRoom) {
231
+ return new InvalidLiveRoom(service, id);
232
+ }
233
+ else {
234
+ throw e;
235
+ }
161
236
  }
162
237
  let room;
163
238
  try {
164
- room = await this.ctx.call(`${serviceId}.room.create`, id, options);
239
+ room = await this.ctx.call(`${service}.room.create`, id, options);
165
240
  }
166
241
  catch (e) {
167
242
  if (options.allowInvalidRoom) {
168
- room = new InvalidLiveRoom(serviceId, id);
243
+ room = new InvalidLiveRoom(service, id);
169
244
  }
170
245
  else {
171
246
  throw appError("room:create_fail", {
172
- message: `创建房间监听实例失败[${serviceId}:${id}]`,
247
+ message: `创建房间监听实例失败[${service}:${id}]`,
173
248
  reason: e,
174
- target: `room/${serviceId}:${id}`,
249
+ target: `room/${service}:${id}`,
175
250
  });
176
251
  }
177
252
  }
@@ -208,8 +283,8 @@ export class Room extends BasePlugin {
208
283
  target: `room/${key}`,
209
284
  });
210
285
  }
211
- const { serviceId, id } = invalidRoom;
212
- const room = await this.create(serviceId, id, {
286
+ const { service, id } = invalidRoom;
287
+ const room = await this.create(service, id, {
213
288
  ...options,
214
289
  allowInvalidRoom: false,
215
290
  });
@@ -236,8 +311,8 @@ export class Room extends BasePlugin {
236
311
  });
237
312
  }
238
313
  // 用无效房间替换掉原房间
239
- const { serviceId, id } = room;
240
- const invalidRoom = new InvalidLiveRoom(serviceId, id);
314
+ const { service, id } = room;
315
+ const invalidRoom = new InvalidLiveRoom(service, id);
241
316
  this.map.set(key, invalidRoom);
242
317
  // 移除插件实例对原房间的所有监听
243
318
  room[this.symbolAbortController]?.abort();
@@ -262,9 +337,9 @@ export class Room extends BasePlugin {
262
337
  return this.map.has(key);
263
338
  }
264
339
  /** 获取房间信息 */
265
- data(key) {
340
+ info(key) {
266
341
  let room = this.map.get(key);
267
- return room ? room.toData() : undefined;
342
+ return room?.toData() || null;
268
343
  }
269
344
  /** 更新房间信息 */
270
345
  update(key) {
@@ -328,8 +403,27 @@ export class Room extends BasePlugin {
328
403
  this.map = new Map(arr);
329
404
  this.ctx.emit("room:move", { key, position });
330
405
  }
331
- /** 获取快照 */
332
- toSnapshot() {
406
+ /** 在不更改列表排序的情况下更改某个房间的key,目前仅用于处理输入房间key与返回房间key不一致的特殊情况,不提供指令,通常情况下请勿使用该方法 */
407
+ changeKey(oldKey, newKey) {
408
+ const arr = [...this.map];
409
+ const index = arr.findIndex(([k]) => k == oldKey);
410
+ if (index == -1) {
411
+ throw appError("room:changekey_unexist", {
412
+ message: "要更改key的房间不存在",
413
+ target: `room/${oldKey}`,
414
+ });
415
+ }
416
+ let room = arr[index][1];
417
+ arr[index][0] = newKey;
418
+ this.map = new Map(arr);
419
+ this.ctx.emit("room:changeKey", {
420
+ oldKey,
421
+ newKey,
422
+ room: room.toData(),
423
+ });
424
+ }
425
+ /** 获取当前数据 */
426
+ getData() {
333
427
  return this.getList().map((room) => room.toData());
334
428
  }
335
429
  }
@@ -20,7 +20,7 @@ export declare class ValueManager {
20
20
  watch(name: string, listener: (value: any) => void): void;
21
21
  unwatch(name: string, listener: (value: any) => void): void;
22
22
  /** 获取注册的所有值 */
23
- toSnapshot(): {
23
+ getData(): {
24
24
  name: string;
25
25
  value: string;
26
26
  }[];
@@ -5,7 +5,7 @@ export class ValueManager {
5
5
  app;
6
6
  constructor(app) {
7
7
  this.app = app;
8
- app.registerCommand("value.snapshot", bindCommand(this.toSnapshot, this));
8
+ app.registerCommand("value.getData", bindCommand(this.getData, this));
9
9
  }
10
10
  /** 注册值 */
11
11
  register(name, { get, set, pluginName }) {
@@ -61,7 +61,7 @@ export class ValueManager {
61
61
  this.app.off(`change:${name}`, listener);
62
62
  }
63
63
  /** 获取注册的所有值 */
64
- toSnapshot() {
64
+ getData() {
65
65
  console.log(this);
66
66
  return [...this.list].map(([name, config]) => ({
67
67
  name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floating-live",
3
- "version": "0.17.0-alpha.12",
3
+ "version": "0.17.0-alpha.13",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",