Compare commits

...
This repository has been archived on 2023-11-14. You can view files and clone it, but cannot push or open issues/pull-requests.

36 Commits

Author SHA1 Message Date
Valerie d3cdb7e1b3 idk, some overhead issue 2021-04-11 20:36:31 -04:00
Bronwen ec6b3a068b Merge branch 'add-electron-app' into service-testing 2021-04-11 20:00:07 -04:00
Bronwen 876c0a5b81 fuckyoufuckyoufuckyoufuckyoufuckyoufuckyoufuckyou 2021-04-11 19:58:54 -04:00
Bronwen d06c108106 i literally cant remove these fucking files bullshit 2021-04-11 19:58:38 -04:00
Bronwen 2845f59e2c fixed module fuckery... i think. 2021-04-11 19:53:39 -04:00
Bronwen 9c73ec3acf API WORKS 2021-04-11 01:53:16 -04:00
Bronwen c19c4c2fec serviceable 2021-04-08 22:02:58 -04:00
Bronwen c9fb26009c its at least not broken 2021-04-08 21:37:53 -04:00
Bronwen 97c33205a8 rollback safety 2021-04-08 20:38:05 -04:00
Marcus 2937e85f39 better settings overrides 2021-04-02 19:35:29 -04:00
Marcus 185aa45e4f put identity name into handshake 2021-04-02 10:08:02 -04:00
Marcus 7b9af3ba47 names over addresses... 2021-04-02 10:06:40 -04:00
Bronwen 556b940cc1 no more delay on pings 2021-04-01 23:21:39 -04:00
Bronwen 966dc965f2 cleanup 2021-04-01 23:01:24 -04:00
Bronwen 94037e7de0 pingtesterooni 2021-04-01 22:17:43 -04:00
Marcus 94c9edf473 tes pingo 2021-04-01 21:18:02 -04:00
Marcus 21a2d597dd pingo pongo 2021-04-01 21:15:41 -04:00
Marcus 7b7f728740 only _try_ to yarn install... 2021-04-01 15:44:39 -04:00
Marcus 19094bdcc5 use different mdns package... 2021-04-01 15:40:09 -04:00
Marcus b8c13336a0 install new yarn packages on reload of service 2021-04-01 15:12:35 -04:00
Marcus 3579aa3f61 stop auto refresh 2021-04-01 15:10:22 -04:00
Marcus a105e5aa93 name upnp naming scheme (fs compatible) 2021-04-01 15:06:22 -04:00
Marcus e0b837876d set port on matched upnp record 2021-04-01 01:24:54 -04:00
Marcus 36e9acd7aa always start server... 2021-04-01 01:22:48 -04:00
Marcus 37f041b3d8 do it... right? 2021-04-01 01:20:23 -04:00
Marcus dc25be448b actually start a server, idk 2021-04-01 01:19:00 -04:00
Marcus d3c33cd113 map indefinite again 2021-04-01 01:13:07 -04:00
Marcus 44f9fde5e2 map indefinite for nodes... 2021-04-01 01:11:42 -04:00
Marcus 33bd6a7244 remove debug other port 2021-04-01 01:10:23 -04:00
Marcus dff0b8c6e4 settings and better stuff 2021-04-01 01:04:17 -04:00
Marcus 99fc805557 better readyStates 2021-03-20 12:40:43 -04:00
Marcus 541eb7847a regions? regions! 2021-03-20 10:42:04 -04:00
Marcus b0265b7ca7 reconstruct packets / organize 2021-03-20 10:36:40 -04:00
Marcus 3bd8634172 remove uneccesary scripts 2021-03-18 21:33:39 -04:00
Marcus 6b69b46b91 Merge branch 'master' into service-testing 2021-02-22 01:45:44 -05:00
Bronwen 5d7e29ff2c Merge remote-tracking branch 'origin/HEAD' into service-testing 2021-02-16 23:14:45 -05:00
124 changed files with 16404 additions and 12495 deletions

12
.editorconfig 100644
View File

@ -0,0 +1,12 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View File

@ -0,0 +1,7 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off"
}
}

View File

@ -0,0 +1,46 @@
/**
* Base webpack config used across other specific configs
*/
import path from 'path';
import webpack from 'webpack';
import { dependencies as externals } from '../../src/package.json';
export default {
externals: [...Object.keys(externals || {})],
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
],
},
output: {
path: path.join(__dirname, '../../src'),
// https://github.com/webpack/webpack/issues/1114
libraryTarget: 'commonjs2',
},
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
modules: [path.join(__dirname, '../src'), 'node_modules'],
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
}),
],
};

View File

@ -0,0 +1,4 @@
/* eslint import/no-unresolved: off, import/no-self-import: off */
require('@babel/register');
module.exports = require('./webpack.config.renderer.dev.babel').default;

View File

@ -0,0 +1,75 @@
/**
* Webpack config for production electron main process
*/
import path from 'path';
import webpack from 'webpack';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
import DeleteSourceMaps from '../scripts/DeleteSourceMaps';
CheckNodeEnv('production');
DeleteSourceMaps();
const devtoolsConfig = process.env.DEBUG_PROD === 'true' ? {
devtool: 'source-map'
} : {};
export default merge(baseConfig, {
...devtoolsConfig,
mode: 'production',
target: 'electron-main',
entry: './src/main.dev.ts',
output: {
path: path.join(__dirname, '../../'),
filename: './src/main.prod.js',
},
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
}),
]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: false,
START_MINIMIZED: false,
}),
],
/**
* Disables webpack processing of __dirname and __filename.
* If you run the bundle in node.js it falls back to these values of node.js.
* https://github.com/webpack/webpack/issues/2010
*/
node: {
__dirname: false,
__filename: false,
},
});

View File

@ -0,0 +1,284 @@
import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import chalk from 'chalk';
import { merge } from 'webpack-merge';
import { spawn, execSync } from 'child_process';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
// at the dev webpack config is not accidentally run in a production environment
if (process.env.NODE_ENV === 'production') {
CheckNodeEnv('development');
}
const port = process.env.PORT || 1212;
const publicPath = `http://localhost:${port}/dist`;
const dllDir = path.join(__dirname, '../dll');
const manifest = path.resolve(dllDir, 'renderer.json');
const requiredByDLLConfig = module.parent.filename.includes(
'webpack.config.renderer.dev.dll'
);
/**
* Warn if the DLL is not built
*/
if (!requiredByDLLConfig && !(fs.existsSync(dllDir) && fs.existsSync(manifest))) {
console.log(
chalk.black.bgYellow.bold(
'The DLL files are missing. Sit back while we build them for you with "yarn build-dll"'
)
);
execSync('yarn build-dll');
}
export default merge(baseConfig, {
devtool: 'inline-source-map',
mode: 'development',
target: 'electron-renderer',
entry: [
'core-js',
'regenerator-runtime/runtime',
require.resolve('../../src/index.tsx'),
],
output: {
publicPath: `http://localhost:${port}/dist/`,
filename: 'renderer.dev.js',
},
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
plugins: [
require.resolve('react-refresh/babel'),
].filter(Boolean),
},
},
],
},
{
test: /\.global\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /^((?!\.global).)*\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
sourceMap: true,
importLoaders: 1,
},
},
],
},
// SASS support - compile all .global.scss files and pipe it to style.css
{
test: /\.global\.(scss|sass)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
},
],
},
// SASS support - compile all other .scss files and pipe it to style.css
{
test: /^((?!\.global).)*\.(scss|sass)$/,
use: [
{
loader: 'style-loader',
},
{
loader: '@teamsupercell/typings-for-css-modules-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
sourceMap: true,
importLoaders: 1,
},
},
{
loader: 'sass-loader',
},
],
},
// WOFF Font
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// WOFF2 Font
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// OTF Font
{
test: /\.otf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'font/otf',
},
},
},
// TTF Font
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
},
// EOT Font
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
// SVG Font
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml',
},
},
},
// Common Image Formats
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
use: 'url-loader',
},
],
},
plugins: [
requiredByDLLConfig
? null
: new webpack.DllReferencePlugin({
context: path.join(__dirname, '../dll'),
manifest: require(manifest),
sourceType: 'var',
}),
new webpack.NoEmitOnErrorsPlugin(),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*
* By default, use 'development' as NODE_ENV. This can be overriden with
* 'staging', for example, by changing the ENV variables in the npm scripts
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
}),
new ReactRefreshWebpackPlugin(),
],
node: {
__dirname: false,
__filename: false,
},
devServer: {
port,
publicPath,
compress: true,
noInfo: false,
stats: 'errors-only',
inline: true,
lazy: false,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
contentBase: path.join(__dirname, 'dist'),
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/,
poll: 100,
},
historyApiFallback: {
verbose: true,
disableDotRule: false,
},
before() {
console.log('Starting Main Process...');
spawn('npm', ['run', 'start:main'], {
shell: true,
env: process.env,
stdio: 'inherit',
})
.on('close', (code) => process.exit(code))
.on('error', (spawnError) => console.error(spawnError));
},
},
});

View File

@ -0,0 +1,72 @@
/**
* Builds the DLL for development electron renderer process
*/
import webpack from 'webpack';
import path from 'path';
import { merge } from 'webpack-merge';
import baseConfig from './webpack.config.base';
import { dependencies } from '../../package.json';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
CheckNodeEnv('development');
const dist = path.join(__dirname, '../dll');
export default merge(baseConfig, {
context: path.join(__dirname, '../..'),
devtool: 'eval',
mode: 'development',
target: 'electron-renderer',
externals: ['fsevents', 'crypto-browserify'],
/**
* Use `module` from `webpack.config.renderer.dev.js`
*/
module: require('./webpack.config.renderer.dev.babel').default.module,
entry: {
renderer: Object.keys(dependencies || {}),
},
output: {
library: 'renderer',
path: dist,
filename: '[name].dev.dll.js',
libraryTarget: 'var',
},
plugins: [
new webpack.DllPlugin({
path: path.join(dist, '[name].json'),
name: '[name]',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: path.join(__dirname, '../../src'),
output: {
path: path.join(__dirname, '../dll'),
},
},
}),
],
});

View File

@ -0,0 +1,162 @@
/**
* Build config for electron renderer process
*/
import path from 'path';
import webpack from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
import DeleteSourceMaps from '../scripts/DeleteSourceMaps';
CheckNodeEnv('production');
DeleteSourceMaps();
const devtoolsConfig = process.env.DEBUG_PROD === 'true' ? {
devtool: 'source-map'
} : {};
export default merge(baseConfig, {
...devtoolsConfig,
mode: 'production',
target: 'electron-renderer',
entry: [
'core-js',
'regenerator-runtime/runtime',
path.join(__dirname, '../../src/index.tsx'),
],
output: {
path: path.join(__dirname, '../../src/dist'),
publicPath: './dist/',
filename: 'renderer.prod.js',
},
module: {
rules: [
{
test: /.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// `./dist` can't be inerhited for publicPath for styles. Otherwise generated paths will be ./dist/dist
publicPath: './',
},
},
'css-loader',
'sass-loader'
],
},
// WOFF Font
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// WOFF2 Font
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// OTF Font
{
test: /\.otf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'font/otf',
},
},
},
// TTF Font
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
},
// EOT Font
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
// SVG Font
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml',
},
},
},
// Common Image Formats
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
use: 'url-loader',
},
],
},
optimization: {
minimize: true,
minimizer:
[
new TerserPlugin({
parallel: true,
}),
new CssMinimizerPlugin(),
],
},
plugins: [
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: false,
}),
new MiniCssExtractPlugin({
filename: 'style.css',
}),
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
],
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
.erb/img/eslint.png 100755

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
.erb/img/jest.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
.erb/img/js.png 100755

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
.erb/img/npm.png 100755

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
.erb/img/react.png 100755

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
.erb/img/yarn.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
export default 'test-file-stub';

