diff --git a/client/electron/go_helpers.ts b/client/electron/go_helpers.ts index 9f6db97334..80784543ad 100644 --- a/client/electron/go_helpers.ts +++ b/client/electron/go_helpers.ts @@ -19,7 +19,6 @@ */ import {pathToEmbeddedTun2socksBinary} from './app_paths'; -import {invokeGoApi} from './go_plugin'; import {ChildProcessHelper} from './process'; import {TransportConfigJson} from '../src/www/app/outline_server_repository/vpn'; @@ -58,13 +57,3 @@ export async function checkUDPConnectivity( } return true; } - -/** - * Fetches a resource from the given URL. - * - * @param url The URL of the resource to fetch. - * @returns A Promise that resolves to the fetched content as a string. - */ -export function fetchResource(url: string): Promise { - return invokeGoApi('FetchResource', url); -} diff --git a/client/electron/go_plugin.ts b/client/electron/go_plugin.ts index c4ee4fd8e5..db80eaf22a 100644 --- a/client/electron/go_plugin.ts +++ b/client/electron/go_plugin.ts @@ -20,6 +20,8 @@ import {pathToBackendLibrary} from './app_paths'; let invokeGoAPIFunc: Function | undefined; +export type GoApiName = 'FetchResource'; + /** * Calls a Go function by invoking the `InvokeGoAPI` function in the native backend library. * @@ -33,7 +35,7 @@ let invokeGoAPIFunc: Function | undefined; * in `./client/go/outline/electron/go_plugin.go`. */ export async function invokeGoApi( - api: 'FetchResource', + api: GoApiName, input: string ): Promise { if (!invokeGoAPIFunc) { diff --git a/client/electron/index.ts b/client/electron/index.ts index 59916f89dc..1244e1b71a 100644 --- a/client/electron/index.ts +++ b/client/electron/index.ts @@ -34,7 +34,7 @@ import { import {autoUpdater} from 'electron-updater'; import {lookupIp} from './connectivity'; -import {fetchResource} from './go_helpers'; +import {GoApiName, invokeGoApi} from './go_plugin'; import {GoVpnTunnel} from './go_vpn_tunnel'; import {installRoutingServices, RoutingDaemon} from './routing_service'; import {TunnelStore} from './tunnel_store'; @@ -501,10 +501,19 @@ function main() { mainWindow?.webContents.send('outline-ipc-push-clipboard'); }); - // Fetches a resource (usually the dynamic key config) from a remote URL. + // This IPC handler allows the renderer process to call Go API functions exposed by the backend. + // It takes two arguments: + // - api: The name of the Go API function to call. + // - input: A string representing the input data to the Go function. + // + // The handler returns the output string from the Go function if successful. + // Both the input string and output string need to be interpreted by the renderer process according + // to the specific API being called. + // If Go function encounters an error, it throws an Error that can be parsed by the `PlatformError`. ipcMain.handle( - 'outline-ipc-fetch-resource', - (_, url: string): Promise => fetchResource(url) + 'outline-ipc-invoke-go-api', + (_, api: GoApiName, input: string): Promise => + invokeGoApi(api, input) ); // Connects to a proxy server specified by a config. diff --git a/client/go/outline/electron/go_plugin.go b/client/go/outline/electron/go_plugin.go index 23f38702f1..c16829d329 100644 --- a/client/go/outline/electron/go_plugin.go +++ b/client/go/outline/electron/go_plugin.go @@ -20,7 +20,7 @@ package main // InvokeGoAPIResult is a struct used to pass result from Go to TypeScript boundary. typedef struct InvokeGoAPIResult_t { - // A string representing the result of the Go function call. + // A string representing the result of the Go function call. // This may be a raw string or a JSON string depending on the API call. const char *Output; @@ -50,7 +50,7 @@ const ( FetchResourceAPI = "FetchResource" ) -// InvokeGoFunc is the unified entry point for TypeScript to invoke various Go functions. +// InvokeGoAPI is the unified entry point for TypeScript to invoke various Go functions. // // The input and output are all defined as string, but they may represent either a raw string, // or a JSON string depending on the API call. @@ -81,6 +81,9 @@ func InvokeGoAPI(api *C.char, input *C.char) C.InvokeGoAPIResult { // newCGoString allocates memory for a C string based on the given Go string. // It should be paired with [FreeCGoString] to avoid memory leaks. func newCGoString(s string) *C.char { + if s == "" { + return nil + } res := C.CString(s) slog.Debug("malloc CGoString", "addr", res) return res @@ -91,8 +94,10 @@ func newCGoString(s string) *C.char { // //export FreeCGoString func FreeCGoString(s *C.char) { - slog.Debug("free CGoString", "addr", s) - C.free(unsafe.Pointer(s)) + if s != nil { + slog.Debug("free CGoString", "addr", s) + C.free(unsafe.Pointer(s)) + } } // marshalCGoErrorJson marshals a PlatformError to a C style JSON string. diff --git a/client/src/www/app/resource_fetcher.electron.ts b/client/src/www/app/resource_fetcher.electron.ts index aad193ea3d..a62a7b2d8a 100644 --- a/client/src/www/app/resource_fetcher.electron.ts +++ b/client/src/www/app/resource_fetcher.electron.ts @@ -21,7 +21,11 @@ import {PlatformError} from '../model/platform_error'; export class ElectronResourceFetcher implements ResourceFetcher { async fetch(url: string): Promise { try { - return await window.electron.methodChannel.invoke('fetch-resource', url); + return await window.electron.methodChannel.invoke( + 'invoke-go-api', + 'FetchResource', + url + ); } catch (e) { throw PlatformError.parseFrom(e); }