mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(electron): add plebbit rpc
This commit is contained in:
@@ -83,6 +83,8 @@ const downloadIpfsClients = async () => {
|
||||
await download(ipfsClientLinuxPUrl, ipfsClientLinuxPath);
|
||||
};
|
||||
|
||||
exports.downloadIpfsClients = downloadIpfsClients
|
||||
|
||||
exports.default = async (context) => {
|
||||
await downloadIpfsClients();
|
||||
};
|
||||
@@ -8,7 +8,7 @@ then
|
||||
fi
|
||||
|
||||
# download ipfs clients
|
||||
node electron/downloadIpfs || { echo "Error: failed script 'node electron/downloadIpfs'" ; exit 1; }
|
||||
node electron/download-ipfs || { echo "Error: failed script 'node electron/download-ipfs'" ; exit 1; }
|
||||
|
||||
dockerfile='
|
||||
FROM electronuserland/builder:16
|
||||
@@ -0,0 +1,2 @@
|
||||
const downloadIpfsClients = require('./before-pack').downloadIpfsClients;
|
||||
downloadIpfsClients();
|
||||
@@ -1,2 +0,0 @@
|
||||
const downloadIpfsClients = require('./beforePack').default;
|
||||
downloadIpfsClients();
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// require this file to log to file in case there's a crash
|
||||
|
||||
const envPaths = require('env-paths').default('plebchan', { suffix: false });
|
||||
const envPaths = require('env-paths').default('plebbit', { suffix: false });
|
||||
const util = require('util');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
+23
-9
@@ -7,18 +7,32 @@ const {
|
||||
Tray,
|
||||
screen: electronScreen,
|
||||
shell,
|
||||
dialog,
|
||||
dialog
|
||||
} = require('electron')
|
||||
const isDev = require('electron-is-dev')
|
||||
const path = require('path')
|
||||
const startIpfs = require('./startIpfs')
|
||||
const startIpfs = require('./start-ipfs')
|
||||
const startPlebbitRpcServer = require('./start-plebbit-rpc')
|
||||
const { URL } = require('node:url')
|
||||
const tcpPortUsed = require('tcp-port-used')
|
||||
|
||||
// retry starting ipfs every 10 second,
|
||||
// in case it was started by another client that shut down and shut down ipfs with it
|
||||
let startIpfsError
|
||||
startIpfs().catch((e) => {
|
||||
startIpfsError = e
|
||||
console.error(e)
|
||||
})
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const started = await tcpPortUsed.check(5001, '127.0.0.1')
|
||||
if (started) {
|
||||
return
|
||||
}
|
||||
await startIpfs()
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
startIpfsError = e
|
||||
dialog.showErrorBox('IPFS error', startIpfsError.message)
|
||||
}
|
||||
}, 10000)
|
||||
|
||||
// use common user agent instead of electron so img, video, audio, iframe elements don't get blocked
|
||||
// https://www.whatismybrowser.com/guides/the-latest-version/chrome
|
||||
@@ -69,7 +83,7 @@ const createMainWindow = () => {
|
||||
width: 1000,
|
||||
height: 600,
|
||||
show: false,
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: '#181818',
|
||||
webPreferences: {
|
||||
webSecurity: true, // must be true or iframe embeds like youtube can do remote code execution
|
||||
nodeIntegration: false,
|
||||
@@ -84,7 +98,7 @@ const createMainWindow = () => {
|
||||
|
||||
// set custom user agent and other headers for window.fetch requests to prevent origin errors
|
||||
mainWindow.webContents.session.webRequest.onBeforeSendHeaders({urls: ['*://*/*']}, (details, callback) => {
|
||||
const isIframe = details.frame.parent !== null
|
||||
const isIframe = !!details.frame?.parent
|
||||
// if not a fetch request (or fetch request is from within iframe), do nothing, filtering webRequest by types doesn't seem to work
|
||||
if (details.resourceType !== 'xhr' || isIframe) {
|
||||
return callback({requestHeaders: details.requestHeaders})
|
||||
@@ -104,7 +118,7 @@ const createMainWindow = () => {
|
||||
|
||||
// fix cors errors for window.fetch. must not be enabled for iframe or can cause remote code execution
|
||||
mainWindow.webContents.session.webRequest.onHeadersReceived({urls: ['*://*/*']}, (details, callback) => {
|
||||
const isIframe = details.frame.parent !== null
|
||||
const isIframe = !!details.frame?.parent
|
||||
// if not a fetch request (or fetch request is from within iframe), do nothing, filtering webRequest by types doesn't seem to work
|
||||
if (details.resourceType !== 'xhr' || isIframe) {
|
||||
return callback({responseHeaders: details.responseHeaders})
|
||||
|
||||
+8
-41
@@ -1,49 +1,16 @@
|
||||
// force IpfsHttpClient to use node-fetch to fix max 6 connections
|
||||
// temporary, eventually we will fork ipfs-http-client and replace
|
||||
// 'native-fetch'
|
||||
const mock = require('mock-require');
|
||||
const fetch = require('node-fetch');
|
||||
mock('ipfs-utils/src/env.js', {
|
||||
isTest: false,
|
||||
isElectron: false,
|
||||
isElectronMain: false,
|
||||
isElectronRenderer: false,
|
||||
isNode: true,
|
||||
isBrowser: false,
|
||||
isWebWorker: false,
|
||||
isEnvWithDom: false,
|
||||
isReactNative: false,
|
||||
});
|
||||
mock('native-fetch', {
|
||||
default: fetch.default,
|
||||
Headers: fetch.Headers,
|
||||
Request: fetch.Request,
|
||||
Response: fetch.Response,
|
||||
});
|
||||
|
||||
const envPaths = require('env-paths').default('plebchan', { suffix: false });
|
||||
const { contextBridge } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// dev uses http://localhost, prod uses file://...index.html
|
||||
const isDev = window.location.protocol === 'http:';
|
||||
const isDev = window.location.protocol === 'http:'
|
||||
|
||||
const defaultPlebbitOptions = {
|
||||
// find the user's OS data path
|
||||
dataPath: !isDev ? envPaths.data : path.join(__dirname, '..', '.plebbit'),
|
||||
ipfsHttpClientsOptions: ['http://localhost:5001/api/v0'] || undefined,
|
||||
// TODO: having to define pubsubHttpClientsOptions and ipfsHttpClientsOptions is a bug with plebbit-js
|
||||
pubsubHttpClientsOptions: ['http://localhost:5001/api/v0'] || undefined,
|
||||
// electron starts the local ipfs gateway on port 11028 because 8080 is too common
|
||||
ipfsGatewayUrls: ['http://localhost:11028'] || undefined,
|
||||
};
|
||||
plebbitRpcClientsOptions: ['ws://localhost:9138']
|
||||
}
|
||||
|
||||
// expose a flag to indicate that we are running in electron
|
||||
contextBridge.exposeInMainWorld('electron', { isElectron: true });
|
||||
|
||||
// expose plebbit-js native functions into electron's renderer
|
||||
contextBridge.exposeInMainWorld('plebbitJsNativeFunctions', require('@plebbit/plebbit-js').nativeFunctions.node)
|
||||
contextBridge.exposeInMainWorld('defaultPlebbitOptions', defaultPlebbitOptions)
|
||||
|
||||
// uncomment to log
|
||||
// localStorage.debug = 'plebbit-js:*,plebbit-react-hooks:*,plebchan:*';
|
||||
// expose a flag to indicate that we are running in electron
|
||||
contextBridge.exposeInMainWorld('electron', { isElectron: true })
|
||||
|
||||
// uncomment for logs
|
||||
// localStorage.debug = 'plebbit-js:*,plebbit-react-hooks:*,plebchan:*'
|
||||
|
||||
@@ -2,9 +2,9 @@ const isDev = require('electron-is-dev');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
const fs = require('fs-extra');
|
||||
const envPaths = require('env-paths').default('plebchan', { suffix: false });
|
||||
const envPaths = require('env-paths').default('plebbit', { suffix: false });
|
||||
const ps = require('node:process');
|
||||
const proxyServer = require('./proxyServer');
|
||||
const proxyServer = require('./proxy-server');
|
||||
|
||||
// use this custom function instead of spawnSync for better logging
|
||||
// also spawnSync might have been causing crash on start on windows
|
||||
@@ -59,7 +59,7 @@ const startIpfs = async () => {
|
||||
} catch (e) {}
|
||||
|
||||
// dont use 8080 port because it's too common
|
||||
await spawnAsync(ipfsPath, ['config', 'Addresses.Gateway', '/ip4/127.0.0.1/tcp/11028'], {
|
||||
await spawnAsync(ipfsPath, ['config', '--json', 'Addresses.Gateway', "null"], {
|
||||
env,
|
||||
hideWindows: true,
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
const tcpPortUsed = require('tcp-port-used')
|
||||
const {PlebbitWsServer} = require('@plebbit/plebbit-js/rpc')
|
||||
const path = require('path')
|
||||
const envPaths = require('env-paths').default('plebbit', { suffix: false })
|
||||
const {randomBytes} = require('crypto')
|
||||
const fs = require('fs-extra')
|
||||
|
||||
let isDev = true
|
||||
try {
|
||||
isDev = require('electron-is-dev')
|
||||
} catch (e) {}
|
||||
|
||||
// PLEB, always run plebbit rpc on this port so all clients can use it
|
||||
const port = 9138
|
||||
const defaultPlebbitOptions = {
|
||||
// find the user's OS data path
|
||||
dataPath: !isDev ? envPaths.data : path.join(__dirname, '..', '.plebbit'),
|
||||
ipfsHttpClientsOptions: ['http://localhost:5001/api/v0'],
|
||||
// TODO: having to define pubsubHttpClientsOptions and ipfsHttpClientsOptions is a bug with plebbit-js
|
||||
pubsubHttpClientsOptions: ['http://localhost:5001/api/v0'],
|
||||
}
|
||||
|
||||
// generate plebbit rpc auth key if doesn't exist
|
||||
const plebbitRpcAuthKeyPath = path.join(defaultPlebbitOptions.dataPath, 'auth-key')
|
||||
let plebbitRpcAuthKey
|
||||
try {
|
||||
plebbitRpcAuthKey = fs.readFileSync(plebbitRpcAuthKeyPath, 'utf8')
|
||||
}
|
||||
catch (e) {
|
||||
plebbitRpcAuthKey = randomBytes(32).toString('base64').replace(/[/+=]/g, '').substring(0, 40)
|
||||
fs.ensureFileSync(plebbitRpcAuthKeyPath)
|
||||
fs.writeFileSync(plebbitRpcAuthKeyPath, plebbitRpcAuthKey)
|
||||
}
|
||||
|
||||
let pendingStart = false
|
||||
const start = async () => {
|
||||
if (pendingStart) {
|
||||
return
|
||||
}
|
||||
pendingStart = true
|
||||
try {
|
||||
const started = await tcpPortUsed.check(port, '127.0.0.1')
|
||||
if (started) {
|
||||
return
|
||||
}
|
||||
const plebbitWebSocketServer = await PlebbitWsServer({port, plebbitOptions: defaultPlebbitOptions, authKey: plebbitRpcAuthKey})
|
||||
|
||||
console.log(`plebbit rpc: listening on ws://localhost:${port} (local connections only)`)
|
||||
console.log(`plebbit rpc: listening on ws://localhost:${port}/${plebbitRpcAuthKey} (secret auth key for remote connections)`)
|
||||
plebbitWebSocketServer.ws.on('connection', (socket, request) => {
|
||||
console.log('plebbit rpc: new connection')
|
||||
// debug raw JSON RPC messages in console
|
||||
if (isDev) {
|
||||
socket.on('message', (message) => console.log(`plebbit rpc: ${message.toString()}`))
|
||||
}
|
||||
})
|
||||
}
|
||||
catch (e) {
|
||||
console.log('failed starting plebbit rpc server', e)
|
||||
}
|
||||
pendingStart = false
|
||||
}
|
||||
|
||||
// retry starting the plebbit rpc server every 1 second,
|
||||
// in case it was started by another client that shut down and shut down the server with it
|
||||
start()
|
||||
setInterval(() => {
|
||||
start()
|
||||
}, 1000)
|
||||
Reference in New Issue
Block a user