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: | ||||
|   workflow_dispatch: | ||||
| 
 | ||||
| env: | ||||
|     REGISTRY: ghcr.io | ||||
|     ORG: dumtruck | ||||
|     PROJECT: konobangu | ||||
| 
 | ||||
| jobs: | ||||
|   build-container: | ||||
|     runs-on: ubuntu-latest | ||||
| @ -18,11 +23,11 @@ jobs: | ||||
|           username: ${{ github.actor }} | ||||
|           password: ${{ secrets.GITHUB_TOKEN }} | ||||
|       - name: Build and push Docker image | ||||
|               uses: docker/build-push-action@v5 | ||||
|               with: | ||||
|                 context: 'packages/testing-torrents' | ||||
|                 file: './Dockerfile' | ||||
|                 push: true | ||||
|                 tags: 'ghcr.io/${{ env.ORG }}/konobangu-testing-torrents:latest' | ||||
|                 cache-from: type=gha | ||||
|                 cache-to: type=gha,mode=max | ||||
|         uses: docker/build-push-action@v5 | ||||
|         with: | ||||
|           context: 'packages/testing-torrents' | ||||
|           file: './Dockerfile' | ||||
|           push: true | ||||
|           tags: 'ghcr.io/${{ env.ORG }}/${{ env.PROJECT }}-testing-torrents:latest' | ||||
|           cache-from: type=gha | ||||
|           cache-to: type=gha,mode=max | ||||
|  | ||||
							
								
								
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							| @ -5,7 +5,6 @@ | ||||
|     "unifiedjs.vscode-mdx", | ||||
|     "mikestead.dotenv", | ||||
|     "christian-kohler.npm-intellisense", | ||||
|     "skellock.just", | ||||
|     "charliermarsh.ruff" | ||||
|     "skellock.just" | ||||
|   ] | ||||
| } | ||||
|  | ||||
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -28,8 +28,5 @@ | ||||
|   "emmet.showExpandedAbbreviation": "never", | ||||
|   "prettier.enable": false, | ||||
|   "typescript.tsdk": "node_modules/typescript/lib", | ||||
|   "rust-analyzer.cargo.features": ["testcontainers"], | ||||
|   "[python]": { | ||||
|     "editor.defaultFormatter": "charliermarsh.ruff"  | ||||
|   } | ||||
|   "rust-analyzer.cargo.features": ["testcontainers"] | ||||
| } | ||||
|  | ||||
							
								
								
									
										14
									
								
								biome.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								biome.json
									
									
									
									
									
								
							| @ -10,7 +10,9 @@ | ||||
