diff --git a/keyserver/src/creators/farcaster-channel-tag-creator.js b/keyserver/src/creators/farcaster-channel-tag-creator.js new file mode 100644 --- /dev/null +++ b/keyserver/src/creators/farcaster-channel-tag-creator.js @@ -0,0 +1,89 @@ +// @flow + +import uuid from 'uuid'; + +import type { + CreateOrUpdateFarcasterChannelTagRequest, + CreateOrUpdateFarcasterChannelTagResponse, +} from 'lib/types/community-types.js'; +import { ServerError } from 'lib/utils/errors.js'; + +import { + uploadBlob, + assignHolder, + download, + type BlobOperationResult, + type BlobDownloadResult, +} from '../services/blob.js'; +import { Viewer } from '../session/viewer.js'; + +async function createOrUpdateFarcasterChannelTag( + viewer: Viewer, + request: CreateOrUpdateFarcasterChannelTagRequest, +): Promise { + const { commCommunityID, farcasterChannelID } = request; + + const blobDownload = await getFarcasterChannelTagBlob(farcasterChannelID); + + if (blobDownload.found) { + throw new ServerError('already_in_use'); + } + + const blobHolder = uuid.v4(); + + const blobResult = await uploadFarcasterChannelTagBlob( + commCommunityID, + farcasterChannelID, + blobHolder, + ); + + if (!blobResult.success) { + if (blobResult.reason === 'HASH_IN_USE') { + throw new ServerError('already_in_use'); + } else { + throw new ServerError('unknown_error'); + } + } + + return { + commCommunityID, + blobHolder, + }; +} + +function farcasterChannelTagBlobHash(secret: string): string { + return `farcaster_channel_tag_${secret}`; +} + +function getFarcasterChannelTagBlob( + secret: string, +): Promise { + const hash = farcasterChannelTagBlobHash(secret); + + return download(hash); +} + +async function uploadFarcasterChannelTagBlob( + commCommunityID: string, + farcasterChannelID: string, + holder: string, +): Promise { + const payload = { + commCommunityID, + farcasterChannelID, + }; + const payloadString = JSON.stringify(payload); + + const hash = farcasterChannelTagBlobHash(farcasterChannelID); + const blob = new Blob([payloadString]); + + const uploadResult = await uploadBlob(blob, hash); + + if (!uploadResult.success) { + return uploadResult; + } + + return await assignHolder({ holder, hash }); +} + +export { createOrUpdateFarcasterChannelTag, uploadFarcasterChannelTagBlob }; diff --git a/lib/types/community-types.js b/lib/types/community-types.js --- a/lib/types/community-types.js +++ b/lib/types/community-types.js @@ -16,3 +16,13 @@ +id: string, +newCommunityInfo: CommunityInfo, }; + +export type CreateOrUpdateFarcasterChannelTagRequest = { + +commCommunityID: string, + +farcasterChannelID: string, +}; + +export type CreateOrUpdateFarcasterChannelTagResponse = { + +commCommunityID: string, + +blobHolder: string, +};