yaGeey commited on
Commit
4170f15
·
1 Parent(s): c22439c

logmemory & token queue priority

Browse files
Files changed (3) hide show
  1. src/browser.ts +2 -0
  2. src/index.ts +58 -49
  3. src/utils.ts +11 -0
src/browser.ts CHANGED
@@ -2,6 +2,7 @@ import type { Browser, BrowserContext, Page } from 'playwright'
2
  import { chromium } from 'playwright-extra'
3
  import StealthPlugin from 'puppeteer-extra-plugin-stealth'
4
  import { store } from './storage.js'
 
5
 
6
  chromium.use(StealthPlugin())
7
 
@@ -118,5 +119,6 @@ export async function withPage<T>(fn: (page: Page) => Promise<T>): Promise<T | n
118
  .close()
119
  .catch(() => {})
120
  }
 
121
  }
122
  }
 
2
  import { chromium } from 'playwright-extra'
3
  import StealthPlugin from 'puppeteer-extra-plugin-stealth'
4
  import { store } from './storage.js'
5
+ import { logMemory } from './utils.js'
6
 
7
  chromium.use(StealthPlugin())
8
 
 
119
  .close()
120
  .catch(() => {})
121
  }
122
+ logMemory('Context closed')
123
  }
124
  }
src/index.ts CHANGED
@@ -3,7 +3,7 @@ import 'dotenv/config'
3
  import PQueue from 'p-queue'
4
  import { store, type AccessTokenResponse, type TokenResponse } from './storage.js'
5
  import { handleError, closeContexts, withPage } from './browser.js'
6
- import { delay } from './utils.js'
7
  import { updateAllHashes, operations, updateHash } from './hashHandlers.js'
8
  import './cronjobs.js'
9
 
@@ -11,6 +11,12 @@ const app = express()
11
  const PORT = process.env.PORT || 3000
12
  export const queue: PQueue = new PQueue({ concurrency: 1 })
13
 
 
 
 
 
 
 
14
  app.get('/', (req, res) => {
15
  res.send('alive')
16
  })
