Skip to content

Commit d262ae9

Browse files
Integrate Plugin (#109)
* Integrated electron-plugin with subpath import * Corrected getAppPath() * copy plugin testing workflow * Removed electron-plugin/.github * Configured electron-plugin tests --------- Co-authored-by: gwleuverink <willem@leuver.ink>
1 parent ab6c82f commit d262ae9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+21034
-4430
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: plugin-tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- name: Use Node.js
15+
uses: actions/setup-node@v1
16+
with:
17+
node-version: 18.x
18+
- name: Install dependencies
19+
working-directory: ./resources/js/
20+
run: npm install
21+
- name: Run tests
22+
working-directory: ./resources/js/
23+
run: npm run plugin:test
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": ["@typescript-eslint", "prettier"],
5+
"extends": [
6+
"eslint:recommended",
7+
"plugin:@typescript-eslint/eslint-recommended",
8+
"plugin:@typescript-eslint/recommended",
9+
"prettier"
10+
],
11+
"env": {
12+
"browser": true,
13+
"node": true
14+
},
15+
"rules": {
16+
"prettier/prettier": "error"
17+
}
18+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# production
2+
build
3+
dist-ssr
4+
*.local
5+
6+
# logs
7+
logs
8+
*.log
9+
npm-debug.log*
10+
yarn-debug.log*
11+
yarn-error.log*
12+
pnpm-debug.log*
13+
lerna-debug.log*
14+
15+
# editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
25+
coverage
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": [
3+
"stylelint-config-recommended",
4+
"stylelint-config-sass-guidelines"
5+
],
6+
"overrides": [
7+
{
8+
"files": ["**/*.scss"],
9+
"customSyntax": "postcss-scss"
10+
}
11+
],
12+
"rules": {
13+
"function-parentheses-space-inside": null,
14+
"no-descending-specificity": null,
15+
"max-nesting-depth": 2,
16+
"selector-max-id": 1
17+
}
18+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
presets: [
3+
'@babel/preset-typescript',
4+
],
5+
};
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3+
return new (P || (P = Promise))(function (resolve, reject) {
4+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7+
step((generator = generator.apply(thisArg, _arguments || [])).next());
8+
});
9+
};
10+
import { app } from "electron";
11+
import { autoUpdater } from "electron-updater";
12+
import state from "./server/state";
13+
import { electronApp, optimizer } from "@electron-toolkit/utils";
14+
import { retrieveNativePHPConfig, retrievePhpIniSettings, runScheduler, startAPI, startPhpApp, startQueue, startWebsockets, } from "./server";
15+
import { notifyLaravel } from "./server/utils";
16+
import { resolve } from "path";
17+
import ps from "ps-node";
18+
class NativePHP {
19+
constructor() {
20+
this.processes = [];
21+
this.schedulerInterval = undefined;
22+
}
23+
bootstrap(app, icon, phpBinary, cert) {
24+
require("@electron/remote/main").initialize();
25+
state.icon = icon;
26+
state.php = phpBinary;
27+
state.caCert = cert;
28+
this.bootstrapApp(app);
29+
this.addEventListeners(app);
30+
}
31+
addEventListeners(app) {
32+
app.on("open-url", (event, url) => {
33+
notifyLaravel("events", {
34+
event: "\\Native\\Laravel\\Events\\App\\OpenedFromURL",
35+
payload: [url],
36+
});
37+
});
38+
app.on("open-file", (event, path) => {
39+
notifyLaravel("events", {
40+
event: "\\Native\\Laravel\\Events\\App\\OpenFile",
41+
payload: [path],
42+
});
43+
});
44+
app.on("window-all-closed", () => {
45+
if (process.platform !== "darwin") {
46+
app.quit();
47+
}
48+
});
49+
app.on("before-quit", () => {
50+
if (this.schedulerInterval) {
51+
clearInterval(this.schedulerInterval);
52+
}
53+
this.killChildProcesses();
54+
});
55+
app.on("browser-window-created", (_, window) => {
56+
optimizer.watchWindowShortcuts(window);
57+
});
58+
app.on("activate", function (event, hasVisibleWindows) {
59+
if (!hasVisibleWindows) {
60+
notifyLaravel("booted");
61+
}
62+
event.preventDefault();
63+
});
64+
}
65+
bootstrapApp(app) {
66+
return __awaiter(this, void 0, void 0, function* () {
67+
yield app.whenReady();
68+
const config = yield this.loadConfig();
69+
this.setDockIcon();
70+
this.setAppUserModelId(config);
71+
this.setDeepLinkHandler(config);
72+
this.startAutoUpdater(config);
73+
yield this.startElectronApi();
74+
state.phpIni = yield this.loadPhpIni();
75+
yield this.startPhpApp();
76+
yield this.startQueueWorker();
77+
yield this.startWebsockets();
78+
this.startScheduler();
79+
yield notifyLaravel("booted");
80+
});
81+
}
82+
loadConfig() {
83+
return __awaiter(this, void 0, void 0, function* () {
84+
let config = {};
85+
try {
86+
const result = yield retrieveNativePHPConfig();
87+
config = JSON.parse(result.stdout);
88+
}
89+
catch (error) {
90+
console.error(error);
91+
}
92+
return config;
93+
});
94+
}
95+
setDockIcon() {
96+
if (process.platform === "darwin" &&
97+
process.env.NODE_ENV === "development") {
98+
app.dock.setIcon(state.icon);
99+
}
100+
}
101+
setAppUserModelId(config) {
102+
electronApp.setAppUserModelId(config === null || config === void 0 ? void 0 : config.app_id);
103+
}
104+
setDeepLinkHandler(config) {
105+
const deepLinkProtocol = config === null || config === void 0 ? void 0 : config.deeplink_scheme;
106+
if (deepLinkProtocol) {
107+
if (process.defaultApp) {
108+
if (process.argv.length >= 2) {
109+
app.setAsDefaultProtocolClient(deepLinkProtocol, process.execPath, [
110+
resolve(process.argv[1]),
111+
]);
112+
}
113+
}
114+
else {
115+
app.setAsDefaultProtocolClient(deepLinkProtocol);
116+
}
117+
}
118+
}
119+
startAutoUpdater(config) {
120+
var _a;
121+
if (((_a = config === null || config === void 0 ? void 0 : config.updater) === null || _a === void 0 ? void 0 : _a.enabled) === true) {
122+
autoUpdater.checkForUpdatesAndNotify();
123+
}
124+
}
125+
startElectronApi() {
126+
return __awaiter(this, void 0, void 0, function* () {
127+
const electronApi = yield startAPI();
128+
state.electronApiPort = electronApi.port;
129+
console.log("Electron API server started on port", electronApi.port);
130+
});
131+
}
132+
loadPhpIni() {
133+
return __awaiter(this, void 0, void 0, function* () {
134+
let config = {};
135+
try {
136+
const result = yield retrievePhpIniSettings();
137+
config = JSON.parse(result.stdout);
138+
}
139+
catch (error) {
140+
console.error(error);
141+
}
142+
return config;
143+
});
144+
}
145+
startPhpApp() {
146+
return __awaiter(this, void 0, void 0, function* () {
147+
this.processes.push(yield startPhpApp());
148+
});
149+
}
150+
startQueueWorker() {
151+
return __awaiter(this, void 0, void 0, function* () {
152+
this.processes.push(yield startQueue());
153+
});
154+
}
155+
startWebsockets() {
156+
return __awaiter(this, void 0, void 0, function* () {
157+
this.processes.push(yield startWebsockets());
158+
});
159+
}
160+
startScheduler() {
161+
const now = new Date();
162+
const delay = (60 - now.getSeconds()) * 1000 + (1000 - now.getMilliseconds());
163+
setTimeout(() => {
164+
console.log("Running scheduler...");
165+
runScheduler();
166+
this.schedulerInterval = setInterval(() => {
167+
console.log("Running scheduler...");
168+
runScheduler();
169+
}, 60 * 1000);
170+
}, delay);
171+
}
172+
killChildProcesses() {
173+
this.processes
174+
.filter((p) => p !== undefined)
175+
.forEach((process) => {
176+
try {
177+
ps.kill(process.pid);
178+
}
179+
catch (err) {
180+
console.error(err);
181+
}
182+
});
183+
}
184+
}
185+
export default new NativePHP();
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { ipcRenderer } from 'electron';
2+
import * as remote from '@electron/remote';
3+
import Native from './native';
4+
window.Native = Native;
5+
window.remote = remote;
6+
ipcRenderer.on('log', (event, { level, message, context }) => {
7+
if (level === 'error') {
8+
console.error(`[${level}] ${message}`, context);
9+
}
10+
else if (level === 'warn') {
11+
console.warn(`[${level}] ${message}`, context);
12+
}
13+
else {
14+
console.log(`[${level}] ${message}`, context);
15+
}
16+
});
17+
ipcRenderer.on('native-event', (event, data) => {
18+
data.event = data.event.replace(/^(\\)+/, '');
19+
if (window.Livewire) {
20+
window.Livewire.dispatch('native:' + data.event, data.payload);
21+
}
22+
if (window.livewire) {
23+
window.livewire.components.components().forEach(component => {
24+
if (Array.isArray(component.listeners)) {
25+
component.listeners.forEach(event => {
26+
if (event.startsWith('native')) {
27+
let event_parts = event.split(/(native:|native-)|:|,/);
28+
if (event_parts[1] == 'native:') {
29+
event_parts.splice(2, 0, 'private', undefined, 'nativephp', undefined);
30+
}
31+
let [s1, signature, channel_type, s2, channel, s3, event_name,] = event_parts;
32+
if (data.event === event_name) {
33+
window.livewire.emit(event, data.payload);
34+
}
35+
}
36+
});
37+
}
38+
});
39+
}
40+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ipcRenderer } from 'electron';
2+
export default {
3+
on: (event, callback) => {
4+
ipcRenderer.on('native-event', (_, data) => {
5+
event = event.replace(/^(\\)+/, '');
6+
data.event = data.event.replace(/^(\\)+/, '');
7+
if (event === data.event) {
8+
return callback(data.payload, event);
9+
}
10+
});
11+
}
12+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

0 commit comments

Comments
 (0)