feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useCallback, useEffect, useRef } from 'react';
import { useMemoizedFn } from 'ahooks';
import { URI, useIDEService } from '@coze-project-ide/client';
import { getURLByURI } from '../utils';
import { MessageEventService, type MessageEvent } from '../services';
import { URI_SCHEME } from '../constants';
import { useIDENavigate } from './use-ide-navigate';
export const useMessageEventService = () =>
useIDEService<MessageEventService>(MessageEventService);
/**
* 获取向 widget 发送信息函数的 hooks
*/
export const useSendMessageEvent = () => {
const messageEventService = useMessageEventService();
const navigate = useIDENavigate();
/**
* 向以 uri 为索引的 widget 发送信息
*/
const send = useCallback(
<T>(target: string | URI, data: MessageEvent<T>) => {
const uri =
typeof target === 'string'
? new URI(`${URI_SCHEME}://${target}`)
: target;
messageEventService.send(uri, data);
},
[messageEventService],
);
/**
* 向以 uri 为索引的 widget 发送信息,并且打开/激活此 widget
* 此函数比较常用
*/
const sendOpen = useCallback(
<T>(target: string | URI, data: MessageEvent<T>) => {
const uri =
typeof target === 'string'
? new URI(`${URI_SCHEME}://${target}`)
: target;
messageEventService.send(uri, data);
navigate(getURLByURI(uri));
},
[messageEventService, navigate],
);
return { send, sendOpen };
};
/**
* 监听向指定 uri 对应的唯一 widget 发送消息的 hook
* 监听消息的 widget 一定是知道 this.uri所以入参无须支持 string
* 注:虽然 widget.uri 的值是会变得,但其 withoutQuery().toString() 一定是不变的,所以 uri 可以认定为不变
*/
export const useListenMessageEvent = (
uri: URI,
cb: (e: MessageEvent) => void,
) => {
const messageEventService = useMessageEventService();
// 尽管 uri 对应的唯一 key 不会变化,但 uri 内存地址仍然会变化,这里显式的固化 uri 的不变性
const uriRef = useRef(uri);
// 保证 callback 函数的可变性
const listener = useMemoizedFn(() => {
const queue = messageEventService.on(uri);
queue.forEach(cb);
});
useEffect(() => {
// 组件挂在时去队列中取一次,有可能在组件未挂载前已经被发送了消息
listener();
const disposable = messageEventService.onSend(e => {
if (messageEventService.compare(e.uri, uriRef.current)) {
listener();
}
});
return () => disposable.dispose();
}, [messageEventService, listener, uriRef]);
};