@@ -46,60 +52,63 @@ app.get('/token', async (req, res) => {
46
  return res.json({ access: store.access!, client: store.client! } satisfies TokenResponse)
47
  }
48
 
49
- const result = await queue.add(async () => {
50
- // if there was a request before, check it's result before making new one
51
- if (isTokenValid()) {
52
- console.log('Returning cached data')
53
- return { access: store.access!, client: store.client! } satisfies TokenResponse
54
- }
55
-
56
- return await withPage<TokenResponse>(async (page) => {
57
- // access token
58
- const accessTokenPromise = page
59
- .waitForResponse(async (res) => res.url().includes('https://open.spotify.com/api/token') && res.status() === 200)
60
- .then(async (res) => res.json() as Promise<AccessTokenResponse>)
61
-
62
- // client token
63
- const clientTokenPromise = page
64
- .waitForResponse(
65
- async (res) => res.url().includes('https://clienttoken.spotify.com/v1/clienttoken') && res.status() === 200,
66
- )
67
- .then(async (res) => {
68
- const json = await res.json().catch(() => null)
69
- const req = res.request()
70
- const payload = req.postDataJSON()
71
-
72
- return {
73
- ...json.granted_token,
74
- client_version: payload.client_data.client_version,
75
- }
76
- })
77
-
78
- // get tokens
79
- const [accessTokenRes, clientTokenRes] = await Promise.all([
80
- accessTokenPromise,
81
- clientTokenPromise,
82
- page.goto('https://open.spotify.com/', { waitUntil: 'domcontentloaded', timeout: 60000 }),
83
- ])
84
- console.log('Token obtained successfully')
85
-
86
- // format data
87
- store.access = accessTokenRes
88
- store.client = {
89
- expiresAt: Date.now() + clientTokenRes.refresh_after_seconds * 1000,
90
- token: clientTokenRes.token,
91
- version: clientTokenRes.client_version,
92
  }
93
- return { access: store.access!, client: store.client! } satisfies TokenResponse
94
- })
95
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  if (!result) throw new Error('Failed to obtain token')
97
 
98
  res.json(result)
99
  })
100
 
101
  app.get('/hashes', (req, res) => {
102
- const raw = req.query.names as string | undefined
103
  if (raw) {
104
  const names = raw.split(',')
105
  const filtered = Object.fromEntries(Object.entries(store.hashes).filter(([key]) => names.includes(key)))
@@ -110,7 +119,7 @@ app.get('/hashes', (req, res) => {
110
  })
111
 
112
  app.put('/hashes', async (req, res) => {
113
- const raw = req.query.names as string
114
  let tempHash = store.tempHashes
115
 
116
  const names = raw ? raw.split(',') : null
 
3
  import PQueue from 'p-queue'
4
  import { store, type AccessTokenResponse, type TokenResponse } from './storage.js'
5
  import { handleError, closeContexts, withPage } from './browser.js'
6
+ import { delay, logMemory } from './utils.js'
7
  import { updateAllHashes, operations, updateHash } from './hashHandlers.js'
8
  import './cronjobs.js'
9
 
 
11
  const PORT = process.env.PORT || 3000
12
  export const queue: PQueue = new PQueue({ concurrency: 1 })
13
 
14
+ app.use((req, res, next) => {
15
+ logMemory(`--> Start ${req.method} ${req.url}`)
16
+ res.on('finish', () => logMemory(`<-- End ${req.method} ${req.url}`))
17
+ next()
18
+ })
19
+
20
  app.get('/', (req, res) => {
21
  res.send('alive')
22
  })
 
52
  return res.json({ access: store.access!, client: store.client! } satisfies TokenResponse)
53
  }
54
 
55
+ const result = await queue.add(
56
+ async () => {
57
+ // if there was a request before, check it's result before making new one
58
+ if (isTokenValid()) {
59
+ console.log('Returning cached data')
60
+ return { access: store.access!, client: store.client! } satisfies TokenResponse
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
+
63
+ return await withPage<TokenResponse>(async (page) => {
64
+ // access token
65
+ const accessTokenPromise = page
66
+ .waitForResponse(async (res) => res.url().includes('https://open.spotify.com/api/token') && res.status() === 200)
67
+ .then(async (res) => res.json() as Promise<AccessTokenResponse>)
68
+
69
+ // client token
70
+ const clientTokenPromise = page
71
+ .waitForResponse(
72
+ async (res) => res.url().includes('https://clienttoken.spotify.com/v1/clienttoken') && res.status() === 200,
73
+ )
74
+ .then(async (res) => {
75
+ const json = await res.json().catch(() => null)
76
+ const req = res.request()
77
+ const payload = req.postDataJSON()
78
+
79
+ return {
80
+ ...json.granted_token,
81
+ client_version: payload.client_data.client_version,
82
+ }
83
+ })
84
+
85
+ // get tokens
86
+ const [accessTokenRes, clientTokenRes] = await Promise.all([
87
+ accessTokenPromise,
88
+ clientTokenPromise,
89
+ page.goto('https://open.spotify.com/', { waitUntil: 'domcontentloaded', timeout: 60000 }),
90
+ ])
91
+ console.log('Token obtained successfully')
92
+
93
+ // format data
94
+ store.access = accessTokenRes
95
+ store.client = {
96
+ expiresAt: Date.now() + clientTokenRes.refresh_after_seconds * 1000,
97
+ token: clientTokenRes.token,
98
+ version: clientTokenRes.client_version,
99
+ }
100
+ return { access: store.access!, client: store.client! } satisfies TokenResponse
101
+ })
102
+ },
103
+ { priority: 1 },
104
+ )
105
  if (!result) throw new Error('Failed to obtain token')
106
 
107
  res.json(result)
108
  })
109
 
110
  app.get('/hashes', (req, res) => {
111
+ const raw = String(req.query.names || '')
112
  if (raw) {
113
  const names = raw.split(',')
114
  const filtered = Object.fromEntries(Object.entries(store.hashes).filter(([key]) => names.includes(key)))
 
119
  })
120
 
121
  app.put('/hashes', async (req, res) => {
122
+ const raw = String(req.query.names || '')
123
  let tempHash = store.tempHashes
124
 
125
  const names = raw ? raw.split(',') : null
src/utils.ts CHANGED
@@ -11,3 +11,14 @@ export function generateRandomString(maxLength: number): string {
11
  }
12
 
13
  export const delay = (ms: number, jitter = 500) => new Promise((resolve) => setTimeout(resolve, ms + Math.random() * jitter))
 
 
 
 
 
 
 
 
 
 
 
 
11
  }
12
 
13
  export const delay = (ms: number, jitter = 500) => new Promise((resolve) => setTimeout(resolve, ms + Math.random() * jitter))
14
+
15
+ export function logMemory(label: string = '') {
16
+ const usage = process.memoryUsage()
17
+ // RSS (Resident Set Size) — це загальний обсяг пам'яті процесу,
18
+ // включаючи C++ об'єкти (Chromium), що критично для Playwright.
19
+ const rss = Math.round(usage.rss / 1024 / 1024)
20
+ const heap = Math.round(usage.heapUsed / 1024 / 1024)
21
+ const external = Math.round(usage.external / 1024 / 1024)
22
+
23
+ console.log(`[MEM] ${label} -> RSS: ${rss} MB | Heap: ${heap} MB | Ext: ${external} MB`)
24
+ }