View File

@ -0,0 +1,8 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off",
"import/no-extraneous-dependencies": "off"
}
}

View File

@ -0,0 +1,6 @@
const path = require('path');
require('@babel/register')({
extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'],
cwd: path.join(__dirname, '../..'),
});

View File

@ -0,0 +1,25 @@
// Check if the renderer and main bundles are built
import path from 'path';
import chalk from 'chalk';
import fs from 'fs';
const mainPath = path.join(__dirname, '../../src/main.prod.js');
const rendererPath = path.join(
__dirname, '../../src/dist/renderer.prod.js'
);
if (!fs.existsSync(mainPath)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
'The main process is not built yet. Build it by running "yarn build:main"'
)
);
}
if (!fs.existsSync(rendererPath)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
'The renderer process is not built yet. Build it by running "yarn build:renderer"'
)
);
}

View File

@ -0,0 +1,52 @@
import fs from 'fs';
import chalk from 'chalk';
import { execSync } from 'child_process';
import { dependencies } from '../../package.json';
if (dependencies) {
const dependenciesKeys = Object.keys(dependencies);
const nativeDeps = fs
.readdirSync('node_modules')
.filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`));
if (nativeDeps.length === 0) {
process.exit(0);
}
try {
// Find the reason for why the dependency is installed. If it is installed
// because of a devDependency then that is okay. Warn when it is installed
// because of a dependency
const { dependencies: dependenciesObject } = JSON.parse(
execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
);
const rootDependencies = Object.keys(dependenciesObject);
const filteredRootDependencies = rootDependencies.filter((rootDependency) =>
dependenciesKeys.includes(rootDependency)
);
if (filteredRootDependencies.length > 0) {
const plural = filteredRootDependencies.length > 1;
console.log(`
${chalk.whiteBright.bgYellow.bold(
'Webpack does not work with native dependencies.'
)}
${chalk.bold(filteredRootDependencies.join(', '))} ${
plural ? 'are native dependencies' : 'is a native dependency'
} and should be installed inside of the "./src" folder.
First, uninstall the packages from "./package.json":
${chalk.whiteBright.bgGreen.bold('yarn remove your-package')}
${chalk.bold(
'Then, instead of installing the package to the root "./package.json":'
)}
${chalk.whiteBright.bgRed.bold('yarn add your-package')}
${chalk.bold('Install the package to "./src/package.json"')}
${chalk.whiteBright.bgGreen.bold('cd ./src && yarn add your-package')}
Read more about native dependencies at:
${chalk.bold(
'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure'
)}
`);
process.exit(1);
}
} catch (e) {
console.log('Native dependencies could not be checked');
}
}

View File

@ -0,0 +1,16 @@
import chalk from 'chalk';
export default function CheckNodeEnv(expectedEnv) {
if (!expectedEnv) {
throw new Error('"expectedEnv" not set');
}
if (process.env.NODE_ENV !== expectedEnv) {
console.log(
chalk.whiteBright.bgRed.bold(
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
)
);
process.exit(2);
}
}

View File

@ -0,0 +1,16 @@
import chalk from 'chalk';
import detectPort from 'detect-port';
const port = process.env.PORT || '1212';
detectPort(port, (err, availablePort) => {
if (port !== String(availablePort)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 yarn start`
)
);
} else {
process.exit(0);
}
});

View File

@ -0,0 +1,7 @@
import path from 'path';
import rimraf from 'rimraf';
export default function deleteSourceMaps() {
rimraf.sync(path.join(__dirname, '../../src/dist/*.js.map'));
rimraf.sync(path.join(__dirname, '../../src/*.js.map'));
}

View File

@ -0,0 +1,22 @@
import path from 'path';
import { execSync } from 'child_process';
import fs from 'fs';
import { dependencies } from '../../src/package.json';
const nodeModulesPath = path.join(__dirname, '../../src/node_modules');
if (
Object.keys(dependencies || {}).length > 0 &&
fs.existsSync(nodeModulesPath)
) {
const electronRebuildCmd =
'../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .';
const cmd =
process.platform === 'win32'
? electronRebuildCmd.replace(/\//g, '\\')
: electronRebuildCmd;
execSync(cmd, {
cwd: path.join(__dirname, '../../src'),
stdio: 'inherit',
});
}

View File

@ -0,0 +1,28 @@
const { notarize } = require('electron-notarize');
const { build } = require('../../package.json');
exports.default = async function notarizeMacos(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== 'darwin') {
return;
}
if (!process.env.CI) {
console.warn('Skipping notarizing step. Packaging is not running in CI');
return;
}
if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
console.warn('Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set');
return;
}
const appName = context.packager.appInfo.productFilename;
await notarize({
appBundleId: build.appId,
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_ID_PASS,
});
};

56
.eslintignore 100644
View File

