Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 3,608 Bytes
38d787b f42b4a1 1185ec1 38d787b f276512 38d787b f276512 38d787b f276512 38d787b f276512 38d787b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
"use server"
import { WhoAmIUser, whoAmI } from "@/lib/huggingface/hub/src"
import { UserInfo } from "@/types/general"
import { adminApiKey } from "./config"
import { redis } from "./redis"
export async function getCurrentUser(apiKey: string): Promise<UserInfo> {
if (!apiKey) {
throw new Error(`the apiKey is required`)
}
const credentials = { accessToken: apiKey }
const huggingFaceUser = await whoAmI({ credentials }) as unknown as WhoAmIUser
const id = huggingFaceUser.id
const user: UserInfo = {
id,
type: apiKey === adminApiKey ? "admin" : "normal",
userName: huggingFaceUser.name,
fullName: huggingFaceUser.fullname,
thumbnail: huggingFaceUser.avatarUrl,
channels: [],
hfApiToken: apiKey, // <- on purpose, and safe (only this user sees their token)
}
await redis.set(`users:${id}`, user)
// the user id is not available in the channel info, only user name (slug)
// so we use this projection to recover the ID from a slug
// alternatively we could also use a Redis index, to avoid doing two calls
// (for get id and get user)
await redis.set(`userSlugToId:${user.userName}`, user.id)
return user
}
/**
* Attention this returns the *full* user, including the API key
*
* We use the API on behalf of the user, but it is confidential nevertheless,
* so we should not share it with 3rd parties unbeknownst to the user
*
* @param hfUserId
* @returns
*/
export async function getUserFromId(hfUserId: string): Promise<UserInfo | undefined> {
const maybeUser = await redis.get<UserInfo>(`users:${hfUserId}`)
if (maybeUser?.id) {
return maybeUser
}
return undefined
}
export async function getUserIdFromSlug(hfUserSlugName: string): Promise<string> {
// the user id is not available in the channel info, only user name (slug)
// so we use a projection to recover the ID from a slug
const maybeUserId = await redis.get<string>(`userSlugToId:${hfUserSlugName}`)
return maybeUserId || ""
}
/**
* This function doesn NOT return the user apiKey, for security reasons
*
* We use the API on behalf of the user, but it is confidential nevertheless,
* so we should not share it with 3rd parties unbeknownst to the user
*
* @param userIdOrSlugName
* @returns
*/
export async function getUser(userIdOrSlugName: string): Promise<UserInfo | undefined> {
// the user id is not available in the channel info, only user name (slug)
// so we use a projection to recover the ID from a slug
// alternatively, we could also use a Redis index, to avoid doing two calls
// (for get id and get user)
let maybeUserId = await getUserIdFromSlug(userIdOrSlugName)
maybeUserId ||= userIdOrSlugName
const maybeUser = await getUserFromId(maybeUserId)
// sanitize the output a bit
if (maybeUser) {
const publicFacingUser: UserInfo = {
...maybeUser,
hfApiToken: undefined, // <-- important!
}
delete publicFacingUser.hfApiToken
return publicFacingUser
}
return undefined
}
export async function getUsers(ids: string[]): Promise<Record<string, UserInfo>> {
try {
const maybeUsers = await redis.mget<UserInfo[]>(ids.map(userId => `users:${userId}`))
const usersById: Record<string, UserInfo> = {}
maybeUsers.forEach((user, index) => {
if (user?.id) {
const publicFacingUser: UserInfo = {
...user,
hfApiToken: undefined, // <-- important!
}
delete publicFacingUser.hfApiToken
usersById[user.id] = publicFacingUser
}
})
return usersById
} catch (err) {
return {}
}
} |