wip: node-mobile

This commit is contained in:
ThaUnknown 2023-12-05 23:29:45 +01:00
parent 5cdcfda4a1
commit 65bd321f4a
14 changed files with 122 additions and 1765 deletions

View file

@ -14,7 +14,8 @@ const config = {
},
plugins: {
SplashScreen: { launchShowDuration: 0 },
CapacitorHttp: { enabled: false }
CapacitorHttp: { enabled: false },
CapacitorNodeJS: { nodeDir: 'nodejs' }
}
}

50
capacitor/config-node.sh Normal file
View file

@ -0,0 +1,50 @@
#!/bin/bash
# instructions
# Install Android NDK
# Set $ANDROID_NDK_PATH (example: ~/Android/Sdk/ndk/26.1.10909125)
# Download and extract android .zip for nodejs-mobile from https://github.com/nodejs-mobile/nodejs-mobile/releases/tag/v18.17.2
# Update LIBNODE_PATH
# npm install nodejs-mobile-gyp
# install other npm packages like normal
# run this script
toolchain_target_arch=aarch64
node_target_arch=arm64
android_api_level=22
toolchain_folder=$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin
export LIBNODE_PATH=~/Downloads/nodejs-mobile
export PATH=$toolchain_folder:$PATH
export CC=$toolchain_folder/${toolchain_target_arch}-linux-android${android_api_level}-clang
export CXX=$toolchain_folder/${toolchain_target_arch}-linux-android${android_api_level}-clang++
export LINK=$toolchain_folder/${toolchain_target_arch}-linux-android${android_api_level}-clang++
export AR=$toolchain_folder/llvm-ar
export npm_config_verbose=1
export npm_config_nodedir=${LIBNODE_PATH}
export npm_config_node_gyp=$(pwd)/node_modules/nodejs-mobile-gyp/bin/node-gyp.js
export npm_config_arch=${node_target_arch}
export npm_config_plaform=android
export npm_config_format=make-android
export npm_gyp_defines="target_arch=$node_target_arch v8_target_arch=$node_target_arch android_target_arch=$node_target_arch host_os=linux OS=android"
#mv node_modules ../node_modules.bak
# --from-from-source is used by node-pre-gyp
npm rebuild --build-from-source
# Remove executable permissions from native node modules
# find node_modules -iname '*.node' -exec chmod -x '{}' \;
# buildroot=$(pwd)/ncc
# target=arm64-android
# buildpath="${buildroot}/${target}"
# if [ ! -d "${buildpath}" ]; then
# mkdir -p "${buildpath}"
# fi
# ncc build --source-map -d --asset-builds --target es2022 -o ${buildpath} src/offline.ts
# rm -rf node_modules
# mv ../node_modules.bak node_modules

View file

@ -42,14 +42,9 @@
"@capacitor/core": "^5.5.1",
"@capacitor/ios": "^5.5.1",
"@capacitor/status-bar": "^5.0.6",
"@superfrogbe/cordova-plugin-chrome-apps-sockets-udp": "github:superfrogbe/cordova-plugin-chrome-apps-sockets-udp",
"capacitor-default-gateway": "github:funniray/capacitor-default-gateway",
"capacitor-dns": "github:funniray/capacitor-dns",
"capacitor-os-interfaces-hack": "github:funniray/capacitor-os-interfaces-hack",
"capacitor-nodejs": "github:hampoelz/capacitor-nodejs",
"capacitor-plugin-safe-area": "^2.0.5",
"common": "workspace:*",
"cordova-plugin-chrome-apps-common": "^1.0.7",
"cordova-plugin-chrome-apps-sockets-tcp": "github:KoenLav/cordova-plugin-chrome-apps-sockets-tcp",
"cordova-plugin-navigationbar": "^1.0.31",
"cordova-plugin-screen-orientation": "^3.0.4",
"es6-promise-plugin": "^4.2.2",

View file