@ -0,0 +1,56 @@
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# App packaged
release
src/*.main.prod.js
src/main.prod.js
src/main.prod.js.map
src/renderer.prod.js
src/renderer.prod.js.map
src/style.css
src/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
__snapshots__
# Package.json
package.json
.travis.yml
*.css.d.ts
*.sass.d.ts
*.scss.d.ts

26
.eslintrc.js 100644
View File

@ -0,0 +1,26 @@
module.exports = {
extends: 'erb',
rules: {
// A temporary hack related to IDE not resolving correct package.json
'import/no-extraneous-dependencies': 'off',
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json',
tsconfigRootDir: __dirname,
createDefaultProgram: true,
},
settings: {
'import/resolver': {
// See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below
node: {},
webpack: {
config: require.resolve('./.erb/configs/webpack.config.eslint.js'),
},
},
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
},
};

12
.gitattributes vendored 100644
View File

@ -0,0 +1,12 @@
* text eol=lf
*.exe binary
*.png binary
*.jpg binary
*.jpeg binary
*.ico binary
*.icns binary
*.eot binary
*.otf binary
*.ttf binary
*.woff binary
*.woff2 binary

5
.github/FUNDING.yml vendored 100644
View File

@ -0,0 +1,5 @@
# These are supported funding model platforms
github: [electron-react-boilerplate, amilajack]
patreon: amilajack
open_collective: electron-react-boilerplate-594

View File

@ -0,0 +1,67 @@
---
name: Bug report
about: You're having technical issues. 🐞
labels: 'bug'
---
<!-- Please use the following issue template or your issue will be closed -->
## Prerequisites
<!-- If the following boxes are not ALL checked, your issue is likely to be closed -->
- [ ] Using yarn
- [ ] Using an up-to-date [`master` branch](https://github.com/electron-react-boilerplate/electron-react-boilerplate/tree/master)
- [ ] Using latest version of devtools. [Check the docs for how to update](https://electron-react-boilerplate.js.org/docs/dev-tools/)
- [ ] Tried solutions mentioned in [#400](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400)
- [ ] For issue in production release, add devtools output of `DEBUG_PROD=true yarn build && yarn start`
## Expected Behavior
<!--- What should have happened? -->
## Current Behavior
<!--- What went wrong? -->
## Steps to Reproduce
<!-- Add relevant code and/or a live example -->
<!-- Add stack traces -->
1.
2.
3.
4.
## Possible Solution (Not obligatory)
<!--- Suggest a reason for the bug or how to fix it. -->
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Did you make any changes to the boilerplate after cloning it? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
- Node version :
- electron-react-boilerplate version or branch :
- Operating System and version :
- Link to your project :
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->

View File

@ -0,0 +1,19 @@
---
name: Question
about: Ask a question.❓
labels: 'question'
---
## Summary
<!-- What do you need help with? -->
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->

View File

@ -0,0 +1,15 @@
---
name: Feature request
about: You want something added to the boilerplate. 🎉
labels: 'enhancement'
---
<!---
❗️❗️ Also, please consider donating (https://opencollective.com/electron-react-boilerplate-594) ❗️❗️
Donations will ensure the following:
🔨 Long term maintenance of the project
🛣 Progress on the roadmap
🐛 Quick responses to bug reports and help requests
-->

6
.github/config.yml vendored 100644
View File

@ -0,0 +1,6 @@
requiredHeaders:
- Prerequisites
- Expected Behavior
- Current Behavior
- Possible Solution
- Your Environment

17
.github/stale.yml vendored 100644
View File

@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pr
- discussion
- e2e
- enhancement
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

55
.github/workflows/publish.yml vendored 100644
View File

@ -0,0 +1,55 @@
name: Publish
on:
push:
branches:
- master
jobs:
publish:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- name: Checkout git repo
uses: actions/checkout@v1
- name: Install Node, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 15
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: |
yarn install --prefer-offline
- name: Install dependencies
run: |
yarn install
- name: Publish releases
env:
# These values are used for auto updates signing
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASS: ${{ secrets.APPLE_ID_PASS }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
# This is used for uploading release assets to github
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
yarn postinstall && yarn build && yarn electron-builder --publish always --win --mac --linux

33
.github/workflows/test.yml vendored 100644
View File

@ -0,0 +1,33 @@
name: Test
on: [push, pull_request]
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1
with:
node-version: 15
- name: yarn install
run: |
yarn install --frozen-lockfile --network-timeout 300000
- name: yarn test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
yarn package
yarn lint
yarn tsc
yarn test

52
.gitignore vendored
View File

@ -1,3 +1,51 @@
.vscode
node_modules
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# App packaged
release
src/main.prod.js
src/main.prod.js.map
src/renderer.prod.js
src/renderer.prod.js.map
src/style.css
src/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
*.css.d.ts
*.sass.d.ts
*.scss.d.ts
.vscode

533
CHANGELOG.md 100644
View File

@ -0,0 +1,533 @@
# 2.1.0
- Migrate to `css-minifier-webpack-plugin`
# 2.0.1
## Fixes
- Fix broken css linking in production build
# 2.0.0
## Breaking Changes
- drop redux
- remove counter example app
- simplify directory structure
- move `dll` dir to `.erb` dir
- fix icon/font import paths
- migrate to `react-refresh` from `react-hot-loader`
- migrate to webpack@5
- migrate to electron@11
- remove e2e tests and testcafe integration
- rename `app` dir to more conventional `src` dir
- rename `resources` dir to `assets`
- simplify npm scripts
- drop stylelint
- simplify styling of boilerplate app
- remove `START_HOT` env variable
- notarize support
- landing page boilerplate
- docs updates
- restore removed debugging support
# 1.4.0
- Migrate to `eslint-config-erb@2`
- Rename `dev` npm script to `start`
- GitHub Actions: only publish GitHub releases when on master branch
# 1.3.1
- Fix sass building bug ([#2540](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2540))
- Fix CI bug related to E2E tests and network timeouts
- Move automated dependency PRs to `next` ([#2554](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2554))
- Bump dependencies to patch semver
# 1.3.0
- Fixes E2E tests ([#2516](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2516))
- Fixes preload entrypoint ([#2503](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2503))
- Downgrade to `electron@8`
- Bump dependencies to latest semver
# 1.2.0
- Migrate to redux toolkit
- Lazy load routes with react suspense
- Drop support for azure-pipelines and use only github actions
- Bump all deps to latest semver
- Remove `test-e2e` script from tests (blocked on release of https://github.com/DevExpress/testcafe-browser-provider-electron/pull/65)
- Swap `typed-css-modules-webpack-plugin` for `typings-for-css-modules-loader`
- Use latest version of `eslint-config-erb`
- Remove unnecessary file extensions from ts exclude
- Add experimental support for vscode debugging
- Revert https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2365 as default for users, provide as opt in option
# 1.1.0
- Fix #2402
- Simplify configs (https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2406)
# 1.0.0
- Migrate to TypeScript from Flow ([#2363](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2363))
- Use browserslist for `@babel/preset-env` targets ([#2368](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2368))
- Use preload script, disable `nodeIntegration` in renderer process for [improved security](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content) ([#2365](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2365))
- Add support for azure pipelines ([#2369](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2369))
- Disable sourcemaps in production
# 0.18.1 (2019.12.12)
- Fix HMR env bug ([#2343](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2343))
- Bump all deps to latest semver
- Bump to `electron@7`
# 0.18.0 (2019.11.19)
- Bump electron to `electron@6` (`electron@7` introduces breaking changes to testcafe end to end tests)
- Revert back to [two `package.json` structure](https://www.electron.build/tutorials/two-package-structure)
- Bump all deps to latest semver
# 0.17.1 (2018.11.20)
- Fix `yarn test-e2e` and testcafe for single package.json structure
- Fixes incorrect path in `yarn start` script
- Bumped deps
- Bump g++ in travis
- Change clone arguments to clone only master
- Change babel config to target current electron version
For full change list, see https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2021
# 0.17.0 (2018.10.30)
- upgraded to `babel@7` (thanks to @vikr01 🎉🎉🎉)
- migrated from [two `package.json` structure](https://www.electron.build/tutorials/two-package-structure) (thanks to @HyperSprite!)
- initial auto update support (experimental)
- migrate from greenkeeper to [renovate](https://renovatebot.com)
- added issue template
- use `babel-preset-env` to target current electron version
- add [opencollective](https://opencollective.com/electron-react-boilerplate-594) banner message display in postinstall script (help support ERB 🙏)
- fix failing ci issues
# 0.16.0 (2018.10.3)
- removed unused dependencies
- migrate from `react-redux-router` to `connect-react-router`
- move webpack configs to `./webpack` dir
- use `g++` on travis when testing linux
- migrate from `spectron` to `testcafe` for e2e tests
- add linting support for config styles
- changed stylelint config
- temporarily disabled flow in appveyor to make ci pass
- added necessary infra to publish releases from ci
# 0.15.0 (2018.8.25)
- Performance: cache webpack uglify results
- Feature: add start minimized feature
- Feature: lint and fix styles with prettier and stylelint
- Feature: add greenkeeper support
# 0.14.0 (2018.5.24)
- Improved CI timings
- Migrated README commands to yarn from npm
- Improved vscode config
- Updated all dependencies to latest semver
- Fix `electron-rebuild` script bug
- Migrated to `mini-css-extract-plugin` from `extract-text-plugin`
- Added `optimize-css-assets-webpack-plugin`
- Run `prettier` on json, css, scss, and more filetypes
# 0.13.3 (2018.5.24)
- Add git precommit hook, when git commit will use `prettier` to format git add code
- Add format code function in `lint-fix` npm script which can use `prettier` to format project js code
# 0.13.2 (2018.1.31)
- Hot Module Reload (HMR) fixes
- Bumped all dependencies to latest semver
- Prevent error propagation of `CheckNativeDeps` script
# 0.13.1 (2018.1.13)
- Hot Module Reload (HMR) fixes
- Bumped all dependencies to latest semver
- Fixed electron-rebuild script
- Fixed tests scripts to run on all platforms
- Skip redux logs in console in test ENV
# 0.13.0 (2018.1.6)
#### Additions
- Add native dependencies check on postinstall
- Updated all dependencies to latest semver
# 0.12.0 (2017.7.8)
#### Misc
- Removed `babel-polyfill`
- Renamed and alphabetized npm scripts
#### Breaking
- Changed node dev `__dirname` and `__filename` to node built in fn's (https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/1035)
- Renamed `src/bundle.js` to `src/renderer.prod.js` for consistency
- Renamed `dll/vendor.js` to `dll/renderer.dev.dll.js` for consistency
#### Additions
- Enable node_modules cache on CI
# 0.11.2 (2017.5.1)
Yay! Another patch release. This release mostly includes refactorings and router bug fixes. Huge thanks to @anthonyraymond!
⚠️ Windows electron builds are failing because of [this issue](https://github.com/electron/electron/issues/9321). This is not an issue with the boilerplate ⚠️
#### Breaking
- **Renamed `./src/main.development.js` => `./src/main.{dev,prod}.js`:** [#963](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/963)
#### Fixes
- **Fixed reloading when not on `/` path:** [#958](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/958) [#949](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/949)
#### Additions
- **Added support for stylefmt:** [#960](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/960)
# 0.11.1 (2017.4.23)
You can now debug the production build with devtools like so:
```
DEBUG_PROD=true npm run package
```
🎉🎉🎉
#### Additions
- **Added support for debugging production build:** [#fab245a](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/941/commits/fab245a077d02a09630f74270806c0c534a4ff95)
#### Bug Fixes
- **Fixed bug related to importing native dependencies:** [#933](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/933)
#### Improvements
- **Updated all deps to latest semver**
# 0.11.0 (2017.4.19)
Here's the most notable changes since `v0.10.0`. Its been about a year since a release has been pushed. Expect a new release to be published every 3-4 weeks.
#### Breaking Changes
- **Dropped support for node < 6**
- **Refactored webpack config files**
- **Migrate to two-package.json project structure**
- **Updated all devDeps to latest semver**
- **Migrated to Jest:** [#768](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/768)
- **Migrated to `react-router@4`**
- **Migrated to `electron-builder@4`**
- **Migrated to `webpack@2`**
- **Migrated to `react-hot-loader@3`**
- **Changed default live reload server PORT to `1212` from `3000`**
#### Additions
- **Added support for Yarn:** [#451](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/451)
- **Added support for Flow:** [#425](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/425)
- **Added support for stylelint:** [#911](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/911)
- **Added support for electron-builder:** [#876](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/876)
- **Added optional support for SASS:** [#880](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/880)
- **Added support for eslint-plugin-flowtype:** [#911](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/911)
- **Added support for appveyor:** [#280](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/280)
- **Added support for webpack dlls:** [#860](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/860)
- **Route based code splitting:** [#884](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/884)
- **Added support for Webpack Bundle Analyzer:** [#922](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/922)
#### Improvements
- **Parallelize renderer and main build processes when running `npm run build`**
- **Dynamically generate electron app menu**
- **Improved vscode integration:** [#856](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/856)
#### Bug Fixes
- **Fixed hot module replacement race condition bug:** [#917](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/917) [#920](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/920)
# 0.10.0 (2016.4.18)
#### Improvements
- **Use Babel in main process with Webpack build:** [#201](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/201)
- **Change targets to built-in support by webpack:** [#197](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/197)
- **use es2015 syntax for webpack configs:** [#195](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/195)
- **Open application when webcontent is loaded:** [#192](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/192)
- **Upgraded dependencies**
#### Bug fixed
- **Fix `npm list electron-prebuilt` in package.js:** [#188](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/188)
# 0.9.0 (2016.3.23)
#### Improvements
- **Added [redux-logger](https://github.com/fcomb/redux-logger)**
- **Upgraded [react-router-redux](https://github.com/reactjs/react-router-redux) to v4**
- **Upgraded dependencies**
- **Added `npm run dev` command:** [#162](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/162)
- **electron to v0.37.2**
#### Breaking Changes
- **css module as default:** [#154](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/154).
- **set default NODE_ENV to production:** [#140](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/140)
# 0.8.0 (2016.2.17)
#### Bug fixed
- **Fix lint errors**
- **Fix Webpack publicPath for production builds**: [#119](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/119).
- **package script now chooses correct OS icon extension**
#### Improvements
- **babel 6**
- **Upgrade Dependencies**
- **Enable CSS source maps**
- **Add json-loader**: [#128](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/128).
- **react-router 2.0 and react-router-redux 3.0**
# 0.7.1 (2015.12.27)
#### Bug fixed
- **Fixed npm script on windows 10:** [#103](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/103).
- **history and react-router version bump**: [#109](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/109), [#110](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/110).
#### Improvements
- **electron 0.36**
# 0.7.0 (2015.12.16)
#### Bug fixed
- **Fixed process.env.NODE_ENV variable in webpack:** [#74](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/74).
- **add missing object-assign**: [#76](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/76).
- **packaging in npm@3:** [#77](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/77).
- **compatibility in windows:** [#100](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/100).
- **disable chrome debugger in production env:** [#102](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/102).
#### Improvements
- **redux**
- **css-modules**
- **upgrade to react-router 1.x**
- **unit tests**
- **e2e tests**
- **travis-ci**
- **upgrade to electron 0.35.x**
- **use es2015**
- **check dev engine for node and npm**
# 0.6.5 (2015.11.7)
#### Improvements
- **Bump style-loader to 0.13**
- **Bump css-loader to 0.22**
# 0.6.4 (2015.10.27)
#### Improvements
- **Bump electron-debug to 0.3**
# 0.6.3 (2015.10.26)
#### Improvements
- **Initialize ExtractTextPlugin once:** [#64](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/64).
# 0.6.2 (2015.10.18)
#### Bug fixed
- **Babel plugins production env not be set properly:** [#57](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/57).
# 0.6.1 (2015.10.17)
#### Improvements
- **Bump electron to v0.34.0**
# 0.6.0 (2015.10.16)
#### Breaking Changes
- **From react-hot-loader to react-transform**
# 0.5.2 (2015.10.15)
#### Improvements
- **Run tests with babel-register:** [#29](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/29).
# 0.5.1 (2015.10.12)
#### Bug fixed
- **Fix #51:** use `path.join(__dirname` instead of `./`.
# 0.5.0 (2015.10.11)
#### Improvements
- **Simplify webpack config** see [#50](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/50).
#### Breaking Changes
- **webpack configs**
- **port changed:** changed default port from 2992 to 3000.
- **npm scripts:** remove `start-dev` and `dev-server`. rename `hot-dev-server` to `hot-server`.
# 0.4.3 (2015.9.22)
#### Bug fixed
- **Fix #45 zeromq crash:** bump version of `electron-prebuilt`.
# 0.4.2 (2015.9.15)
#### Bug fixed
- **run start-hot breaks chrome refresh(CTRL+R) (#42)**: bump `electron-debug` to `0.2.1`
# 0.4.1 (2015.9.11)
#### Improvements
- **use electron-prebuilt version for packaging (#33)**
# 0.4.0 (2015.9.5)
#### Improvements
- **update dependencies**
# 0.3.0 (2015.8.31)
#### Improvements
- **eslint-config-airbnb**
# 0.2.10 (2015.8.27)
#### Features
- **custom placeholder icon**
#### Improvements
- **electron-renderer as target:** via [webpack-target-electron-renderer](https://github.com/chentsulin/webpack-target-electron-renderer)
# 0.2.9 (2015.8.18)
#### Bug fixed
- **Fix hot-reload**
# 0.2.8 (2015.8.13)
#### Improvements
- **bump electron-debug**
- **babelrc**
- **organize webpack scripts**
# 0.2.7 (2015.7.9)
#### Bug fixed
- **defaultProps:** fix typos.
# 0.2.6 (2015.7.3)
#### Features
- **menu**
#### Bug fixed
- **package.js:** include webpack build.
# 0.2.5 (2015.7.1)
#### Features
- **NPM Script:** support multi-platform
- **package:** `--all` option
# 0.2.4 (2015.6.9)
#### Bug fixed
- **Eslint:** typo, [#17](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/17) and improve `.eslintrc`
# 0.2.3 (2015.6.3)
#### Features
- **Package Version:** use latest release electron version as default
- **Ignore Large peerDependencies**
#### Bug fixed
- **Npm Script:** typo, [#6](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/6)
- **Missing css:** [#7](https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/7)
# 0.2.2 (2015.6.2)
#### Features
- **electron-debug**
#### Bug fixed
- **Webpack:** add `.json` and `.node` to extensions for imitating node require.
- **Webpack:** set `node_modules` to externals for native module support.
# 0.2.1 (2015.5.30)
#### Bug fixed
- **Webpack:** #1, change build target to `atom`.
# 0.2.0 (2015.5.30)
#### Features
- **Ignore:** `test`, `tools`, `release` folder and devDependencies in `package.json`.
- **Support asar**
- **Support icon**
# 0.1.0 (2015.5.27)
#### Features
- **Webpack:** babel, react-hot, ...
- **Flux:** actions, api, components, containers, stores..
- **Package:** darwin (osx), linux and win32 (windows) platform.

76
CODE_OF_CONDUCT.md 100644
View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at electronreactboilerplate@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

21
LICENSE 100644
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-present Electron React Boilerplate
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

157
README.md 100644
View File

@ -0,0 +1,157 @@
<img src=".erb/img/erb-banner.png" width="100%" />
<br>
<p>
Electron React Boilerplate uses <a href="https://electron.atom.io/">Electron</a>, <a href="https://facebook.github.io/react/">React</a>, <a href="https://github.com/reactjs/react-router">React Router</a>, <a href="https://webpack.js.org/">Webpack</a> and <a href="https://www.npmjs.com/package/react-refresh">React Fast Refresh</a>.
</p>
<br>
<div align="center">
[![Build Status][github-actions-status]][github-actions-url]
[![Dependency Status][david-image]][david-url]
[![DevDependency Status][david-dev-image]][david-dev-url]
[![Github Tag][github-tag-image]][github-tag-url]
[![OpenCollective](https://opencollective.com/electron-react-boilerplate/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/electron-react-boilerplate/sponsors/badge.svg)](#sponsors)
[![Good first issues open][good-first-issue-image]][good-first-issue-url]
[![StackOverflow][stackoverflow-img]][stackoverflow-url]
</div>
## Install
- **If you have installation or compilation issues with this project, please see [our debugging guide](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400)**
First, clone the repo via git and install dependencies:
```bash
git clone --depth 1 --single-branch https://github.com/electron-react-boilerplate/electron-react-boilerplate.git your-project-name
cd your-project-name
yarn
```
## Starting Development
Start the app in the `dev` environment:
```bash
yarn start
```
## Packaging for Production
To package apps for the local platform:
```bash
yarn package
```
## Docs
See our [docs and guides here](https://electron-react-boilerplate.js.org/docs/installation)
## Donations
**Donations will ensure the following:**
- 🔨 Long term maintenance of the project
- 🛣 Progress on the [roadmap](https://electron-react-boilerplate.js.org/docs/roadmap)
- 🐛 Quick responses to bug reports and help requests
## Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/electron-react-boilerplate#backer)]
<a href="https://opencollective.com/electron-react-boilerplate/backer/0/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/1/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/2/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/3/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/4/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/5/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/6/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/7/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/8/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/9/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/10/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/10/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/11/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/11/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/12/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/12/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/13/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/13/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/14/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/14/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/15/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/15/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/16/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/16/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/17/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/17/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/18/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/18/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/19/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/19/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/20/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/20/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/21/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/21/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/22/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/22/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/23/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/23/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/24/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/24/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/25/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/25/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/26/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/26/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/27/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/27/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/28/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/28/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/backer/29/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/backer/29/avatar.svg"></a>
## Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/electron-react-boilerplate-594#sponsor)]
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/0/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/1/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/2/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/3/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/4/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/5/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/6/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/7/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/8/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/9/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/9/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/10/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/10/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/11/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/11/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/12/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/12/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/13/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/13/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/14/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/14/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/15/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/15/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/16/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/16/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/17/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/17/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/18/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/18/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/19/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/19/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/20/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/20/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/21/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/21/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/22/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/22/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/23/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/23/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/24/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/24/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/25/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/25/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/26/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/26/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/27/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/27/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/28/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/28/avatar.svg"></a>
<a href="https://opencollective.com/electron-react-boilerplate/sponsor/29/website" target="_blank"><img src="https://opencollective.com/electron-react-boilerplate/sponsor/29/avatar.svg"></a>
## Maintainers
- [Amila Welihinda](https://github.com/amilajack)
- [John Tran](https://github.com/jooohhn)
- [C. T. Lin](https://github.com/chentsulin)
- [Jhen-Jie Hong](https://github.com/jhen0409)
## License
MIT © [Electron React Boilerplate](https://github.com/electron-react-boilerplate)
[github-actions-status]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/workflows/Test/badge.svg
[github-actions-url]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/actions
[github-tag-image]: https://img.shields.io/github/tag/electron-react-boilerplate/electron-react-boilerplate.svg?label=version
[github-tag-url]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/releases/latest
[stackoverflow-img]: https://img.shields.io/badge/stackoverflow-electron_react_boilerplate-blue.svg
[stackoverflow-url]: https://stackoverflow.com/questions/tagged/electron-react-boilerplate
[david-image]: https://img.shields.io/david/electron-react-boilerplate/electron-react-boilerplate.svg
[david-url]: https://david-dm.org/electron-react-boilerplate/electron-react-boilerplate
[david-dev-image]: https://img.shields.io/david/dev/electron-react-boilerplate/electron-react-boilerplate.svg?label=devDependencies
[david-dev-url]: https://david-dm.org/electron-react-boilerplate/electron-react-boilerplate?type=dev
[good-first-issue-image]: https://img.shields.io/github/issues/electron-react-boilerplate/electron-react-boilerplate/good%20first%20issue.svg?label=good%20first%20issues
[good-first-issue-url]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues?q=is%3Aopen+is%3Aissue+label%3A"good+first+issue"

14
assets/assets.d.ts vendored 100644
View File

@ -0,0 +1,14 @@
declare module '*.svg' {
const content: any;
export default content;
}
declare module '*.png' {
const content: any;
export default content;
}
declare module '*.jpg' {
const content: any;
export default content;
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
</dict>
</plist>

BIN
assets/icon.icns 100644

Binary file not shown.

BIN
assets/icon.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
assets/icon.png 100755

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

23
assets/icon.svg 100644
View File

@ -0,0 +1,23 @@
<svg width="232" height="232" viewBox="0 0 232 232" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_b)">
<path d="M231.5 1V0.5H231H1H0.5V1V231V231.5H1H231H231.5V231V1ZM40.5 25C40.5 33.0082 34.0082 39.5 26 39.5C17.9918 39.5 11.5 33.0082 11.5 25C11.5 16.9918 17.9918 10.5 26 10.5C34.0082 10.5 40.5 16.9918 40.5 25ZM220.5 25C220.5 33.0082 214.008 39.5 206 39.5C197.992 39.5 191.5 33.0082 191.5 25C191.5 16.9918 197.992 10.5 206 10.5C214.008 10.5 220.5 16.9918 220.5 25ZM40.5 205C40.5 213.008 34.0082 219.5 26 219.5C17.9918 219.5 11.5 213.008 11.5 205C11.5 196.992 17.9918 190.5 26 190.5C34.0082 190.5 40.5 196.992 40.5 205ZM220.5 205C220.5 213.008 214.008 219.5 206 219.5C197.992 219.5 191.5 213.008 191.5 205C191.5 196.992 197.992 190.5 206 190.5C214.008 190.5 220.5 196.992 220.5 205ZM209.5 111C209.5 162.639 167.639 204.5 116 204.5C64.3613 204.5 22.5 162.639 22.5 111C22.5 59.3613 64.3613 17.5 116 17.5C167.639 17.5 209.5 59.3613 209.5 111Z" fill="white" stroke="white"/>
<path d="M63.5 146.5C63.5 149.959 60.8969 152.5 58 152.5C55.1031 152.5 52.5 149.959 52.5 146.5C52.5 143.041 55.1031 140.5 58 140.5C60.8969 140.5 63.5 143.041 63.5 146.5Z" stroke="white" stroke-width="5"/>
<path d="M54.9856 139.466C54.9856 139.466 51.1973 116.315 83.1874 93.1647C115.178 70.014 133.698 69.5931 133.698 69.5931" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M178.902 142.686C177.27 139.853 173.652 138.88 170.819 140.512C167.987 142.144 167.014 145.762 168.646 148.595C170.277 151.427 173.896 152.4 176.728 150.768C179.561 149.137 180.534 145.518 178.902 142.686Z" stroke="white" stroke-width="5"/>
<path d="M169.409 151.555C169.409 151.555 151.24 166.394 115.211 150.232C79.182 134.07 69.5718 118.232 69.5718 118.232" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M109.577 41.9707C107.966 44.8143 108.964 48.4262 111.808 50.038C114.651 51.6498 118.263 50.6512 119.875 47.8075C121.487 44.9639 120.488 41.3521 117.645 39.7403C114.801 38.1285 111.189 39.1271 109.577 41.9707Z" stroke="white" stroke-width="5"/>
<path d="M122.038 45.6467C122.038 45.6467 144.047 53.7668 148.412 93.0129C152.778 132.259 144.012 148.579 144.012 148.579" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M59.6334 105C59.6334 105 50.4373 82.1038 61.3054 73.3616C72.1736 64.6194 96 69.1987 96 69.1987" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M149.532 66.9784C149.532 66.9784 174.391 68.9134 177.477 82.6384C180.564 96.3634 165.799 115.833 165.799 115.833" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M138.248 163.363C138.248 163.363 124.023 183.841 110.618 179.573C97.2129 175.305 87.8662 152.728 87.8662 152.728" stroke="white" stroke-width="5" stroke-linecap="round"/>
<path d="M116 119C120.418 119 124 115.642 124 111.5C124 107.358 120.418 104 116 104C111.582 104 108 107.358 108 111.5C108 115.642 111.582 119 116 119Z" fill="white"/>
</g>
<defs>
<filter id="filter0_b" x="-4" y="-4" width="240" height="240" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImage" stdDeviation="2"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

62
babel.config.js 100644
View File

@ -0,0 +1,62 @@
/* eslint global-require: off, import/no-extraneous-dependencies: off */
const developmentEnvironments = ['development', 'test'];
const developmentPlugins = [require('@babel/plugin-transform-runtime')];
const productionPlugins = [
require('babel-plugin-dev-expression'),
// babel-preset-react-optimize
require('@babel/plugin-transform-react-constant-elements'),
require('@babel/plugin-transform-react-inline-elements'),
require('babel-plugin-transform-react-remove-prop-types'),
];
module.exports = (api) => {
// See docs about api at https://babeljs.io/docs/en/config-files#apicache
const development = api.env(developmentEnvironments);
return {
presets: [
// @babel/preset-env will automatically target our browserslist targets
require('@babel/preset-env'),
require('@babel/preset-typescript'),
[require('@babel/preset-react'), { development }],
],
plugins: [
// Stage 0
require('@babel/plugin-proposal-function-bind'),
// Stage 1
require('@babel/plugin-proposal-export-default-from'),
require('@babel/plugin-proposal-logical-assignment-operators'),
[require('@babel/plugin-proposal-optional-chaining'), { loose: false }],
[
require('@babel/plugin-proposal-pipeline-operator'),
{ proposal: 'minimal' },
],
[
require('@babel/plugin-proposal-nullish-coalescing-operator'),
{ loose: false },
],
require('@babel/plugin-proposal-do-expressions'),
// Stage 2
[require('@babel/plugin-proposal-decorators'), { legacy: true }],
require('@babel/plugin-proposal-function-sent'),
require('@babel/plugin-proposal-export-namespace-from'),
require('@babel/plugin-proposal-numeric-separator'),
require('@babel/plugin-proposal-throw-expressions'),
// Stage 3
require('@babel/plugin-syntax-dynamic-import'),
require('@babel/plugin-syntax-import-meta'),
[require('@babel/plugin-proposal-class-properties'), { loose: true }],
require('@babel/plugin-proposal-json-strings'),
...(development ? developmentPlugins : productionPlugins),
],
};
};

