Skip to content

Commit b3d3995

Browse files
committed
rebase?
1 parent 784bcc7 commit b3d3995

File tree

5 files changed

+75
-52
lines changed

5 files changed

+75
-52
lines changed

app/composables/useAtproto.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,29 @@ export function useLikePackage(packageName: string) {
7171

7272
export function useUnlikePackage(packageName: string) {
7373
const { user } = useAtproto()
74+
const data = ref<PackageLikes | null>(null)
75+
const error = ref<Error | null>(null)
76+
const pending = ref(false)
77+
78+
const mutate = async () => {
79+
pending.value = true
80+
error.value = null
81+
82+
try {
83+
const result = await $fetch<PackageLikes>('/api/auth/social/like', {
84+
method: 'DELETE',
85+
body: { packageName },
86+
})
7487

75-
const { data, error, pending, execute } = useFetch<PackageLikes>('/api/auth/social/like', {
76-
method: 'DELETE',
77-
body: { packageName },
78-
immediate: false,
79-
watch: false,
80-
onResponseError: async ({ error: e }) => {
88+
data.value = result
89+
return result
90+
} catch (e) {
91+
error.value = e as FetchError
8192
await handleAuthError(e, user.value?.handle)
82-
},
83-
})
93+
} finally {
94+
pending.value = false
95+
}
96+
}
8497

85-
return { data, error, pending, mutate: execute }
98+
return { data, error, pending, mutate }
8699
}

server/api/auth/social/like.delete.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,7 @@ export default eventHandlerWithOAuthSession(async (event, oAuthSession) => {
1919
})
2020
}
2121

22-
const cachedFetch = event.context.cachedFetch
23-
if (!cachedFetch) {
24-
// TODO: Probably needs to add in a normal fetch if not provided
25-
// but ideally should not happen
26-
throw createError({
27-
status: 500,
28-
message: 'cachedFetch not provided in context',
29-
})
30-
}
31-
32-
const likesUtil = new PackageLikesUtils(cachedFetch)
22+
const likesUtil = new PackageLikesUtils()
3323

3424
const getTheUsersLikedRecord = await likesUtil.getTheUsersLikedRecord(
3525
body.packageName,
@@ -40,10 +30,10 @@ export default eventHandlerWithOAuthSession(async (event, oAuthSession) => {
4030
await checkOAuthScope(oAuthSession, LIKES_SCOPE)
4131
const client = new Client(oAuthSession)
4232

43-
var result = await client.delete(dev.npmx.feed.like, {
33+
await client.delete(dev.npmx.feed.like, {
4434
rkey: getTheUsersLikedRecord.rkey,
4535
})
46-
console.log(result)
47-
return await likesUtil.unlikeAPackageAndReturnLikes(body.packageName, loggedInUsersDid)
36+
var result = await likesUtil.unlikeAPackageAndReturnLikes(body.packageName, loggedInUsersDid)
37+
return result
4838
}
4939
})

server/api/auth/social/like.post.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,7 @@ export default eventHandlerWithOAuthSession(async (event, oAuthSession) => {
2020
})
2121
}
2222

23-
const cachedFetch = event.context.cachedFetch
24-
if (!cachedFetch) {
25-
// TODO: Probably needs to add in a normal fetch if not provided
26-
// but ideally should not happen
27-
throw createError({
28-
status: 500,
29-
message: 'cachedFetch not provided in context',
30-
})
31-
}
32-
33-
const likesUtil = new PackageLikesUtils(cachedFetch)
23+
const likesUtil = new PackageLikesUtils()
3424

3525
const hasLiked = await likesUtil.hasTheUserLikedThePackage(body.packageName, loggedInUsersDid)
3626
if (hasLiked) {
@@ -59,5 +49,5 @@ export default eventHandlerWithOAuthSession(async (event, oAuthSession) => {
5949
})
6050
}
6151

62-
return await likesUtil.likeAPackageAndRetunLikes(body.packageName, loggedInUsersDid)
52+
return await likesUtil.likeAPackageAndRetunLikes(body.packageName, loggedInUsersDid, result.uri)
6353
})

server/api/social/likes/[...pkg].get.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,7 @@ export default eventHandlerWithOAuthSession(async (event, oAuthSession, _) => {
66
message: 'package name not provided',
77
})
88
}
9-
const cachedFetch = event.context.cachedFetch
10-
if (!cachedFetch) {
11-
// TODO: Probably needs to add in a normal fetch if not provided
12-
// but ideally should not happen
13-
throw createError({
14-
status: 500,
15-
message: 'cachedFetch not provided in context',
16-
})
17-
}
189

19-
const likesUtil = new PackageLikesUtils(cachedFetch)
10+
const likesUtil = new PackageLikesUtils()
2011
return await likesUtil.getLikes(packageName, oAuthSession?.did.toString())
2112
})

server/utils/atproto/utils/likes.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,35 @@ export type PackageLikes = {
1212
userHasLiked: boolean
1313
}
1414

