Skip to content
Merged
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
1 change: 1 addition & 0 deletions resources/electron/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
out
*.log
!build
dist
3 changes: 2 additions & 1 deletion resources/electron/electron-builder.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ export default {
copyright: appCopyright,
directories: {
buildResources: 'build',
output: isBuilding ? join(process.env.APP_PATH, 'dist') : undefined,
output: isBuilding ? join(process.env.APP_PATH, 'nativephp', 'electron', 'dist') : undefined,
},
files: [
'!**/.vscode/*',
'!src/*',
'!dist/*',
'!electron.vite.config.{js,ts,mjs,cjs}',
'!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}',
'!{.env,.env.*,.npmrc,pnpm-lock.yaml}',
Expand Down
3 changes: 2 additions & 1 deletion resources/electron/electron-plugin/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ class NativePHP {
this.mainWindow = null;
this.schedulerInterval = undefined;
}
bootstrap(app, icon, phpBinary, cert) {
bootstrap(app, icon, phpBinary, cert, appPath) {
initialize();
state.icon = icon;
state.php = phpBinary;
state.caCert = cert;
state.appPath = appPath;
this.bootstrapApp(app);
this.addEventListeners(app);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import killSync from "kill-sync";
import { fileURLToPath } from "url";
import { join } from "path";
const router = express.Router();
function startProcess(settings) {
function startProcess(settings, useNodeRuntime = false) {
const { alias, cmd, cwd, env, persistent, spawnTimeout = 30000 } = settings;
if (getProcess(alias) !== undefined) {
return state.processes[alias];
Expand All @@ -26,7 +26,7 @@ function startProcess(settings) {
cwd,
stdio: 'pipe',
serviceName: alias,
env: Object.assign(Object.assign({}, process.env), env)
env: Object.assign(Object.assign(Object.assign({}, process.env), env), { USE_NODE_RUNTIME: useNodeRuntime ? '1' : '0' })
});
const startTimeout = setTimeout(() => {
if (!state.processes[alias] || !state.processes[alias].pid) {
Expand Down Expand Up @@ -157,6 +157,10 @@ router.post('/start', (req, res) => {
const proc = startProcess(req.body);
res.json(proc);
});
router.post('/start-node', (req, res) => {
const proc = startProcess(req.body, true);
res.json(proc);
});
router.post('/start-php', (req, res) => {
const proc = startPhpProcess(req.body);
res.json(proc);
Expand Down
11 changes: 9 additions & 2 deletions resources/electron/electron-plugin/dist/server/childProcess.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { spawn } from "child_process";
const proc = spawn(process.argv[2], process.argv.slice(3));
import { spawn, fork } from "child_process";
const useNodeRuntime = process.env.USE_NODE_RUNTIME === '1';
const [command, ...args] = process.argv.slice(2);
const proc = useNodeRuntime
? fork(command, args, {
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
execPath: process.execPath
})
: spawn(command, args);
process.parentPort.on('message', (message) => {
proc.stdin.write(message.data);
});
Expand Down
13 changes: 8 additions & 5 deletions resources/electron/electron-plugin/dist/server/php.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@ const databasePath = join(app.getPath('userData'), 'database');
const databaseFile = join(databasePath, 'database.sqlite');
const bootstrapCache = join(app.getPath('userData'), 'bootstrap', 'cache');
const argumentEnv = getArgumentEnv();
const appPath = getAppPath();
mkdirpSync(bootstrapCache);
mkdirpSync(join(storagePath, 'logs'));
mkdirpSync(join(storagePath, 'framework', 'cache'));
mkdirpSync(join(storagePath, 'framework', 'sessions'));
mkdirpSync(join(storagePath, 'framework', 'views'));
mkdirpSync(join(storagePath, 'framework', 'testing'));
function runningSecureBuild() {
return existsSync(join(appPath, 'build', '__nativephp_app_bundle'))
return existsSync(join(getAppPath(), 'build', '__nativephp_app_bundle'))
&& process.env.NODE_ENV !== 'development';
}
function shouldMigrateDatabase(store) {
Expand Down Expand Up @@ -73,6 +72,7 @@ function canBindToPort(port) {
function retrievePhpIniSettings() {
return __awaiter(this, void 0, void 0, function* () {
const env = getDefaultEnvironmentVariables();
const appPath = getAppPath();
const phpOptions = {
cwd: appPath,
env
Expand All @@ -87,6 +87,7 @@ function retrievePhpIniSettings() {
function retrieveNativePHPConfig() {
return __awaiter(this, void 0, void 0, function* () {
const env = getDefaultEnvironmentVariables();
const appPath = getAppPath();
const phpOptions = {
cwd: appPath,
env
Expand All @@ -100,7 +101,7 @@ function retrieveNativePHPConfig() {
}
function callPhp(args, options, phpIniSettings = {}) {
if (args[0] === 'artisan' && runningSecureBuild()) {
args.unshift(join(appPath, 'build', '__nativephp_app_bundle'));
args.unshift(join(getAppPath(), 'build', '__nativephp_app_bundle'));
}
let iniSettings = Object.assign(getDefaultPhpIniSettings(), phpIniSettings);
Object.keys(iniSettings).forEach(key => {
Expand All @@ -116,7 +117,7 @@ function callPhp(args, options, phpIniSettings = {}) {
}
function callPhpSync(args, options, phpIniSettings = {}) {
if (args[0] === 'artisan' && runningSecureBuild()) {
args.unshift(join(appPath, 'build', '__nativephp_app_bundle'));
args.unshift(join(getAppPath(), 'build', '__nativephp_app_bundle'));
}
let iniSettings = Object.assign(getDefaultPhpIniSettings(), phpIniSettings);
Object.keys(iniSettings).forEach(key => {
Expand All @@ -140,7 +141,7 @@ function getArgumentEnv() {
return env;
}
function getAppPath() {
let appPath = join(import.meta.dirname, '../../resources/app/').replace('app.asar', 'app.asar.unpacked');
let appPath = state.appPath;
if (process.env.NODE_ENV === 'development' || argumentEnv.TESTING == 1) {
appPath = process.env.APP_PATH || argumentEnv.APP_PATH;
}
Expand All @@ -150,6 +151,7 @@ function ensureAppFoldersAreAvailable() {
console.log('Copying storage folder...');
console.log('Storage path:', storagePath);
if (!existsSync(storagePath) || process.env.NODE_ENV === 'development') {
const appPath = getAppPath();
console.log("App path:", appPath);
copySync(join(appPath, 'storage'), storagePath);
}
Expand All @@ -163,6 +165,7 @@ function ensureAppFoldersAreAvailable() {
}
function startScheduler(secret, apiPort, phpIniSettings = {}) {
const env = getDefaultEnvironmentVariables(secret, apiPort);
const appPath = getAppPath();
const phpOptions = {
cwd: appPath,
env
Expand Down
1 change: 1 addition & 0 deletions resources/electron/electron-plugin/dist/server/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default {
phpPort: null,
phpIni: null,
caCert: null,
appPath: null,
icon: null,
store: settingsStore,
randomSecret: generateRandomString(32),
Expand Down
4 changes: 3 additions & 1 deletion resources/electron/electron-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ class NativePHP {
app: CrossProcessExports.App,
icon: string,
phpBinary: string,
cert: string
cert: string,
appPath: string
) {

initialize();

state.icon = icon;
state.php = phpBinary;
state.caCert = cert;
state.appPath = appPath;

this.bootstrapApp(app);
this.addEventListeners(app);
Expand Down
22 changes: 13 additions & 9 deletions resources/electron/electron-plugin/src/server/php.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const databasePath = join(app.getPath('userData'), 'database')
const databaseFile = join(databasePath, 'database.sqlite')
const bootstrapCache = join(app.getPath('userData'), 'bootstrap', 'cache')
const argumentEnv = getArgumentEnv();
const appPath = getAppPath();

mkdirpSync(bootstrapCache);
mkdirpSync(join(storagePath, 'logs'));
Expand All @@ -29,7 +28,7 @@ mkdirpSync(join(storagePath, 'framework', 'views'));
mkdirpSync(join(storagePath, 'framework', 'testing'));

function runningSecureBuild() {
return existsSync(join(appPath, 'build', '__nativephp_app_bundle'))
return existsSync(join(getAppPath(), 'build', '__nativephp_app_bundle'))
&& process.env.NODE_ENV !== 'development';
}

Expand Down Expand Up @@ -90,6 +89,7 @@ function canBindToPort(port: number): Promise<boolean> {

async function retrievePhpIniSettings() {
const env = getDefaultEnvironmentVariables() as any;
const appPath = getAppPath();

const phpOptions = {
cwd: appPath,
Expand All @@ -107,6 +107,7 @@ async function retrievePhpIniSettings() {

async function retrieveNativePHPConfig() {
const env = getDefaultEnvironmentVariables() as any;
const appPath = getAppPath()

const phpOptions = {
cwd: appPath,
Expand All @@ -125,7 +126,7 @@ async function retrieveNativePHPConfig() {
function callPhp(args, options, phpIniSettings = {}) {

if (args[0] === 'artisan' && runningSecureBuild()) {
args.unshift(join(appPath, 'build', '__nativephp_app_bundle'));
args.unshift(join(getAppPath(), 'build', '__nativephp_app_bundle'));
}

let iniSettings = Object.assign(getDefaultPhpIniSettings(), phpIniSettings);
Expand Down Expand Up @@ -154,7 +155,7 @@ function callPhp(args, options, phpIniSettings = {}) {
function callPhpSync(args, options, phpIniSettings = {}) {

if (args[0] === 'artisan' && runningSecureBuild()) {
args.unshift(join(appPath, 'build', '__nativephp_app_bundle'));
args.unshift(join(getAppPath(), 'build', '__nativephp_app_bundle'));
}

let iniSettings = Object.assign(getDefaultPhpIniSettings(), phpIniSettings);
Expand Down Expand Up @@ -196,7 +197,7 @@ function getArgumentEnv() {
}

function getAppPath() {
let appPath = join(import.meta.dirname, '../../../build/app/')
let appPath = state.appPath

if (process.env.NODE_ENV === 'development' || argumentEnv.TESTING == 1) {
appPath = process.env.APP_PATH || argumentEnv.APP_PATH;
Expand All @@ -209,10 +210,12 @@ function ensureAppFoldersAreAvailable() {
// if (!runningSecureBuild()) {
console.log('Copying storage folder...');
console.log('Storage path:', storagePath);
if (!existsSync(storagePath) || process.env.NODE_ENV === 'development') {
console.log("App path:", appPath);
copySync(join(appPath, 'storage'), storagePath)
}

if (!existsSync(storagePath) || process.env.NODE_ENV === 'development') {
const appPath = getAppPath();
console.log("App path:", appPath);
copySync(join(appPath, 'storage'), storagePath)
}
// }

mkdirSync(databasePath, {recursive: true})
Expand All @@ -227,6 +230,7 @@ function ensureAppFoldersAreAvailable() {

function startScheduler(secret, apiPort, phpIniSettings = {}) {
const env = getDefaultEnvironmentVariables(secret, apiPort);
const appPath = getAppPath();

const phpOptions = {
cwd: appPath,
Expand Down
2 changes: 2 additions & 0 deletions resources/electron/electron-plugin/src/server/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface State {
phpPort: number | null;
phpIni: any;
caCert: string | null;
appPath: string | null;
icon: string | null;
processes: Record<string, {pid: any, proc: UtilityProcess, settings: Record<string, any>}>;
windows: Record<string, BrowserWindow>;
Expand Down Expand Up @@ -56,6 +57,7 @@ export default {
phpPort: null,
phpIni: null,
caCert: null,
appPath: null,
icon: null,
store: settingsStore,
randomSecret: generateRandomString(32),
Expand Down
5 changes: 3 additions & 2 deletions resources/electron/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import NativePHP from '#plugin'
import path from 'path'

const buildPath = path.resolve(import.meta.dirname, import.meta.env.MAIN_VITE_NATIVEPHP_BUILD_PATH);

const defaultIcon = path.join(buildPath, 'icon.png')
const certificate = path.join(buildPath, 'cacert.pem')

const executable = process.platform === 'win32' ? 'php.exe' : 'php';
const phpBinary = path.join(buildPath,'php', executable);
const appPath = path.join(buildPath, 'app')

/**
* Turn on the lights for the NativePHP app.
Expand All @@ -17,5 +17,6 @@ NativePHP.bootstrap(
app,
defaultIcon,
phpBinary,
certificate
certificate,
appPath
);
3 changes: 2 additions & 1 deletion src/Builder/Concerns/PrunesVendorDirectory.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public function pruneVendorDirectory()
// Remove custom php binary package directory
$binaryPackageDirectory = $this->binaryPackageDirectory();
if (! empty($binaryPackageDirectory) && $filesystem->exists($this->buildPath($binaryPackageDirectory))) {
$filesystem->remove($this->buildPath('app', $binaryPackageDirectory));
$binariesInBuildPath = $this->buildPath("app/{$binaryPackageDirectory}");
$filesystem->remove($binariesInBuildPath);
}
}
}
20 changes: 16 additions & 4 deletions src/ChildProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function start(
?array $env = null,
bool $persistent = false
): self {
$cmd = is_array($cmd) ? array_values($cmd) : [$cmd];
$cmd = $this->parseCommand($cmd);

$process = $this->client->post('child-process/start', [
'alias' => $alias,
Expand All @@ -84,7 +84,7 @@ public function start(
*/
public function php(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false, ?array $iniSettings = null): self
{
$cmd = is_array($cmd) ? array_values($cmd) : [$cmd];
$cmd = $this->parseCommand($cmd);

$process = $this->client->post('child-process/start-php', [
'alias' => $alias,
Expand All @@ -100,7 +100,7 @@ public function php(string|array $cmd, string $alias, ?array $env = null, ?bool

public function node(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false): self
{
$cmd = is_array($cmd) ? array_values($cmd) : [$cmd];
$cmd = $this->parseCommand($cmd);

$process = $this->client->post('child-process/start-node', [
'alias' => $alias,
Expand All @@ -119,7 +119,7 @@ public function node(string|array $cmd, string $alias, ?array $env = null, ?bool
*/
public function artisan(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false, ?array $iniSettings = null): self
{
$cmd = is_array($cmd) ? array_values($cmd) : [$cmd];
$cmd = $this->parseCommand($cmd);

$cmd = ['artisan', ...$cmd];

Expand Down Expand Up @@ -173,4 +173,16 @@ protected function fromRuntimeProcess($process)

return $this;
}

/* Convert a cmd string to array representation (explode on space, except within quotes) */
protected function parseCommand(string|array $cmd): array
{
if (is_array($cmd)) {
return array_values($cmd);
}

preg_match_all('/"[^"]*"|\'[^\']*\'|[^\s]+/', $cmd, $matches);

return array_filter($matches[0]);
}
}
2 changes: 2 additions & 0 deletions src/Contracts/ChildProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public function php(string|array $cmd, string $alias, ?array $env = null, ?bool

public function artisan(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false, ?array $iniSettings = null): self;

public function node(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false): self;

public function stop(?string $alias = null): void;

public function restart(?string $alias = null): ?self;
Expand Down
14 changes: 14 additions & 0 deletions src/Contracts/Shell.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Native\Desktop\Contracts;

interface Shell
{
public function showInFolder(string $path): void;

public function openFile(string $path): string;

public function trashFile(string $path): void;

public function openExternal(string $url): void;
}
Loading