View File

@ -1,26 +0,0 @@
(async () => {
const { title } = require('../lib/title');
const net = require('net');
const os = require('os');
const log = require('signale');
const { config } = require('./../package.json');
const { hri } = require('human-readable-ids');
const { Profiles } = require('../lib/Profiles');
const profiles = new Profiles('client');
const yargs = require('yargs').argv;
const identity = yargs.profile ?
await profiles.get(yargs.profile) :
await profiles.get((await profiles.all())[0]);
// const id = hri.random();
// console.log(id)
// title(id);
// title(identity.name.replace(/-/g, ' '));
// await profiles.create();
})();

View File

@ -1,38 +0,0 @@
class STPPacket {
cmd = 'NOOP';
data = {};
meta = {};
toBuffer() {
return Buffer.from(`\x02${JSON.stringify({
cmd: this.cmd,
data: this.data,
meta: this.meta
})}\x03`);
}
}
class KeyExchangePacket extends STPPacket {
constructor(key, type = 'pkcs8-pem') {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.type = type;
}
}
function basicPacket(commandName) {
return class extends STPPacket {
constructor() {
super();
this.cmd = commandName;
}
}
}
module.exports.STPPacket = STPPacket;
module.exports.KeyExchangePacket = KeyExchangePacket;
module.exports.AckPacket = basicPacket('ACK')
module.exports.GetClientsPacket = basicPacket('NODES')

