diff --git a/apps/server/package.json b/apps/server/package.json index 70edd6d..a7e1f52 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -5,7 +5,7 @@ "license": "CC BY-ND", "description": "Server side of rage-fw example", "scripts": { - "build": "esbuild src/index.ts --bundle --platform=node --target=node14.10 --format=cjs --outfile=../../server/packages/server/index.js" + "build": "esbuild src/index.ts --bundle --platform=node --target=node14.10 --external:*.node --format=cjs --outfile=../../server/packages/server/index.js" }, "dependencies": { "@entityseven/rage-fw-server": "latest" diff --git a/apps/server/src/benchmark/index.ts b/apps/server/src/benchmark/index.ts deleted file mode 100644 index 621fb5e..0000000 --- a/apps/server/src/benchmark/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Calculates Pi using the Leibniz formula for a given number of iterations. - * (Identical logic to the AssemblyScript version) - * @param iterations Number of terms in the series. - * @returns Approximate value of Pi. - */ -export function calculatePiLeibnizTs(iterations: number): number { - let pi_div_4: number = 0.0 - let sign: number = 1.0 - - for (let i: number = 0; i < iterations; i++) { - let term = sign / (2.0 * i + 1.0) - pi_div_4 += term - sign = -sign // Flip the sign - } - return pi_div_4 * 4.0 -} - -/** - * Helper function to check if a number is prime (Trial Division). - * (Identical logic to the AssemblyScript version) - * @param num The number to check. - * @returns True if prime, false otherwise. - */ -function isPrimeTs(num: number): boolean { - if (num <= 1) return false - if (num <= 3) return true - if (num % 2 == 0 || num % 3 == 0) return false - - // Only need to check up to sqrt(num) - // Optimized loop: check 6k ± 1 - for (let i: number = 5; i * i <= num; i = i + 6) { - if (num % i == 0 || num % (i + 2) == 0) { - return false - } - } - return true -} - -/** - * Counts prime numbers up to a given limit using trial division. - * (Identical logic to the AssemblyScript version) - * @param limit The upper bound (exclusive) to search for primes. - * @returns The count of prime numbers found. - */ -export function countPrimesTs(limit: number): number { - let count: number = 0 - for (let i: number = 2; i < limit; i++) { - if (isPrimeTs(i)) { - count++ - } - } - return count -} - -export function addTs(a: number, b: number): number { - return a + b -} diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 0d21bd5..8c92f16 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,71 +1,3 @@ -import { InitWasm } from './wasm' -import { addTs, calculatePiLeibnizTs, countPrimesTs } from './benchmark' +import { checkLicense, doSensitiveOperation } from './x86_64-pc-windows-msvc' -import { performance } from 'perf_hooks' -/** - * Runs a function, measures its execution time, and prints the result. - * @param name Name of the benchmark. - * @param func The function to execute. - * @param args Arguments to pass to the function. - */ -function runBenchmark( - name: string, - func: (...args: any[]) => any, - ...args: any[] -) { - console.log(`\nRunning benchmark: ${name}`) - console.log(`Arguments: ${args.join(', ')}`) - - const startTime = performance.now() - const result = func(...args) - const endTime = performance.now() - const duration = endTime - startTime - - console.log(`Result: ${result}`) - console.log(`Execution Time: ${duration.toFixed(3)} ms`) - return duration -} - -// --- Benchmark Parameters --- -const PI_ITERATIONS = 100_000_000_000 // High number for Pi calculation -const PRIME_LIMIT = 100_000_000 // Limit for prime counting -// --- End Benchmark Parameters --- - -InitWasm().then(wasm => { - // Verify AS module loaded - const sumAs = wasm.addAs(5, 7) - console.log(`AS Module Loaded Verification (addAs(5, 7)): ${sumAs}`) - if (sumAs !== 12) { - console.warn('AS addAs function did not return expected result!') - } - const sumTs = addTs(5, 7) - console.log(`TS Implementation Verification (addTs(5, 7)): ${sumTs}`) - - // --- Run Benchmarks --- - - // Benchmark: Calculate Pi - runBenchmark( - 'TypeScript: Calculate Pi (Leibniz)', - calculatePiLeibnizTs, - PI_ITERATIONS, - ) - runBenchmark( - 'AssemblyScript: Calculate Pi (Leibniz)', - wasm.calculatePiLeibnizAs, - PI_ITERATIONS, - ) - - // Benchmark: Count Primes - runBenchmark( - 'TypeScript: Count Primes (Trial Division)', - countPrimesTs, - PRIME_LIMIT, - ) - runBenchmark( - 'AssemblyScript: Count Primes (Trial Division)', - wasm.countPrimesAs, - PRIME_LIMIT, - ) - - console.log('\nBenchmark finished.') -}) +console.log(doSensitiveOperation('test')) diff --git a/apps/server/src/wasm/index.ts b/apps/server/src/wasm/index.ts deleted file mode 100644 index 3107433..0000000 --- a/apps/server/src/wasm/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { __AdaptedExports, instantiate } from './release' - -import * as path from 'node:path' -import * as fs from 'node:fs/promises' - -export async function InitWasm(): Promise { - return new Promise(async resolve => { - const wasmFilePath = path.resolve(__dirname, 'release.wasm') - - const wasm: typeof __AdaptedExports = await instantiate( - await (async () => { - return globalThis.WebAssembly.compile( - await fs.readFile(wasmFilePath), - ) - })(), - { env: '' }, - ) - - resolve(wasm) - }) -} diff --git a/apps/server/src/wasm/release.d.ts b/apps/server/src/wasm/release.d.ts deleted file mode 100644 index 5b0c339..0000000 --- a/apps/server/src/wasm/release.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -declare namespace __AdaptedExports { - /** - * assembly/index/calculatePiLeibnizAs - * @param iterations `i32` - * @returns `f64` - */ - export function calculatePiLeibnizAs(iterations: number): number; - /** - * assembly/index/countPrimesAs - * @param limit `i32` - * @returns `i32` - */ - export function countPrimesAs(limit: number): number; - /** - * assembly/index/addAs - * @param a `i32` - * @param b `i32` - * @returns `i32` - */ - export function addAs(a: number, b: number): number; -} -/** Instantiates the compiled WebAssembly module with the given imports. */ -export declare function instantiate(module: WebAssembly.Module, imports: { -}): Promise; diff --git a/apps/server/src/wasm/release.js b/apps/server/src/wasm/release.js deleted file mode 100644 index 7e98f71..0000000 --- a/apps/server/src/wasm/release.js +++ /dev/null @@ -1,4 +0,0 @@ -export async function instantiate(module, imports = {}) { - const { exports } = await WebAssembly.instantiate(module, imports); - return exports; -} diff --git a/apps/server/src/x86_64-pc-windows-msvc/gta5.win32-x64-msvc.node b/apps/server/src/x86_64-pc-windows-msvc/gta5.win32-x64-msvc.node new file mode 100644 index 0000000..0d2d43d Binary files /dev/null and b/apps/server/src/x86_64-pc-windows-msvc/gta5.win32-x64-msvc.node differ diff --git a/apps/server/src/x86_64-pc-windows-msvc/index.d.ts b/apps/server/src/x86_64-pc-windows-msvc/index.d.ts new file mode 100644 index 0000000..49d915a --- /dev/null +++ b/apps/server/src/x86_64-pc-windows-msvc/index.d.ts @@ -0,0 +1,31 @@ +/* tslint:disable */ +/* eslint-disable */ + +/* auto-generated by NAPI-RS */ + +/** + * # checkLicense + * Accepts a 16-character license key string. + * Gets the server's local IPv4 address, prints it to the console, + * and validates the key. If valid, unlocks other functions. + * + * Returns `true` if the license key is valid, `false` otherwise. + */ +export declare function checkLicense(licenseKey: string): boolean +/** + * # doSensitiveOperation + * An example function that should only run if the license is validated. + * Takes a name as input and returns a greeting string. + */ +export declare function doSensitiveOperation(name: string): string +/** + * # getSecretData + * Another example function that should only run if the license is validated. + * Returns a dummy secret number. + */ +export declare function getSecretData(): number +/** + * # isLicensed (Optional utility) + * Allows JavaScript to check the current license status without triggering exit. + */ +export declare function isLicensed(): boolean diff --git a/apps/server/src/x86_64-pc-windows-msvc/index.js b/apps/server/src/x86_64-pc-windows-msvc/index.js new file mode 100644 index 0000000..931197d --- /dev/null +++ b/apps/server/src/x86_64-pc-windows-msvc/index.js @@ -0,0 +1,318 @@ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') + +const { platform, arch } = process + +let nativeBinding = null +let localFileExisted = false +let loadError = null + +function isMusl() { + // For Node 10 + if (!process.report || typeof process.report.getReport !== 'function') { + try { + const lddPath = require('child_process').execSync('which ldd').toString().trim() + return readFileSync(lddPath, 'utf8').includes('musl') + } catch (e) { + return true + } + } else { + const { glibcVersionRuntime } = process.report.getReport().header + return !glibcVersionRuntime + } +} + +switch (platform) { + case 'android': + switch (arch) { + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'gta5.android-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.android-arm64.node') + } else { + nativeBinding = require('gta5-android-arm64') + } + } catch (e) { + loadError = e + } + break + case 'arm': + localFileExisted = existsSync(join(__dirname, 'gta5.android-arm-eabi.node')) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.android-arm-eabi.node') + } else { + nativeBinding = require('gta5-android-arm-eabi') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Android ${arch}`) + } + break + case 'win32': + switch (arch) { + case 'x64': + localFileExisted = existsSync( + join(__dirname, 'gta5.win32-x64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.win32-x64-msvc.node') + } else { + nativeBinding = require('gta5-win32-x64-msvc') + } + } catch (e) { + loadError = e + } + break + case 'ia32': + localFileExisted = existsSync( + join(__dirname, 'gta5.win32-ia32-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.win32-ia32-msvc.node') + } else { + nativeBinding = require('gta5-win32-ia32-msvc') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'gta5.win32-arm64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.win32-arm64-msvc.node') + } else { + nativeBinding = require('gta5-win32-arm64-msvc') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Windows: ${arch}`) + } + break + case 'darwin': + localFileExisted = existsSync(join(__dirname, 'gta5.darwin-universal.node')) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.darwin-universal.node') + } else { + nativeBinding = require('gta5-darwin-universal') + } + break + } catch {} + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'gta5.darwin-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.darwin-x64.node') + } else { + nativeBinding = require('gta5-darwin-x64') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'gta5.darwin-arm64.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.darwin-arm64.node') + } else { + nativeBinding = require('gta5-darwin-arm64') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on macOS: ${arch}`) + } + break + case 'freebsd': + if (arch !== 'x64') { + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + } + localFileExisted = existsSync(join(__dirname, 'gta5.freebsd-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.freebsd-x64.node') + } else { + nativeBinding = require('gta5-freebsd-x64') + } + } catch (e) { + loadError = e + } + break + case 'linux': + switch (arch) { + case 'x64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-x64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-x64-musl.node') + } else { + nativeBinding = require('gta5-linux-x64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-x64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-x64-gnu.node') + } else { + nativeBinding = require('gta5-linux-x64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-arm64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-arm64-musl.node') + } else { + nativeBinding = require('gta5-linux-arm64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-arm64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-arm64-gnu.node') + } else { + nativeBinding = require('gta5-linux-arm64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-arm-musleabihf.node') + } else { + nativeBinding = require('gta5-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('gta5-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-riscv64-musl.node') + } else { + nativeBinding = require('gta5-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-riscv64-gnu.node') + } else { + nativeBinding = require('gta5-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync( + join(__dirname, 'gta5.linux-s390x-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./gta5.linux-s390x-gnu.node') + } else { + nativeBinding = require('gta5-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Linux: ${arch}`) + } + break + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) +} + +if (!nativeBinding) { + if (loadError) { + throw loadError + } + throw new Error(`Failed to load native binding`) +} + +const { checkLicense, doSensitiveOperation, getSecretData, isLicensed } = nativeBinding + +module.exports.checkLicense = checkLicense +module.exports.doSensitiveOperation = doSensitiveOperation +module.exports.getSecretData = getSecretData +module.exports.isLicensed = isLicensed