mirror of https://github.com/Chocobozzz/PeerTube
				
				
				
			
		
			
				
	
	
		
			80 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
| import { pathExists } from 'fs-extra/esm'
 | |
| import { writeFile } from 'fs/promises'
 | |
| import maxmind, { CountryResponse, Reader } from 'maxmind'
 | |
| import { join } from 'path'
 | |
| import { CONFIG } from '@server/initializers/config.js'
 | |
| import { logger, loggerTagsFactory } from './logger.js'
 | |
| import { isBinaryResponse, peertubeGot } from './requests.js'
 | |
| 
 | |
| const lTags = loggerTagsFactory('geo-ip')
 | |
| 
 | |
| const mmbdFilename = 'dbip-country-lite-latest.mmdb'
 | |
| const mmdbPath = join(CONFIG.STORAGE.BIN_DIR, mmbdFilename)
 | |
| 
 | |
| export class GeoIP {
 | |
|   private static instance: GeoIP
 | |
| 
 | |
|   private reader: Reader<CountryResponse>
 | |
| 
 | |
|   private constructor () {
 | |
|   }
 | |
| 
 | |
|   async safeCountryISOLookup (ip: string): Promise<string> {
 | |
|     if (CONFIG.GEO_IP.ENABLED === false) return null
 | |
| 
 | |
|     await this.initReaderIfNeeded()
 | |
| 
 | |
|     try {
 | |
|       const result = this.reader.get(ip)
 | |
|       if (!result) return null
 | |
| 
 | |
|       return result.country.iso_code
 | |
|     } catch (err) {
 | |
|       logger.error('Cannot get country from IP.', { err })
 | |
| 
 | |
|       return null
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   async updateDatabase () {
 | |
|     if (CONFIG.GEO_IP.ENABLED === false) return
 | |
| 
 | |
|     const url = CONFIG.GEO_IP.COUNTRY.DATABASE_URL
 | |
| 
 | |
|     logger.info('Updating GeoIP database from %s.', url, lTags())
 | |
| 
 | |
|     const gotOptions = { context: { bodyKBLimit: 200_000 }, responseType: 'buffer' as 'buffer' }
 | |
| 
 | |
|     try {
 | |
|       const gotResult = await peertubeGot(url, gotOptions)
 | |
| 
 | |
|       if (!isBinaryResponse(gotResult)) {
 | |
|         throw new Error('Not a binary response')
 | |
|       }
 | |
| 
 | |
|       await writeFile(mmdbPath, gotResult.body)
 | |
| 
 | |
|       // Reinit reader
 | |
|       this.reader = undefined
 | |
| 
 | |
|       logger.info('GeoIP database updated %s.', mmdbPath, lTags())
 | |
|     } catch (err) {
 | |
|       logger.error('Cannot update GeoIP database from %s.', url, { err, ...lTags() })
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   private async initReaderIfNeeded () {
 | |
|     if (!this.reader) {
 | |
|       if (!await pathExists(mmdbPath)) {
 | |
|         await this.updateDatabase()
 | |
|       }
 | |
| 
 | |
|       this.reader = await maxmind.open(mmdbPath)
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static get Instance () {
 | |
|     return this.instance || (this.instance = new this())
 | |
|   }
 | |
| }
 |