View File

@ -1,11 +0,0 @@
const EventEmitter = require('events')
class Node extends EventEmitter {
constructor() {
}
}
module.exports.Node = Node;

View File

View File

View File

@ -1,27 +0,0 @@
(async () => {
const { config } = require('./../package.json');
const net = require('net');
const dns = require('dns');
const stp = require('../lib/STP');
const os = require('os');
const { title } = require('../lib/title');
const { hri } = require('human-readable-ids');
const log = require('signale');
const Keyv = require('keyv');
const { KeyvFile } = require('keyv-file');
const kv = new Keyv({
store: new KeyvFile({
filename: `${os.tmpdir()}/valnet/name-server/data.json`
})
});
const { Identity } = require('./../lib/Identity');
title('Name Server');
const identity = new Identity('name-server', 'default');
})();

View File

@ -1,40 +1,293 @@
{
"name": "valnet",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"config": {
"ports": {
"relay": 5600,
"http": 5700,
"service": 5000
},
"addresses": {
"relay": "valnet.xyz"
}
},
"scripts": {
"name-server": "supervisor -w name-server,lib -n exit name-server/index.js",
"relay": "supervisor -w relay,lib -n exit relay/index.js",
"relay:service": "supervisor -- relay/service",
"client:a": "supervisor -w client,lib -n exit -- client/index.js --profile J2aV59rsIgcdd5k2",
"client:b": "supervisor -w client,lib -n exit -- client/index.js --profile LsE8OnVzr1iYrkT0"
},
"dependencies": {
"express": "^4.17.1",
"express-ws": "^4.0.0",
"font-ascii": "^1.2.1",
"gradient-string": "^1.2.0",
"human-readable-ids": "^1.0.4",
"ip": "^1.1.5",
"keyv": "^4.0.3",
"keyv-file": "^0.2.0",
"nat-upnp": "^1.1.1",
"nedb": "^1.8.0",
"node-rsa": "^1.1.1",
"printable-characters": "^1.0.42",
"signale": "^1.4.0",
"supervisor": "^0.12.0",
"yargs": "^16.1.0"
}
}
{
"config": {
"ports": {
"relay": 5600,
"relayEnd": 5699,
"http": 5700,
"service": 5000
},
"endpoints": [
"valnet.xyz:5500",
"35.196.210.135:5600"
]
},
"name": "electron-react-boilerplate",
"productName": "ElectronReact",
"description": "Electron application boilerplate based on React, React Router, Webpack, React Fast Refresh for rapid application development",
"scripts": {
"postinstall": "node -r @babel/register .erb/scripts/CheckNativeDep.js && electron-builder install-app-deps && yarn cross-env NODE_ENV=development webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.babel.js && opencollective-postinstall && yarn-deduplicate yarn.lock",
"build": "concurrently \"yarn build:main\" \"yarn build:renderer\"",
"build:main": "cross-env NODE_ENV=production webpack --config ./.erb/configs/webpack.config.main.prod.babel.js",
"build:renderer": "cross-env NODE_ENV=production webpack --config ./.erb/configs/webpack.config.renderer.prod.babel.js",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir src",
"lint": "cross-env NODE_ENV=development eslint . --cache --ext .js,.jsx,.ts,.tsx",
"package": "rm -rf src/dist && yarn build && electron-builder build --publish never",
"start": "node -r @babel/register ./.erb/scripts/CheckPortInUse.js && cross-env yarn start:renderer",
"start:main": "cross-env NODE_ENV=development electron -r ./.erb/scripts/BabelRegister ./src/main.dev.ts",
"start:renderer": "cross-env NODE_ENV=development webpack serve --config ./.erb/configs/webpack.config.renderer.dev.babel.js",
"test": "jest",
"relay": "supervisor -w relay,src -n exit relay/index.mjs",
"relay:service": "supervisor -w relay,src -- relay/service.mjs",
"sloc": "find lib -type f | xargs wc -l"
},
"build": {
"productName": "ElectronReact",
"appId": "org.erb.ElectronReact",
"files": [
"dist/",
"node_modules/",
"index.html",
"main.prod.js",
"main.prod.js.map",
"package.json"
],
"afterSign": ".erb/scripts/Notarize.js",
"mac": {
"target": [
"dmg"
],
"type": "distribution",
"hardenedRuntime": true,
"entitlements": "assets/entitlements.mac.plist",
"entitlementsInherit": "assets/entitlements.mac.plist",
"gatekeeperAssess": false
},
"dmg": {
"contents": [
{
"x": 130,
"y": 220
},
{
"x": 410,
"y": 220,
"type": "link",
"path": "/Applications"
}
]
},
"win": {
"target": [
"nsis"
]
},
"linux": {
"target": [
"AppImage"
],
"category": "Development"
},
"directories": {
"app": "src",
"buildResources": "assets",
"output": "release"
},
"extraResources": [
"./assets/**"
],
"publish": {
"provider": "github",
"owner": "electron-react-boilerplate",
"repo": "electron-react-boilerplate"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/electron-react-boilerplate/electron-react-boilerplate.git"
},
"author": {
"name": "Electron React Boilerplate Maintainers",
"email": "electronreactboilerplate@gmail.com",
"url": "https://electron-react-boilerplate.js.org"
},
"contributors": [
{
"name": "Amila Welihinda",
"email": "amilajack@gmail.com",
"url": "https://github.com/amilajack"
},
{
"name": "John Tran",
"email": "jptran318@gmail.com",
"url": "https://github.com/jooohhn"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues"
},
"keywords": [
"electron",
"boilerplate",
"react",
"typescript",
"ts",
"sass",
"webpack",
"hot",
"reload"
],
"homepage": "https://github.com/electron-react-boilerplate/electron-react-boilerplate#readme",
"jest": {
"testURL": "http://localhost/",
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/.erb/mocks/fileMock.js",
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"js",
"jsx",
"ts",
"tsx",
"json"
],
"moduleDirectories": [
"node_modules",
"src/node_modules"
],
"setupFiles": [
"./.erb/scripts/CheckBuildsExist.js"
]
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-decorators": "^7.12.1",
"@babel/plugin-proposal-do-expressions": "^7.12.1",
"@babel/plugin-proposal-export-default-from": "^7.12.1",
"@babel/plugin-proposal-export-namespace-from": "^7.12.1",
"@babel/plugin-proposal-function-bind": "^7.12.1",
"@babel/plugin-proposal-function-sent": "^7.12.1",
"@babel/plugin-proposal-json-strings": "^7.12.1",
"@babel/plugin-proposal-logical-assignment-operators": "^7.12.1",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
"@babel/plugin-proposal-pipeline-operator": "^7.12.1",
"@babel/plugin-proposal-throw-expressions": "^7.12.1",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-transform-react-constant-elements": "^7.12.1",
"@babel/plugin-transform-react-inline-elements": "^7.12.1",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.12.7",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
"@teamsupercell/typings-for-css-modules-loader": "^2.4.0",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.2",
"@types/enzyme": "^3.10.5",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/history": "4.7.6",
"@types/jest": "^26.0.15",
"@types/node": "14.14.10",
"@types/react": "^16.9.44",
"@types/react-dom": "^16.9.9",
"@types/react-router-dom": "^5.1.6",
"@types/react-test-renderer": "^16.9.3",
"@types/webpack-env": "^1.15.2",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.1.0",
"babel-loader": "^8.2.2",
"babel-plugin-dev-expression": "^0.2.2",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"browserslist-config-erb": "^0.0.1",
"chalk": "^4.1.0",
"concurrently": "^5.3.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.2",
"css-loader": "^5.0.1",
"css-minimizer-webpack-plugin": "^1.1.5",
"detect-port": "^1.3.0",
"electron": "^11.0.1",
"electron-builder": "^22.3.6",
"electron-devtools-installer": "^3.1.1",
"electron-notarize": "^1.0.0",
"electron-rebuild": "^2.3.2",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",
"enzyme-to-json": "^3.5.0",
"eslint": "^7.5.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-airbnb-typescript": "^12.0.0",
"eslint-config-erb": "^2.0.0",
"eslint-import-resolver-webpack": "^0.13.0",
"eslint-plugin-compat": "^3.8.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^24.1.3",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.0.8",
"file-loader": "^6.0.0",
"husky": "^4.2.5",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.1.0",
"lint-staged": "^10.2.11",
"mini-css-extract-plugin": "^1.3.1",
"node-sass": "^5.0.0",
"opencollective-postinstall": "^2.0.3",
"react-refresh": "^0.9.0",
"react-test-renderer": "^17.0.1",
"rimraf": "^3.0.0",
"sass-loader": "^10.1.0",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.0.3",
"typescript": "^4.0.5",
"url-loader": "^4.1.0",
"webpack": "^5.5.1",
"webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.4.0",
"yarn-deduplicate": "^3.1.0"
},
"dependencies": {
"bonjour": "^3.5.0",
"debug": "^4.3.1",
"electron-debug": "^3.1.0",
"electron-log": "^4.2.4",
"electron-updater": "^4.3.4",
"font-ascii": "^1.2.1",
"gradient-string": "^1.2.0",
"history": "^5.0.0",
"human-readable-ids": "^1.0.4",
"keyv": "^4.0.3",
"keyv-file": "^0.2.0",
"md5": "^2.3.0",
"menubar": "^9.0.3",
"nat-upnp": "^1.1.1",
"nedb": "^1.8.0",
"node-ipc": "^9.1.4",
"node-rsa": "^1.1.1",
"printable-characters": "^1.0.42",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"regenerator-runtime": "^0.13.5",
"signale": "^1.4.0",
"source-map-support": "^0.5.19",
"supervisor": "^0.12.0",
"uuid": "^8.3.2"
},
"devEngines": {
"node": ">=10.x",
"npm": ">=6.x",
"yarn": ">=1.21.3"
},
"collective": {
"url": "https://opencollective.com/electron-react-boilerplate-594"
},
"browserslist": [],
"renovate": {
"extends": [
"bliss"
],
"baseBranches": [
"next"
]
}
}

View File

@ -1,115 +0,0 @@
(async () => {
const { title } = require('../lib/title');
const net = require('net');
const log = require('signale').scope('relay');
const { config } = require('../package.json');
const { Identity } = require('../lib/Identity');
const stp = require('../lib/STP');
title('relay', false);
const identity = await new Identity('relay', 'default');
const upnp = require('../lib/upnp');
const clients = [];
// const client = stp.connect(identity, config.ports.relay, '127.0.0.1');
// upnp.mapIndefinite(5600);
// ==================================== [STP SERVER]
stp.createServer({
identity: identity,
port: config.ports.relay
}, socket => {
log.info('secured connection from ' + socket.remoteAddress);
clients.push(socket);
});
function connectNetwork(t = 1000) {
if(t > 60000) t /= 2;
const client = stp.connect({
identity,
port: config.ports.relay,
ip: config.addresses.relay
});
client.on('ready', () => {
log.success('connectd to relay!');
t = 500;
})
client.on('error', e => {
});
client.on('close', e => {
t *= 2;
setTimeout(connectNetwork.bind(global, t), t);
log.warn('disconnected from relay');
log.warn('retrying connection... ' + (t/1000) + 's')
});
}
connectNetwork();
// ==================================== [EXPRESS]
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.end(`
<table style="min-width: 300px">
<tr>
<th>Id</th>
<th>Address</th>
<th>loopback</th>
</tr>
${clients.map((client, index) => `
<tr>
<td><pre>${index}</pre></td>
<td><pre>${client.remoteAddress}</pre></td>
<td><pre>${client.loopback}</pre></td>
</tr>
`).join('')}
</table>
`);
});
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
})
app.get('/clients', (req, res) => {
res.json({
clients: clients.map((client, index) => {
return {
id: index,
address: client.remoteAddress,
loopback: client.loopback,
identity: client.identity.publicKey,
connected: client.secured
}
})
})
})
// app.post
app.listen(config.ports.http).on('error', e => {
log.warn(e);
setTimeout(_ => {
app.listen(config.ports.http).on('error', e => {
log.error(e);
});
}, config.ports.http);
});
})();

