Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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 config/nativephp-internal.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
'storage/hot',

// Only needed for local testing
'vendor/nativephp/desktop/.git',
'vendor/nativephp/desktop/resources',
'vendor/nativephp/desktop/vendor',
'vendor/nativephp/php-bin',
Expand Down
81 changes: 80 additions & 1 deletion resources/electron/electron-plugin/src/server/php.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {mkdirSync, statSync, writeFileSync, existsSync} from 'fs'
import { mkdirSync, statSync, writeFileSync, existsSync, readFileSync } from 'fs';
import fs_extra from 'fs-extra';

const {copySync, mkdirpSync} = fs_extra;
Expand Down Expand Up @@ -49,6 +49,65 @@ function shouldOptimize(store) {
// return runningSecureBuild() && store.get('optimized_version') !== app.getVersion();
}

function hasNightwatchInstalled(appPath: string) {
const candidateRoots = [
appPath,
join(appPath, "build", "__nativephp_app_bundle")
];

for (const root of candidateRoots) {
if (existsSync(join(root, "vendor", "laravel", "nightwatch"))) {
return true;
}

const composerLock = join(root, "composer.lock");

if (!existsSync(composerLock)) {
continue;
}

try {
if (readFileSync(composerLock, "utf8").includes("\"name\": \"laravel/nightwatch\"")) {
return true;
}
} catch {
// ignore and keep looking
}
}

return false;
}

function getNightwatchToken(appPath: string) {
if (process.env.NIGHTWATCH_TOKEN) {
return process.env.NIGHTWATCH_TOKEN;
}

const candidateRoots = [
appPath,
join(appPath, "build", "__nativephp_app_bundle")
];

for (const root of candidateRoots) {
const envPath = join(root, ".env");

if (!existsSync(envPath)) {
continue;
}

try {
const content = readFileSync(envPath, "utf8");
const match = content.match(/^NIGHTWATCH_TOKEN=(.+)$/m);

if (match && match[1]) {
return match[1].replace(/^['"]|['"]$/g, "");
}
} catch {
// ignore and keep looking
}
}
}

async function getPhpPort() {
// Try get-port first (fast path)
const suggestedPort = await getPort({
Expand Down Expand Up @@ -277,6 +336,9 @@ interface EnvironmentVariables {
APP_ROUTES_CACHE?: string;
APP_EVENTS_CACHE?: string;
VIEW_COMPILED_PATH?: string;

NIGHTWATCH_TOKEN?: string;
NIGHTWATCH_INGEST_URI?: string;
}

function getDefaultEnvironmentVariables(secret?: string, apiPort?: number): EnvironmentVariables {
Expand Down Expand Up @@ -342,6 +404,17 @@ function serveApp(secret, apiPort, phpIniSettings): Promise<ProcessResult> {

const env = getDefaultEnvironmentVariables(secret, apiPort);


const nightwatchToken = getNightwatchToken(appPath);
let phpNightWatchPort: number | undefined;
if (nightwatchToken && hasNightwatchInstalled(appPath)) {
phpNightWatchPort = await getPhpPort();
env.NIGHTWATCH_TOKEN = nightwatchToken;
env.NIGHTWATCH_INGEST_URI = `127.0.0.1:${phpNightWatchPort}`;
} else if (nightwatchToken) {
console.log("Skipping Nightwatch: package not installed.");
}

const phpOptions = {
cwd: appPath,
env
Expand All @@ -351,6 +424,12 @@ function serveApp(secret, apiPort, phpIniSettings): Promise<ProcessResult> {
name: 'nativephp', // So it doesn't conflict with settings of the app
});

if(env.NIGHTWATCH_INGEST_URI && phpNightWatchPort) {
console.log('Starting Nightwatch server...');
callPhp(['artisan', 'nightwatch:agent', `--listen-on=${env.NIGHTWATCH_INGEST_URI}`], phpOptions, phpIniSettings)
console.log('Nightwatch server started on port:', phpNightWatchPort);
}

// Cache the project
if (shouldOptimize(store)) {
console.log('Caching view and routes...');
Expand Down
5 changes: 3 additions & 2 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
use Native\Desktop\Http\Controllers\CreateSecurityCookieController;
use Native\Desktop\Http\Controllers\DispatchEventFromAppController;
use Native\Desktop\Http\Controllers\NativeAppBootedController;
use Native\Desktop\Http\Middleware\OptionalNightwatchNever;
use Native\Desktop\Http\Middleware\PreventRegularBrowserAccess;

Route::group(['middleware' => PreventRegularBrowserAccess::class], function () {
Route::group(['middleware' => [OptionalNightwatchNever::class, PreventRegularBrowserAccess::class]], function () {
Route::post('_native/api/booted', NativeAppBootedController::class);
Route::post('_native/api/events', DispatchEventFromAppController::class);
})->withoutMiddleware(VerifyCsrfToken::class);

Route::get('_native/api/cookie', CreateSecurityCookieController::class);
Route::get('_native/api/cookie', CreateSecurityCookieController::class)->middleware(OptionalNightwatchNever::class);
20 changes: 20 additions & 0 deletions src/Http/Middleware/OptionalNightwatchNever.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Native\Desktop\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class OptionalNightwatchNever
{
public function handle(Request $request, Closure $next): mixed
{
if (class_exists(\Laravel\Nightwatch\Http\Middleware\Sample::class)) {
$middleware = app(\Laravel\Nightwatch\Http\Middleware\Sample::class);

return $middleware->handle($request, $next, 0.0);
}

return $next($request);
}
}
Loading