fix: fix testing torrents container
This commit is contained in:
		
							parent
							
								
									a0fc4c04d9
								
							
						
					
					
						commit
						1fca69fa66
					
				| @ -3,6 +3,11 @@ name: Build and Push Testing Torrents Container | |||||||
| on: | on: | ||||||
|   workflow_dispatch: |   workflow_dispatch: | ||||||
| 
 | 
 | ||||||
|  | env: | ||||||
|  |     REGISTRY: ghcr.io | ||||||
|  |     ORG: dumtruck | ||||||
|  |     PROJECT: konobangu | ||||||
|  | 
 | ||||||
| jobs: | jobs: | ||||||
|   build-container: |   build-container: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
| @ -23,6 +28,6 @@ jobs: | |||||||
|           context: 'packages/testing-torrents' |           context: 'packages/testing-torrents' | ||||||
|           file: './Dockerfile' |           file: './Dockerfile' | ||||||
|           push: true |           push: true | ||||||
|                 tags: 'ghcr.io/${{ env.ORG }}/konobangu-testing-torrents:latest' |           tags: 'ghcr.io/${{ env.ORG }}/${{ env.PROJECT }}-testing-torrents:latest' | ||||||
|           cache-from: type=gha |           cache-from: type=gha | ||||||
|           cache-to: type=gha,mode=max |           cache-to: type=gha,mode=max | ||||||
							
								
								
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							| @ -5,7 +5,6 @@ | |||||||
|     "unifiedjs.vscode-mdx", |     "unifiedjs.vscode-mdx", | ||||||
|     "mikestead.dotenv", |     "mikestead.dotenv", | ||||||
|     "christian-kohler.npm-intellisense", |     "christian-kohler.npm-intellisense", | ||||||
|     "skellock.just", |     "skellock.just" | ||||||
|     "charliermarsh.ruff" |  | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -28,8 +28,5 @@ | |||||||
|   "emmet.showExpandedAbbreviation": "never", |   "emmet.showExpandedAbbreviation": "never", | ||||||
|   "prettier.enable": false, |   "prettier.enable": false, | ||||||
|   "typescript.tsdk": "node_modules/typescript/lib", |   "typescript.tsdk": "node_modules/typescript/lib", | ||||||
|   "rust-analyzer.cargo.features": ["testcontainers"], |   "rust-analyzer.cargo.features": ["testcontainers"] | ||||||
|   "[python]": { |  | ||||||
|     "editor.defaultFormatter": "charliermarsh.ruff"  |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								biome.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								biome.json
									
									
									
									
									
								
							| @ -10,7 +10,9 @@ | |||||||
|         "noNonNullAssertion": "off" |         "noNonNullAssertion": "off" | ||||||
|       }, |       }, | ||||||
|       "suspicious": { |       "suspicious": { | ||||||
|         "noExplicitAny": "off" |         "noExplicitAny": "off", | ||||||
|  |         "noConsole": "off", | ||||||
|  |         "noConsoleLog": "off" | ||||||
|       }, |       }, | ||||||
|       "a11y": { |       "a11y": { | ||||||
|         "noSvgWithoutTitle": "off" |         "noSvgWithoutTitle": "off" | ||||||
| @ -27,14 +29,6 @@ | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "files": { |   "files": { | ||||||
|     "ignore": [ |     "ignore": [".vscode/*.json"] | ||||||
|       "packages/design-system/components/ui/**", |  | ||||||
|       "packages/design-system/lib/**", |  | ||||||
|       "packages/design-system/hooks/**", |  | ||||||
|       "packages/collaboration/config.ts", |  | ||||||
|       "apps/docs/**/*.json", |  | ||||||
|       "apps/email/.react-email/**", |  | ||||||
|       ".vscode/*.json" |  | ||||||
|     ] |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,31 +0,0 @@ | |||||||
| version: '3' |  | ||||||
| 
 |  | ||||||
| services: |  | ||||||
|   webui: |  | ||||||
|     image: node:22-alpine |  | ||||||
|     ports: |  | ||||||
|       - '5000:5000' |  | ||||||
|     volumes: |  | ||||||
|       - ./apps/webui:/home/node/app |  | ||||||
|       - node_modules:/home/node/app/node_modules |  | ||||||
|     working_dir: /home/node/app/ |  | ||||||
|     command: sh -c "yarn install && yarn dev" |  | ||||||
|     depends_on: |  | ||||||
|       - mongo |  | ||||||
|     env_file: |  | ||||||
|       - .env |  | ||||||
| 
 |  | ||||||
|   mongo: |  | ||||||
|     image: mongo:latest |  | ||||||
|     ports: |  | ||||||
|       - '27017:27017' |  | ||||||
|     command: |  | ||||||
|       - --storageEngine=wiredTiger |  | ||||||
|     volumes: |  | ||||||
|       - data:/data/db |  | ||||||
|     logging: |  | ||||||
|       driver: none |  | ||||||
| 
 |  | ||||||
| volumes: |  | ||||||
|   data: |  | ||||||
|   node_modules: |  | ||||||
| @ -1,11 +1,14 @@ | |||||||
| FROM node:23-slim AS nodebt | FROM node:23-slim AS nodebt | ||||||
|  | RUN npm install -g pnpm | ||||||
|  | ENV PNPM_HOME="/pnpm" | ||||||
|  | ENV PATH="$PNPM_HOME:$PATH" | ||||||
| 
 | 
 | ||||||
| FROM nodebt AS deps | FROM nodebt AS deps | ||||||
| 
 | 
 | ||||||
| RUN mkdir -p /app/workspace | RUN mkdir -p /app/workspace | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| COPY package.json /app/ | COPY package.json /app/ | ||||||
| RUN npm install | RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --no-frozen-lockfile | ||||||
| 
 | 
 | ||||||
| FROM deps AS app | FROM deps AS app | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,28 +1,30 @@ | |||||||
| import Fastify from 'fastify'; |  | ||||||
| import fastifyStatic from '@fastify/static'; | import fastifyStatic from '@fastify/static'; | ||||||
| import { join } from 'node:path'; | import Fastify from 'fastify'; | ||||||
| 
 | 
 | ||||||
| import WebTorrent, { Torrent } from 'webtorrent'; | import fs from 'node:fs'; | ||||||
| import createTorrent from 'create-torrent' | import fsp from 'node:fs/promises'; | ||||||
|  | import path from 'node:path'; | ||||||
| // @ts-ignore
 | // @ts-ignore
 | ||||||
| import TrackerServer from 'bittorrent-tracker/server' | import TrackerServer from 'bittorrent-tracker/server'; | ||||||
| import fs, { existsSync, mkdirSync, writeFileSync } from 'node:fs'; | import createTorrent from 'create-torrent'; | ||||||
|  | import WebTorrent, { type Torrent } from 'webtorrent'; | ||||||
| 
 | 
 | ||||||
| // Configuration
 | // Configuration
 | ||||||
| const API_PORT = 6080; | const API_PORT = 6080; | ||||||
| const TRACKER_PORT = 6081; | const TRACKER_PORT = 6081; | ||||||
| // Get local IP address for broader accessibility
 | const STATIC_API_PATH = '/api/static'; | ||||||
| const LOCAL_IP = '127.0.0.1'; | const LOCAL_IP = '127.0.0.1'; | ||||||
|  | const WORKSPACE_PATH = 'workspace'; | ||||||
| const TRACKER_URL = `http://${LOCAL_IP}:${TRACKER_PORT}/announce`; | const TRACKER_URL = `http://${LOCAL_IP}:${TRACKER_PORT}/announce`; | ||||||
| const API_BASE_URL = `http://${LOCAL_IP}:${API_PORT}/api/static/`; | const API_BASE_URL = `http://${LOCAL_IP}:${API_PORT}/${STATIC_API_PATH}/`; | ||||||
| 
 | 
 | ||||||
| // Initialize Fastify instance
 | // Initialize Fastify instance
 | ||||||
| const app = Fastify({ logger: true }); | const app = Fastify({ logger: true }); | ||||||
| 
 | 
 | ||||||
| // Mount static file service, mapping ./workspace directory to /api/static route
 | // Mount static file service, mapping ./workspace directory to /api/static route
 | ||||||
| app.register(fastifyStatic, { | app.register(fastifyStatic, { | ||||||
|     root: join(process.cwd(), 'workspace'), |   root: path.join(process.cwd(), WORKSPACE_PATH), | ||||||
|     prefix: '/api/static', |   prefix: STATIC_API_PATH, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const tracker = new TrackerServer({ | const tracker = new TrackerServer({ | ||||||
| @ -33,7 +35,6 @@ const tracker = new TrackerServer({ | |||||||
|   trustProxy: true, // enable trusting x-forwarded-for header for remote IP [default=false]
 |   trustProxy: true, // enable trusting x-forwarded-for header for remote IP [default=false]
 | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| // Define request and response type definitions
 | // Define request and response type definitions
 | ||||||
| interface FileItem { | interface FileItem { | ||||||
|   path: string; |   path: string; | ||||||
| @ -53,23 +54,20 @@ interface ResponseSchema { | |||||||
| // Start local Tracker
 | // Start local Tracker
 | ||||||
| async function startTracker(): Promise<void> { | async function startTracker(): Promise<void> { | ||||||
|   return new Promise<void>((resolve, reject) => { |   return new Promise<void>((resolve, reject) => { | ||||||
|         tracker.listen(TRACKER_PORT, "localhost", () => { |     tracker.listen(TRACKER_PORT, 'localhost', () => { | ||||||
|       console.log(`Tracker listening on port ${TRACKER_PORT}`); |       console.log(`Tracker listening on port ${TRACKER_PORT}`); | ||||||
|       resolve(); |       resolve(); | ||||||
|     }); |     }); | ||||||
|     tracker.on('error', (err: any) => { |     tracker.on('error', (err: any) => { | ||||||
|             console.error(`Tracker error: ${err}`) |  | ||||||
|       reject(`Tracker error: ${err}`); |       reject(`Tracker error: ${err}`); | ||||||
|     }); |     }); | ||||||
|         tracker.on('warning', (warn: any) => console.warn(`Tracker warning: ${warn}`)); |     tracker.on('warning', (warn: any) => | ||||||
|  |       console.warn(`Tracker warning: ${warn}`) | ||||||
|  |     ); | ||||||
|     // Log tracked torrents
 |     // Log tracked torrents
 | ||||||
|     tracker.on('update', (addr: any, params: any) => { |     tracker.on('update', (addr: any, params: any) => { | ||||||
|       console.log(`Tracker update: ${params.info_hash} from ${addr}`); |       console.log(`Tracker update: ${params.info_hash} from ${addr}`); | ||||||
|     }); |     }); | ||||||
|         tracker.on('stop', function () { |  | ||||||
|             reject(`Tracker stopped`); |  | ||||||
|         }) |  | ||||||
|          |  | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -78,18 +76,17 @@ const webTorrent = new WebTorrent({}); | |||||||
| 
 | 
 | ||||||
| // Generate mock file
 | // Generate mock file
 | ||||||
| async function generateMockFile(filePath: string, size: number) { | async function generateMockFile(filePath: string, size: number) { | ||||||
|   const dir = join(filePath, '..'); |   const dir = path.dirname(filePath); | ||||||
|   if (!existsSync(dir)) { |   if (!fs.existsSync(dir)) { | ||||||
|     mkdirSync(dir, { recursive: true }) |     await fsp.mkdir(dir, { recursive: true }); | ||||||
|   }; |   } | ||||||
| 
 | 
 | ||||||
|   fs.writeFileSync(filePath, 'w'); |   await fsp.truncate(filePath, size); | ||||||
|   fs.truncateSync(filePath, size); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Generate torrent file
 | // Generate torrent file
 | ||||||
| function generateTorrent(folderPath: string, torrentPath: string): Promise<void> { | function generateTorrent(folderPath: string, torrentPath: string) { | ||||||
|     return new Promise((resolve, reject) => { |   return new Promise<void>((resolve, reject) => { | ||||||
|     createTorrent( |     createTorrent( | ||||||
|       folderPath, |       folderPath, | ||||||
|       { |       { | ||||||
| @ -97,15 +94,15 @@ function generateTorrent(folderPath: string, torrentPath: string): Promise<void> | |||||||
|         private: false, |         private: false, | ||||||
|         createdBy: 'WebTorrent', |         createdBy: 'WebTorrent', | ||||||
|         comment: 'Generated by WebTorrent server', |         comment: 'Generated by WebTorrent server', | ||||||
|           urlList: [API_BASE_URL] |         urlList: [API_BASE_URL], | ||||||
|       }, |       }, | ||||||
|         (err, torrent) => { |       async (err, torrent) => { | ||||||
|         if (err) { |         if (err) { | ||||||
|           reject(new Error(`Failed to create torrent: ${err}`)); |           reject(new Error(`Failed to create torrent: ${err}`)); | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|           writeFileSync(torrentPath, torrent); |         await fsp.writeFile(torrentPath, torrent); | ||||||
|           if (!existsSync(torrentPath)) { |         if (!fs.existsSync(torrentPath)) { | ||||||
|           reject(new Error(`Torrent file ${torrentPath} was not created`)); |           reject(new Error(`Torrent file ${torrentPath} was not created`)); | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
| @ -114,37 +111,45 @@ function generateTorrent(folderPath: string, torrentPath: string): Promise<void> | |||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   }); |   }); | ||||||
|   } | } | ||||||
| 
 | 
 | ||||||
| // Add torrent and seed
 | // Add torrent and seed
 | ||||||
| async function seedTorrent(torrentPath: string): Promise<Torrent> { | async function seedTorrent(torrentPath: string): Promise<Torrent> { | ||||||
|   return new Promise((resolve) => { |   return new Promise((resolve) => { | ||||||
|         const torrent = webTorrent.seed(torrentPath, { |     const torrent = webTorrent.seed( | ||||||
|  |       torrentPath, | ||||||
|  |       { | ||||||
|         announce: [TRACKER_URL], |         announce: [TRACKER_URL], | ||||||
|         }, (t) => { |       }, | ||||||
|  |       (t) => { | ||||||
|         resolve(t); |         resolve(t); | ||||||
|         }); |       } | ||||||
|  |     ); | ||||||
|     torrent.on('error', (err) => console.error(`Torrent error: ${err}`)); |     torrent.on('error', (err) => console.error(`Torrent error: ${err}`)); | ||||||
|         torrent.on('wire', (wire) => console.log(`Connected to peer: ${wire.peerId}`)); |     torrent.on('wire', (wire) => | ||||||
|         torrent.on('done', () => console.log(`Torrent ${torrent.infoHash} fully seeded`)); |       console.log(`Connected to peer: ${wire.peerId}`) | ||||||
|     }) |     ); | ||||||
|  |     torrent.on('done', () => | ||||||
|  |       console.log(`Torrent ${torrent.infoHash} fully seeded`) | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Handle POST request to /api/torrents/mock
 | // Handle POST request to /api/torrents/mock
 | ||||||
| app.post<{ Body: RequestSchema }>('/api/torrents/mock', async (req, _reply) => { | app.post<{ Body: RequestSchema }>('/api/torrents/mock', async (req, _reply) => { | ||||||
|   const { id, fileList } = req.body; |   const { id, fileList } = req.body; | ||||||
| 
 | 
 | ||||||
|   const idFolder = join('./workspace', id); |   const idFolder = path.join(WORKSPACE_PATH, id); | ||||||
|   if (!existsSync(idFolder)) { |   if (!fs.existsSync(idFolder)) { | ||||||
|     mkdirSync(idFolder, { recursive: true }) |     await fsp.mkdir(idFolder, { recursive: true }); | ||||||
|   }; |   } | ||||||
| 
 | 
 | ||||||
|   for (const fileItem of fileList) { |   for (const fileItem of fileList) { | ||||||
|     const filePath = join(idFolder, fileItem.path); |     const filePath = path.join(idFolder, fileItem.path); | ||||||
|     await generateMockFile(filePath, fileItem.size); |     await generateMockFile(filePath, fileItem.size); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const torrentPath = join('./workspace', `${id}.torrent`); |   const torrentPath = path.join(WORKSPACE_PATH, `${id}.torrent`); | ||||||
|   await generateTorrent(idFolder, torrentPath); |   await generateTorrent(idFolder, torrentPath); | ||||||
| 
 | 
 | ||||||
|   const torrent = await seedTorrent(torrentPath); |   const torrent = await seedTorrent(torrentPath); | ||||||
| @ -160,8 +165,7 @@ app.post<{ Body: RequestSchema }>('/api/torrents/mock', async (req, _reply) => { | |||||||
| async function main() { | async function main() { | ||||||
|   try { |   try { | ||||||
|     await startTracker(); |     await startTracker(); | ||||||
|     await app.listen({ port: API_PORT, host: '0.0.0.0' }); |     await app.listen({ port: API_PORT, host: LOCAL_IP }); | ||||||
|     console.log(`Fastify running on http://0.0.0.0:${API_PORT}`); |  | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     console.error('Startup error:', err); |     console.error('Startup error:', err); | ||||||
|     webTorrent.destroy(); |     webTorrent.destroy(); | ||||||
|  | |||||||
| @ -18,5 +18,12 @@ | |||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/create-torrent": "^5.0.2", |     "@types/create-torrent": "^5.0.2", | ||||||
|     "@types/webtorrent": "^0.110.0" |     "@types/webtorrent": "^0.110.0" | ||||||
|  |   }, | ||||||
|  |   "pnpm": { | ||||||
|  |     "onlyBuiltDependencies": [ | ||||||
|  |       "utf-8-validate", | ||||||
|  |       "node-datachannel", | ||||||
|  |       "utp-native" | ||||||
|  |     ] | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										1567
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1567
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,6 +1,7 @@ | |||||||
| packages: | packages: | ||||||
|   - packages/* |   - packages/* | ||||||
|   - apps/* |   - apps/* | ||||||
|  |   - '!packages/testing-torrents' | ||||||
| onlyBuiltDependencies: | onlyBuiltDependencies: | ||||||
|   - '@biomejs/biome' |   - '@biomejs/biome' | ||||||
|   - bufferutil |   - bufferutil | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user