86
relay/index.mjs 100644
View File

@ -0,0 +1,86 @@
// process.env.DEBUG = 'xyz:valnet:*';
'use strict';
import { title } from '../src/lib/title.js';
import { Identity } from '../src/lib/Identity.js';
import { config } from '../src/lib/config/index.js';
import appdata from '../src/lib/appdata.js';
import Node from '../src/lib/node.js';
import Signale from 'signale';
import { ensureDirSync } from 'fs-extra';
import express from 'express';
title('relay', false);
const log = Signale.scope('RLAY');
const node = new Node();
(async () => {
// ==================================== [EXPRESS]
const app = express();
ensureDirSync(`${appdata}/valnet/relay`);
app.get('/', (req, res) => {
res.end(`
<table style="min-width: 300px">
<tr>
<th>Id</th>
<th>Address</th>
<th>loopback</th>
</tr>
${clients.map((client, index) => `
<tr>
<td><pre>${index}</pre></td>
<td><pre>${client.remoteAddress}</pre></td>
<td><pre>${client.loopback}</pre></td>
</tr>
`).join('')}
</table>
`);
});
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
})
app.get('/clients', (req, res) => {
res.json({
clients: clients.map((client, index) => {
return {
id: index,
address: client.remoteAddress,
loopback: client.loopback,
identity: client.identity.publicKey,
connected: client.secured
}
})
})
})
// app.post
app.listen(config.ports.http).on('error', e => {
log.warn(e);
setTimeout(_ => {
app.listen(config.ports.http).on('error', e => {
log.error(e);
});
}, config.ports.http);
});
})();

View File

