@@ -4,15 +4,21 @@ import {createRequire} from "module";
44import path from "path" ;
55import { getConsoleLogPrefix } from "../../utils/getConsoleLogPrefix.js" ;
66import { runningInElectron } from "../../utils/runtime.js" ;
7- import { BuildGpu } from "../types.js" ;
7+ import { BuildGpu , LlamaLogLevel } from "../types.js" ;
8+ import { LlamaLogLevelToAddonLogLevel } from "../Llama.js" ;
89import type { BindingModule } from "../AddonTypes.js" ;
910
1011const require = createRequire ( import . meta. url ) ;
1112const __filename = fileURLToPath ( import . meta. url ) ;
1213const detectedFileName = path . basename ( __filename ) ;
1314const expectedFileName = "testBindingBinary" ;
1415
15- export async function testBindingBinary ( bindingBinaryPath : string , gpu : BuildGpu , testTimeout : number = 1000 * 60 * 5 ) : Promise < boolean > {
16+ export async function testBindingBinary (
17+ bindingBinaryPath : string ,
18+ gpu : BuildGpu ,
19+ testTimeout : number = 1000 * 60 * 5 ,
20+ pipeOutputOnNode : boolean = false
21+ ) : Promise < boolean > {
1622 if ( ! detectedFileName . startsWith ( expectedFileName ) ) {
1723 console . warn (
1824 getConsoleLogPrefix ( ) +
@@ -57,7 +63,8 @@ export async function testBindingBinary(bindingBinaryPath: string, gpu: BuildGpu
5763 onExit ( code : number ) : void
5864 } ) : {
5965 sendMessage ( message : ParentToChildMessage ) : void ,
60- killProcess ( ) : void
66+ killProcess ( ) : void ,
67+ pipeMessages ( ) : void
6168 } {
6269 if ( forkFunction . type === "electron" ) {
6370 let exited = false ;
@@ -88,20 +95,28 @@ export async function testBindingBinary(bindingBinaryPath: string, gpu: BuildGpu
8895
8996 return {
9097 sendMessage : ( message : ParentToChildMessage ) => subProcess . postMessage ( message ) ,
91- killProcess : cleanupElectronFork
98+ killProcess : cleanupElectronFork ,
99+ pipeMessages : ( ) => void 0
92100 } ;
93101 }
94102
103+ let pipeSet = false ;
95104 const subProcess = forkFunction . fork ( __filename , [ ] , {
96105 detached : false ,
97106 silent : true ,
107+ stdio : pipeOutputOnNode
108+ ? [ "ignore" , "pipe" , "pipe" , "ipc" ]
109+ : [ "ignore" , "ignore" , "ignore" , "ipc" ] ,
98110 env : {
99111 ...process . env ,
100112 TEST_BINDING_CP : "true"
101113 }
102114 } ) ;
103115
104116 function cleanupNodeFork ( ) {
117+ subProcess . stdout ?. off ( "data" , onStdout ) ;
118+ subProcess . stderr ?. off ( "data" , onStderr ) ;
119+
105120 if ( subProcess . exitCode == null )
106121 subProcess . kill ( "SIGKILL" ) ;
107122
@@ -121,9 +136,36 @@ export async function testBindingBinary(bindingBinaryPath: string, gpu: BuildGpu
121136 onExit ( subProcess . exitCode ?? - 1 ) ;
122137 }
123138
139+ function onStdout ( data : string ) {
140+ if ( ! pipeSet )
141+ return ;
142+
143+ process . stdout . write ( data ) ;
144+ }
145+
146+ function onStderr ( data : string ) {
147+ if ( ! pipeSet )
148+ return ;
149+
150+ process . stderr . write ( data ) ;
151+ }
152+
153+ if ( pipeOutputOnNode ) {
154+ subProcess . stdout ?. on ( "data" , onStdout ) ;
155+ subProcess . stderr ?. on ( "data" , onStderr ) ;
156+ }
157+
158+ function pipeMessages ( ) {
159+ if ( ! pipeOutputOnNode || pipeSet )
160+ return ;
161+
162+ pipeSet = true ;
163+ }
164+
124165 return {
125166 sendMessage : ( message : ParentToChildMessage ) => subProcess . send ( message ) ,
126- killProcess : cleanupNodeFork
167+ killProcess : cleanupNodeFork ,
168+ pipeMessages
127169 } ;
128170 }
129171
@@ -169,6 +211,13 @@ export async function testBindingBinary(bindingBinaryPath: string, gpu: BuildGpu
169211 bindingBinaryPath,
170212 gpu
171213 } ) ;
214+ } else if ( message . type === "loaded" ) {
215+ subProcess ! . pipeMessages ( ) ; // only start piping error logs if the binary loaded successfully
216+ subProcess ! . sendMessage ( {
217+ type : "test" ,
218+ bindingBinaryPath,
219+ gpu
220+ } ) ;
172221 } else if ( message . type === "done" ) {
173222 testPassed = true ;
174223 subProcess ! . sendMessage ( { type : "exit" } ) ;
@@ -189,13 +238,28 @@ export async function testBindingBinary(bindingBinaryPath: string, gpu: BuildGpu
189238}
190239
191240if ( process . env . TEST_BINDING_CP === "true" && ( process . parentPort != null || process . send != null ) ) {
241+ let binding : BindingModule ;
192242 const sendMessage = process . parentPort != null
193243 ? ( message : ChildToParentMessage ) => process . parentPort . postMessage ( message )
194244 : ( message : ChildToParentMessage ) => process . send ! ( message ) ;
195245 const onMessage = async ( message : ParentToChildMessage ) => {
196246 if ( message . type === "start" ) {
197247 try {
198- const binding : BindingModule = require ( message . bindingBinaryPath ) ;
248+ binding = require ( message . bindingBinaryPath ) ;
249+
250+ const errorLogLevel = LlamaLogLevelToAddonLogLevel . get ( LlamaLogLevel . error ) ;
251+ if ( errorLogLevel != null )
252+ binding . setLoggerLogLevel ( errorLogLevel ) ;
253+
254+ sendMessage ( { type : "loaded" } ) ;
255+ } catch ( err ) {
256+ console . error ( err ) ;
257+ process . exit ( 1 ) ;
258+ }
259+ } else if ( message . type === "test" ) {
260+ try {
261+ if ( binding == null )
262+ throw new Error ( "Binding binary is not loaded" ) ;
199263
200264 binding . loadBackends ( ) ;
201265 const loadedGpu = binding . getGpuType ( ) ;
@@ -235,9 +299,13 @@ type ParentToChildMessage = {
235299 type : "start" ,
236300 bindingBinaryPath : string ,
237301 gpu : BuildGpu
302+ } | {
303+ type : "test" ,
304+ bindingBinaryPath : string ,
305+ gpu : BuildGpu
238306} | {
239307 type : "exit"
240308} ;
241309type ChildToParentMessage = {
242- type : "ready" | "done"
310+ type : "ready" | "loaded" | " done"
243311} ;
0 commit comments