From 10fa95ec9ace05553b479b87dd0c54b5f4612605 Mon Sep 17 00:00:00 2001 From: jyyi1 Date: Tue, 12 Nov 2024 22:47:12 -0500 Subject: [PATCH] include shared library in the app --- client/electron/app_paths.ts | 11 +++++++ client/electron/go_helpers.ts | 15 +++++---- client/electron/go_plugin.ts | 57 +++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 client/electron/go_plugin.ts diff --git a/client/electron/app_paths.ts b/client/electron/app_paths.ts index 8808655647..7aa4e04a3e 100644 --- a/client/electron/app_paths.ts +++ b/client/electron/app_paths.ts @@ -56,6 +56,17 @@ export function pathToEmbeddedTun2socksBinary() { ); } +export function pathToBackendLibrary() { + return path.join( + unpackedAppPath(), + 'client', + 'output', + 'build', + isWindows ? 'windows' : 'linux', + isWindows ? 'backend.dll' : 'libbackend.so' + ); +} + /** * Get the parent directory path containing the background service binaries. * On Windows, this folder contains `OutlineService.exe`. diff --git a/client/electron/go_helpers.ts b/client/electron/go_helpers.ts index 7071682c24..fb69cb2ac9 100644 --- a/client/electron/go_helpers.ts +++ b/client/electron/go_helpers.ts @@ -19,6 +19,7 @@ */ import {pathToEmbeddedTun2socksBinary} from './app_paths'; +import {goFetchResource} from './go_plugin'; import {ChildProcessHelper} from './process'; import {TransportConfigJson} from '../src/www/app/outline_server_repository/vpn'; @@ -66,13 +67,15 @@ export async function checkUDPConnectivity( * @returns A Promise that resolves to the fetched content as a string. * @throws ProcessTerminatedExitCodeError if tun2socks failed to run. */ -export function fetchResource( +export async function fetchResource( url: string, debugMode: boolean = false ): Promise { - const tun2socks = new ChildProcessHelper(pathToEmbeddedTun2socksBinary()); - tun2socks.isDebugModeEnabled = debugMode; - - console.debug('[tun2socks] - fetching resource ...'); - return tun2socks.launch(['-fetchUrl', url]); + console.debug('[tun2socks] - preparing library calls ...'); + const result = await goFetchResource(url); + console.debug('[tun2socks] - result: ', result); + if (result.Error) { + throw new Error(`Returned error handle: ${result.Error}`); + } + return result.Content; } diff --git a/client/electron/go_plugin.ts b/client/electron/go_plugin.ts new file mode 100644 index 0000000000..352652d0f6 --- /dev/null +++ b/client/electron/go_plugin.ts @@ -0,0 +1,57 @@ +// Copyright 2024 The Outline Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {promisify} from 'node:util'; +import koffi from 'koffi'; +import {pathToBackendLibrary} from './app_paths'; + +export type GoPlatformErrorHandle = number; + +export interface GoFetchResourceResult { + Content: string; + Error: GoPlatformErrorHandle; +} + +var goFetchResourceFunc: koffi.KoffiFunction | undefined; + +export function goFetchResource(url: string): Promise { + if (!goFetchResourceFunc) { + const lib = ensureBackendLibraryLoaded(); + const resultStruct = koffi.struct('FetchResourceResult', { + Content: 'CStr', + Error: 'GoPlatformErrorHandle', + }); + goFetchResourceFunc = lib.func('FetchResource', resultStruct, ['str']); + } + return promisify(goFetchResourceFunc.async)(url); +} + +var backendLib: koffi.IKoffiLib | undefined; + +function ensureBackendLibraryLoaded(): koffi.IKoffiLib { + if (!backendLib) { + backendLib = koffi.load(pathToBackendLibrary()); + defineCommonFunctions(backendLib); + } + return backendLib; +} + +var goStr: koffi.IKoffiCType | undefined; +var goFreeString: koffi.KoffiFunction | undefined; + +function defineCommonFunctions(lib: koffi.IKoffiLib) { + goFreeString = lib.func('FreeString', koffi.types.void, [koffi.types.str]); + goStr = koffi.disposable('CStr', koffi.types.str, goFreeString); + koffi.alias('GoPlatformErrorHandle', koffi.types.uintptr_t); +}