Skip to content

Commit

Permalink
feat: permanent upnp mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
ThaUnknown committed Apr 19, 2024
1 parent 7a2367f commit a1ca14c
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 157 deletions.
3 changes: 2 additions & 1 deletion capacitor/src/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export const SUPPORTS = {
torrentPersist: false,
keybinds: false,
isAndroid: true,
externalPlayer: false
externalPlayer: false,
permamentNAT: false // no way of safely closing app
}
18 changes: 9 additions & 9 deletions common/jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["./*"],
"three": ["./types.d.ts"],
"rxjs": ["./types.d.ts"],
},
"checkJs": true,
"target": "ESNext",
"moduleResolution": "bundler",
"moduleResolution": "node",
"module": "ESNext",
"allowSyntheticDefaultImports": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"resolveJsonModule": true,
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"module": "ESNext",
"types": ["./types.d.ts"],
"allowSyntheticDefaultImports": true
"baseUrl": "./",
"paths": {
"@/*": ["./*"],
"three": ["./types.d.ts"],
"rxjs": ["./types.d.ts"],
},
},
"exclude": [
"node_modules", "dist", "build", "git_modules", ".svelte-kit", "public", "android", "@types/three",
Expand Down
3 changes: 2 additions & 1 deletion common/modules/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export const SUPPORTS = {
keybinds: true,
extensions: true,
isAndroid: false,
externalPlayer: true
externalPlayer: true,
permamentNAT: true
}
11 changes: 9 additions & 2 deletions common/modules/webtorrent.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export default class TorrentClient extends WebTorrent {
playerProcess = null
torrentPath = ''

ipc

constructor (ipc, storageQuota, serverMode, torrentPath, controller) {
const settings = { ...defaults, ...storedSettings }
super({
Expand All @@ -47,8 +49,10 @@ export default class TorrentClient extends WebTorrent {
downloadLimit: settings.torrentSpeed * 1048576 || 0,
uploadLimit: settings.torrentSpeed * 1572864 || 0, // :trolled:
torrentPort: settings.torrentPort || 0,
dhtPort: settings.dhtPort || 0
dhtPort: settings.dhtPort || 0,
natUpnp: SUPPORTS.permamentNAT ? 'permanent' : true
})
this.ipc = ipc
this.torrentPath = torrentPath
this._ready = new Promise(resolve => {
ipc.on('port', ({ ports }) => {
Expand Down Expand Up @@ -279,8 +283,11 @@ export default class TorrentClient extends WebTorrent {
}

destroy () {
if (this.destroyed) return
this.parser?.destroy()
this.server.close()
super.destroy()
super.destroy(() => {
this.ipc.send('destroyed')
})
}
}
4 changes: 3 additions & 1 deletion common/webpack.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

/** @type {(parentDir: string, alias?: Record<string, string>, aliasFields?: (string | string[]), filename?: string) => import('webpack').WebpackOptionsNormalized} */
module.exports = (parentDir, alias = {}, aliasFields = 'browser', filename = 'app') => ({
devtool: 'source-map',
entry: [join(__dirname, 'main.js')],
entry: join(__dirname, 'main.js'),
stats: { warnings: false },
output: {
path: join(parentDir, 'build'),
filename: 'renderer.js'
Expand Down
3 changes: 2 additions & 1 deletion electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"main": "build/main.js",
"homepage": "https://github.com/ThaUnknown/miru#readme",
"scripts": {
"start": "cross-env NODE_ENV=development concurrently --kill-others \"npm run web:watch\" \"npm run electron:start\"",
"start": "cross-env NODE_ENV=development webpack build && concurrently --kill-others \"npm run web:watch\" \"npm run electron:start\"",
"web:watch": "webpack serve",
"web:build": "cross-env NODE_ENV=production webpack build",
"electron:start": "electron ./build/main.js",
Expand All @@ -25,6 +25,7 @@
"webpack-merge": "^5.10.0"
},
"dependencies": {
"@paymoapp/electron-shutdown-handler": "^1.0.15",
"utp-native": "^2.5.3"
},
"standard": {
Expand Down
134 changes: 134 additions & 0 deletions electron/src/main/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { join } from 'node:path'
import process from 'node:process'

import { BrowserWindow, MessageChannelMain, app, dialog, ipcMain, powerMonitor, shell } from 'electron'
import electronShutdownHandler from '@paymoapp/electron-shutdown-handler'

import { development } from './util.js'
import Discord from './discord.js'
import Protocol from './protocol.js'
import Updater from './updater.js'
import Dialog from './dialog.js'
import store from './store.js'

export default class App {
webtorrentWindow = new BrowserWindow({
show: development,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
nodeIntegration: true,
contextIsolation: false,
backgroundThrottling: false
}
})

mainWindow = new BrowserWindow({
width: 1600,
height: 900,
frame: process.platform === 'darwin', // Only keep the native frame on Mac
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#17191c',
symbolColor: '#eee',
height: 28
},
backgroundColor: '#17191c',
autoHideMenuBar: true,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
enableBlinkFeatures: 'FontAccess, AudioVideoTracks',
backgroundThrottling: false,
preload: join(__dirname, '/preload.js')
},
icon: join(__dirname, '/logo_filled.png'),
show: false
})

discord = new Discord(this.mainWindow)
protocol = new Protocol(this.mainWindow)
updater = new Updater(this.mainWindow)
dialog = new Dialog(this.webtorrentWindow)

constructor () {
this.mainWindow.setMenuBarVisibility(false)
this.mainWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
this.mainWindow.once('ready-to-show', () => this.mainWindow.show())
this.mainWindow.on('minimize', () => this.mainWindow.webContents.postMessage('visibilitychange', 'hidden'))
this.mainWindow.on('restore', () => this.mainWindow.webContents.postMessage('visibilitychange', 'visible'))
ipcMain.on('devtools', () => this.webtorrentWindow.webContents.openDevTools())

this.mainWindow.on('closed', () => this.destroy())
ipcMain.on('close', () => this.destroy())
app.on('before-quit', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})

powerMonitor.on('shutdown', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})

if (process.platform === 'win32') {
// this message usually fires in dev-mode from the parent process
process.on('message', data => {
if (data === 'graceful-exit') this.destroy()
})
electronShutdownHandler.setWindowHandle(this.mainWindow.getNativeWindowHandle())
electronShutdownHandler.blockShutdown('Saving torrent data...')
electronShutdownHandler.on('shutdown', async () => {
await this.destroy()
electronShutdownHandler.releaseShutdown()
})
} else {
process.on('SIGTERM', () => this.destroy())
}

const torrentLoad = this.webtorrentWindow.loadURL(development ? 'http://localhost:5000/background.html' : `file://${join(__dirname, '/background.html')}`)
this.mainWindow.loadURL(development ? 'http://localhost:5000/app.html' : `file://${join(__dirname, '/app.html')}`)

if (development) {
this.webtorrentWindow.webContents.openDevTools()
this.mainWindow.webContents.openDevTools()
}

let crashcount = 0
this.mainWindow.webContents.on('render-process-gone', async (e, { reason }) => {
if (reason === 'crashed') {
if (++crashcount > 10) {
await dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Miru', detail: 'App crashed too many times. For a fix visit https://miru.watch/faq/', icon: '/renderer/public/logo_filled.png' })
shell.openExternal('https://miru.watch/faq/')
} else {
app.relaunch()
}
app.quit()
}
})

ipcMain.on('portRequest', async ({ sender }) => {
const { port1, port2 } = new MessageChannelMain()
await torrentLoad
this.webtorrentWindow.webContents.postMessage('port', null, [port1])
this.webtorrentWindow.webContents.postMessage('player', store.get('player'))
this.webtorrentWindow.webContents.postMessage('torrentPath', store.get('torrentPath'))
sender.postMessage('port', null, [port2])
})
}

destroyed = false

async destroy () {
if (this.destroyed) return
this.webtorrentWindow.webContents.postMessage('destroy', null)
await new Promise(resolve => {
ipcMain.once('destroyed', resolve)
setTimeout(resolve, 5000).unref?.()
})
this.destroyed = true
app.quit()
}
}
13 changes: 5 additions & 8 deletions electron/src/main/discord.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,15 @@ export default class Discord {
}
}

discord
discord = new Client({ transport: 'ipc' })

/** @type {Discord['defaultStatus'] | undefined} */
allowDiscordDetails
/** @type {Discord['defaultStatus'] | undefined} */
cachedPresence

/**
* @param {import('electron').BrowserWindow} window
*/
/** @param {import('electron').BrowserWindow} window */
constructor (window) {
this.discord = new Client({
transport: 'ipc'
})

ipcMain.on('show-discord-status', (event, data) => {
this.allowDiscordDetails = data
this.debouncedDiscordRPC(this.allowDiscordDetails ? this.cachedPresence : undefined)
Expand Down
Loading

0 comments on commit a1ca14c

Please sign in to comment.