@ -3,9 +3,9 @@ import { StatusBar, Style } from '@capacitor/status-bar'
import { SafeArea } from 'capacitor-plugin-safe-area'
import { App } from '@capacitor/app'
import { Browser } from '@capacitor/browser'
import { ipcRendererUI, main } from './ipc.js'
// import { ipcRendererUI, main } from './ipc.js'
main.on('open', url => Browser.open({ url }))
// main.on('open', url => Browser.open({ url }))
App.addListener('appUrlOpen', ({ url }) => handleProtocol(url))

View file

@ -1,466 +0,0 @@
// @ts-nocheck
/*! chrome-dgram. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* global chrome */
/**
* UDP / Datagram Sockets
* ======================
*
* Datagram sockets are available through require('chrome-dgram').
*/
const EventEmitter = require('events')
const series = require('run-series')
const BIND_STATE_UNBOUND = 0
const BIND_STATE_BINDING = 1
const BIND_STATE_BOUND = 2
// Track open sockets to route incoming data (via onReceive) to the right handlers.
const sockets = {}
const noop = () => {}
// Thorough check for Chrome App since both Edge and Chrome implement dummy chrome object
if (typeof chrome?.sockets?.udp === 'object') {
chrome.sockets.udp.onReceive.addListener(onReceive)
chrome.sockets.udp.onReceiveError.addListener(onReceiveError)
}
function onReceive (info) {
if (info.socketId in sockets) {
sockets[info.socketId]._onReceive(info)
} else {
console.error('Unknown socket id: ' + info.socketId)
}
}
function onReceiveError (info) {
if (info.socketId in sockets) {
sockets[info.socketId]._onReceiveError(info.resultCode)
} else {
console.error('Unknown socket id: ' + info.socketId)
}
}
/**
* dgram.createSocket(type, [callback])
*
* Creates a datagram Socket of the specified types. Valid types are `udp4`
* and `udp6`.
*
* Takes an optional callback which is added as a listener for message events.
*
* Call socket.bind if you want to receive datagrams. socket.bind() will bind
* to the "all interfaces" address on a random port (it does the right thing
* for both udp4 and udp6 sockets). You can then retrieve the address and port
* with socket.address().address and socket.address().port.
*
* @param {string} type Either 'udp4' or 'udp6'
* @param {function} listener Attached as a listener to message events.
* Optional
* @return {Socket} Socket object
*/
exports.createSocket = function (type, listener) {
return new Socket(type, listener)
}
/**
* Class: dgram.Socket
*
* The dgram Socket class encapsulates the datagram functionality. It should
* be created via `dgram.createSocket(type, [callback])`.
*
* Event: 'message'
* - msg Buffer object. The message
* - rinfo Object. Remote address information
* Emitted when a new datagram is available on a socket. msg is a Buffer and
* rinfo is an object with the sender's address information and the number
* of bytes in the datagram.
*
* Event: 'listening'
* Emitted when a socket starts listening for datagrams. This happens as soon
* as UDP sockets are created.
*
* Event: 'close'
* Emitted when a socket is closed with close(). No new message events will
* be emitted on this socket.
*
* Event: 'error'
* - exception Error object
* Emitted when an error occurs.
*/
class Socket extends EventEmitter {
constructor (options, listener) {
super()
if (typeof options === 'string') options = { type: options }
if (options.type !== 'udp4' && options.type !== 'udp6') throw new Error('Bad socket type specified. Valid types are: udp4')
if (typeof listener === 'function') this.on('message', listener)
this._destroyed = false
this._bindState = BIND_STATE_UNBOUND
this._bindTasks = []
}
/**
* socket.bind(port, [address], [callback])
*
* For UDP sockets, listen for datagrams on a named port and optional address.
* If address is not specified, the OS will try to listen on all addresses.
* After binding is done, a "listening" event is emitted and the callback(if
* specified) is called. Specifying both a "listening" event listener and
* callback is not harmful but not very useful.
*
* A bound datagram socket keeps the node process running to receive
* datagrams.
*
* If binding fails, an "error" event is generated. In rare case (e.g. binding
* a closed socket), an Error may be thrown by this method.
*
* @param {number} port
* @param {string} address Optional
* @param {function} callback Function with no parameters, Optional. Callback
* when binding is done.
*/
bind (port, address, callback) {
if (typeof address === 'function') {
callback = address
address = undefined
}
if (!address) address = '0.0.0.0'
if (!port) port = 0
if (this._bindState !== BIND_STATE_UNBOUND) throw new Error('Socket is already bound')
this._bindState = BIND_STATE_BINDING
if (typeof callback === 'function') this.once('listening', callback)
chrome.sockets.udp.create(createInfo => {
this.id = createInfo.socketId
sockets[this.id] = this
const bindFns = this._bindTasks.map(({ fn }) => fn)
series(bindFns, err => {
if (err) return this.emit('error', err)
chrome.sockets.udp.bind(this.id, address, port, result => {
if (result < 0) {
this.emit('error', new Error('Socket ' + this.id + ' failed to bind. ' +
chrome.runtime.lastError.message))
return
}
chrome.sockets.udp.getInfo(this.id, socketInfo => {
if (!socketInfo.localPort || !socketInfo.localAddress) {
this.emit('error', new Error('Cannot get local port/address for Socket ' + this.id))
return
}
this._port = socketInfo.localPort
this._address = socketInfo.localAddress
this._bindState = BIND_STATE_BOUND
this.emit('listening')
for (const t of this._bindTasks) {
t.callback()
}
})
})
})
})
}
/**
* Internal function to receive new messages and emit `message` events.
*/
_onReceive (info) {
const buf = Buffer.from(new Uint8Array(info.data))
const rinfo = {
address: info.remoteAddress,
family: 'IPv4',
port: info.remotePort,
size: buf.length
}
this.emit('message', buf, rinfo)
}
_onReceiveError (resultCode) {
this.emit('error', new Error('Socket ' + this.id + ' receive error ' + resultCode))
}
/**
* socket.send(buf, offset, length, port, address, [callback])
*
* For UDP sockets, the destination port and IP address must be
* specified. A string may be supplied for the address parameter, and it will
* be resolved with DNS. An optional callback may be specified to detect any
* DNS errors and when buf may be re-used. Note that DNS lookups will delay
* the time that a send takes place, at least until the next tick. The only
* way to know for sure that a send has taken place is to use the callback.
*
* If the socket has not been previously bound with a call to bind, it's
* assigned a random port number and bound to the "all interfaces" address
* (0.0.0.0 for udp4 sockets, ::0 for udp6 sockets).
*
* @param {Buffer|Arrayish|string} buf Message to be sent
* @param {number} offset Offset in the buffer where the message starts. Optional.
* @param {number} length Number of bytes in the message. Optional.
* @param {number} port destination port
* @param {string} address destination IP
* @param {function} callback Callback when message is done being delivered.
* Optional.
*
* Valid combinations:
* send(buffer, offset, length, port, address, callback)
* send(buffer, offset, length, port, address)
* send(buffer, offset, length, port)
* send(bufferOrList, port, address, callback)
* send(bufferOrList, port, address)
* send(bufferOrList, port)
*
*/
send (buffer, offset, length, port, address, callback = noop) {
let list
const cb = callback || noop
if (address || (port && typeof port !== 'function')) {
buffer = this.sliceBuffer(buffer, offset, length)
} else {
callback = port
port = offset
address = length
}
if (!Array.isArray(buffer)) {
if (typeof buffer === 'string') {
list = [Buffer.from(buffer)]
} else if (!(buffer instanceof Uint8Array)) {
throw new TypeError('First argument must be a buffer or a string')
} else {
list = [Buffer.from(buffer)]
}
} else if (!(list = this.fixBufferList(buffer))) {
throw new TypeError('Buffer list arguments must be buffers or strings')
}
port = port >>> 0
if (port === 0 || port > 65535) {
throw new RangeError('Port should be > 0 and < 65536')
}
if (this._bindState === BIND_STATE_UNBOUND) this.bind(0)
// If the socket hasn't been bound yet, push the outbound packet onto the
// send queue and send after binding is complete.
if (this._bindState !== BIND_STATE_BOUND) {
// If the send queue hasn't been initialized yet, do it, and install an
// event handler that flishes the send queue after binding is done.
if (!this._sendQueue) {
this._sendQueue = []
this.once('listening', () => {
// Flush the send queue.
for (let i = 0; i < this._sendQueue.length; i++) {
this.send.apply(this, this._sendQueue[i])
}
this._sendQueue = undefined
})
}
this._sendQueue.push([buffer, offset, length, port, address, callback])
return
}
const ab = Buffer.concat(list).buffer
chrome.sockets.udp.send(this.id, ab, address, port, sendInfo => {
if (sendInfo.resultCode < 0) {
const err = new Error('Socket ' + this.id + ' send error ' + sendInfo.resultCode)
cb(err)
this.emit('error', err)
} else {
cb(null)
}
})
}
sliceBuffer (buffer, offset, length) {
buffer = Buffer.from(buffer)
offset = offset >>> 0
length = length >>> 0
// assuming buffer is browser implementation (`buffer` package on npm)
let buf = buffer.buffer
if (buffer.byteOffset || buffer.byteLength !== buf.byteLength) {
buf = buf.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength)
}
if (offset || length !== buffer.length) {
buf = buf.slice(offset, length)
}
return Buffer.from(buf)
}
fixBufferList (list) {
const newlist = new Array(list.length)
for (let i = 0, l = list.length; i < l; i++) {
const buf = list[i]
if (typeof buf === 'string') {
newlist[i] = Buffer.from(buf)
} else if (!(buf instanceof Uint8Array)) {
return null
} else {
newlist[i] = Buffer.from(buf)
}
}
return newlist
}
/**
* Close the underlying socket and stop listening for data on it.
*/
close () {
if (this._destroyed) return
delete sockets[this.id]
chrome.sockets.udp.close(this.id)
this._destroyed = true
this.emit('close')
}
/**
* Returns an object containing the address information for a socket. For UDP
* sockets, this object will contain address, family and port.
*
* @return {Object} information
*/
address () {
return {
address: this._address,
port: this._port,
family: 'IPv4'
}
}
setBroadcast (flag) {
// No chrome.sockets equivalent
}
setTTL (ttl) {
// No chrome.sockets equivalent
}
// NOTE: Multicast code is untested. Pull requests accepted for bug fixes and to
// add tests!
/**
* Sets the IP_MULTICAST_TTL socket option. TTL stands for "Time to Live," but
* in this context it specifies the number of IP hops that a packet is allowed
* to go through, specifically for multicast traffic. Each router or gateway
* that forwards a packet decrements the TTL. If the TTL is decremented to 0
* by a router, it will not be forwarded.
*
* The argument to setMulticastTTL() is a number of hops between 0 and 255.
* The default on most systems is 1.
*
* NOTE: The Chrome version of this function is async, whereas the node
* version is sync. Keep this in mind.
*
* @param {number} ttl
* @param {function} callback CHROME-SPECIFIC: Called when the configuration
* operation is done.
*/
setMulticastTTL (ttl, callback = noop) {
const setMulticastTTL = callback => {
chrome.sockets.udp.setMulticastTimeToLive(this.id, ttl, callback)
}
if (this._bindState === BIND_STATE_BOUND) {
setMulticastTTL(callback)
} else {
this._bindTasks.push({
fn: setMulticastTTL,
callback
})
}
}
/**
* Sets or clears the IP_MULTICAST_LOOP socket option. When this option is
* set, multicast packets will also be received on the local interface.
*
* NOTE: The Chrome version of this function is async, whereas the node
* version is sync. Keep this in mind.
*
* @param {boolean} flag
* @param {function} callback CHROME-SPECIFIC: Called when the configuration
* operation is done.
*/
setMulticastLoopback (flag, callback = noop) {
const setMulticastLoopback = callback => {
chrome.sockets.udp.setMulticastLoopbackMode(this.id, flag, callback)
}
if (this._bindState === BIND_STATE_BOUND) {
setMulticastLoopback(callback)
} else {
this._bindTasks.push({
fn: setMulticastLoopback,
callback
})
}
}
/**
* Tells the kernel to join a multicast group with IP_ADD_MEMBERSHIP socket
* option.
*
* If multicastInterface is not specified, the OS will try to add membership
* to all valid interfaces.
*
* NOTE: The Chrome version of this function is async, whereas the node
* version is sync. Keep this in mind.
*
* @param {string} multicastAddress
* @param {string} [multicastInterface] Optional
* @param {function} callback CHROME-SPECIFIC: Called when the configuration
* operation is done.
*/
addMembership (multicastAddress, multicastInterface, callback = noop) {
chrome.sockets.udp.joinGroup(this.id, multicastAddress, callback)
}
/**
* Opposite of addMembership - tells the kernel to leave a multicast group
* with IP_DROP_MEMBERSHIP socket option. This is automatically called by the
* kernel when the socket is closed or process terminates, so most apps will
* never need to call this.
*
* NOTE: The Chrome version of this function is async, whereas the node
* version is sync. Keep this in mind.
*
* If multicastInterface is not specified, the OS will try to drop membership
* to all valid interfaces.
*
* @param {[type]} multicastAddress
* @param {[type]} multicastInterface Optional
* @param {function} callback CHROME-SPECIFIC: Called when the configuration
* operation is done.
*/
dropMembership (multicastAddress, multicastInterface, callback = noop) {
chrome.sockets.udp.leaveGroup(this.id, multicastAddress, callback)
}
unref () {
// No chrome.sockets equivalent
}
ref () {
// No chrome.sockets equivalent
}
}
exports.Socket = Socket

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
import { gateway4async } from 'capacitor-default-gateway'
let v4Gateway
export const v4 = () => {}
v4.sync = () => v4Gateway
export const ready = gateway4async().then(gateway => {
v4Gateway = gateway
})

