mirror of
https://github.com/fluencelabs/fluent-pad
synced 2025-04-25 08:52:14 +00:00
Users list with online statuses syncrhonization works
This commit is contained in:
parent
4879878e9f
commit
735c5cbe0c
@ -3,35 +3,38 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { connect } from 'src/fluence';
|
import { connect } from 'src/fluence';
|
||||||
|
|
||||||
import './App.scss';
|
import './App.scss';
|
||||||
import { FluenceClientContext } from './FluenceClientContext';
|
import { FluenceClientContext, useFluenceClient } from './FluenceClientContext';
|
||||||
import { UserList } from './UserList';
|
import { UserList } from './UserList';
|
||||||
import * as calls from 'src/fluence/calls';
|
import * as calls from 'src/fluence/calls';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [client, setClient] = useState<FluenceClient | null>(null);
|
const [client, setClient] = useState<FluenceClient | null>(null);
|
||||||
const [isConnected, setIsConnected] = useState<boolean>(false);
|
const [isInRoom, setIsInRoom] = useState<boolean>(false);
|
||||||
const [isInRoom, setIsInRoom] = useState(false);
|
|
||||||
const [nickName, setNickName] = useState('myNickName');
|
const [nickName, setNickName] = useState('myNickName');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fn = async () => {
|
const fn = async () => {
|
||||||
const c = await connect();
|
const c = await connect();
|
||||||
setIsConnected(true);
|
|
||||||
setClient(c);
|
setClient(c);
|
||||||
};
|
};
|
||||||
// fn();
|
fn();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const joinRoom = async () => {
|
const joinRoom = async () => {
|
||||||
const c = await connect();
|
if (!client) {
|
||||||
setIsConnected(true);
|
return;
|
||||||
setClient(c);
|
}
|
||||||
await calls.joinRoom(nickName);
|
|
||||||
|
await calls.joinRoom(client, nickName);
|
||||||
setIsInRoom(true);
|
setIsInRoom(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const leaveRoom = async () => {
|
const leaveRoom = async () => {
|
||||||
await calls.leaveRoom();
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await calls.leaveRoom(client);
|
||||||
setIsInRoom(false);
|
setIsInRoom(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,7 +42,7 @@ const App = () => {
|
|||||||
<FluenceClientContext.Provider value={client}>
|
<FluenceClientContext.Provider value={client}>
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<div>
|
<div>
|
||||||
<div>Connection status: {isConnected ? 'connected' : 'disconnected'}</div>
|
<div>Connection status: {client ? 'connected' : 'disconnected'}</div>
|
||||||
<div>
|
<div>
|
||||||
<label>Nickname: </label>
|
<label>Nickname: </label>
|
||||||
<input
|
<input
|
||||||
@ -53,7 +56,7 @@ const App = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button disabled={isInRoom} onClick={joinRoom}>
|
<button disabled={isInRoom || !client} onClick={joinRoom}>
|
||||||
Join Room
|
Join Room
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -64,7 +67,7 @@ const App = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>{isConnected && client && isInRoom && <UserList />}</div>
|
<div>{isInRoom && client && <UserList selfName={nickName} />}</div>
|
||||||
</div>
|
</div>
|
||||||
</FluenceClientContext.Provider>
|
</FluenceClientContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -28,7 +28,7 @@ type PeerId = string;
|
|||||||
|
|
||||||
const refreshTimeoutMs = 7000;
|
const refreshTimeoutMs = 7000;
|
||||||
|
|
||||||
export const UserList = () => {
|
export const UserList = (props: { selfName: string }) => {
|
||||||
const client = useFluenceClient()!;
|
const client = useFluenceClient()!;
|
||||||
const [users, setUsers] = useState<Map<PeerId, User>>(new Map());
|
const [users, setUsers] = useState<Map<PeerId, User>>(new Map());
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ export const UserList = () => {
|
|||||||
calls.updateOnlineStatuses(client);
|
calls.updateOnlineStatuses(client);
|
||||||
}, refreshTimeoutMs);
|
}, refreshTimeoutMs);
|
||||||
|
|
||||||
subscribeToEvent(client, fluentPadServiceId, notifyUserAddedFnName, (args, _) => {
|
const unsub1 = subscribeToEvent(client, fluentPadServiceId, notifyUserAddedFnName, (args, _) => {
|
||||||
const users = args.flatMap((x) => x).flatMap((x) => x) as calls.User[];
|
const users = args.flatMap((x) => x).flatMap((x) => x) as calls.User[];
|
||||||
setUsers((prev) => {
|
setUsers((prev) => {
|
||||||
const result = new Map(prev);
|
const result = new Map(prev);
|
||||||
@ -54,29 +54,31 @@ export const UserList = () => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isCurrentUser = u.peer_id === client.selfPeerId.toB58String();
|
||||||
|
|
||||||
result.set(u.peer_id, {
|
result.set(u.peer_id, {
|
||||||
name: u.name,
|
name: u.name,
|
||||||
id: u.peer_id,
|
id: u.peer_id,
|
||||||
isOnline: false,
|
isOnline: isCurrentUser,
|
||||||
shouldBecomeOnline: false,
|
shouldBecomeOnline: isCurrentUser,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
subscribeToEvent(client, fluentPadServiceId, notifyUserRemovedFnName, (args, _) => {
|
const unsub2 = subscribeToEvent(client, fluentPadServiceId, notifyUserRemovedFnName, (args, _) => {
|
||||||
const users = args.flatMap((x) => x) as calls.User[];
|
const users = args.flatMap((x) => x) as PeerId[];
|
||||||
setUsers((prev) => {
|
setUsers((prev) => {
|
||||||
const result = new Map(prev);
|
const result = new Map(prev);
|
||||||
for (let u of users) {
|
for (let u of users) {
|
||||||
result.delete(u.peer_id);
|
result.delete(u);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsub = subscribeToEvent(client, fluentPadServiceId, notifyOnlineFnName, (args, _) => {
|
const unsub3 = subscribeToEvent(client, fluentPadServiceId, notifyOnlineFnName, (args, _) => {
|
||||||
const [[peerId], immediately] = args;
|
const [[peerId], immediately] = args;
|
||||||
setUsers((prev) => {
|
setUsers((prev) => {
|
||||||
const result = new Map(prev);
|
const result = new Map(prev);
|
||||||
@ -94,11 +96,14 @@ export const UserList = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// don't block
|
// don't block
|
||||||
calls.getInitialUserList(client);
|
calls.getUserList(client);
|
||||||
|
calls.notifySelfAdded(client, props.selfName);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(listRefreshTimer);
|
clearTimeout(listRefreshTimer);
|
||||||
unsub();
|
unsub1();
|
||||||
|
unsub2();
|
||||||
|
unsub3();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
historyServiceId,
|
historyServiceId,
|
||||||
notifyOnlineFnName,
|
notifyOnlineFnName,
|
||||||
notifyUserAddedFnName,
|
notifyUserAddedFnName,
|
||||||
|
notifyUserRemovedFnName,
|
||||||
servicesNodePid,
|
servicesNodePid,
|
||||||
userListServiceId,
|
userListServiceId,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
@ -40,7 +41,13 @@ const throwIfError = (result: ServiceResult) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const notifyOnlineStatusesAir = `
|
export const updateOnlineStatuses = async (client: FluenceClient) => {
|
||||||
|
const particle = new Particle(
|
||||||
|
`
|
||||||
|
(seq
|
||||||
|
(call myRelay ("op" "identity") [])
|
||||||
|
(seq
|
||||||
|
(call node (userlist "get_users") [] allUsers)
|
||||||
(fold allUsers.$.users! u
|
(fold allUsers.$.users! u
|
||||||
(par
|
(par
|
||||||
(seq
|
(seq
|
||||||
@ -59,16 +66,6 @@ const notifyOnlineStatusesAir = `
|
|||||||
(next u)
|
(next u)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
`;
|
|
||||||
|
|
||||||
export const updateOnlineStatuses = async (client: FluenceClient) => {
|
|
||||||
const particle = new Particle(
|
|
||||||
`
|
|
||||||
(seq
|
|
||||||
(call myRelay ("op" "identity") [])
|
|
||||||
(seq
|
|
||||||
(call node (userlist "get_users") [] allUsers)
|
|
||||||
${notifyOnlineStatusesAir}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
`,
|
`,
|
||||||
@ -86,20 +83,54 @@ export const updateOnlineStatuses = async (client: FluenceClient) => {
|
|||||||
sendParticle(client, particle);
|
sendParticle(client, particle);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getInitialUserList = async (client: FluenceClient) => {
|
export const notifySelfAdded = (client: FluenceClient, name: string) => {
|
||||||
const particle = new Particle(
|
const particle = new Particle(
|
||||||
`
|
`
|
||||||
(seq
|
(seq
|
||||||
(call myRelay ("op" "identity") [])
|
(call myRelay ("op" "identity") [])
|
||||||
(seq
|
(seq
|
||||||
(call node (userlist "get_users") [] allUsers)
|
(call node (userlist "get_users") [] allUsers)
|
||||||
|
(fold allUsers.$.users! u
|
||||||
(par
|
(par
|
||||||
|
(seq
|
||||||
|
(call u.$.relay_id ("op" "identity") [])
|
||||||
|
(call u.$.peer_id (fluentPadServiceId notifyUserAdded) [myUser])
|
||||||
|
)
|
||||||
|
(next u)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
node: servicesNodePid,
|
||||||
|
userlist: userListServiceId,
|
||||||
|
myRelay: client.relayPeerID.toB58String(),
|
||||||
|
myPeerId: client.selfPeerId.toB58String(),
|
||||||
|
fluentPadServiceId: fluentPadServiceId,
|
||||||
|
notifyUserAdded: notifyUserAddedFnName,
|
||||||
|
myUser: {
|
||||||
|
name: name,
|
||||||
|
peer_id: client.selfPeerId.toB58String(),
|
||||||
|
relay_id: client.relayPeerID.toB58String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
sendParticle(client, particle);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserList = async (client: FluenceClient) => {
|
||||||
|
const particle = new Particle(
|
||||||
|
`
|
||||||
|
(seq
|
||||||
|
(call myRelay ("op" "identity") [])
|
||||||
|
(seq
|
||||||
|
(call node (userlist "get_users") [] allUsers)
|
||||||
(seq
|
(seq
|
||||||
(call myRelay ("op" "identity") [])
|
(call myRelay ("op" "identity") [])
|
||||||
(call myPeerId (fluentPadServiceId notifyUserAdded) [allUsers.$.users!])
|
(call myPeerId (fluentPadServiceId notifyUserAdded) [allUsers.$.users!])
|
||||||
)
|
)
|
||||||
${notifyOnlineStatusesAir}
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
`,
|
`,
|
||||||
@ -117,7 +148,7 @@ export const getInitialUserList = async (client: FluenceClient) => {
|
|||||||
await sendParticle(client, particle);
|
await sendParticle(client, particle);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const joinRoom = async (nickName: string) => {
|
export const joinRoom = async (client: FluenceClient, nickName: string) => {
|
||||||
let joinRoomAir = `
|
let joinRoomAir = `
|
||||||
(call node (userlist "join") [user] result)
|
(call node (userlist "join") [user] result)
|
||||||
`;
|
`;
|
||||||
@ -125,30 +156,50 @@ export const joinRoom = async (nickName: string) => {
|
|||||||
const data = new Map();
|
const data = new Map();
|
||||||
data.set('user', {
|
data.set('user', {
|
||||||
name: nickName,
|
name: nickName,
|
||||||
peer_id: fluenceClient.selfPeerId.toB58String(),
|
peer_id: client.selfPeerId.toB58String(),
|
||||||
relay_id: fluenceClient.relayPeerID.toB58String(),
|
relay_id: client.relayPeerID.toB58String(),
|
||||||
});
|
});
|
||||||
data.set('userlist', userListServiceId);
|
data.set('userlist', userListServiceId);
|
||||||
data.set('node', servicesNodePid);
|
data.set('node', servicesNodePid);
|
||||||
|
|
||||||
const [result] = await fluenceClient.fetch<[GetUsersResult]>(joinRoomAir, ['result'], data);
|
const [result] = await client.fetch<[GetUsersResult]>(joinRoomAir, ['result'], data);
|
||||||
throwIfError(result);
|
throwIfError(result);
|
||||||
return result.users;
|
return result.users;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const leaveRoom = async () => {
|
export const leaveRoom = async (client: FluenceClient) => {
|
||||||
let leaveRoomAir = `
|
const particle = new Particle(
|
||||||
(call node (userlist "leave") [ownPeerId] callResult)
|
`
|
||||||
`;
|
(seq
|
||||||
|
(call myRelay ("op" "identity") [])
|
||||||
|
(seq
|
||||||
|
(call node (userlist "leave") [myPeerId])
|
||||||
|
(seq
|
||||||
|
(call node (userlist "get_users") [] allUsers)
|
||||||
|
(fold allUsers.$.users! u
|
||||||
|
(par
|
||||||
|
(seq
|
||||||
|
(call u.$.relay_id ("op" "identity") [])
|
||||||
|
(call u.$.peer_id (fluentPadServiceId notifyUserRemoved) [myPeerId])
|
||||||
|
)
|
||||||
|
(next u)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
node: servicesNodePid,
|
||||||
|
userlist: userListServiceId,
|
||||||
|
myRelay: client.relayPeerID.toB58String(),
|
||||||
|
myPeerId: client.selfPeerId.toB58String(),
|
||||||
|
fluentPadServiceId: fluentPadServiceId,
|
||||||
|
notifyUserRemoved: notifyUserRemovedFnName,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const data = new Map();
|
await sendParticle(client, particle);
|
||||||
data.set('ownPeerId', fluenceClient.selfPeerId.toB58String());
|
|
||||||
data.set('userlist', userListServiceId);
|
|
||||||
data.set('node', servicesNodePid);
|
|
||||||
|
|
||||||
const [result] = await fluenceClient.fetch<[ServiceResult]>(leaveRoomAir, ['callResult'], data);
|
|
||||||
throwIfError(result);
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeUser = async (userPeerId: string) => {
|
export const removeUser = async (userPeerId: string) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user