mirror of
https://github.com/open-webui/open-webui
synced 2025-02-06 13:10:16 +00:00
feat: active user count
This commit is contained in:
parent
4925a6530b
commit
bbfa54a6b9
@ -7,6 +7,8 @@ sio = socketio.AsyncServer(cors_allowed_origins=[], async_mode="asgi")
|
|||||||
app = socketio.ASGIApp(sio, socketio_path="/ws/socket.io")
|
app = socketio.ASGIApp(sio, socketio_path="/ws/socket.io")
|
||||||
|
|
||||||
# Dictionary to maintain the user pool
|
# Dictionary to maintain the user pool
|
||||||
|
|
||||||
|
|
||||||
USER_POOL = {}
|
USER_POOL = {}
|
||||||
|
|
||||||
|
|
||||||
@ -22,24 +24,25 @@ async def connect(sid, environ, auth):
|
|||||||
user = Users.get_user_by_id(data["id"])
|
user = Users.get_user_by_id(data["id"])
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
USER_POOL[sid] = {
|
USER_POOL[sid] = user.id
|
||||||
"id": user.id,
|
|
||||||
"name": user.name,
|
|
||||||
"email": user.email,
|
|
||||||
"role": user.role,
|
|
||||||
}
|
|
||||||
print(f"user {user.name}({user.id}) connected with session ID {sid}")
|
print(f"user {user.name}({user.id}) connected with session ID {sid}")
|
||||||
|
|
||||||
|
print(len(set(USER_POOL)))
|
||||||
|
await sio.emit("user-count", {"count": len(set(USER_POOL))})
|
||||||
|
|
||||||
|
|
||||||
|
@sio.on("user-count")
|
||||||
|
async def user_count(sid):
|
||||||
|
print("user-count", sid)
|
||||||
|
await sio.emit("user-count", {"count": len(set(USER_POOL))})
|
||||||
|
|
||||||
|
|
||||||
@sio.event
|
@sio.event
|
||||||
def disconnect(sid):
|
async def disconnect(sid):
|
||||||
if sid in USER_POOL:
|
if sid in USER_POOL:
|
||||||
disconnected_user = USER_POOL.pop(sid)
|
disconnected_user = USER_POOL.pop(sid)
|
||||||
print(f"user {disconnected_user} disconnected with session ID {sid}")
|
print(f"user {disconnected_user} disconnected with session ID {sid}")
|
||||||
|
|
||||||
|
await sio.emit("user-count", {"count": len(USER_POOL)})
|
||||||
else:
|
else:
|
||||||
print(f"Unknown session ID {sid} disconnected")
|
print(f"Unknown session ID {sid} disconnected")
|
||||||
|
|
||||||
|
|
||||||
@sio.event
|
|
||||||
def disconnect(sid):
|
|
||||||
print("disconnect", sid)
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu } from 'bits-ui';
|
import { DropdownMenu } from 'bits-ui';
|
||||||
import { createEventDispatcher, getContext } from 'svelte';
|
import { createEventDispatcher, getContext, onMount } from 'svelte';
|
||||||
|
|
||||||
import { flyAndScale } from '$lib/utils/transitions';
|
import { flyAndScale } from '$lib/utils/transitions';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
|
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
|
||||||
import { showSettings } from '$lib/stores';
|
import { showSettings, activeUserCount } from '$lib/stores';
|
||||||
import { fade, slide } from 'svelte/transition';
|
import { fade, slide } from 'svelte/transition';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
@ -107,7 +107,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<hr class=" dark:border-gray-800 my-2 p-0" />
|
<hr class=" dark:border-gray-800 my-1.5 p-0" />
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
|
||||||
@ -139,6 +139,30 @@
|
|||||||
<div class=" self-center font-medium">{$i18n.t('Sign Out')}</div>
|
<div class=" self-center font-medium">{$i18n.t('Sign Out')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{#if $activeUserCount}
|
||||||
|
<hr class=" dark:border-gray-800 my-1.5 p-0" />
|
||||||
|
|
||||||
|
<div class="flex rounded-md py-1.5 px-3 text-xs gap-2.5 items-center">
|
||||||
|
<div class=" flex items-center">
|
||||||
|
<span class="relative flex size-2">
|
||||||
|
<span
|
||||||
|
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"
|
||||||
|
/>
|
||||||
|
<span class="relative inline-flex rounded-full size-2 bg-green-500" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" translate-y-[0.25px]">
|
||||||
|
<span class=" font-medium">
|
||||||
|
{$i18n.t('Active Users')}:
|
||||||
|
</span>
|
||||||
|
<span class=" font-semibold">
|
||||||
|
{$activeUserCount}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- <DropdownMenu.Item class="flex items-center px-3 py-2 text-sm font-medium">
|
<!-- <DropdownMenu.Item class="flex items-center px-3 py-2 text-sm font-medium">
|
||||||
<div class="flex items-center">Profile</div>
|
<div class="flex items-center">Profile</div>
|
||||||
</DropdownMenu.Item> -->
|
</DropdownMenu.Item> -->
|
||||||
|
@ -15,6 +15,7 @@ export const MODEL_DOWNLOAD_POOL = writable({});
|
|||||||
export const mobile = writable(false);
|
export const mobile = writable(false);
|
||||||
|
|
||||||
export const socket: Writable<null | Socket> = writable(null);
|
export const socket: Writable<null | Socket> = writable(null);
|
||||||
|
export const activeUserCount: Writable<null | number> = writable(null);
|
||||||
|
|
||||||
export const theme = writable('system');
|
export const theme = writable('system');
|
||||||
export const chatId = writable('');
|
export const chatId = writable('');
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
import { onMount, tick, setContext } from 'svelte';
|
import { onMount, tick, setContext } from 'svelte';
|
||||||
import { config, user, theme, WEBUI_NAME, mobile, socket } from '$lib/stores';
|
import { config, user, theme, WEBUI_NAME, mobile, socket, activeUserCount } from '$lib/stores';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { Toaster, toast } from 'svelte-sonner';
|
import { Toaster, toast } from 'svelte-sonner';
|
||||||
|
|
||||||
@ -69,7 +69,12 @@
|
|||||||
console.log('connected');
|
console.log('connected');
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.set(_socket);
|
await socket.set(_socket);
|
||||||
|
|
||||||
|
_socket.on('user-count', (data) => {
|
||||||
|
console.log('user-count', data);
|
||||||
|
activeUserCount.set(data.count);
|
||||||
|
});
|
||||||
|
|
||||||
if (localStorage.token) {
|
if (localStorage.token) {
|
||||||
// Get Session User Info
|
// Get Session User Info
|
||||||
|
Loading…
Reference in New Issue
Block a user