Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/run-plugin-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: plugin-tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Install dependencies
working-directory: ./resources/js/electron-plugin
run: npm install
- name: Run tests
working-directory: ./resources/js/electron-plugin
run: npm test
9 changes: 9 additions & 0 deletions resources/js/electron-plugin/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
18 changes: 18 additions & 0 deletions resources/js/electron-plugin/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"env": {
"browser": true,
"node": true
},
"rules": {
"prettier/prettier": "error"
}
}
29 changes: 29 additions & 0 deletions resources/js/electron-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# dependencies
node_modules

# production
build
dist-ssr
*.local
*.tgz

# logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
coverage
18 changes: 18 additions & 0 deletions resources/js/electron-plugin/.stylelintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": [
"stylelint-config-recommended",
"stylelint-config-sass-guidelines"
],
"overrides": [
{
"files": ["**/*.scss"],
"customSyntax": "postcss-scss"
}
],
"rules": {
"function-parentheses-space-inside": null,
"no-descending-specificity": null,
"max-nesting-depth": 2,
"selector-max-id": 1
}
}
13 changes: 13 additions & 0 deletions resources/js/electron-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @nativephp/electron-plugin

The Electron back-end for NativePHP.

## Development

When making changes to the Electron plugin you need to run `npm run build:watch` from this plugin directory.

You'll only see the changes after restarting NativePHP with `native:serve`.

## Issues

