Skip to content

Commit c7911df

Browse files
authored
Merge pull request #179 from NativePHP/feat/bundle-builds
Feat: bundle builds
2 parents e581f16 + 45231cd commit c7911df

21 files changed

+1373
-318
lines changed

composer.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@
3434
"php": "^8.1",
3535
"illuminate/contracts": "^10.0|^11.0|^12.0",
3636
"laravel/prompts": "^0.1.1|^0.2|^0.3",
37-
"nativephp/laravel": "^1.0-beta.2",
37+
"nativephp/laravel": "dev-feat/bundle-builds",
3838
"nativephp/php-bin": "^0.6",
3939
"spatie/laravel-package-tools": "^1.16.4",
40-
"symfony/filesystem": "^6.4|^7.2"
40+
"symfony/filesystem": "^6.4|^7.2",
41+
"ext-zip": "*"
4142
},
4243
"require-dev": {
4344
"laravel/pint": "^1.0",

phpstan.neon

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ parameters:
44
- src
55
- config
66
- database
7-
tmpDir: build/phpstan
87
checkOctaneCompatibility: true
98
checkModelProperties: true
10-
9+
noEnvCallsOutsideOfConfig: false

resources/js/electron-builder.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,7 @@ try {
4040
}
4141

4242
if (isBuilding) {
43-
console.log();
44-
console.log('===================================================================');
45-
console.log(' Building for ' + targetOs);
46-
console.log('===================================================================');
47-
console.log();
48-
console.log('Updater config', updaterConfig);
49-
console.log();
43+
console.log(' • updater config', updaterConfig);
5044
}
5145

5246
export default {

resources/js/electron-plugin/dist/index.js

+17-11
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,6 @@ class NativePHP {
6767
}
6868
event.preventDefault();
6969
});
70-
if (process.platform === 'win32') {
71-
app.on('second-instance', (event, commandLine, workingDirectory) => {
72-
if (this.mainWindow) {
73-
if (this.mainWindow.isMinimized())
74-
this.mainWindow.restore();
75-
this.mainWindow.focus();
76-
}
77-
this.handleDeepLink(commandLine.pop());
78-
});
79-
}
8070
}
8171
bootstrapApp(app) {
8272
return __awaiter(this, void 0, void 0, function* () {
@@ -135,12 +125,28 @@ class NativePHP {
135125
else {
136126
app.setAsDefaultProtocolClient(deepLinkProtocol);
137127
}
138-
if (process.platform === 'win32') {
128+
if (process.platform !== "darwin") {
139129
const gotTheLock = app.requestSingleInstanceLock();
140130
if (!gotTheLock) {
141131
app.quit();
142132
return;
143133
}
134+
else {
135+
app.on("second-instance", (event, commandLine, workingDirectory) => {
136+
if (this.mainWindow) {
137+
if (this.mainWindow.isMinimized())
138+
this.mainWindow.restore();
139+
this.mainWindow.focus();
140+
}
141+
notifyLaravel("events", {
142+
event: "\\Native\\Laravel\\Events\\App\\OpenedFromURL",
143+
payload: {
144+
url: commandLine[commandLine.length - 1],
145+
workingDirectory: workingDirectory,
146+
},
147+
});
148+
});
149+
}
144150
}
145151
}
146152
}

resources/js/electron-plugin/dist/server/api/childProcess.js

+91-49
Original file line numberDiff line numberDiff line change
@@ -11,80 +11,122 @@ import express from 'express';
1111
import { utilityProcess } from 'electron';
1212
import state from '../state.js';
1313
import { notifyLaravel } from "../utils.js";
14-
import { getDefaultEnvironmentVariables, getDefaultPhpIniSettings } from "../php.js";
14+
import { getAppPath, getDefaultEnvironmentVariables, getDefaultPhpIniSettings, runningSecureBuild } from "../php.js";
1515
import killSync from "kill-sync";
1616
import { fileURLToPath } from "url";
17+
import { join } from "path";
1718
const router = express.Router();
1819
function startProcess(settings) {
19-
const { alias, cmd, cwd, env, persistent } = settings;
20+
const { alias, cmd, cwd, env, persistent, spawnTimeout = 30000 } = settings;
2021
if (getProcess(alias) !== undefined) {
2122
return state.processes[alias];
2223
}
23-
const proc = utilityProcess.fork(fileURLToPath(new URL('../../electron-plugin/dist/server/childProcess.js', import.meta.url)), cmd, {
24-
cwd,
25-
stdio: 'pipe',
26-
serviceName: alias,
27-
env: Object.assign(Object.assign({}, process.env), env)
28-
});
29-
proc.stdout.on('data', (data) => {
30-
notifyLaravel('events', {
31-
event: 'Native\\Laravel\\Events\\ChildProcess\\MessageReceived',
32-
payload: {
33-
alias,
34-
data: data.toString(),
24+
try {
25+
const proc = utilityProcess.fork(fileURLToPath(new URL('../../electron-plugin/dist/server/childProcess.js', import.meta.url)), cmd, {
26+
cwd,
27+
stdio: 'pipe',
28+
serviceName: alias,
29+
env: Object.assign(Object.assign({}, process.env), env)
30+
});
31+
const startTimeout = setTimeout(() => {
32+
if (!state.processes[alias] || !state.processes[alias].pid) {
33+
console.error(`Process [${alias}] failed to start within timeout period`);
34+
try {
35+
proc.kill();
36+
}
37+
catch (e) {
38+
}
39+
notifyLaravel('events', {
40+
event: 'Native\\Laravel\\Events\\ChildProcess\\StartupError',
41+
payload: {
42+
alias,
43+
error: 'Startup timeout exceeded',
44+
}
45+
});
3546
}
47+
}, spawnTimeout);
48+
proc.stdout.on('data', (data) => {
49+
notifyLaravel('events', {
50+
event: 'Native\\Laravel\\Events\\ChildProcess\\MessageReceived',
51+
payload: {
52+
alias,
53+
data: data.toString(),
54+
}
55+
});
3656
});
37-
});
38-
proc.stderr.on('data', (data) => {
39-
console.error('Error received from process [' + alias + ']:', data.toString());
40-
notifyLaravel('events', {
41-
event: 'Native\\Laravel\\Events\\ChildProcess\\ErrorReceived',
42-
payload: {
43-
alias,
44-
data: data.toString(),
57+
proc.stderr.on('data', (data) => {
58+
console.error('Process [' + alias + '] ERROR:', data.toString().trim());
59+
notifyLaravel('events', {
60+
event: 'Native\\Laravel\\Events\\ChildProcess\\ErrorReceived',
61+
payload: {
62+
alias,
63+
data: data.toString(),
64+
}
65+
});
66+
});
67+
proc.on('spawn', () => {
68+
clearTimeout(startTimeout);
69+
console.log('Process [' + alias + '] spawned!');
70+
state.processes[alias] = {
71+
pid: proc.pid,
72+
proc,
73+
settings
74+
};
75+
notifyLaravel('events', {
76+
event: 'Native\\Laravel\\Events\\ChildProcess\\ProcessSpawned',
77+
payload: [alias, proc.pid]
78+
});
79+
});
80+
proc.on('exit', (code) => {
81+
clearTimeout(startTimeout);
82+
console.log(`Process [${alias}] exited with code [${code}].`);
83+
notifyLaravel('events', {
84+
event: 'Native\\Laravel\\Events\\ChildProcess\\ProcessExited',
85+
payload: {
86+
alias,
87+
code,
88+
}
89+
});
90+
const settings = Object.assign({}, getSettings(alias));
91+
delete state.processes[alias];
92+
if (settings === null || settings === void 0 ? void 0 : settings.persistent) {
93+
console.log('Process [' + alias + '] watchdog restarting...');
94+
setTimeout(() => startProcess(settings), 1000);
4595
}
4696
});
47-
});
48-
proc.on('spawn', () => {
49-
console.log('Process [' + alias + '] spawned!');
50-
state.processes[alias] = {
51-
pid: proc.pid,
97+
return {
98+
pid: null,
5299
proc,
53100
settings
54101
};
102+
}
103+
catch (error) {
104+
console.error(`Failed to create process [${alias}]: ${error.message}`);
55105
notifyLaravel('events', {
56-
event: 'Native\\Laravel\\Events\\ChildProcess\\ProcessSpawned',
57-
payload: [alias, proc.pid]
58-
});
59-
});
60-
proc.on('exit', (code) => {
61-
console.log(`Process [${alias}] exited with code [${code}].`);
62-
notifyLaravel('events', {
63-
event: 'Native\\Laravel\\Events\\ChildProcess\\ProcessExited',
106+
event: 'Native\\Laravel\\Events\\ChildProcess\\StartupError',
64107
payload: {
65108
alias,
66-
code,
109+
error: error.toString(),
67110
}
68111
});
69-
const settings = Object.assign({}, getSettings(alias));
70-
delete state.processes[alias];
71-
if (settings.persistent) {
72-
console.log('Process [' + alias + '] watchdog restarting...');
73-
startProcess(settings);
74-
}
75-
});
76-
return {
77-
pid: null,
78-
proc,
79-
settings
80-
};
112+
return {
113+
pid: null,
114+
proc: null,
115+
settings,
116+
error: error.message
117+
};
118+
}
81119
}
82120
function startPhpProcess(settings) {
83121
const defaultEnv = getDefaultEnvironmentVariables(state.randomSecret, state.electronApiPort);
84-
const iniSettings = Object.assign(Object.assign({}, getDefaultPhpIniSettings()), state.phpIni);
122+
const customIniSettings = settings.iniSettings || {};
123+
const iniSettings = Object.assign(Object.assign(Object.assign({}, getDefaultPhpIniSettings()), state.phpIni), customIniSettings);
85124
const iniArgs = Object.keys(iniSettings).map(key => {
86125
return ['-d', `${key}=${iniSettings[key]}`];
87126
}).flat();
127+
if (settings.cmd[0] === 'artisan' && runningSecureBuild()) {
128+
settings.cmd.unshift(join(getAppPath(), 'build', '__nativephp_app_bundle'));
129+
}
88130
settings = Object.assign(Object.assign({}, settings), { cmd: [state.php, ...iniArgs, ...settings.cmd], env: Object.assign(Object.assign({}, settings.env), defaultEnv) });
89131
return startProcess(settings);
90132
}

resources/js/electron-plugin/dist/server/api/notification.js

+39-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { Notification } from 'electron';
33
import { notifyLaravel } from "../utils.js";
44
const router = express.Router();
55
router.post('/', (req, res) => {
6-
const { title, body, subtitle, silent, icon, hasReply, timeoutType, replyPlaceholder, sound, urgency, actions, closeButtonText, toastXml, event: customEvent } = req.body;
6+
const { title, body, subtitle, silent, icon, hasReply, timeoutType, replyPlaceholder, sound, urgency, actions, closeButtonText, toastXml, event: customEvent, reference, } = req.body;
77
const eventName = customEvent !== null && customEvent !== void 0 ? customEvent : '\\Native\\Laravel\\Events\\Notifications\\NotificationClicked';
8+
const notificationReference = reference !== null && reference !== void 0 ? reference : (Date.now() + '.' + Math.random().toString(36).slice(2, 9));
89
const notification = new Notification({
910
title,
1011
body,
@@ -22,11 +23,45 @@ router.post('/', (req, res) => {
2223
});
2324
notification.on("click", (event) => {
2425
notifyLaravel('events', {
25-
event: eventName,
26-
payload: JSON.stringify(event)
26+
event: eventName || '\\Native\\Laravel\\Events\\Notifications\\NotificationClicked',
27+
payload: {
28+
reference: notificationReference,
29+
event: JSON.stringify(event),
30+
},
31+
});
32+
});
33+
notification.on("action", (event, index) => {
34+
notifyLaravel('events', {
35+
event: '\\Native\\Laravel\\Events\\Notifications\\NotificationActionClicked',
36+
payload: {
37+
reference: notificationReference,
38+
index,
39+
event: JSON.stringify(event),
40+
},
41+
});
42+
});
43+
notification.on("reply", (event, reply) => {
44+
notifyLaravel('events', {
45+
event: '\\Native\\Laravel\\Events\\Notifications\\NotificationReply',
46+
payload: {
47+
reference: notificationReference,
48+
reply,
49+
event: JSON.stringify(event),
50+
},
51+
});
52+
});
53+
notification.on("close", (event) => {
54+
notifyLaravel('events', {
55+
event: '\\Native\\Laravel\\Events\\Notifications\\NotificationClosed',
56+
payload: {
57+
reference: notificationReference,
58+
event: JSON.stringify(event),
59+
},
2760
});
2861
});
2962
notification.show();
30-
res.sendStatus(200);
63+
res.status(200).json({
64+
reference: notificationReference,
65+
});
3166
});
3267
export default router;

0 commit comments

Comments
 (0)