15+
//Cache keys and helpers
1516
const CACHE_PREFIX = 'atproto-likes:'
1617
const CACHE_PACKAGE_TOTAL_KEY = (packageName: string) => `${CACHE_PREFIX}:${packageName}:total`
1718
const CACHE_USER_LIKES_KEY = (packageName: string, did: string) =>
18-
`${CACHE_PREFIX}${packageName}:users:${did}`
19+
`${CACHE_PREFIX}${packageName}:users:${did}:liked`
20+
const CACHE_USERS_BACK_LINK = (packageName: string, did: string) =>
21+
`${CACHE_PREFIX}${packageName}:users:${did}:backlink`
1922

2023
const CACHE_MAX_AGE = CACHE_MAX_AGE_ONE_MINUTE * 5
2124

25+
/**
26+
* Logic to handle liking, unliking, and seeing if a user has liked a package on npmx
27+
*/
2228
export class PackageLikesUtils {
2329
private readonly constellation: Constellation
2430
private readonly cache: CacheAdapter
2531

26-
constructor(cachedFunction: CachedFetchFunction) {
27-
this.constellation = new Constellation(cachedFunction)
32+
constructor() {
33+
this.constellation = new Constellation(
34+
// Passes in a fetch wrapped as cachedfetch since are already doing some heavy caching here
35+
async <T = unknown>(
36+
url: string,
37+
options: Parameters<typeof $fetch>[1] = {},
38+
_ttl?: number,
39+
): Promise<CachedFetchResult<T>> => {
40+
const data = (await $fetch<T>(url, options)) as T
41+
return { data, isStale: false, cachedAt: null }
42+
},
43+
)
2844
this.cache = getCacheAdatper(CACHE_PREFIX)
2945
}
3046

@@ -34,7 +50,6 @@ export class PackageLikesUtils {
3450
* @returns
3551
*/
3652
private async constellationLikes(subjectRef: string) {
37-
// TODO: I need to see what failed fetch calls do here
3853
const { data: totalLinks } = await this.constellation.getLinksDistinctDids(
3954
subjectRef,
4055
likeNsid,
@@ -65,7 +80,6 @@ export class PackageLikesUtils {
6580
[[usersDid]],
6681
0,
6782
)
68-
//TODO: need to double check this logic
6983
return userLikes.total > 0
7084
}
7185

@@ -135,18 +149,34 @@ export class PackageLikesUtils {
135149
* to the user's atproto repostiory
136150
* @param packageName
137151
* @param usersDid
152+
* @param atUri - The URI of the like record
138153
*/
139-
async likeAPackageAndRetunLikes(packageName: string, usersDid: string): Promise<PackageLikes> {
154+
async likeAPackageAndRetunLikes(
155+
packageName: string,
156+
usersDid: string,
157+
atUri: string,
158+
): Promise<PackageLikes> {
140159
const totalLikesKey = CACHE_PACKAGE_TOTAL_KEY(packageName)
141160
const subjectRef = PACKAGE_SUBJECT_REF(packageName)
142161

162+
const splitAtUri = atUri.replace('at://', '').split('/')
163+
const backLink = {
164+
did: usersDid,
165+
collection: splitAtUri[1],
166+
rkey: splitAtUri[2],
167+
} as Backlink
168+
169+
// We store the backlink incase a user is liking and unlikign rapidly. constellation takes a few seconds to capture the backlink
170+
const usersBackLinkKey = CACHE_USERS_BACK_LINK(packageName, usersDid)
171+
await this.cache.set(usersBackLinkKey, backLink, CACHE_MAX_AGE)
172+
143173
let totalLikes = await this.cache.get<number>(totalLikesKey)
144174
if (!totalLikes) {
145175
totalLikes = await this.constellationLikes(subjectRef)
146176
totalLikes = totalLikes + 1
147177
await this.cache.set(totalLikesKey, totalLikes, CACHE_MAX_AGE)
148178
}
149-
// We already know the user has not liked the package so set in the cache
179+
// We already know the user has not liked the package before so set in the cache
150180
await this.cache.set(CACHE_USER_LIKES_KEY(packageName, usersDid), true, CACHE_MAX_AGE)
151181
return {
152182
totalLikes: totalLikes,
@@ -164,6 +194,12 @@ export class PackageLikesUtils {
164194
packageName: string,
165195
usersDid: string,
166196
): Promise<Backlink | undefined> {
197+
const usersBackLinkKey = CACHE_USERS_BACK_LINK(packageName, usersDid)
198+
const backLink = await this.cache.get<Backlink>(usersBackLinkKey)
199+
if (backLink) {
200+
return backLink
201+
}
202+
167203
const subjectRef = PACKAGE_SUBJECT_REF(packageName)
168204
const { data: userLikes } = await this.constellation.getBackLinks(
169205
subjectRef,
@@ -198,7 +234,10 @@ export class PackageLikesUtils {
198234
totalLikes = totalLikes - 1
199235
await this.cache.set(totalLikesKey, totalLikes, CACHE_MAX_AGE)
200236

237+
//Clean up
201238
await this.cache.delete(CACHE_USER_LIKES_KEY(packageName, usersDid))
239+
await this.cache.delete(CACHE_USERS_BACK_LINK(packageName, usersDid))
240+
202241
return {
203242
totalLikes: totalLikes,
204243
userHasLiked: false,

0 commit comments

Comments
 (0)