TeaSpeak-Client/modules/renderer/require-handler.ts
2020-04-04 14:27:42 +02:00

112 lines
3.5 KiB
TypeScript

import * as path from "path";
import {remote} from "electron";
import * as electron from "electron";
import * as os from "os";
const Module = require("module");
interface ModuleOverride {
name?: string,
test: string | RegExp | ((request: string) => boolean);
callback: (this: string, request: string, parent?: NodeJS.Module) => any;
}
const overrides: ModuleOverride[] = [];
function proxied_load(request: string, parent?: NodeJS.Module) {
for(const override of overrides) {
let test_satisfied = false;
if(typeof override.test === "string") {
test_satisfied = override.test === request;
} else if(typeof override.test === "function") {
test_satisfied = override.test(request);
} else if(typeof override === "object") {
if(override.test instanceof RegExp)
test_satisfied = !!request.match(override.test);
}
if(test_satisfied) {
//console.log("Using override %s for %s", override.name || "unnamed", request);
return override.callback.apply(this, arguments);
}
}
//console.log("No override found for %s", request);
return proxied_load.original_load.apply(this, arguments);
}
function shared_backend_loader(request: string) {
if(!request.startsWith("tc-backend/")) throw "invalid target";
const target = request.substr(11);
return require(path.join(backend_root, target));
}
namespace proxied_load {
export let original_load: typeof Module.require;
}
let backend_root: string;
export function initialize(backend_root_: string) {
backend_root = backend_root_;
proxied_load.original_load = Module._load;
Module._load = proxied_load;
window["backend-loader"] = {
require: shared_backend_loader
};
}
overrides.push({
name: "tc-loader",
test: "tc-loader",
callback: () => window["loader"]
});
overrides.push({
name: "native loader",
test: /^tc-native\/[a-zA-Z_-]+$/,
callback: request => {
const name = request.substr(10);
const file_mapping = {
connection: "teaclient_connection.node",
ppt: "teaclient_ppt.node",
dns: "teaclient_dns.node"
};
if(typeof file_mapping[name] !== "string")
throw "unknown native module";
const app_path = (remote || electron).app.getAppPath();
let target_path;
if(app_path.endsWith(".asar")) {
target_path = path.join(path.dirname(app_path), "native", file_mapping[name]);
} else {
/* from source code */
target_path = path.join(app_path, "native", "build", os.platform() + "_" + os.arch(), file_mapping[name]);
}
return require(target_path);
}
});
overrides.push({
name: "shared loader",
test: /^tc-shared\/.*/,
callback: request => {
const webpack_path = path.dirname("shared/js/" + request.substr(10)); //FIXME: Get the prefix from a variable!
const loader = require("tc-loader");
const mapping = loader.module_mapping().find(e => e.application === "client-app"); //FIXME: Variable name!
if(!mapping) throw "missing mapping";
const entries = mapping.modules.filter(e => e.context === webpack_path);
if(!entries.length) throw "unknown target path";
const basename = path.basename(request, path.extname(request));
const entry = entries.find(e => path.basename(e.resource, path.extname(e.resource)) === basename);
if(!entry) throw "unknown import";
return window["shared-require"](entry.id);
}
});