Add automatic nearby discovery and simplify device presence UI
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { readDeviceInfo } from './deviceInfo';
|
||||
import { createRefreshQueue } from './refreshQueue';
|
||||
import { ref } from 'vue';
|
||||
import { io } from 'socket.io-client';
|
||||
@@ -23,7 +24,22 @@ export const device = ref(null),
|
||||
spaces = ref([]),
|
||||
discoveryEnabled = ref(false),
|
||||
error = ref('');
|
||||
export const pendingPeers = ref([]);
|
||||
let pendingTimer;
|
||||
let deviceInfo = {};
|
||||
export const nextCursor = ref(null);
|
||||
export const locationSettings = ref({ enabled: false, radiusMeters: 100, refreshMs: 120000 });
|
||||
export async function publishLocation(position) {
|
||||
if (!socket?.connected) throw Error('서버 연결을 확인해 주세요.');
|
||||
const result = await socket.timeout(5000).volatile.emitWithAck('location:update', position);
|
||||
if (!result?.ok) throw Error(result?.message ?? '위치를 확인하지 못했습니다.');
|
||||
}
|
||||
export function clearLocation() {
|
||||
if (socket?.connected) socket.emit('location:clear');
|
||||
}
|
||||
export function reserveLocationAcceptance(requestId) {
|
||||
if (socket?.connected) socket.emit('location:accept', { requestId });
|
||||
}
|
||||
let socket;
|
||||
let reauthorizing;
|
||||
const drafts = new Map();
|
||||
@@ -58,13 +74,14 @@ export async function bootstrap() {
|
||||
if (navigator.locks) await navigator.locks.request('hop-session-bootstrap', init);
|
||||
else await init();
|
||||
await refreshAccount();
|
||||
deviceInfo = await readDeviceInfo();
|
||||
connect();
|
||||
await refresh();
|
||||
startReconciliation();
|
||||
}
|
||||
function connect() {
|
||||
socket?.disconnect();
|
||||
socket = io({ auth: { csrfToken: csrfToken.value }, reconnection: true });
|
||||
socket = io({ auth: { csrfToken: csrfToken.value, deviceInfo }, reconnection: true });
|
||||
socket.on('connect', () => {
|
||||
connected.value = true;
|
||||
void refresh().catch(showError);
|
||||
@@ -91,7 +108,7 @@ function connect() {
|
||||
csrfToken.value = session.csrfToken;
|
||||
sessionExpiresAt.value = session.expiresAt;
|
||||
if (socket) {
|
||||
socket.auth = { csrfToken: csrfToken.value };
|
||||
socket.auth = { csrfToken: csrfToken.value, deviceInfo };
|
||||
socket.connect();
|
||||
}
|
||||
})()
|
||||
@@ -100,10 +117,20 @@ function connect() {
|
||||
reauthorizing = undefined;
|
||||
});
|
||||
});
|
||||
socket.on('device:updated', (event) => {
|
||||
const known = new Set(peers.value.map((peer) => peer.id));
|
||||
pendingPeers.value = (event?.devices ?? [])
|
||||
.filter((peer) => !known.has(peer.id))
|
||||
.map((peer) => peer.id);
|
||||
clearTimeout(pendingTimer);
|
||||
pendingTimer = setTimeout(() => {
|
||||
pendingPeers.value = [];
|
||||
}, 5000);
|
||||
void refresh().catch(showError);
|
||||
});
|
||||
for (const event of [
|
||||
'device:online',
|
||||
'device:offline',
|
||||
'device:updated',
|
||||
'space:updated',
|
||||
'request:created',
|
||||
'request:updated',
|
||||
@@ -119,7 +146,15 @@ export const refresh = createRefreshQueue(async () => {
|
||||
const snapshot = await api('/device/snapshot');
|
||||
device.value = snapshot.device;
|
||||
peers.value = snapshot.devices;
|
||||
pendingPeers.value = pendingPeers.value.filter(
|
||||
(id) => !snapshot.devices.some((peer) => peer.id === id),
|
||||
);
|
||||
discoveryEnabled.value = snapshot.sameNetworkDiscoveryEnabled;
|
||||
locationSettings.value = snapshot.locationDiscovery ?? {
|
||||
enabled: false,
|
||||
radiusMeters: 100,
|
||||
refreshMs: 120000,
|
||||
};
|
||||
requests.value = snapshot.requests;
|
||||
items.value = snapshot.items;
|
||||
nextCursor.value = snapshot.nextCursor;
|
||||
|
||||
Reference in New Issue
Block a user