UNPKG

@osobh/reactar

Version:

AR Library for React Native and Expo

131 lines (111 loc) 3.51 kB
// src/core/UserSessionManager.ts import { EventEmitter } from 'events'; export interface ARUser { userId: string; deviceId: string; position: { x: number; y: number; z: number }; rotation: { x: number; y: number; z: number }; lastUpdate: number; isActive: boolean; } export interface UserSessionOptions { serverUrl?: string; heartbeatInterval?: number; inactivityTimeout?: number; } export class UserSessionManager extends EventEmitter { private options: UserSessionOptions; private users: Map<string, ARUser>; private currentUser: ARUser | null = null; private heartbeatInterval: NodeJS.Timeout | null = null; constructor(options: UserSessionOptions = {}) { super(); this.options = { serverUrl: options.serverUrl || 'https://ar-session-service.example.com', heartbeatInterval: options.heartbeatInterval || 1000, inactivityTimeout: options.inactivityTimeout || 5000, }; this.users = new Map(); } /** * Initializes a user session */ public async initializeSession(deviceId: string): Promise<ARUser> { try { const userId = `user-${Math.random().toString(36).substr(2, 9)}`; this.currentUser = { userId, deviceId, position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 }, lastUpdate: Date.now(), isActive: true, }; this.users.set(userId, this.currentUser); this.emit('userJoined', this.currentUser); this.startHeartbeat(); return this.currentUser; } catch (error) { this.emit('error', error); throw error; } } /** * Updates the current user's position and rotation */ public updateUserPosition(position: { x: number; y: number; z: number }, rotation: { x: number; y: number; z: number }): void { if (!this.currentUser) { throw new Error('No active user session'); } this.currentUser.position = position; this.currentUser.rotation = rotation; this.currentUser.lastUpdate = Date.now(); this.users.set(this.currentUser.userId, this.currentUser); this.emit('userUpdated', this.currentUser); } /** * Handles incoming user updates from other devices */ public handleRemoteUserUpdate(user: ARUser): void { if (user.userId === this.currentUser?.userId) return; const existingUser = this.users.get(user.userId); if (existingUser) { Object.assign(existingUser, user); } else { this.users.set(user.userId, user); this.emit('userJoined', user); } this.emit('userUpdated', user); } /** * Gets all active users in the session */ public getActiveUsers(): ARUser[] { const now = Date.now(); return Array.from(this.users.values()).filter( user => user.isActive && now - user.lastUpdate < this.options.inactivityTimeout! ); } private startHeartbeat(): void { if (this.heartbeatInterval) return; this.heartbeatInterval = setInterval(() => { if (this.currentUser) { this.currentUser.lastUpdate = Date.now(); this.emit('heartbeat', this.currentUser); } }, this.options.heartbeatInterval); } /** * Ends the current user's session */ public endSession(): void { if (!this.currentUser) return; this.currentUser.isActive = false; this.emit('userLeft', this.currentUser); if (this.heartbeatInterval) { clearInterval(this.heartbeatInterval); this.heartbeatInterval = null; } this.currentUser = null; } }