Please raise any issues on the [NativePHP/laravel](https://github.com/NativePHP/laravel/issues) repo.
5 changes: 5 additions & 0 deletions resources/js/electron-plugin/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@babel/preset-typescript',
],
};
189 changes: 189 additions & 0 deletions resources/js/electron-plugin/dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const electron_1 = require("electron");
const electron_updater_1 = require("electron-updater");
const state_1 = __importDefault(require("./server/state"));
const utils_1 = require("@electron-toolkit/utils");
const server_1 = require("./server");
const utils_2 = require("./server/utils");
const path_1 = require("path");
const ps_node_1 = __importDefault(require("ps-node"));
class NativePHP {
constructor() {
this.processes = [];
this.schedulerInterval = undefined;
}
bootstrap(app, icon, phpBinary, cert) {
require("@electron/remote/main").initialize();
state_1.default.icon = icon;
state_1.default.php = phpBinary;
state_1.default.caCert = cert;
this.bootstrapApp(app);
this.addEventListeners(app);
}
addEventListeners(app) {
app.on("open-url", (event, url) => {
(0, utils_2.notifyLaravel)("events", {
event: "\\Native\\Laravel\\Events\\App\\OpenedFromURL",
payload: [url],
});
});
app.on("open-file", (event, path) => {
(0, utils_2.notifyLaravel)("events", {
event: "\\Native\\Laravel\\Events\\App\\OpenFile",
payload: [path],
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("before-quit", () => {
if (this.schedulerInterval) {
clearInterval(this.schedulerInterval);
}
this.killChildProcesses();
});
app.on("browser-window-created", (_, window) => {
utils_1.optimizer.watchWindowShortcuts(window);
});
app.on("activate", function (event, hasVisibleWindows) {
if (!hasVisibleWindows) {
(0, utils_2.notifyLaravel)("booted");
}
event.preventDefault();
});
}
bootstrapApp(app) {
return __awaiter(this, void 0, void 0, function* () {
yield app.whenReady();
const config = yield this.loadConfig();
this.setDockIcon();
this.setAppUserModelId(config);
this.setDeepLinkHandler(config);
this.startAutoUpdater(config);
yield this.startElectronApi();
state_1.default.phpIni = yield this.loadPhpIni();
yield this.startPhpApp();
yield this.startQueueWorker();
yield this.startWebsockets();
this.startScheduler();
yield (0, utils_2.notifyLaravel)("booted");
});
}
loadConfig() {
return __awaiter(this, void 0, void 0, function* () {
let config = {};
try {
const result = yield (0, server_1.retrieveNativePHPConfig)();
config = JSON.parse(result.stdout);
}
catch (error) {
console.error(error);
}
return config;
});
}
setDockIcon() {
if (process.platform === "darwin" &&
process.env.NODE_ENV === "development") {
electron_1.app.dock.setIcon(state_1.default.icon);
}
}
setAppUserModelId(config) {
utils_1.electronApp.setAppUserModelId(config === null || config === void 0 ? void 0 : config.app_id);
}
setDeepLinkHandler(config) {
const deepLinkProtocol = config === null || config === void 0 ? void 0 : config.deeplink_scheme;
if (deepLinkProtocol) {
if (process.defaultApp) {
if (process.argv.length >= 2) {
electron_1.app.setAsDefaultProtocolClient(deepLinkProtocol, process.execPath, [
(0, path_1.resolve)(process.argv[1]),
]);
}
}
else {
electron_1.app.setAsDefaultProtocolClient(deepLinkProtocol);
}
}
}
startAutoUpdater(config) {
var _a;
if (((_a = config === null || config === void 0 ? void 0 : config.updater) === null || _a === void 0 ? void 0 : _a.enabled) === true) {
electron_updater_1.autoUpdater.checkForUpdatesAndNotify();
}
}
startElectronApi() {
return __awaiter(this, void 0, void 0, function* () {
const electronApi = yield (0, server_1.startAPI)();
state_1.default.electronApiPort = electronApi.port;
console.log("Electron API server started on port", electronApi.port);
});
}
loadPhpIni() {
return __awaiter(this, void 0, void 0, function* () {
let config = {};
try {
const result = yield (0, server_1.retrievePhpIniSettings)();
config = JSON.parse(result.stdout);
}
catch (error) {
console.error(error);
}
return config;
});
}
startPhpApp() {
return __awaiter(this, void 0, void 0, function* () {
this.processes.push(yield (0, server_1.startPhpApp)());
});
}
startQueueWorker() {
return __awaiter(this, void 0, void 0, function* () {
this.processes.push(yield (0, server_1.startQueue)());
});
}
startWebsockets() {
return __awaiter(this, void 0, void 0, function* () {
this.processes.push(yield (0, server_1.startWebsockets)());
});
}
startScheduler() {
const now = new Date();
const delay = (60 - now.getSeconds()) * 1000 + (1000 - now.getMilliseconds());
setTimeout(() => {
console.log("Running scheduler...");
(0, server_1.runScheduler)();
this.schedulerInterval = setInterval(() => {
console.log("Running scheduler...");
(0, server_1.runScheduler)();
}, 60 * 1000);
}, delay);
}
killChildProcesses() {
this.processes
.filter((p) => p !== undefined)
.forEach((process) => {
try {
ps_node_1.default.kill(process.pid);
}
catch (err) {
console.error(err);
}
});
}
}
module.exports = new NativePHP();
67 changes: 67 additions & 0 deletions resources/js/electron-plugin/dist/preload/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
const remote = __importStar(require("@electron/remote"));
const native_1 = __importDefault(require("./native"));
window.Native = native_1.default;
window.remote = remote;
electron_1.ipcRenderer.on('log', (event, { level, message, context }) => {
if (level === 'error') {
console.error(`[${level}] ${message}`, context);
}
else if (level === 'warn') {
console.warn(`[${level}] ${message}`, context);
}
else {
console.log(`[${level}] ${message}`, context);
}
});
electron_1.ipcRenderer.on('native-event', (event, data) => {
if (window.Livewire) {
window.Livewire.dispatch('native:' + data.event, data.payload);
}
if (window.livewire) {
window.livewire.components.components().forEach(component => {
if (Array.isArray(component.listeners)) {
component.listeners.forEach(event => {
if (event.startsWith('native')) {
let event_parts = event.split(/(native:|native-)|:|,/);
if (event_parts[1] == 'native:') {
event_parts.splice(2, 0, 'private', undefined, 'nativephp', undefined);
}
let [s1, signature, channel_type, s2, channel, s3, event_name,] = event_parts;
if (data.event === event_name) {
window.livewire.emit(event, data.payload);
}
}
});
}
});
}
});
14 changes: 14 additions & 0 deletions resources/js/electron-plugin/dist/preload/native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
exports.default = {
on: (event, callback) => {
electron_1.ipcRenderer.on('native-event', (_, data) => {
event = event.replace(/^(\\)+/, '');
data.event = data.event.replace(/^(\\)+/, '');
if (event === data.event) {
return callback(data.payload, event);
}
});
}
};
2 changes: 2 additions & 0 deletions resources/js/electron-plugin/dist/server/ProcessResult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
Loading