Skip to content

Commit

Permalink
Run the dotnet Data Provider from electron (#36)
Browse files Browse the repository at this point in the history
- console messages are passed through to the electron console
- add GHA dotnet build
- also `npx update-browserslist-db@latest`
- note: in dev, close the app (before ctrl + c) so that the dotnet process is killed
  • Loading branch information
irahopkinson authored Feb 27, 2023
1 parent 72b26a8 commit 5a32cf4
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 34 deletions.
20 changes: 18 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,25 @@ on:

jobs:
publish:
name: Build on node ${{ matrix.node_version }} and ${{ matrix.os }}
name: Publish on ${{ matrix.os }}, .Net ${{ matrix.dotnet_version }}, and node ${{ matrix.node_version }}

runs-on: ${{ matrix.os }}

strategy:
matrix:
node_version: [16.x]
os: [macos-latest, ubuntu-latest]
dotnet_version: [7.0.x]
node_version: [16.x]

steps:
- name: Checkout git repo
uses: actions/checkout@v3

- name: Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{matrix.dotnet_version}}

- name: Install Node and NPM
uses: actions/setup-node@v3
with:
Expand All @@ -37,6 +43,16 @@ jobs:
npm install
npm run build
- name: dotnet build - MacOS and Windows
if: ${{ matrix.os == 'macos-latest' }}
run: |
npm run build:data-release:windows
npm run build:data-release:macos
- name: dotnet build - Linux
if: ${{ matrix.os == 'ubuntu-latest' }}
run: npm run build:data-release:linux