|         "noNonNullAssertion": "off" | ||||
|       }, | ||||
|       "suspicious": { | ||||
|         "noExplicitAny": "off" | ||||
|         "noExplicitAny": "off", | ||||
|         "noConsole": "off", | ||||
|         "noConsoleLog": "off" | ||||
|       }, | ||||
|       "a11y": { | ||||
|         "noSvgWithoutTitle": "off" | ||||
| @ -27,14 +29,6 @@ | ||||
|     } | ||||
|   }, | ||||
|   "files": { | ||||
|     "ignore": [ | ||||
|       "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" | ||||
|     ] | ||||
|     "ignore": [".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 | ||||
| RUN npm install -g pnpm | ||||
| ENV PNPM_HOME="/pnpm" | ||||
| ENV PATH="$PNPM_HOME:$PATH" | ||||
| 
 | ||||
| FROM nodebt AS deps | ||||
| 
 | ||||
| RUN mkdir -p /app/workspace | ||||
| WORKDIR /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 | ||||
| 
 | ||||
|  | ||||
| @ -1,39 +1,40 @@ | ||||
| import Fastify from 'fastify'; | ||||
| import fastifyStatic from '@fastify/static'; | ||||
| import { join } from 'node:path'; | ||||
| import Fastify from 'fastify'; | ||||
| 
 | ||||
| import WebTorrent, { Torrent } from 'webtorrent'; | ||||
| import createTorrent from 'create-torrent' | ||||
| import fs from 'node:fs'; | ||||
| import fsp from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| // @ts-ignore
 | ||||
| import TrackerServer from 'bittorrent-tracker/server' | ||||
| import fs, { existsSync, mkdirSync, writeFileSync } from 'node:fs'; | ||||
| import TrackerServer from 'bittorrent-tracker/server'; | ||||
| import createTorrent from 'create-torrent'; | ||||
| import WebTorrent, { type Torrent } from 'webtorrent'; | ||||
| 
 | ||||
| // Configuration
 | ||||
| const API_PORT = 6080; | ||||
| 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 WORKSPACE_PATH = 'workspace'; | ||||
| 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
 | ||||
| const app = Fastify({ logger: true }); | ||||
| 
 | ||||
| // Mount static file service, mapping ./workspace directory to /api/static route
 | ||||
| app.register(fastifyStatic, { | ||||
|     root: join(process.cwd(), 'workspace'), | ||||
|     prefix: '/api/static', | ||||
|   root: path.join(process.cwd(), WORKSPACE_PATH), | ||||
|   prefix: STATIC_API_PATH, | ||||
| }); | ||||
| 
 | ||||
| const tracker = new TrackerServer({ | ||||
|     udp: true, // enable udp server? [default=true]
 | ||||
|     http: true, // enable http server? [default=true]
 | ||||
|     ws: true, // enable websocket server? [default=true]
 | ||||
|     stats: true, // enable web-based statistics? [default=true]
 | ||||
|     trustProxy: true, // enable trusting x-forwarded-for header for remote IP [default=false]
 | ||||
|   udp: true, // enable udp server? [default=true]
 | ||||
|   http: true, // enable http server? [default=true]
 | ||||
|   ws: true, // enable websocket server? [default=true]
 | ||||
|   stats: true, // enable web-based statistics? [default=true]
 | ||||
|   trustProxy: true, // enable trusting x-forwarded-for header for remote IP [default=false]
 | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| // Define request and response type definitions
 | ||||
| interface FileItem { | ||||
|   path: string; | ||||
| @ -52,25 +53,22 @@ interface ResponseSchema { | ||||
| 
 | ||||
| // Start local Tracker
 | ||||
| async function startTracker(): Promise<void> { | ||||
|     return new Promise<void>((resolve, reject) => { | ||||
|         tracker.listen(TRACKER_PORT, "localhost", () => { | ||||
|             console.log(`Tracker listening on port ${TRACKER_PORT}`); | ||||
|             resolve(); | ||||
|         }); | ||||
|         tracker.on('error', (err: any) => { | ||||
|             console.error(`Tracker error: ${err}`) | ||||
|             reject(`Tracker error: ${err}`); | ||||
|         }); | ||||
|         tracker.on('warning', (warn: any) => console.warn(`Tracker warning: ${warn}`)); | ||||
|         // Log tracked torrents
 | ||||
|         tracker.on('update', (addr: any, params: any) => { | ||||
|             console.log(`Tracker update: ${params.info_hash} from ${addr}`); | ||||
|         }); | ||||
|         tracker.on('stop', function () { | ||||
|             reject(`Tracker stopped`); | ||||
|         }) | ||||
|          | ||||
|   return new Promise<void>((resolve, reject) => { | ||||
|     tracker.listen(TRACKER_PORT, 'localhost', () => { | ||||
|       console.log(`Tracker listening on port ${TRACKER_PORT}`); | ||||
|       resolve(); | ||||
|     }); | ||||
|     tracker.on('error', (err: any) => { | ||||
|       reject(`Tracker error: ${err}`); | ||||
|     }); | ||||
|     tracker.on('warning', (warn: any) => | ||||
|       console.warn(`Tracker warning: ${warn}`) | ||||
|     ); | ||||
|     // Log tracked torrents
 | ||||
|     tracker.on('update', (addr: any, params: any) => { | ||||
|       console.log(`Tracker update: ${params.info_hash} from ${addr}`); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Tracker and WebTorrent client
 | ||||
| @ -78,73 +76,80 @@ const webTorrent = new WebTorrent({}); | ||||
| 
 | ||||
| // Generate mock file
 | ||||
| async function generateMockFile(filePath: string, size: number) { | ||||
|   const dir = join(filePath, '..'); | ||||
|   if (!existsSync(dir)) { | ||||
|     mkdirSync(dir, { recursive: true }) | ||||
|   }; | ||||
|   const dir = path.dirname(filePath); | ||||
|   if (!fs.existsSync(dir)) { | ||||
|     await fsp.mkdir(dir, { recursive: true }); | ||||
|   } | ||||
| 
 | ||||
|   fs.writeFileSync(filePath, 'w'); | ||||
|   fs.truncateSync(filePath, size); | ||||
|   await fsp.truncate(filePath, size); | ||||
| } | ||||
| 
 | ||||
| // Generate torrent file
 | ||||
| function generateTorrent(folderPath: string, torrentPath: string): Promise<void> { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       createTorrent( | ||||
|         folderPath, | ||||
|         { | ||||
|           announceList: [[TRACKER_URL]], // Specify tracker URL
 | ||||
|           private: false, | ||||
|           createdBy: 'WebTorrent', | ||||
|           comment: 'Generated by WebTorrent server', | ||||
|           urlList: [API_BASE_URL] | ||||
|         }, | ||||
|         (err, torrent) => { | ||||
|           if (err) { | ||||
|             reject(new Error(`Failed to create torrent: ${err}`)); | ||||
|             return; | ||||
|           } | ||||
|           writeFileSync(torrentPath, torrent); | ||||
|           if (!existsSync(torrentPath)) { | ||||
|             reject(new Error(`Torrent file ${torrentPath} was not created`)); | ||||
|             return; | ||||
|           } | ||||
|           console.log(`Generated torrent with tracker: ${TRACKER_URL}`); | ||||
|           resolve(); | ||||
| function generateTorrent(folderPath: string, torrentPath: string) { | ||||
|   return new Promise<void>((resolve, reject) => { | ||||
|     createTorrent( | ||||
|       folderPath, | ||||
|       { | ||||
|         announceList: [[TRACKER_URL]], // Specify tracker URL
 | ||||
|         private: false, | ||||
|         createdBy: 'WebTorrent', | ||||
|         comment: 'Generated by WebTorrent server', | ||||
|         urlList: [API_BASE_URL], | ||||
|       }, | ||||
|       async (err, torrent) => { | ||||
|         if (err) { | ||||
|           reject(new Error(`Failed to create torrent: ${err}`)); | ||||
|           return; | ||||
|         } | ||||
|       ); | ||||
|     }); | ||||
|   } | ||||
|         await fsp.writeFile(torrentPath, torrent); | ||||
|         if (!fs.existsSync(torrentPath)) { | ||||
|           reject(new Error(`Torrent file ${torrentPath} was not created`)); | ||||
|           return; | ||||
|         } | ||||
|         console.log(`Generated torrent with tracker: ${TRACKER_URL}`); | ||||
|         resolve(); | ||||
|       } | ||||
|     ); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Add torrent and seed
 | ||||
| async function seedTorrent(torrentPath: string): Promise<Torrent> { | ||||
|     return new Promise((resolve) => { | ||||
|         const torrent = webTorrent.seed(torrentPath, { | ||||
|             announce: [TRACKER_URL], | ||||
|         }, (t) => { | ||||
|             resolve(t); | ||||
|         }); | ||||
|         torrent.on('error', (err) => console.error(`Torrent error: ${err}`)); | ||||
|         torrent.on('wire', (wire) => console.log(`Connected to peer: ${wire.peerId}`)); | ||||
|         torrent.on('done', () => console.log(`Torrent ${torrent.infoHash} fully seeded`)); | ||||
|     }) | ||||
|   return new Promise((resolve) => { | ||||
|     const torrent = webTorrent.seed( | ||||
|       torrentPath, | ||||
|       { | ||||
|         announce: [TRACKER_URL], | ||||
|       }, | ||||
|       (t) => { | ||||
|         resolve(t); | ||||
|       } | ||||
|     ); | ||||
|     torrent.on('error', (err) => console.error(`Torrent error: ${err}`)); | ||||
|     torrent.on('wire', (wire) => | ||||
|       console.log(`Connected to peer: ${wire.peerId}`) | ||||
|     ); | ||||
|     torrent.on('done', () => | ||||
|       console.log(`Torrent ${torrent.infoHash} fully seeded`) | ||||
|     ); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Handle POST request to /api/torrents/mock
 | ||||
| app.post<{ Body: RequestSchema }>('/api/torrents/mock', async (req, _reply) => { | ||||
|   const { id, fileList } = req.body; | ||||
| 
 | ||||
|   const idFolder = join('./workspace', id); | ||||
|   if (!existsSync(idFolder)) { | ||||
|     mkdirSync(idFolder, { recursive: true }) | ||||
|   }; | ||||
|   const idFolder = path.join(WORKSPACE_PATH, id); | ||||
|   if (!fs.existsSync(idFolder)) { | ||||
|     await fsp.mkdir(idFolder, { recursive: true }); | ||||
|   } | ||||
| 
 | ||||
|   for (const fileItem of fileList) { | ||||
|     const filePath = join(idFolder, fileItem.path); | ||||
|     const filePath = path.join(idFolder, fileItem.path); | ||||
|     await generateMockFile(filePath, fileItem.size); | ||||
|   } | ||||
| 
 | ||||
|   const torrentPath = join('./workspace', `${id}.torrent`); | ||||
|   const torrentPath = path.join(WORKSPACE_PATH, `${id}.torrent`); | ||||
|   await generateTorrent(idFolder, torrentPath); | ||||
| 
 | ||||
|   const torrent = await seedTorrent(torrentPath); | ||||
| @ -160,8 +165,7 @@ app.post<{ Body: RequestSchema }>('/api/torrents/mock', async (req, _reply) => { | ||||
| async function main() { | ||||
|   try { | ||||
|     await startTracker(); | ||||
|     await app.listen({ port: API_PORT, host: '0.0.0.0' }); | ||||
|     console.log(`Fastify running on http://0.0.0.0:${API_PORT}`); | ||||
|     await app.listen({ port: API_PORT, host: LOCAL_IP }); | ||||
|   } catch (err) { | ||||
|     console.error('Startup error:', err); | ||||
|     webTorrent.destroy(); | ||||
| @ -174,8 +178,8 @@ main(); | ||||
| 
 | ||||
| // Graceful shutdown
 | ||||
| process.on('SIGINT', () => { | ||||
|     console.log('Shutting down...'); | ||||
|     tracker.close(); | ||||
|     webTorrent.destroy(); | ||||
|     process.exit(0); | ||||
|   console.log('Shutting down...'); | ||||
|   tracker.close(); | ||||
|   webTorrent.destroy(); | ||||
|   process.exit(0); | ||||
| }); | ||||
| @ -1,22 +1,29 @@ | ||||
| { | ||||
|     "name": "@konobangu/testing-torrents", | ||||
|     "version": "0.0.1", | ||||
|     "description": "Kono bangumi? Testing Torrents", | ||||
|     "main": "main.ts", | ||||
|     "type": "commonjs", | ||||
|     "scripts": { | ||||
|         "start": "tsx main.ts" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@fastify/static": "^8.1.1", | ||||
|         "bittorrent-tracker": "^11.2.1", | ||||
|         "create-torrent": "^6.1.0", | ||||
|         "fastify": "^5.2.2", | ||||
|         "tsx": "^4.19.2", | ||||
|         "webtorrent": "^2.5.19" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@types/create-torrent": "^5.0.2", | ||||
|         "@types/webtorrent": "^0.110.0" | ||||
|     } | ||||
|   "name": "@konobangu/testing-torrents", | ||||
|   "version": "0.0.1", | ||||
|   "description": "Kono bangumi? Testing Torrents", | ||||
|   "main": "main.ts", | ||||
|   "type": "commonjs", | ||||
|   "scripts": { | ||||
|     "start": "tsx main.ts" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@fastify/static": "^8.1.1", | ||||
|     "bittorrent-tracker": "^11.2.1", | ||||
|     "create-torrent": "^6.1.0", | ||||
|     "fastify": "^5.2.2", | ||||
|     "tsx": "^4.19.2", | ||||
|     "webtorrent": "^2.5.19" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/create-torrent": "^5.0.2", | ||||
|     "@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/* | ||||
|   - apps/* | ||||
|   - '!packages/testing-torrents' | ||||
| onlyBuiltDependencies: | ||||
|   - '@biomejs/biome' | ||||
|   - bufferutil | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user