View file

@ -1,27 +1,27 @@
import EventEmitter from 'events'
import { ready } from './gateway.js'
import { NodeJS } from 'capacitor-nodejs'
export const ipcRendererUI = new EventEmitter()
export const main = new EventEmitter()
let portListener
export default {
emit: (event, data) => {
main.emit(event, data)
if (event === 'portRequest') return portRequest()
NodeJS.send({ eventName: event, args: [data] })
},
on: (event, callback) => {
ipcRendererUI.on(event, (...args) => callback(...args))
NodeJS.addListener(event, ({ args }) => callback(...args))
if (event === 'port') portListener = callback
},
once: (event, callback) => {
ipcRendererUI.once(event, (...args) => callback(...args))
const handle = NodeJS.addListener(event, ({ args }) => {
NodeJS.removeListener(handle)
callback(...args)
})
},
off: event => {
ipcRendererUI.removeAllListeners(event)
NodeJS.removeAllListeners(event)
}
}
main.on('portRequest', portRequest)
async function portRequest (data) {
const { port1, port2 } = new MessageChannel()
globalThis.port = {
@ -32,16 +32,12 @@ async function portRequest (data) {
port2.postMessage(a, b)
}
}
await globalThis.controller
await globalThis.prefetchNetworkInterfaces
await ready
await NodeJS.whenReady()
await new Promise(resolve => setTimeout(() => resolve(), 50))
ipcRendererUI.emit('port', { ports: [port2] })
ipcRendererWebTorrent.emit('port', { ports: [port1] })
portListener({ ports: [port2] })
NodeJS.send({ eventName: 'port', args: [{ ports: [port1] }] })
}
export const ipcRendererWebTorrent = new EventEmitter()
const [_platform, arch] = navigator.platform.split(' ')
globalThis.version = {

View file

@ -1,2 +1,10 @@
import './webtorrent.js'
import './capacitor.js'
import TorrentClient from 'common/modules/webtorrent.js'
import { statfs } from 'fs/promises'
import { channel } from 'bridge'
async function storageQuota (directory) {
const { bsize, bavail } = await statfs(directory)
return bsize * bavail
}
globalThis.client = new TorrentClient(channel, storageQuota, 'browser')

View file

@ -4,10 +4,10 @@ export const SUPPORTS = {
offscreenRender: false,
update: false,
angle: false,
doh: false,
doh: true,
dht: true,
discord: false,
torrentPort: false,
torrentPort: true,
torrentPath: false,
torrentPersist: false
torrentPersist: true
}

View file

@ -1,34 +0,0 @@
import TorrentClient from 'common/modules/webtorrent.js'
import { ipcRendererWebTorrent } from './ipc.js'
import { prefetchNetworkInterfaces } from 'os'
import { ready } from './gateway.js'
globalThis.chrome.runtime = { lastError: false, id: 'something' }
const controller = (async () => {
const reg = await navigator.serviceWorker.register(new URL('webtorrent/dist/sw.min.js', import.meta.url))
const worker = reg.active || reg.waiting || reg.installing
if (!worker) throw new Error('No worker registration')
return new Promise(resolve => {
function checkState ({ state }) {
if (state === 'activated') {
resolve(reg)
return true
}
}
if (!checkState(worker)) worker.addEventListener('statechange', ({ target }) => checkState(target))
})
})()
globalThis.prefetchNetworkInterfaces = await prefetchNetworkInterfaces()
globalThis.controller = controller
async function storageQuota () {
const { quota, usage } = await navigator.storage.estimate()
return quota - usage
}
await prefetchNetworkInterfaces
await ready
globalThis.client = new TorrentClient(ipcRendererWebTorrent, storageQuota, 'browser', controller, { torrentPort: Math.floor(Math.random() * 65535 + 1) })

View file

@ -1,4 +1,3 @@
const webpack = require('webpack')
const commonConfig = require('common/webpack.config.cjs')
const { merge } = require('webpack-merge')
const { join, resolve } = require('path')
@ -7,57 +6,41 @@ const mode = process.env.NODE_ENV?.trim() || 'development'
/** @type {import('webpack').Configuration} */
const capacitorConfig = {
devtool: 'source-map',
entry: [join(__dirname, 'src', 'main.js')],
output: {
path: join(__dirname, 'build', 'nodejs'),
filename: 'index.js'
},
mode,
plugins: [
new webpack.ProvidePlugin({
process: 'webtorrent/polyfills/process-fast.js',
Buffer: ['buffer', 'Buffer']
}),
new webpack.DefinePlugin({ global: 'globalThis' })
],
externals: {
'utp-native': 'require("utp-native")',
bridge: 'require("bridge")'
},
resolve: {
aliasFields: [],
mainFields: ['module', 'main', 'node'],
alias: {
wrtc: false,
'bittorrent-tracker/lib/client/http-tracker.js': resolve('../node_modules/bittorrent-tracker/lib/client/http-tracker.js')
}
},
target: 'node',
devServer: {
devMiddleware: { writeToDisk: true },
devMiddleware: {
writeToDisk: true
},
hot: true,
client: {
overlay: { errors: true, warnings: false, runtimeErrors: false }
},
port: 5001
port: 5000
}
}
const alias = {
fs: false,
ws: false,
'default-gateway': join(__dirname, 'src', 'gateway.js'),
'load-ip-set': false,
'node-fetch': false,
'webtorrent/lib/utp.cjs': false,
'@/modules/ipc.js': join(__dirname, 'src', 'ipc.js'),
'@/modules/support.js': join(__dirname, 'src', 'support.js'),
net: join(__dirname, 'src', 'chrome-net.js'),
dgram: join(__dirname, 'src', 'chrome-dgram.js'),
os: 'capacitor-os-interfaces-hack',
dns: 'capacitor-dns',
http: 'stream-http',
https: 'stream-http',
'utp-native': false,
socks: false,
assert: 'assert',
ut_pex: 'ut_pex',
path: 'path-esm',
'fs-chunk-store': 'hybrid-chunk-store',
stream: 'stream-browserify',
timers: 'timers-browserify',
crypto: 'crypto-browserify',
buffer: 'buffer',
'@silentbot1/nat-api': '@silentbot1/nat-api',
'bittorrent-tracker': 'bittorrent-tracker',
querystring: 'querystring',
zlib: 'webtorrent/polyfills/inflate-sync-web.js',
'bittorrent-tracker/server.js': false,
'cross-fetch-ponyfill': resolve('../node_modules/cross-fetch-ponyfill/browser.js'),
'abort-controller': false,
'bittorrent-tracker/lib/client/http-tracker.js': resolve('../node_modules/bittorrent-tracker/lib/client/http-tracker.js')
'@/modules/support.js': join(__dirname, 'src', 'support.js')
}
module.exports = merge(commonConfig(__dirname, alias, 'node', 'index'), capacitorConfig)
module.exports = [capacitorConfig, merge(commonConfig(__dirname, alias, 'browser', 'index'), { entry: [join(__dirname, 'src', 'capacitor.js')] })]

View file

@ -33,7 +33,7 @@ try {
export default class TorrentClient extends WebTorrent {
static excludedErrorMessages = ['WebSocket', 'User-Initiated Abort, reason=', 'Connection failed.']
constructor (ipc, storageQuota, serverMode, controller, settingOverrides = {}) {
constructor (ipc, storageQuota, serverMode, settingOverrides = {}, controller) {
const settings = { ...defaults, ...storedSettings, ...settingOverrides }
super({
dht: !settings.torrentDHT,

View file

@ -86,6 +86,9 @@ importers:
capacitor-dns:
specifier: github:funniray/capacitor-dns
version: github.com/funniray/capacitor-dns/6362cd1ad0a6b9b5bdbdc9fee3fba4c8dae91e16(@capacitor/core@5.5.1)
capacitor-nodejs:
specifier: github:hampoelz/capacitor-nodejs
version: github.com/hampoelz/capacitor-nodejs/3ee9d8d1d0266c228249005f73a2403d551d3aac(@capacitor/core@5.5.1)
capacitor-os-interfaces-hack:
specifier: github:funniray/capacitor-os-interfaces-hack
version: github.com/funniray/capacitor-os-interfaces-hack/95a51afe9dee88b3ae8df4b1b96fd106c1655954(@capacitor/core@5.5.1)
@ -9095,6 +9098,17 @@ packages:
'@capacitor/core': 5.5.1
dev: false
github.com/hampoelz/capacitor-nodejs/3ee9d8d1d0266c228249005f73a2403d551d3aac(@capacitor/core@5.5.1):
resolution: {tarball: https://codeload.github.com/hampoelz/capacitor-nodejs/tar.gz/3ee9d8d1d0266c228249005f73a2403d551d3aac}
id: github.com/hampoelz/capacitor-nodejs/3ee9d8d1d0266c228249005f73a2403d551d3aac
name: capacitor-nodejs
version: 1.0.0-beta.6
peerDependencies:
'@capacitor/core': ^5.0.0
dependencies:
'@capacitor/core': 5.5.1
dev: false
github.com/superfrogbe/cordova-plugin-chrome-apps-sockets-udp/4b740017299c81cfc7d5b49c7d6122a6650b57d4:
resolution: {tarball: https://codeload.github.com/superfrogbe/cordova-plugin-chrome-apps-sockets-udp/tar.gz/4b740017299c81cfc7d5b49c7d6122a6650b57d4}
name: '@superfrogbe/cordova-plugin-chrome-apps-sockets-udp'