Skip to content

Commit 0e2756a

Browse files
committed
fix: fixed some sync issues and improved report
1 parent 91f214b commit 0e2756a

30 files changed

+1247
-805
lines changed

Diff for: package-lock.json

+810-495
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: packages/api/src/functions/refreshMetadataCollectionLongProcess/src/refreshMetadata.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ export const refreshMetadata = async (
5252
const linkMetadataInfo =
5353
collection.linkResourceId && collection.linkType
5454
? await pluginFacade.getMetadata({
55-
resourceId: collection.linkResourceId,
56-
linkType: collection.linkType,
55+
link: {
56+
resourceId: collection.linkResourceId,
57+
type: collection.linkType
58+
},
5759
credentials
5860
})
5961
: undefined

Diff for: packages/api/src/functions/refreshMetadataLongProcess/src/retrieveMetadataAndSaveCover.ts

+39-60
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import fs from "fs"
22
import path from "path"
33
import { pluginFacade } from "../../../libs/plugins/facade"
44
import { BookMetadata, directives } from "@oboku/shared"
5-
import {
6-
detectMimeTypeFromContent,
7-
mergeSkippingUndefined
8-
} from "../../../libs/utils"
5+
import { detectMimeTypeFromContent } from "../../../libs/utils"
96
import { Logger } from "@libs/logger"
107
import { METADATA_EXTRACTOR_SUPPORTED_EXTENSIONS } from "../../../constants"
118
import { getBookSourcesMetadata } from "@libs/metadata/getBookSourcesMetadata"
@@ -39,8 +36,9 @@ export const retrieveMetadataAndSaveCover = async (
3936
try {
4037
bookNameForDebug = reduceMetadata(ctx.book.metadata).title || ""
4138

42-
logger.info(
43-
`syncMetadata processing ${ctx.book._id} with resource id ${ctx.link.resourceId}`
39+
console.log(
40+
`processing ${ctx.book._id} with link of type ${ctx.link.type}`,
41+
{ link: ctx.link }
4442
)
4543

4644
const bookIsProtected = await isBookProtected(ctx.db, ctx.book)
@@ -49,31 +47,23 @@ export const retrieveMetadataAndSaveCover = async (
4947
// in case some directive are needed to prevent downloading huge file.
5048
const { canDownload = false, ...linkResourceMetadata } =
5149
(await pluginFacade.getMetadata({
52-
linkType: ctx.link.type,
53-
credentials: ctx.credentials,
54-
resourceId: ctx.link.resourceId
50+
link: ctx.link,
51+
credentials: ctx.credentials
5552
})) ?? {}
5653

57-
const { isbn, ignoreMetadata } = directives.extractDirectivesFromName(
58-
linkResourceMetadata.name ?? ""
59-
)
60-
61-
const existingLinkMetadata = ctx.book.metadata?.find(
62-
(item) => item.type === "link"
63-
)
54+
const { isbn, ignoreMetadataFile, ignoreMetadataSources, googleVolumeId } =
55+
directives.extractDirectivesFromName(linkResourceMetadata.name ?? "")
6456

65-
const newLinkMetadata: BookMetadata = mergeSkippingUndefined(
66-
existingLinkMetadata ?? {},
67-
{
68-
type: "link",
69-
isbn,
70-
title: linkResourceMetadata.name,
71-
contentType: linkResourceMetadata.contentType,
72-
...linkResourceMetadata.bookMetadata
73-
}
74-
)
57+
const linkMetadata: BookMetadata = {
58+
type: "link",
59+
isbn,
60+
title: linkResourceMetadata.name,
61+
contentType: linkResourceMetadata.contentType,
62+
googleVolumeId,
63+
...linkResourceMetadata.bookMetadata
64+
}
7565

76-
let contentType = newLinkMetadata.contentType
66+
let contentType = linkMetadata.contentType
7767
/**
7868
* Not all plugins return the valid content type so
7969
* we can only make some assumptions based on what we have
@@ -83,19 +73,21 @@ export const retrieveMetadataAndSaveCover = async (
8373
(contentType &&
8474
METADATA_EXTRACTOR_SUPPORTED_EXTENSIONS.includes(contentType))
8575

86-
const sourcesMetadata = await getBookSourcesMetadata(
87-
{
88-
...newLinkMetadata,
89-
// some plugins returns filename and not title
90-
title: path.parse(newLinkMetadata.title ?? "").name
91-
},
92-
{
93-
googleApiKey: ctx.googleApiKey,
94-
withGoogle: !bookIsProtected
95-
}
96-
)
97-
98-
const metadataList = [newLinkMetadata, ...sourcesMetadata]
76+
const sourcesMetadata = ignoreMetadataSources
77+
? []
78+
: await getBookSourcesMetadata(
79+
{
80+
...linkMetadata,
81+
// some plugins returns filename and not title
82+
title: path.parse(linkMetadata.title ?? "").name
83+
},
84+
{
85+
googleApiKey: ctx.googleApiKey,
86+
withGoogle: !bookIsProtected
87+
}
88+
)
89+
90+
const metadataList = [linkMetadata, ...sourcesMetadata]
9991

10092
const { filepath: tmpFilePath, metadata: downloadMetadata } =
10193
canDownload && isMaybeExtractAble
@@ -126,14 +118,11 @@ export const retrieveMetadataAndSaveCover = async (
126118
fileToUnlink = tmpFilePath
127119
contentType = downloadMetadata.contentType || contentType
128120

129-
console.log(
130-
`syncMetadata processing ${ctx.book._id}`,
131-
tmpFilePath,
132-
{
133-
linkMetadata: newLinkMetadata
134-
},
135-
contentType
136-
)
121+
console.log(`syncMetadata processing ${ctx.book._id}`, {
122+
linkMetadata,
123+
contentType,
124+
tmpFilePath
125+
})
137126

138127
const isRarArchive = contentType === "application/x-rar"
139128
let archiveExtractor: Extractor<Uint8Array> | undefined = undefined
@@ -145,7 +134,7 @@ export const retrieveMetadataAndSaveCover = async (
145134
(await detectMimeTypeFromContent(tmpFilePath)) || contentType
146135
}
147136

148-
if (ignoreMetadata !== "file") {
137+
if (!ignoreMetadataFile) {
149138
if (isRarArchive) {
150139
archiveExtractor = await getRarArchive(tmpFilePath)
151140
const fileMetadata = await getMetadataFromRarArchive(
@@ -189,19 +178,9 @@ export const retrieveMetadataAndSaveCover = async (
189178
)
190179

191180
await atomicUpdate(ctx.db, "book", ctx.book._id, (old) => {
192-
const linkMetadata = old.metadata?.find((item) => item.type === "link")
193-
194181
return {
195182
...old,
196-
/**
197-
* We should always use previous link metadata. Some
198-
* links do not have server state
199-
*/
200-
metadata: metadataList.map((item) =>
201-
item.type !== "link"
202-
? item
203-
: mergeSkippingUndefined(linkMetadata ?? {}, item)
204-
),
183+
metadata: metadataList,
205184
lastMetadataUpdatedAt: new Date().getTime(),
206185
metadataUpdateStatus: null,
207186
lastMetadataUpdateError: null

Diff for: packages/api/src/functions/syncDataSourceLongProcess/handler.ts

+2-29
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import { ValidatedEventAPIGatewayProxyEvent } from "@libs/api-gateway"
2-
import { AWS_API_URI } from "../../constants"
32
import { configure as configureGoogleDataSource } from "@libs/plugins/google"
43
import { withToken } from "@libs/auth"
54
import schema from "./schema"
65
import { createHttpError } from "@libs/httpErrors"
76
import { getNanoDbForUser } from "@libs/couch/dbHelpers"
8-
import axios from "axios"
97
import { getParametersValue } from "@libs/ssm"
108
import { deleteLock } from "@libs/supabase/deleteLock"
119
import { supabase } from "@libs/supabase/client"
12-
import { pluginFacade } from "@libs/plugins/facade"
13-
import { Logger } from "@libs/logger"
1410
import { withMiddy } from "@libs/middy/withMiddy"
15-
16-
const logger = Logger.child({ module: "handler" })
11+
import { sync } from "@libs/sync/sync"
1712

1813
const lambda: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (
1914
event
@@ -49,32 +44,10 @@ const lambda: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (
4944
throw createHttpError(400)
5045
}
5146

52-
const refreshBookMetadata = async ({ bookId }: { bookId: string }) => {
53-
logger.info(`send refreshBookMetadata request for ${bookId}`)
54-
55-
const response = await axios({
56-
method: `post`,
57-
url: `${AWS_API_URI}/refresh-metadata`,
58-
data: {
59-
bookId
60-
},
61-
headers: {
62-
"content-type": "application/json",
63-
accept: "application/json",
64-
"oboku-credentials": JSON.stringify(credentials),
65-
authorization: authorization
66-
}
67-
})
68-
69-
logger.info(`refreshBookMetadata request success for ${bookId}`)
70-
logger.info(response)
71-
}
72-
73-
await pluginFacade.sync({
47+
await sync({
7448
userName: name,
7549
dataSourceId,
7650
db: await getNanoDbForUser(name, jwtPrivateKey),
77-
refreshBookMetadata,
7851
credentials,
7952
authorization
8053
})

Diff for: packages/api/src/libs/couch/dbHelpers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export const findOne = async <
117117
if (Array.isArray(fieldsWithRequiredFields)) {
118118
fieldsWithRequiredFields.push(`rx_model`)
119119
}
120+
120121
const response = await retryFn(() =>
121122
db.find({
122123
...restQuery,

Diff for: packages/api/src/libs/google/googleBooksApi.ts

+34-7
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@ import { GOOGLE_BOOK_API_URL } from "../../constants"
33
import { Item } from "./types"
44
import { performWithBackoff } from "@libs/utils"
55

6-
export type GoogleBooksApiResult = {
6+
export type GoogleBooksApiVolumesResponseData = {
77
kind: `books#volumes` | `unknown`
88
totalItems: number
99
items?: Item[] // does not exist when totalItems is 0
1010
}
1111

12+
export type GoogleBooksApiVolumeResponseData = Item
13+
1214
/**
1315
* Supports formats like: [9782413023470, 978-1-947804-36-4]
1416
*/
1517
export const findByISBN = async (isbn: string, apiKey: string) => {
18+
const url = `${GOOGLE_BOOK_API_URL}/volumes?q=isbn:${encodeURIComponent(isbn)}&key=${apiKey}`
19+
20+
console.log("[google] [findByISBN]", { url })
21+
1622
const response = await performWithBackoff({
17-
asyncFunction: () =>
18-
axios.get<GoogleBooksApiResult>(
19-
`${GOOGLE_BOOK_API_URL}/volumes?q=isbn:${encodeURIComponent(isbn)}&key=${apiKey}`
20-
),
23+
asyncFunction: () => axios.get<GoogleBooksApiVolumesResponseData>(url),
2124
retry: (error: unknown) => {
2225
// we retry on Too many request error
2326
return isAxiosError(error) && error.response?.status === 429
@@ -36,8 +39,10 @@ export const findByISBN = async (isbn: string, apiKey: string) => {
3639
export const findByTitle = async (name: string, apiKey: string) => {
3740
const uri = `${GOOGLE_BOOK_API_URL}/volumes?q=intitle:${encodeURIComponent(name)}&key=${apiKey}`
3841

42+
console.log("[google] [findByTitle]", { uri })
43+
3944
const response = await performWithBackoff({
40-
asyncFunction: () => axios.get<GoogleBooksApiResult>(uri),
45+
asyncFunction: () => axios.get<GoogleBooksApiVolumesResponseData>(uri),
4146
retry: (error: unknown) => {
4247
// we retry on Too many request error
4348
return isAxiosError(error) && error.response?.status === 429
@@ -53,10 +58,32 @@ export const findByTitle = async (name: string, apiKey: string) => {
5358
throw new Error(`An error occurred during findByISBN`)
5459
}
5560

61+
export const findByVolumeId = async (name: string, apiKey: string) => {
62+
const uri = `${GOOGLE_BOOK_API_URL}/volumes/${encodeURIComponent(name)}?key=${apiKey}`
63+
64+
console.log("[google] [findByVolumeId]", { uri })
65+
66+
const response = await performWithBackoff({
67+
asyncFunction: () => axios.get<GoogleBooksApiVolumeResponseData>(uri),
68+
retry: (error: unknown) => {
69+
// we retry on Too many request error
70+
return isAxiosError(error) && error.response?.status === 429
71+
}
72+
})
73+
74+
if (response.status === 200) {
75+
return {
76+
items: [response.data]
77+
}
78+
}
79+
80+
throw new Error(`An error occurred during findByISBN`)
81+
}
82+
5683
export const findSeriesByTitle = async (name: string, apiKey: string) => {
5784
const response = await performWithBackoff({
5885
asyncFunction: () =>
59-
axios.get<GoogleBooksApiResult>(
86+
axios.get<GoogleBooksApiVolumesResponseData>(
6087
`${GOOGLE_BOOK_API_URL}/volumes?q=intitle:${name}&key=${apiKey}`
6188
),
6289
retry: (error: unknown) => {

Diff for: packages/api/src/libs/google/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type Item = {
1212
title: string
1313
authors: string[]
1414
publisher: string
15-
publishedDate: YEAR
15+
publishedDate?: YEAR
1616
language: "de" | "fr"
1717
pageCount?: number
1818
categories?: Category[]

Diff for: packages/api/src/libs/metadata/extractDateComponents.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function extractDateComponents(dateStr: string) {
1+
export function extractDateComponents(dateStr: string | undefined = "") {
22
const parts = dateStr.split(" ")
33
let day = undefined,
44
month = undefined,

0 commit comments

Comments
 (0)