Ably 空间 SDK
这个 空间 SDK 包含一组目的构建的 API , 帮助您为您的应用程序构建协作环境, 以快速实现远程团队协作 。 试试看 现场演示 以SDK为动力的实时协作实例.

亚伯利 是全世界500多家公司开发商使用的可扩展和5个9s可靠中间软件,用于快速建立实时应用程序——从合作经验和直播到数据广播和通知。 在其全球分布的基础设施的支持下,Ably为各种编程语言和平台提供了25个SDK,以及合作伙伴与Datadog,Kafka,Vercel等技术的融合,这些技术加速了实时经验的提供.
实时协作
事实证明,不需通过调用协调资源,或利用各种工具来回发送文件和电子表格,而是具有实时应用合作的特性,可以提高偏远工作场所的生产力。 这些功能使最终用户能够了解应用程序内其他用户的背景。 这意味着知道:
申请中是谁?
合作最重要的方面之一是知道你还和谁合作。 最常用的显示方法是使用"Avatar Stack"来显示目前还有谁在线,以及最近下线的人.
应用程序中的每个用户在哪里?
了解每个用户在应用程序中的位置可以帮助您理解他们的用意,而无需明确询问他们. 例如,看到一名同事目前正在观看演示文稿甲板的幻灯片2,意味着你可以进行自己的编辑工作来进行幻灯片3,而不会干扰他们的工作. 显示用户的位置可以通过以下方式实现:突出显示他们所选择的UI元素,在他们正在观看的幻灯片上显示一个微型浮雕堆栈,或者显示他们光标的活地位置. 在"太空",我们称之为"成员位置".
每个人在申请中做什么?
用户对app状态的修改不仅需要与你的后端同步进行验证和长期存储,而且还需要立即在UI中被反映,以便用户总是查看最新的信息. 例如,在电子表格应用程序中,如果一个用户在单元格中输入了值,所有其他用户需要立即看到这一变化. Pub/Sub Channels帮助在合作空间灵活地直播最新消息.
SDK 发展状况
目前正在开发SDK空间。 如果你有兴趣成为一个早期的收养人 并提供反馈,那么你可以 注册 欢迎提前进入 给我们反馈。 。 。 .
下一节介绍如何使用SDK. 或者,您可以跳转到:
先决条件
要开始使用此 SDK, 您需要以下操作 :
- 一个Ably账户
- 你们可以 注册 以至宽宏大量.
- Ably API 密钥
安装和认证
从早期版本升级吗 ? 见 升级指南。 。 。 .
备选方案1:利用国家预防机制
安装 Ably Pub/Sub SDK 和 SDK 空间 :
npm install @ably/pubsub-device @ably/spaces
要即时化 SDK 空间,创建 Ably 客户端 并传递给 createSpacesClient()数字 :
import { createSpacesClient } from '@ably/spaces';
import { createClient } from '@ably/pubsub-device';
const client = createClient({ key: "<API-key>", clientId: "<client-ID>" });
const spaces = createSpacesClient(client);
你用得着 基本认证 即直接用于测试目的的 API 密钥, 但强烈建议您使用 符号认证 在生产环境中.
要使用空格,您还必须设置 clientId 以便客户可以识别。 如果你是原型的,你可以使用像 纳米 生成一个ID.
备选案文2:使用CDN
您也可以使用带CDN的 Spaces, 例如 (单位:公斤)数字 :
<script src="https://cdn.ably.com/lib/ably.min-3.js"></script>
<script src="https://cdn.ably.com/spaces/0.6.0/iife/index.bundle.js"></script>
在此之后,以上述国家防范机制备选方案的同样方式,即时宣布SDK:
const client = AblyPubSub.createClient({ key: "<API-key>", clientId: "<client-ID>" });
const spaces = AblySpaces.createSpacesClient(client);
反应开发者的空格
一套反应钩可供任何反应应用程序使用,使其无缝。 见 React Hooks 文档 详细情况.
创建新空间
一个空间是您应用程序的虚拟区域, 您可以在此启用同步协作 。 一个空格可以是网页、电子表格内的工作表、幻灯片放映中的单个幻灯片,或者幻灯片放映本身。 一个空间有一个参与者状态,包含在线和最近留下的成员,他们的配置细节,位置和他们为UI组件获得的任何锁.
创建空格并订阅对参与者状态的任何更新.
// Create a new space
const space = await spaces.get('demoSlideshow');
// Subscribe to space state events
space.subscribe('update', (spaceState) => {
console.log(spaceState.members);
});
// Enter a space, publishing an update event, including optional profile data
await space.enter({
username: 'Claire Lemons',
avatar: 'https://slides-internal.com/users/clemons.png',
});
以下是用户进入空间时用户收到的事件有效载荷的例子:
[
{
"clientId": "clemons#142",
"connectionId": "hd9743gjDc",
"isConnected": true,
"lastEvent": {
"name": "enter",
"timestamp": 1677595689759
},
"location": null,
"profileData": {
"username": "Claire Lemons",
"avatar": "https://slides-internal.com/users/clemons.png"
}
}
]
空间成员
这个 members 命名空间包含用于构建avatar堆栈的方法. 订阅进入、离开、离开空间(超时后)或更新其配置信息的成员.
// Subscribe to all member events in a space
space.members.subscribe((memberUpdate) => {
console.log(memberUpdate);
});
// Subscribe to member enter events only
space.members.subscribe('enter', (memberJoined) => {
console.log(memberJoined);
});
// Subscribe to member leave events only
space.members.subscribe('leave', (memberLeft) => {
console.log(memberLeft);
});
// Subscribe to member remove events only
space.members.subscribe('remove', (memberRemoved) => {
console.log(memberRemoved);
});
// Subscribe to profile updates on members only
space.members.subscribe('updateProfile', (memberProfileUpdated) => {
console.log(memberProfileUpdated);
});
// Subscribe to all updates to members
space.members.subscribe('update', (memberUpdate) => {
console.log(memberUpdate);
});
以下是用户在某一空间更新成员时收到的事件有效载荷的例子:
{
"clientId": "clemons#142",
"connectionId": "hd9743gjDc",
"isConnected": true,
"lastEvent": {
"name": "enter",
"timestamp": 1677595689759
},
"location": null,
"profileData": {
"username": "Claire Lemons",
"avatar": "https://slides-internal.com/users/clemons.png"
}
}
获取空间成员的快照
空间成员拥有获取成员国当前快照的方法:
// Get all members in a space
const allMembers = await space.members.getAll();
// Get your own member object
const myMemberInfo = await space.members.getSelf();
// Get everyone else's member object but yourself
const othersMemberInfo = await space.members.getOthers();
成员地点
这个 locations 命名空间包含用于构建成员位置的方法,使您能够跟踪应用程序中的用户位置。 一个位置可以是窗体字段,电子表格中的多个单元格或者幻灯片甲板编辑器中的幻灯片.
// You need to enter a space before publishing your location
await space.enter({
username: 'Claire Lemons',
avatar: 'https://slides-internal.com/users/clemons.png',
});
// Publish your location based on the UI element selected
await space.locations.set({ slide: '3', component: 'slide-title' });
// Subscribe to location events from all members in a space
space.locations.subscribe('update', (locationUpdate) => {
console.log(locationUpdate);
});
以下是用户在成员改变位置时收到的事件有效载荷的例子:
{
"member": {
"clientId": "clemons#142",
"connectionId": "hd9743gjDc",
"isConnected": true,
"profileData": {
"username": "Claire Lemons",
"avatar": "https://slides-internal.com/users/clemons.png"
},
"location": {
"slide": "3",
"component": "slide-title"
},
"lastEvent": {
"name": "update",
"timestamp": 1
}
},
"previousLocation": {
"slide": "2",
"component": null
},
"currentLocation": {
"slide": "3",
"component": "slide-title"
}
}
获取成员位置的快照
成员地点有方法获取当前成员国的快照:
// Get a snapshot of all the member locations
const allLocations = await space.locations.getAll();
// Get a snapshot of my location
const myLocation = await space.locations.getSelf();
// Get a snapshot of everyone else's locations
const othersLocations = await space.locations.getOthers();
活光标
这个 cursors 命名空间包含用于构建活光标的方法,允许您在应用程序中跟踪成员指针位置的更新。 事件还可以包括相关数据,如指针属性和关联的UI元素的ID:
// You need to enter a space before publishing your cursor updates
await space.enter({
username: 'Claire Lemons',
avatar: 'https://slides-internal.com/users/clemons.png',
});
// Subscribe to events published on "mousemove" by all members
space.cursors.subscribe('update', (cursorUpdate) => {
console.log(cursorUpdate);
});
// Publish a your cursor position on "mousemove" including optional data
window.addEventListener('mousemove', ({ clientX, clientY }) => {
space.cursors.set({ position: { x: clientX, y: clientY }, data: { color: 'red' } });
});
以下是用户在移动光标时收到的事件有效载荷的例子:
{
"connectionId": "hd9743gjDc",
"clientId": "clemons#142",
"position": { "x": 864, "y": 32 },
"data": { "color": "red" }
}
获取成员光标的快照
成员光标有获取成员国当前快照的方法:
// Get a snapshot of all the cursors
const allCursors = await space.cursors.getAll();
// Get a snapshot of my cursor
const myCursor = await space.cursors.getSelf();
// Get a snapshot of everyone else's cursors
const othersCursors = await space.cursors.getOthers();
组件锁定
在成员编辑的同时使用组件锁定 API 锁定状态组件,以减少出现相冲突修改的可能性 .
锁用独特的字符串识别出,"Spaces SDK"认为,在任何特定时间,一个成员最多持有一个带有给定字符串的锁.
组件锁定 API 支持四个操作:查询,获取,发布,以及订阅.
查询
space.locks.get 用于查询当前锁定标识符是否以及由谁锁定。 它返回一个 Lock 类型,其字段如下:
type Lock = {
id: string;
status: LockStatus;
member: SpaceMember;
timestamp: number;
attributes?: LockAttributes;
reason?: Types.ErrorInfo;
};
例如:
// check if the id is locked
const isLocked = space.locks.get(id) !== undefined;
// check which member has the lock
const { member } = space.locks.get(id);
// check the lock attributes assigned by the member holding the lock
const { attributes } = space.locks.get(id);
const value = attributes.get(key);
space.locks.getAll 返回当前锁定为数组的所有锁定标识符 Lock数字 :
const allLocks = space.locks.getAll();
for (const lock of allLocks) {
// ...
}
获取
space.locks.acquire 请求使用存在获取锁.
它返回一个承诺,一旦发出存在请求,它就会解决.
const req = await space.locks.acquire(id);
// or with some attributes
const attributes = new Map();
attributes.set('key', 'value');
const req = await space.locks.acquire(id, { attributes });
如果锁定请求已经存在, 它会丢出一个错误 pending 或者说 locked。 。 。 .
释放
space.locks.release 通过将其从存在中去除而释放出先前要求的锁.
它返回一个承诺,一旦发出存在请求,它就会解决.
await space.locks.release(id);
订阅
space.locks.subscribe 赞同所有成员的锁状态变化.
调用时使用类型值 Lock。 。 。 .
space.locks.subscribe('update', (lock) => {
// lock.member is the requesting member
// lock.request is the request made by the member
});
// or with destructuring:
space.locks.subscribe('update', ({ member, request }) => {
// request.status is the status of the request, one of PENDING, LOCKED, or UNLOCKED
// request.reason is an ErrorInfo if the status is UNLOCKED
});
这种变化发生于:
- (单位:千美元)
pending请求向locked因为请求成员现在持有锁 - (单位:千美元)
pending请求向unlocked因为请求成员不持有锁 因为另一个成员已经持有锁 - (单位:千美元)
locked请求向unlocked因为锁不是被同时提出的优先请求释放就是无效 - a 一个
unlocked请求向locked因为请求成员重新获得锁