@ -1,17 +1,29 @@
import Signale from 'signale';
import { execSync, spawn } from 'child_process';
import Datastore from 'nedb';
import { config } from '../src/lib/config/index.js';
import express from 'express';
(async () => {
const log = require('signale').scope('service');
const { execSync, spawn } = require('child_process');
const log = Signale.scope('SRVC');
const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
let proc;
const Datastore = require('nedb');
const logs = new Datastore({
filename: 'svc.log',
autoload: true
});
const { config } = require('../package.json');
const express = require('express');
const app = express();
try {
logp('Attempting yarn install...')
appendLogs('yarn', execSync(`yarn`));
} catch (e) {
logp('failed to yarn install...')
}
logp('==================================');
logp('Starting Valnet Node as a Service!');
logp('Syncing to branch: ' + branch);
@ -41,7 +53,7 @@ setInterval(function update() {
}, 5000);
(function keepAlive() {
proc = spawn('node', ['relay'], {
proc = spawn('node', ['./relay/index.mjs'], {
stdio: 'pipe'
});
@ -130,14 +142,14 @@ ${docs.map(logItem => logItem.message).join('').replace(/\u001B\[.*?[A-Za-z]/g,
</pre>
<br><br><br><br><br><br>
<script>
requestAnimationFrame(_ => {
requestAnimationFrame(_ => {
window.scrollTo(0,document.body.scrollHeight);
});
});
setTimeout(_ => {
location.reload();
}, 2000);
// requestAnimationFrame(_ => {
// requestAnimationFrame(_ => {
// window.scrollTo(0,document.body.scrollHeight);
// });
// });
// setTimeout(_ => {
// location.reload();
// }, 2000);
</script>
</body>
</html>

60
src/App.global.css 100644
View File

@ -0,0 +1,60 @@
/*
* @NOTE: Prepend a `~` to css file paths that are in your node_modules
* See https://github.com/webpack-contrib/sass-loader#imports
*/
body {
position: relative;
color: white;
height: 100vh;
background: linear-gradient(
200.96deg,
#fedc2a -29.09%,
#dd5789 51.77%,
#7a2c9e 129.35%
);
font-family: sans-serif;
overflow-y: hidden;
display: flex;
justify-content: center;
align-items: center;
}
button {
background-color: white;
padding: 10px 20px;
border-radius: 10px;
border: none;
appearance: none;
font-size: 1.3rem;
box-shadow: 0px 8px 28px -6px rgba(24, 39, 75, 0.12),
0px 18px 88px -4px rgba(24, 39, 75, 0.14);
transition: transform ease-in 0.1s;
cursor: pointer;
}
button:hover {
transform: scale(1.05);
}
li {
list-style: none;
}
a {
text-decoration: none;
height: fit-content;
width: fit-content;
margin: 10px;
}
a:hover {
opacity: 1;
text-decoration: none;
}
.Hello {
display: flex;
justify-content: center;
align-items: center;
margin: 20px 0;
}

69
src/App.tsx 100644
View File

@ -0,0 +1,69 @@
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import icon from '../assets/icon.svg';
import './App.global.css';
import { IpcClient } from './lib/ipc.js';
class Hello extends React.Component {
api = new IpcClient('valnet');
constructor(props: {} | Readonly<{}>) {
super(props);
this.getData();
}
async getData() {
console.log(await this.api.getClients())
}
async killApp() {
// alert(this);
await this.api.kill(1);
}
render() {
return (
<div>
<div className="Hello">
<img width="200px" alt="icon" src={icon} />
</div>
<h1>electron-react-boilerplate</h1>
<div className="Hello">
<a
href="#"
rel="noreferrer"
onClick={this.killApp.bind(this)}
>
<button type="button">
<span role="img" aria-label="books">
📚
</span>
Kill App
</button>
</a>
<a
target="#"
rel="noreferrer"
>
<button type="button">
<span role="img" aria-label="books">
🙏
</span>
Donate
</button>
</a>
</div>
</div>
);
}
}
export default function App() {
return (
<Router>
<Switch>
<Route path="/" component={Hello} />
</Switch>
</Router>
);
}

View File

@ -0,0 +1,10 @@
import React from 'react';
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import App from '../App';
describe('App', () => {
it('should render', () => {
expect(render(<App />)).toBeTruthy();
});
});

44
src/index.html 100644
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello Electron React!</title>
<script>
(() => {
if (process?.env?.NODE_ENV !== 'development') {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './dist/style.css';
// HACK: Writing the script path should be done with webpack
document.getElementsByTagName('head')[0].appendChild(link);
}
})();
</script>
</head>
<body>
<div id="root"></div>
<script>
const scripts = [];
if (process.env.NODE_ENV === 'development') {
// Dynamically insert the DLL script in development env in the
// renderer process
scripts.push('../.erb/dll/renderer.dev.dll.js');
// Dynamically insert the bundled app script in the renderer process
const port = process.env.PORT || 1212;
scripts.push(`http://localhost:${port}/dist/renderer.dev.js`);
} else {
scripts.push('./dist/renderer.prod.js');
}
if (scripts.length) {
document.write(
scripts
.map((script) => `<script defer src="${script}"><\/script>`)
.join('')
);
}
</script>
</body>
</html>

7
src/index.tsx 100644
View File

@ -0,0 +1,7 @@
import React from 'react';
import { render } from 'react-dom';
import App from './App';
render(<App />, document.getElementById('root'));

163
src/lib/Gateway.js 100644
View File

@ -0,0 +1,163 @@
const { config } = require('./config');
const Keyv = require('keyv');
const { KeyvFile } = require('keyv-file');
const { Signale } = require('signale');
const log = new Signale().scope('GTWY');
const stp = require('./STP');
const appdata = require('./appdata');
class Gateway {
constructor(identity, endpoints) {
this.identity = identity;
this.endpoints = new Keyv({
store: new KeyvFile({
filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json`
})
});
this.ready = this.insertEndpoints(endpoints)
.then(this.networkTest.bind(this));
}
async insertEndpoints(endpoints) {
for (const endpoint of endpoints) {
const storeValue = await this.endpoints.get(endpoint);
if (storeValue) continue;
const [host, port] = endpoint.split(':');
const record = new EndpointRecord(host, port, null, 'unknown');
const currentEnpoints = await this.endpoints.get('cache') || [];
if (currentEnpoints.indexOf(endpoint) === -1) {
currentEnpoints.push(endpoint);
await this.endpoints.set('cache', currentEnpoints);
}
await this.endpoints.set(endpoint, record);
}
log.info('gateway endpoints:');
for(const endpoint of (await this.endpoints.get('cache'))) {
log.info(`\t${endpoint}`);
}
}
async networkTest() {
const endpoints = (await Promise.all(
(await this.endpoints.get('cache'))
.map(endpoint => this.endpoints.get(endpoint))
)).map(EndpointRecord.fromJson);
for (const endpoint of endpoints) {
await this.testEndpoint(endpoint.host, endpoint.port);
}
}
async testEndpoint(host, port) {
const log = new Signale({ scope: `${host}:${port}` });
const interactive = new Signale({ interactive: true, scope: `${host}:${port}` });
await new Promise(async (res, rej) => {
let pings = [];
let maxPings = 1;
let connectionAttempts = 0;
let wasConnected = false;
const done = _ => connectionAttempts === 2 || pings.length === maxPings
log.info('Starting connection test...');
while (!done()) {
await new Promise(async (res) => {
const client = stp.connect({
identity: this.identity,
ip: host,
port: parseInt(port)
});
client.on('error', _ => _);
client.on('ready', async () => {
wasConnected = true;
while (pings.length < maxPings) {
log.info(`[${pings.length + 1}/${maxPings}] Testing connection`);
pings.push(await client.ping());
// await new Promise(res => setTimeout(res, 1000));
}
client.tcpSocket.destroy();
res();
});
client.on('close', () => {
connectionAttempts ++;
if(!done() && wasConnected) {
log.warn(`Lost connection, Retrying...`);
}
wasConnected = false;
res();
});
});
}
if (pings.length === maxPings) {
const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings);
const pingRecord = new PingRecord(average, pings.length, new Date().getTime());
const endpointRecord = new EndpointRecord(host, port, pingRecord, 'online');
await this.endpoints.set(`${host}:${port}`, endpointRecord);
log.success(`Test complete. Average Ping: ${average}ms`);
} else {
log.error(`Could not complete connection test`)
}
res();
});
}
}
class EndpointRecord {
/**
* @param {Object|string} json string / object representation
* @returns {EndpointRecord}
*/
static fromJson(obj) {
if (typeof obj === 'string')
return EndpointRecord.fromJson(JSON.parse(obj));
return new EndpointRecord(
obj.host,
obj.port,
obj.lastPing ? new PingRecord(
obj.lastPing.average,
obj.lastPing.tests,
obj.lastPing.date
) : null,
obj.status
);
}
constructor(host, port, lastPing, status) {
this.host = host;
this.port = port;
this.lastPing = lastPing;
this.status = status;
}
}
class PingRecord {
constructor(average, tests, date) {
this.average = average;
this.tests = tests;
this.date = date;
}
}
module.exports = Gateway

View File

@ -4,18 +4,19 @@ const { hri } = require('human-readable-ids');
const os = require('os');
const NodeRSA = require('node-rsa');
let log = require('signale').scope('Identity(null)');
const appdata = require('./appdata');
module.exports.Identity = class Identity {
kv;
key;
name;
/// ASYNC CONSTRUCTOR
constructor(module, id) {
return new Promise(async (res, rej) => {
const kv = new Keyv({
const store = new Keyv({
store: new KeyvFile({
filename: `${os.tmpdir()}/valnet/${module}/${id}.json`
filename: `${appdata}/valnet/${module}/${id}.json`
})
});
@ -24,26 +25,26 @@ module.exports.Identity = class Identity {
this.key = await new Promise(async (res) => {
log.info(`Searching for identity`);
if(! await kv.get('private-key')
|| ! await kv.get('public-key')
|| ! await kv.get('name')) {
if(! await store.get('private-key')
|| ! await store.get('public-key')
|| ! await store.get('name')) {
log.warn(`no keypair found, generating...`);
const name = hri.random();
const key = new NodeRSA({b: 512});
key.generateKeyPair();
await kv.set('name', name);
await kv.set('private-key', key.exportKey('pkcs8-private-pem'));
await kv.set('public-key', key.exportKey('pkcs8-public-pem'));
await store.set('name', name);
await store.set('private-key', key.exportKey('pkcs8-private-pem'));
await store.set('public-key', key.exportKey('pkcs8-public-pem'));
log.success(`done!`);
}
const identity = new NodeRSA();
identity.importKey(await kv.get('private-key'), 'pkcs8-private-pem');
identity.importKey(await kv.get('public-key'), 'pkcs8-public-pem');
identity.importKey(await store.get('private-key'), 'pkcs8-private-pem');
identity.importKey(await store.get('public-key'), 'pkcs8-public-pem');
log.info(`Identity imported.`);
this.name = await kv.get('name');
this.name = await store.get('name');
res(identity);
});
@ -67,6 +68,6 @@ module.exports.Identity = class Identity {
}
toString() {
return `[Identity(${this.name})]`;
return `[Identity ${this.name}]`;
}
}

View File

@ -1,142 +1,187 @@
const net = require('net');
const EventEmitter = require('events');
const NodeRSA = require('node-rsa');
const log = require('signale').scope('stp');
const {
KeyExchangePacket,
AckPacket
} = require('./packets');
const { rejects } = require('assert');
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
const server = new Server(identity, port);
server.on('connection', connection => {
cb(connection);
});
// return 5;
}
module.exports.connect = function({
identity,
port,
ip
}) {
return new STPSocket(net.connect(port, ip), identity);
}
class Server extends EventEmitter {
tcpServer;
identity;
port;
constructor(identity, port) {
super();
this.identity = identity;
this.port = port;
this.openServer();
}
openServer() {
log.info(`opening STP server on ${this.port}`);
this.tcpServer = net.createServer(this.tcpConnectClient.bind(this));
this.tcpServer.on('error', e => {
log.warn(e)
setTimeout(this.openServer.bind(this), 5000);
})
this.tcpServer.listen(this.port);
}
tcpConnectClient(tcpSocket) {
const socket = new STPSocket(tcpSocket, this.identity);
socket.on('ready', () => {
this.emit('connection', socket);
})
}
}
class STPSocket extends EventEmitter {
tcpSocket;
readyState = 0;
buffer = '';
externalKey;
identity;
get loopback() {
return this.identity.publicKey ===
this.externalKey.exportKey('pkcs8-public-pem');
}
get remoteAddress() {
return this.tcpSocket.remoteAddress;
}
get remoteIdentity() {
return this.externalKey.exportKey('pkcs8-public-pem');
}
get open() {
return this.tcpSocket.readyState === 'open'
}
get secured() {
return this.readyState;
}
constructor(tcpSocket, identity) {
super();
this.tcpSocket = tcpSocket;
this.identity = identity;
if(this.open) this.handshake();
else this.tcpSocket.on('connect', this.handshake.bind(this));
this.tcpSocket.on('data', this.data.bind(this));
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
}
data(evt) {
this.buffer += evt.toString();
this.processBuffer();
}
processBuffer() {
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
this.buffer = '';
for(const message of parts) {
if(message.endsWith('\x03')) {
const obj = JSON.parse(message.substr(1, message.length - 2));
this.processMessage(obj);
} else {
this.buffer += message;
}
}
}
processMessage(obj) {
switch(obj.cmd) {
case 'KEY': {
if(this.readyState === 0) {
this.externalKey = new NodeRSA();
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
this.tcpSocket.write(new AckPacket().toBuffer());
this.readyState = 1;
}
break;
}
case 'ACK': {
if(this.readyState === 1) {
this.readyState = 2;
this.emit('ready');
}
break;
}
}
}
handshake() {
const pk = this.identity.publicKey;
const packet = new KeyExchangePacket(pk);
const buffer = packet.toBuffer();
this.tcpSocket.write(buffer);
}
}
const net = require('net');
const EventEmitter = require('events');
const NodeRSA = require('node-rsa');
const log = require('signale').scope('_STP');
const debug = require('debug')('xyz:valnet:stp');
const {
KeyExchangePacket,
AckPacket,
PingPacket,
PongPacket
} = require('./packets');
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
const server = new Server(identity, port);
server.on('connection', connection => {
cb(connection);
});
// return 5;
}
module.exports.connect = function({
identity,
port,
ip
}) {
return new STPSocket(net.connect(port, ip), identity);
}
class Server extends EventEmitter {
tcpServer;
identity;
port;
constructor(identity, port) {
super();
this.identity = identity;
this.port = port;
this.openServer();
}
openServer() {
// log.info(`opening STP server on ${this.port}`);
this.tcpServer = net.createServer(this.tcpConnectClient.bind(this));
this.tcpServer.on('error', e => {
log.warn(e)
setTimeout(this.openServer.bind(this), 5000);
})
this.tcpServer.listen(this.port);
}
tcpConnectClient(tcpSocket) {
const socket = new STPSocket(tcpSocket, this.identity);
socket.on('ready', () => {
this.emit('connection', socket);
})
}
}
class STPSocket extends EventEmitter {
tcpSocket;
buffer = '';
externalKey;
identity;
externalName;
CONNECTING = Symbol('connecting');
EXCHANGE = Symbol('exchange');
SECURED = Symbol('secured');
readyState = this.CONNECTING;
pingCallbacks = new Map();
get loopback() {
return this.identity.publicKey ===
this.externalKey.exportKey('pkcs8-public-pem');
}
get remoteAddress() {
return this.tcpSocket.remoteAddress;
}
get remoteName() {
return this.externalName;
}
get remoteIdentity() {
return this.externalKey.exportKey('pkcs8-public-pem');
}
get open() {
return this.tcpSocket.readyState === 'open';
}
get secured() {
return this.readyState;
}
constructor(tcpSocket, identity) {
super();
this.tcpSocket = tcpSocket;
this.identity = identity;
if(this.open) this.handshake();
else this.tcpSocket.on('connect', this.handshake.bind(this));
this.tcpSocket.on('data', this.data.bind(this));
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
}
data(evt) {
this.buffer += evt.toString();
this.processBuffer();
}
processBuffer() {
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
this.buffer = '';
for(const message of parts) {
if(message.endsWith('\x03')) {
const obj = JSON.parse(message.substr(1, message.length - 2));
this.processMessage(obj);
} else {
this.buffer += message;
}
}
}
processMessage(obj) {
if(this.readyState === this.CONNECTING && obj.cmd === 'KEY') {
debug('received remote public key...');
this.externalKey = new NodeRSA();
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
this.externalName = obj.meta.name;
this.tcpSocket.write(new AckPacket().toBuffer());
this.readyState = this.EXCHANGE;
debug('sent acknowledgement...');
return;
}
if(this.readyState === this.EXCHANGE && obj.cmd === 'ACK') {
debug('received acknowledgement...');
this.readyState = this.SECURED;
this.emit('ready');
return;
}
if (this.readyState === this.SECURED && obj.cmd === 'PING') {
this.tcpSocket.write(new PongPacket(obj.data.id).toBuffer());
return;
}
if (this.readyState === this.SECURED && obj.cmd === 'PONG') {
if (this.pingCallbacks.has(obj.data.id)) {
this.pingCallbacks.get(obj.data.id)();
}
return;
}
}
handshake() {
debug('connected')
const pk = this.identity.publicKey;
const packet = new KeyExchangePacket(pk, {
name: this.identity.name
});
const buffer = packet.toBuffer();
this.tcpSocket.write(buffer);
debug('sent public key...')
}
async ping() {
const startTime = new Date().getTime();
return await new Promise(async (res) => {
const packet = new PingPacket();
this.pingCallbacks.set(packet.data.id, _ => {
res(new Date().getTime() - startTime);
this.pingCallbacks.delete(packet.data.id);
});
this.tcpSocket.write(packet.toBuffer());
debug('ping sent...');
})
}
}

View File

@ -0,0 +1,115 @@
const md5 = require('md5');
// #region === [ private lib functions ] ===
class STPPacket {
cmd = 'NOOP';
data = {};
meta = {};
toBuffer() {
return Buffer.from(`\x02${JSON.stringify({
cmd: this.cmd,
data: this.data,
meta: this.meta
})}\x03`);
}
}
function basicPacket(commandName) {
return class extends STPPacket {
constructor() {
super();
this.cmd = commandName;
}
}
}
// #endregion
// #region === [ exotic packet classes ] ===
class KeyExchangePacket extends STPPacket {
constructor(key, {
type = 'pkcs8-pem',
name = 'anonymous'
} = {}) {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.name = name;
this.meta.type = type;
}
}
class ClientsPacket extends STPPacket {
constructor(clients) {
super();
this.cmd = 'NODES'
this.data.clients = clients;
}
}
class PingPacket extends STPPacket {
constructor() {
super();
this.cmd = 'PING';
this.data.id = md5(Date());
}
}
class PongPacket extends STPPacket {
constructor(id) {
super();
this.cmd = 'PONG';
this.data.id = id;
}
}
// #endregion
// #region === [ ordinary packet classes ] ===
const AckPacket = basicPacket('ACK');
const GetClientsPacket = basicPacket('QNODES');
// #endregion
// #region === [ public lib functions ] ===
function reconstructPacket(packet) {
if(packet.startsWith('\x02'))
return reconstructPacket(packet.substr(1));
if(packet.endsWith('\x03'))
return reconstructPacket(packet.substr(0, packet.length - 1));
const obj = JSON.parse(packet);
switch(obj.cmd) {
case 'KEY': return new KeyExchangePacket(obj.data.key, obj.meta);
case 'NODES': return new ClientsPacket(obj.data.clients);
case 'QNODES': return new GetClientsPacket();
case 'ACK': return new AckPacket();
case 'NOOP': return new STPPacket();
default: throw new TypeError(`Unknown command ${obj.cmd}`);
}
}
// #endregion
// #region === [ exports ] ===
module.exports.KeyExchangePacket = KeyExchangePacket;
module.exports.ClientsPacket = ClientsPacket;
module.exports.PingPacket = PingPacket;
module.exports.PongPacket = PongPacket;
module.exports.AckPacket = AckPacket;
module.exports.GetClientsPacket = GetClientsPacket;
module.exports.reconstructPacket = reconstructPacket;
// #endregion

View File

@ -0,0 +1,26 @@
const { EventEmitter } = require('events');
module.exports.StreamJsonParser = class StreamJsonParser extends EventEmitter {
buffer = '';
data(evt) {
// toString it, in case its a buffer!
this.buffer += evt.toString();
this.processBuffer();
}
processBuffer() {
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
this.buffer = '';
for(const message of parts) {
if(message.endsWith('\x03')) {
const obj = JSON.parse(message.substr(1, message.length - 2));
this.emit('message', obj);
} else {
this.buffer += message;
}
}
}
}

View File

@ -0,0 +1,3 @@
const appdata = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share");
module.exports = appdata;

View File

@ -0,0 +1,12 @@
module.exports = {
"ports": {
"relay": 5600,
"relayEnd": 5699,
"http": 5700,
"service": 5000
},
"endpoints": [
"valnet.xyz:5500",
"35.196.210.135:5600"
]
}

View File

@ -0,0 +1,34 @@
const { readFileSync, writeFileSync, existsSync } = require('fs');
const { ensureDirSync } = require('fs-extra');
const config = require('./defaults.js');
const deepmerge = require('deepmerge');
const appdata = require('../appdata');
ensureDirSync(`${appdata}/valnet/relay`);
const filepath = `${appdata}/valnet/relay/config.json`;
const configObject = {};
module.exports.config = configObject;
function loadObject(obj) {
for(const key in obj) {
configObject[key] = obj[key];
}
}
try {
if(!existsSync(filepath))
writeFileSync(filepath, JSON.stringify({}, null, 2));
const json = readFileSync(filepath);
const data = JSON.parse(json);
loadObject(deepmerge(config, data, {
arrayMerge: (_, sourceArray, __) => sourceArray
}));
} catch(e) {
}

87
src/lib/ipc.js 100644
View File

@ -0,0 +1,87 @@
const ipc = require('node-ipc');
const { EventEmitter } = require('events');
const uuid = require('uuid');
ipc.config.silent = true;
class IpcServer extends EventEmitter {
functions = new Map();
constructor(name) {
super();
ipc.serve('/tmp/app.' + name, () => {
ipc.server.on('connect', this.newClient.bind(this));
})
ipc.server.start();
}
registerFunction(name, fn) {
if(!fn) return this.registerFunction(name.name, name);
const sanitizedName = name.replace('bound ', '');
this.functions.set(sanitizedName, fn);
}
newClient(socket) {
ipc.server.on('req', (evt, incommingSocket) => {
if (incommingSocket !== socket) return;
const [
name,
...args
] = evt;
if(!this.functions.has(name)) {
console.log('fn not in here boos')
socket.emit('data', undefined);
return;
}
const fn = this.functions.get(name);
const result = fn(...args);
ipc.server.emit(socket, 'res', result);
});
}
}
function IpcClient(name) {
this.currentCb = _ => _;
const handler = {
get(target, fnName) {
if(fnName === 'then') {
return undefined;
} else if (fnName === 'ready') {
return this.name;
}
return function(...args) {
return new Promise(res => {
this.currentCb = (result) => {
res(result);
}
ipc.of[name].emit('req', [fnName, ...args]);
})
}
}
};
this.proxy = new Proxy(this, handler);
this.name = name;
this.ready = new Promise(res => {
ipc.connectTo(name, () => {
ipc.of[name].on('connect', _ => res());
ipc.of[name].on('res', result => {
this.currentCb(result);
});
});
});
return this.proxy;
}
module.exports = {
IpcServer,
IpcClient
};

139
src/lib/node.js 100644
View File

@ -0,0 +1,139 @@
const EventEmitter = require('events')
const stp = require('./STP');
const upnp = require('./upnp');
const md5 = require('md5');
const { config, write } = require('./config/index.js');
const log = require('signale').scope('NODE');
const bonjour = require('bonjour')();
const Gateway = require('./Gateway');
const { Identity } = require('./Identity');
const { IpcServer } = require('./ipc.js');
class Node extends EventEmitter {
clients = [];
hash = null;
name = null;
readyPromise = null;
port = null;
identity;
multicastAd = null;
multicastBrowser = null;
connected = false;
multicastDevices = [];
upnpEnabled = false;
constructor() {
super();
this.readyPromise = this.setupIdentity()
.then(this.negotiatePort.bind(this))
.catch(this.serverStartupFailed.bind(this))
.then(this.startServer.bind(this))
.then(this.connectNetwork.bind(this))
}
async setupIdentity() {
const identity = await new Identity('relay', 'default');
this.identity = identity;
this.hash = md5(identity.publicKey);
this.name = `valnet-node-${identity.name}`;
}
async connectNetwork() {
const gateway = new Gateway(this.identity, config.endpoints);
}
async serverStartupFailed(error) {
log.warn('port negotiation failed, using config port: ' + config.ports.relay);
log.warn('If This is meant to be a server, you\'ll');
log.warn('need to manually forward the port.');
log.warn('elsewise, this warning is safe to ignore.');
}
async startServer() {
log.info('creating Valnet Node on port ' + this.port + '...');
stp.createServer({
identity: this.identity,
port: this.port
}, (connection) => {
log.info('incomming connection from ' + connection.remoteName);
});
log.info('advertising node on multicast...');
this.multicastAd = bonjour.publish({
name: this.name,
type: 'stp',
port: this.port,
protocol: 'tcp'
});
this.multicastBrowser = bonjour.find({type: 'stp'});
this.multicastBrowser.on('up', this.serviceUp.bind(this));
this.multicastBrowser.on('down', this.serviceDown.bind(this));
const ipcServer = new IpcServer('valnet');
ipcServer.registerFunction(this.getClients.bind(this));
ipcServer.registerFunction(this.kill.bind(this));
// log.success('Node successfully registered!');
}
getClients() {
log.debug(this.clients);
return this.clients;
}
kill(code) {
process.exit(code);
}
async serviceUp(device) {
this.multicastDevices.push(device);
}
async serviceDown(device) {
this.multicastDevices = this.multicastDevices.filter(testDevice => {
return testDevice.host !== device.host
|| testDevice.port !== device.port
})
}
async negotiatePort() {
const mappings = await upnp.mappings();
const matchingMappings = mappings.filter(mapping => {
return mapping.description === this.name
});
const alreadyMapped = matchingMappings.length > 0;
const takenPorts = mappings.map(mapping => mapping.public.port);
if(alreadyMapped) {
this.port = matchingMappings[0].public.port;
this.upnpEnabled = true;
log.success(`upnp port ${this.port} already registered!`);
return;
}
for(let port = config.ports.relay; port <= config.ports.relayEnd; port ++) {
if(takenPorts.indexOf(port) === -1) {
await upnp.mapIndefinite(port, this.name);
this.port = port;
this.upnpEnabled = true;
log.success(`registered upnp port ${this.port}`);
return;
}
}
}
static get Node() {
return Node;
}
get ready() {
return this.readyPromise;
}
}
module.exports = Node;

Some files were not shown because too many files have changed in this diff Show More