1+ /*
2+ Copyright (c) Anthony Beaumont
3+ This source code is licensed under the MIT License
4+ found in the LICENSE file in the root directory of this source tree.
5+ */
6+
7+ /*
8+ ⚠️ Experimental and not yet tested
9+ Based on https://github.com/nodejs/node/pull/46905
10+ */
11+
12+ import { platform } from "node:process" ;
13+ import { getNativeFunction } from "node:ffi" ;
14+ import { Failure } from "@xan105/error" ;
15+ import { asBoolean , asArray } from "@xan105/is/opt" ;
16+ import {
17+ shouldObj ,
18+ shouldObjWithinObj ,
19+ shouldStringNotEmpty
20+ } from "@xan105/is/assert" ;
21+
22+ function load ( path , option = { } ) {
23+
24+ shouldStringNotEmpty ( path ) ;
25+ shouldObj ( option ) ;
26+
27+ const options = {
28+ ignoreLoadingFail : asBoolean ( option . ignoreLoadingFail ) ?? false ,
29+ ignoreMissingSymbol : asBoolean ( option . ignoreMissingSymbol ) ?? false
30+ } ;
31+
32+ const ext = {
33+ "win32" : ".dll" ,
34+ "darwin" : ".dylib" ,
35+ } [ platform ] ?? ".so" ;
36+
37+ if ( path . indexOf ( ext ) === - 1 ) path += ext ;
38+
39+ const handle = function ( symbol , result , parameters ) {
40+ try {
41+ return getNativeFunction ( path , symbol , result , parameters ) ;
42+ } catch ( err ) {
43+ if ( err . code === "ERR_FFI_LIBRARY_LOAD_FAILED" && options . ignoreLoadingFail )
44+ return undefined ;
45+ else if ( err . code === "ERR_FFI_SYMBOL_NOT_FOUND" && options . ignoreMissingSymbol )
46+ return undefined ;
47+
48+ throw new Failure ( err . message , {
49+ code : "ERR_FFI" ,
50+ cause : err ,
51+ info : { lib : path , symbol }
52+ } ) ;
53+ }
54+ } ;
55+
56+ return handle ;
57+ }
58+
59+ function dlopen ( path , symbols , option ) {
60+
61+ shouldObjWithinObj ( symbols ) ;
62+
63+ const lib = Object . create ( null ) ;
64+ const handle = load ( path , option ) ;
65+
66+ for ( const [ name , definition ] of Object . entries ( symbols ) ) {
67+
68+ if ( name === "__proto__" ) continue ; //not allowed
69+
70+ const parameters = asArray ( definition . parameters ) ?? [ ] ;
71+ const result = definition . result || "void" ;
72+ const nonblocking = asBoolean ( definition . nonblocking ) ?? false ;
73+ const symbol = definition . symbol || name ;
74+
75+ const fn = handle ( symbol , result , parameters ) ;
76+ if ( typeof fn === "function" ) lib [ name ] = fn ;
77+ }
78+
79+ return lib ;
80+ }
81+
82+ export { load , dlopen }
0 commit comments