- name: Publish releases - Windows and MacOS
# If the branch is labeled as a release version (e.g. "release/v1.2.3"),
if: ${{ matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/heads/release/v') && contains(github.ref, '.') }}
Expand Down
14 changes: 13 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,38 @@ on:

jobs:
test:
name: Test on ${{ matrix.os }}, .Net ${{ matrix.dotnet_version }}, and node ${{ matrix.node_version }}

runs-on: ${{ matrix.os }}

strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
dotnet_version: [7.0.x]
node_version: [16.x]

steps:
- name: Check out Git repository
uses: actions/checkout@v3

- name: Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{matrix.dotnet_version}}

- name: Install Node.js and NPM
uses: actions/setup-node@v3
with:
node-version: 16
node-version: ${{ matrix.node_version }}
cache: npm

- name: npm install
run: |
npm install
- name: dotnet build
run: npm run build:data-release

- name: npm test
env:
# no hardlinks so dependencies are copied
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ Set up pre-requisites for building:

Add the system libraries needed for Electron, [Build Instructions (Linux)](https://www.electronjs.org/docs/latest/development/build-instructions-linux).

### All Platforms Development Pre-requisites

Install `dotnet` [.NET 7 SDK from here](https://learn.microsoft.com/en-us/dotnet/core/install/).

To check if `dotnet` is installed run (ensure you have a v7 SDK):

```bash
dotnet --version
dotnet --list-sdks
```

### Cloning and installing dependencies (all platforms)

Clone the repo and install dependencies:
Expand All @@ -59,7 +70,7 @@ Start the app in the `dev` environment:
npm start
```

After you run `npm start`, you can edit the Electron and frontend files, and they will hot reload. To edit C# files, you must stop the `npm start` process (or only close Paranext), run `npm run build:c-sharp`, and restart `npm start` (or if you only closed Paranext, make a trivial edit to `src/main/main.ts`, and save it to launch Paranext again).
After you run `npm start`, you can edit the Electron and frontend files, and they will hot reload. To edit C# files, you must stop the `npm start` process (or only close Paranext), run `npm run build:data`, and restart `npm start` (or if you only closed Paranext, make a trivial edit to `src/main/main.ts`, and save it to launch Paranext again).

## Packaging for Production

Expand Down
1 change: 1 addition & 0 deletions c-sharp/ParanextDataProvider.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Paranext.DataProvider</RootNamespace>
<SelfContained>true</SelfContained>
</PropertyGroup>

<ItemGroup>
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 24 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"build:data": "dotnet build c-sharp/ParanextDataProvider.sln",
"build:data-release": "run-script-os",
"build:data-release:windows": "dotnet publish c-sharp/ParanextDataProvider.csproj -p:PublishProfile=FolderProfile",
"build:data-release:linux": "dotnet publish c-sharp/ParanextDataProvider.csproj -p:PublishProfile=FolderProfile -r linux-x64 -o ./c-sharp/bin/Release/net7.0/publish/linux-x64/",
"build:data-release:macos": "dotnet publish c-sharp/ParanextDataProvider.csproj -p:PublishProfile=FolderProfile -r osx-x64 -o ./c-sharp/bin/Release/net7.0/publish/osx-x64/ && dotnet publish c-sharp/ParanextDataProvider.csproj -p:PublishProfile=FolderProfile -r osx-arm64 -o ./c-sharp/bin/Release/net7.0/publish/osx-arm64/",
"build:data-release:windows": "dotnet publish c-sharp/ParanextDataProvider.csproj -r win-x64 -o ./c-sharp/bin/Release/net7.0/publish/win-x64/",
"build:data-release:linux": "dotnet publish c-sharp/ParanextDataProvider.csproj -r linux-x64 -o ./c-sharp/bin/Release/net7.0/publish/linux-x64/",
"build:data-release:macos": "dotnet publish c-sharp/ParanextDataProvider.csproj -r osx-x64 -o ./c-sharp/bin/Release/net7.0/publish/osx-x64/ && dotnet publish c-sharp/ParanextDataProvider.csproj -p:PublishProfile=FolderProfile -r osx-arm64 -o ./c-sharp/bin/Release/net7.0/publish/osx-arm64/",
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"package": "ts-node ./.erb/scripts/clean.js dist && npm run build && npm run build:data-release && electron-builder build --publish never",
Expand All @@ -59,6 +59,7 @@
"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only -r tsconfig-paths/register .",
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"start:data": "dotnet run --project c-sharp/ParanextDataProvider.csproj",
"test": "jest"
},
"lint-staged": {
Expand Down Expand Up @@ -178,6 +179,12 @@
"x64"
]
},
"extraResources": [
{
"from": "./c-sharp/bin/Release/net7.0/publish/osx-${arch}/",
"to": "./dotnet/"
}
],
"type": "distribution",
"hardenedRuntime": true,
"entitlements": "assets/entitlements.mac.plist",
Expand All @@ -203,12 +210,25 @@
"nsis",
"nsis-web",
"portable"
],
"extraResources": [
{
"from": "./c-sharp/bin/Release/net7.0/publish/win-x64/",
"to": "./dotnet/"
}
]
},
"linux": {
"target": [
"AppImage"
],
"category": "Development",
"extraResources": [
{
"from": "./c-sharp/bin/Release/net7.0/publish/linux-x64/",
"to": "./dotnet/"
}
],
"extraFiles": [
{
"from": "/usr/lib/x86_64-linux-gnu/libnss3.so",
Expand Down Expand Up @@ -466,8 +486,7 @@
"from": "/usr/lib/x86_64-linux-gnu/libgio-2.0.so.0",
"to": "usr/lib/libgio-2.0.so.0"
}
],
"category": "Development"
]
},
"directories": {
"app": "release/app",
Expand Down
43 changes: 27 additions & 16 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import path from 'path';
import { app, BrowserWindow, shell, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import windowStateKeeper from 'electron-window-state';
import dotnetDataProvider from '@main/services/dotnet-data-provider.service';
import * as NetworkService from '@shared/services/NetworkService';
import papi from '@shared/services/papi';
import { CommandHandler } from '@shared/util/PapiUtil';
import windowStateKeeper from 'electron-window-state';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';

Expand Down Expand Up @@ -134,10 +135,17 @@ app.on('window-all-closed', () => {
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
if (process.platform !== 'darwin') {
// TODO: cleanly stop the provider (close the ws or send command) - IJH 2022-02-23
dotnetDataProvider.kill();
app.quit();
}
});

app.on('will-quit', () => {
// TODO: cleanly stop the provider (close the ws or send command) - IJH 2022-02-23
dotnetDataProvider.kill();
});

// #endregion

// #region IPC HANDLING SETUP
Expand Down Expand Up @@ -190,20 +198,23 @@ const commandHandlers: { [commandName: string]: CommandHandler } = {
},
};

NetworkService.initialize()
.then(() => {
// Set up test handlers
Object.entries(ipcHandlers).forEach(([ipcHandle, handler]) => {
NetworkService.registerRequestHandler(
ipcHandle,
async (...args: unknown[]) =>
handler({} as Electron.IpcMainInvokeEvent, ...args),
);
});
Object.entries(commandHandlers).forEach(([commandName, handler]) => {
papi.commands.registerCommand(commandName, handler);
});
})
.catch((e) => console.error(e));
(async () => {
await NetworkService.initialize();
// Set up test handlers
Object.entries(ipcHandlers).forEach(([ipcHandle, handler]) => {
NetworkService.registerRequestHandler(
ipcHandle,
async (...args: unknown[]) =>
handler({} as Electron.IpcMainInvokeEvent, ...args),
);
});
Object.entries(commandHandlers).forEach(([commandName, handler]) => {
papi.commands.registerCommand(commandName, handler);
});

// Start the dotnet data provider early so its ready when needed once the
// WebSocket is up.
dotnetDataProvider.start();
})().catch(console.error);

// #endregion
70 changes: 70 additions & 0 deletions src/main/services/dotnet-data-provider.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
import path from 'path';

let dotnet: ChildProcessWithoutNullStreams | undefined;

function killDotnetDataProvider() {
if (!dotnet) return;

if (dotnet.kill()) {
console.log('[dotnet data provider] was killed');
} else {
console.error(
'[dotnet data provider] was not stopped! Investigate other .kill() options',
);
}
dotnet = undefined;
}

/**
* Starts the Dotnet Data Provider if it isn't already running.
*/
function startDotnetDataProvider() {
if (dotnet) return;

// default values for development
let command = process.platform.includes('win') ? 'npm.cmd' : 'npm';
let args: string[] = ['run', 'start:data'];

if (process.env.NODE_ENV === 'production') {
if (process.platform === 'win32') {
command = path.join(
process.resourcesPath,
'dotnet',
'ParanextDataProvider.exe',
);
args = [];
} else {
command = path.join(
process.resourcesPath,
'dotnet',
'ParanextDataProvider',
);
args = [];
}
}

dotnet = spawn(command, args);

dotnet.stdout.on('data', (data) => {
console.log(`[dotnet data provider] stdout: ${data}`);
});

dotnet.stderr.on('data', (data) => {
console.error(`[dotnet data provider] stderr: ${data}`);
});

dotnet.on('close', (code, signal) => {
if (signal) {
console.log(`[dotnet data provider] terminated with signal ${signal}`);
} else {
console.log(`[dotnet data provider] exited with code ${code}`);
}
});
}

const dotnetDataProvider = {
start: startDotnetDataProvider,
kill: killDotnetDataProvider,
};
export default dotnetDataProvider;
10 changes: 7 additions & 3 deletions src/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ const executeMany = async <T,>(fn: () => Promise<T>) => {
}
};

let addResult = 0;

const Hello = () => {
const [promiseReturn, setPromiseReturn] = useState('');
const [promiseReturn, setPromiseReturn] = useState('Click a button.');

const [NODE_ENV] = usePromise(
useCallback(() => getVar('NODE_ENV'), []),
Expand Down Expand Up @@ -136,8 +138,10 @@ const Hello = () => {
<button
type="button"
onClick={async () => {
const result = await runPromise(() => addOne(78));
console.log(`added: '${result}'`);
await runPromise(async () => {
addResult = (await addOne(addResult)) as number;
return `C# addOne: ${addResult}`;
});
}}
>
Test C#
Expand Down

0 comments on commit 5a32cf4

Please sign in to comment.