mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-11-27 10:00:57 +00:00
Merge pull request #343 from gnh1201/dev
Support the file association registration for WelsonJS supported file types
This commit is contained in:
commit
2317be5c49
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -551,3 +551,4 @@ settings.ini
|
|||
defaultService.js
|
||||
lib/*.private.js
|
||||
data/python313.zip
|
||||
do_not_push_production_on_friday.js
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ namespace WelsonJS.Launcher
|
|||
ZipFile.ExtractToDirectory(filePath, _workingDirectory);
|
||||
|
||||
// record the first deploy time
|
||||
RecordFirstDeployTime(_workingDirectory, _instanceId);
|
||||
Program.RecordFirstDeployTime(_workingDirectory, _instanceId);
|
||||
|
||||
// follow the sub-directory
|
||||
_workingDirectory = Program.GetWorkingDirectory(_instanceId, true);
|
||||
|
|
@ -194,41 +194,6 @@ namespace WelsonJS.Launcher
|
|||
|
||||
return Program._resourceServer.IsRunning();
|
||||
}
|
||||
|
||||
private void RecordFirstDeployTime(string directory, string instanceId)
|
||||
{
|
||||
// get current time
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// record to the metadata database
|
||||
InstancesForm instancesForm = new InstancesForm();
|
||||
try
|
||||
{
|
||||
instancesForm.GetDatabaseInstance().Insert(new Dictionary<string, object>
|
||||
{
|
||||
["InstanceId"] = instanceId,
|
||||
["FirstDeployTime"] = now
|
||||
}, out _);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
instancesForm.Dispose();
|
||||
|
||||
// record to the instance directory
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(directory, ".welsonjs_first_deploy_time");
|
||||
string text = now.ToString(_dateTimeFormat);
|
||||
File.WriteAllText(filePath, text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInAdministrator()
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Configuration;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
|
|
@ -19,9 +20,13 @@ namespace WelsonJS.Launcher
|
|||
|
||||
public static Mutex _mutex;
|
||||
public static ResourceServer _resourceServer;
|
||||
public static string _dateTimeFormat;
|
||||
|
||||
static Program()
|
||||
{
|
||||
// get the date time format
|
||||
_dateTimeFormat = GetAppConfig("DateTimeFormat");
|
||||
|
||||
// set up logger
|
||||
_logger = new TraceLogger();
|
||||
|
||||
|
|
@ -41,8 +46,22 @@ namespace WelsonJS.Launcher
|
|||
}
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// if set the target file path
|
||||
string targetFilePath = GetTargetFilePath(args);
|
||||
if (!string.IsNullOrEmpty(targetFilePath))
|
||||
{
|
||||
try {
|
||||
HandleTargetFilePath(targetFilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error($"Initialization failed: {e}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// create the mutex
|
||||
_mutex = new Mutex(true, "WelsonJS.Launcher", out bool createdNew);
|
||||
if (!createdNew)
|
||||
|
|
@ -56,14 +75,203 @@ namespace WelsonJS.Launcher
|
|||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainForm(_logger));
|
||||
|
||||
// destory the mutex
|
||||
try {
|
||||
// release the mutex
|
||||
try
|
||||
{
|
||||
_mutex.ReleaseMutex();
|
||||
} catch { /* ignore if not owned */ }
|
||||
}
|
||||
catch { /* ignore if not owned */ }
|
||||
_mutex.Dispose();
|
||||
}
|
||||
|
||||
public static void RunCommandPrompt(string workingDirectory, string entryFileName, string scriptName, bool isConsoleApplication = false, bool isInteractiveServiceAapplication = false)
|
||||
public static void RecordFirstDeployTime(string directory, string instanceId)
|
||||
{
|
||||
// get current time
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// record to the metadata database
|
||||
using (InstancesForm instancesForm = new InstancesForm())
|
||||
{
|
||||
try
|
||||
{
|
||||
instancesForm.GetDatabaseInstance().Insert(new Dictionary<string, object>
|
||||
{
|
||||
["InstanceId"] = instanceId,
|
||||
["FirstDeployTime"] = now
|
||||
}, out _);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// record to the instance directory
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(directory, ".welsonjs_first_deploy_time");
|
||||
string text = now.ToString(_dateTimeFormat);
|
||||
File.WriteAllText(filePath, text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetTargetFilePath(string[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0) return null;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string token = args[i];
|
||||
if (string.Equals(token, "--file", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(token, "/file", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (i + 1 < args.Length)
|
||||
{
|
||||
return args[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (token.StartsWith("--file=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return token.Substring("--file=".Length).Trim('"');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void HandleTargetFilePath(string filePath)
|
||||
{
|
||||
string fileExtension = Path.GetExtension(filePath);
|
||||
|
||||
if (String.IsNullOrEmpty(fileExtension))
|
||||
{
|
||||
throw new ArgumentException("The file extension is null or empty");
|
||||
}
|
||||
|
||||
if (fileExtension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new NotImplementedException("Not implemented yet.");
|
||||
}
|
||||
|
||||
if (fileExtension.Equals(".js", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string instanceId = Guid.NewGuid().ToString();
|
||||
string workingDirectory = CreateInstanceDirectory(instanceId);
|
||||
|
||||
string appRoot = GetAppRootDirectory();
|
||||
string appBaseSource = Path.Combine(appRoot, "app.js");
|
||||
if (!File.Exists(appBaseSource))
|
||||
{
|
||||
throw new FileNotFoundException("app.js not found in application root.", appBaseSource);
|
||||
}
|
||||
|
||||
string appBaseDestination = Path.Combine(workingDirectory, "app.js");
|
||||
File.Copy(appBaseSource, appBaseDestination, overwrite: true);
|
||||
|
||||
string assetsSource = Path.Combine(appRoot, "app", "assets", "js");
|
||||
string assetsDestination = Path.Combine(workingDirectory, "app", "assets", "js");
|
||||
CopyDirectoryRecursive(assetsSource, assetsDestination);
|
||||
|
||||
string libSource = Path.Combine(appRoot, "lib");
|
||||
string libDestination = Path.Combine(workingDirectory, "lib");
|
||||
CopyDirectoryRecursive(libSource, libDestination);
|
||||
|
||||
string entrypointDestination = Path.Combine(workingDirectory, "bootstrap.js");
|
||||
File.Copy(filePath, entrypointDestination, overwrite: true);
|
||||
|
||||
RecordFirstDeployTime(workingDirectory, instanceId);
|
||||
|
||||
RunCommandPrompt(
|
||||
workingDirectory: workingDirectory,
|
||||
entryFileName: "app.js",
|
||||
scriptName: "bootstrap",
|
||||
isConsoleApplication: true,
|
||||
isInteractiveServiceApplication: false
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new NotSupportedException($"Unsupported file type: {fileExtension}");
|
||||
}
|
||||
|
||||
private static string GetAppRootDirectory()
|
||||
{
|
||||
string[] candidates = new[]
|
||||
{
|
||||
GetAppConfig("AppRootDirectory"),
|
||||
AppDomain.CurrentDomain.BaseDirectory,
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WelsonJS"),
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WelsonJS"),
|
||||
};
|
||||
|
||||
foreach (string dir in candidates)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dir))
|
||||
continue;
|
||||
|
||||
string appJs = Path.Combine(dir, "app.js");
|
||||
if (File.Exists(appJs))
|
||||
return dir;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("Could not locate app.js in any known application root directory.");
|
||||
}
|
||||
|
||||
private static string CreateInstanceDirectory(string instanceId)
|
||||
{
|
||||
string workingDirectory = GetWorkingDirectory(instanceId);
|
||||
|
||||
try
|
||||
{
|
||||
// check if the working directory exists
|
||||
if (Directory.Exists(workingDirectory))
|
||||
{
|
||||
throw new InvalidOperationException("GUID validation failed. Directory already exists.");
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(workingDirectory);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Instance Initialization failed");
|
||||
}
|
||||
|
||||
return workingDirectory;
|
||||
}
|
||||
|
||||
private static void CopyDirectoryRecursive(string sourceDir, string destDir)
|
||||
{
|
||||
if (!Directory.Exists(sourceDir))
|
||||
{
|
||||
throw new DirectoryNotFoundException("Source directory not found: " + sourceDir);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(destDir);
|
||||
|
||||
foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
string normalizedSource = sourceDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
string relativePath = file.Substring(normalizedSource.Length + 1).TrimStart(
|
||||
Path.DirectorySeparatorChar,
|
||||
Path.AltDirectorySeparatorChar
|
||||
);
|
||||
string targetPath = Path.Combine(destDir, relativePath);
|
||||
string targetDir = Path.GetDirectoryName(targetPath);
|
||||
if (!Directory.Exists(targetDir))
|
||||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
File.Copy(file, targetPath, overwrite: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunCommandPrompt(string workingDirectory, string entryFileName, string scriptName, bool isConsoleApplication = false, bool isInteractiveServiceApplication = false)
|
||||
{
|
||||
if (!isConsoleApplication)
|
||||
{
|
||||
|
|
@ -93,33 +301,37 @@ namespace WelsonJS.Launcher
|
|||
};
|
||||
process.Start();
|
||||
|
||||
process.StandardInput.WriteLine("pushd " + workingDirectory);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
StreamWriter input = process.StandardInput;
|
||||
StreamReader output = process.StandardOutput;
|
||||
|
||||
if (isInteractiveServiceAapplication)
|
||||
input.WriteLine("pushd " + workingDirectory);
|
||||
input.WriteLine();
|
||||
input.Flush();
|
||||
output.ReadLine();
|
||||
|
||||
if (isInteractiveServiceApplication)
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c startInteractiveService.bat");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
input.WriteLine($"start cmd /c startInteractiveService.bat");
|
||||
input.WriteLine();
|
||||
input.Flush();
|
||||
output.ReadLine();
|
||||
}
|
||||
else if (!isConsoleApplication)
|
||||
{
|
||||
process.StandardInput.WriteLine(entryFileName);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
input.WriteLine(entryFileName);
|
||||
input.WriteLine();
|
||||
input.Flush();
|
||||
output.ReadLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
input.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
||||
input.WriteLine();
|
||||
input.Flush();
|
||||
output.ReadLine();
|
||||
}
|
||||
process.StandardInput.Close();
|
||||
input.Close();
|
||||
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
|
|
|
|||
298
afterInstall.ps1
Normal file
298
afterInstall.ps1
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
# ================================
|
||||
# CONFIGURATION
|
||||
# ================================
|
||||
$AppName = "welsonjs"
|
||||
$TargetDir = Join-Path $env:APPDATA $AppName
|
||||
$TmpDir = Join-Path $env:TEMP "$AppName-downloads"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[*] Target directory : $TargetDir"
|
||||
Write-Host "[*] Temporary directory: $TmpDir"
|
||||
Write-Host ""
|
||||
|
||||
# Ensure base directories exist
|
||||
New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $TmpDir -Force | Out-Null
|
||||
|
||||
|
||||
# ================================
|
||||
# ARCHITECTURE DETECTION
|
||||
# ================================
|
||||
$arch = "x86"
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { $arch = "x64" }
|
||||
elseif ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { $arch = "arm64" }
|
||||
if ($env:PROCESSOR_ARCHITEW6432 -eq "AMD64") { $arch = "x64" }
|
||||
elseif ($env:PROCESSOR_ARCHITEW6432 -eq "ARM64") { $arch = "arm64" }
|
||||
|
||||
Write-Host "[*] Detected architecture: $arch"
|
||||
Write-Host ""
|
||||
|
||||
|
||||
# ================================
|
||||
# HELPER FUNCTIONS
|
||||
# ================================
|
||||
|
||||
function Ensure-EmptyDirectory {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
# If a file exists at the path, remove it
|
||||
if (Test-Path $Path -PathType Leaf) {
|
||||
Write-Host "[WARN] A file exists at path '$Path'. Deleting it..."
|
||||
Remove-Item -Path $Path -Force
|
||||
}
|
||||
|
||||
# Ensure directory exists
|
||||
if (-not (Test-Path $Path -PathType Container)) {
|
||||
Write-Host "[*] Creating directory: $Path"
|
||||
New-Item -ItemType Directory -Path $Path -Force | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Download-File {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Url,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Destination
|
||||
)
|
||||
|
||||
Write-Host "[*] Downloading file..."
|
||||
Write-Host " URL : $Url"
|
||||
Write-Host " OUT : $Destination"
|
||||
|
||||
try {
|
||||
Invoke-WebRequest -Uri $Url -OutFile $Destination -UseBasicParsing -ErrorAction Stop
|
||||
Write-Host "[OK] Download completed."
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host "[ERROR] Failed to download: $Url"
|
||||
Write-Host $_.Exception.Message
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
function Extract-Zip {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$ZipPath,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$DestDir
|
||||
)
|
||||
|
||||
Write-Host "[*] Extracting ZIP:"
|
||||
Write-Host " $ZipPath"
|
||||
Write-Host " -> $DestDir"
|
||||
|
||||
# Make sure destination directory exists and is a directory
|
||||
Ensure-EmptyDirectory -Path $DestDir
|
||||
|
||||
# Temporary extraction folder inside destination
|
||||
$TmpExtract = Join-Path $DestDir "__tmp_extract__"
|
||||
Ensure-EmptyDirectory -Path $TmpExtract
|
||||
|
||||
Write-Host "[DEBUG] PowerShell command:"
|
||||
Write-Host " Expand-Archive -LiteralPath `"$ZipPath`" -DestinationPath `"$TmpExtract`" -Force"
|
||||
|
||||
try {
|
||||
Expand-Archive -LiteralPath $ZipPath -DestinationPath $TmpExtract -Force -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
Write-Host "[ERROR] Failed to extract ZIP with Expand-Archive: $ZipPath"
|
||||
Write-Host $_.Exception.Message
|
||||
throw
|
||||
}
|
||||
|
||||
# Check extracted entries
|
||||
$entries = Get-ChildItem -LiteralPath $TmpExtract
|
||||
|
||||
if (-not $entries -or $entries.Count -eq 0) {
|
||||
Write-Host "[ERROR] No entries were extracted from ZIP: $ZipPath"
|
||||
throw "ZIP appears to be empty or extraction failed."
|
||||
}
|
||||
|
||||
if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) {
|
||||
Write-Host "[*] Detected single root directory inside ZIP. Flattening..."
|
||||
|
||||
# Move children of the single root directory into destination
|
||||
$innerItems = Get-ChildItem -LiteralPath $entries[0].FullName
|
||||
foreach ($item in $innerItems) {
|
||||
Move-Item -LiteralPath $item.FullName -Destination $DestDir -Force
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "[*] ZIP has multiple top-level entries. Copying all..."
|
||||
|
||||
foreach ($item in $entries) {
|
||||
Move-Item -LiteralPath $item.FullName -Destination $DestDir -Force
|
||||
}
|
||||
}
|
||||
|
||||
# Clean up temp extraction folder
|
||||
Remove-Item -LiteralPath $TmpExtract -Recurse -Force
|
||||
|
||||
Write-Host "[OK] ZIP extraction completed."
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Extract-TarGz {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$TarGzPath,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$DestDir
|
||||
)
|
||||
|
||||
Write-Host "[*] Extracting TAR.GZ:"
|
||||
Write-Host " $TarGzPath"
|
||||
Write-Host " -> $DestDir"
|
||||
|
||||
Ensure-EmptyDirectory -Path $DestDir
|
||||
|
||||
# Modern Windows ships with tar, but we validate its presence
|
||||
$tarCmd = Get-Command tar -ErrorAction SilentlyContinue
|
||||
if (-not $tarCmd) {
|
||||
Write-Host "[ERROR] 'tar' command not found. Cannot extract TAR.GZ."
|
||||
throw "tar command not found."
|
||||
}
|
||||
|
||||
Write-Host "[DEBUG] tar command:"
|
||||
Write-Host " tar -xzf `"$TarGzPath`" -C `"$DestDir`""
|
||||
|
||||
try {
|
||||
& tar -xzf "$TarGzPath" -C "$DestDir"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "tar exit code $LASTEXITCODE"
|
||||
}
|
||||
Write-Host "[OK] TAR.GZ extraction completed."
|
||||
Write-Host ""
|
||||
}
|
||||
catch {
|
||||
Write-Host "[ERROR] Failed to extract TAR.GZ: $TarGzPath"
|
||||
Write-Host $_.Exception.Message
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ================================
|
||||
# SET DOWNLOAD URLS BASED ON ARCH
|
||||
# ================================
|
||||
$PythonUrl = $null
|
||||
$CurlUrl = $null
|
||||
$YaraUrl = $null
|
||||
$WamrUrl = $null
|
||||
|
||||
switch ($arch) {
|
||||
"x64" {
|
||||
# Python embeddable (x64)
|
||||
$PythonUrl = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-embeddable-amd64.zip"
|
||||
|
||||
# curl (x64, mingw)
|
||||
$CurlUrl = "https://curl.se/windows/latest.cgi?p=win64-mingw.zip"
|
||||
|
||||
# YARA (x64, GitHub — as you specified)
|
||||
$YaraUrl = "https://github.com/VirusTotal/yara/releases/download/v4.5.5/yara-4.5.5-2368-win64.zip"
|
||||
|
||||
# WAMR (x64 only)
|
||||
$WamrUrl = "https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/WAMR-2.4.3/iwasm-2.4.3-x86_64-windows-2022.tar.gz"
|
||||
}
|
||||
|
||||
"arm64" {
|
||||
# Python embeddable (ARM64)
|
||||
$PythonUrl = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-embeddable-arm64.zip"
|
||||
|
||||
# curl (ARM64)
|
||||
$CurlUrl = "https://curl.se/windows/latest.cgi?p=win64a-mingw.zip"
|
||||
|
||||
# DO NOT install YARA/WAMR on ARM64
|
||||
$YaraUrl = $null
|
||||
$WamrUrl = $null
|
||||
}
|
||||
|
||||
default {
|
||||
# Treat anything else as x86
|
||||
# Python embeddable (x86)
|
||||
$PythonUrl = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-embeddable-win32.zip"
|
||||
|
||||
# curl (x86)
|
||||
$CurlUrl = "https://downloads.sourceforge.net/project/muldersoft/cURL/curl-8.17.0-win-x86-full.2025-11-09.zip";
|
||||
|
||||
# Do NOT install YARA/WAMR on x86 (same policy as before)
|
||||
$YaraUrl = $null
|
||||
$WamrUrl = $null
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "[*] Python URL: $PythonUrl"
|
||||
Write-Host "[*] curl URL : $CurlUrl"
|
||||
if ($YaraUrl) {
|
||||
Write-Host "[*] YARA URL : $YaraUrl"
|
||||
} else {
|
||||
Write-Host "[*] YARA : skipped on this architecture"
|
||||
}
|
||||
if ($WamrUrl) {
|
||||
Write-Host "[*] WAMR URL : $WamrUrl"
|
||||
} else {
|
||||
Write-Host "[*] WAMR : skipped on this architecture"
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
|
||||
# ================================
|
||||
# DOWNLOAD FILES
|
||||
# ================================
|
||||
$PythonZip = Join-Path $TmpDir "python.zip"
|
||||
$CurlZip = Join-Path $TmpDir "curl.zip"
|
||||
$YaraZip = Join-Path $TmpDir "yara.zip"
|
||||
$WamrTgz = Join-Path $TmpDir "wamr.tar.gz"
|
||||
|
||||
try {
|
||||
Download-File -Url $PythonUrl -Destination $PythonZip
|
||||
Download-File -Url $CurlUrl -Destination $CurlZip
|
||||
|
||||
if ($YaraUrl) {
|
||||
Download-File -Url $YaraUrl -Destination $YaraZip
|
||||
}
|
||||
|
||||
if ($WamrUrl) {
|
||||
Download-File -Url $WamrUrl -Destination $WamrTgz
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "[FATAL] Download phase failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# ================================
|
||||
# EXTRACT FILES
|
||||
# ================================
|
||||
try {
|
||||
Extract-Zip -ZipPath $PythonZip -DestDir (Join-Path $TargetDir "python")
|
||||
Extract-Zip -ZipPath $CurlZip -DestDir (Join-Path $TargetDir "curl")
|
||||
|
||||
if ($YaraUrl) {
|
||||
Extract-Zip -ZipPath $YaraZip -DestDir (Join-Path $TargetDir "yara")
|
||||
}
|
||||
|
||||
if ($WamrUrl) {
|
||||
Extract-TarGz -TarGzPath $WamrTgz -DestDir (Join-Path $TargetDir "wamr")
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "[FATAL] Extraction phase failed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# ================================
|
||||
# FINISH
|
||||
# ================================
|
||||
Write-Host "[*] All tools installed successfully."
|
||||
Write-Host "[*] Installed into: $TargetDir"
|
||||
Write-Host ""
|
||||
exit 0
|
||||
231
data/korea_business_areacode.json
Normal file
231
data/korea_business_areacode.json
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
{
|
||||
"title": "Korea Business Number Area Code",
|
||||
"author": "Namhyeon Go <gnh1201@catswords.re.kr>, WelsonJS OSS team",
|
||||
"website": "https://github.com/gnh1201/welsonjs",
|
||||
"created_on": "2025-11-19",
|
||||
"data": {
|
||||
"seoul": [
|
||||
100,
|
||||
101,
|
||||
104,
|
||||
105,
|
||||
106,
|
||||
107,
|
||||
108,
|
||||
109,
|
||||
110,
|
||||
113,
|
||||
114,
|
||||
117,
|
||||
119,
|
||||
120,
|
||||
145,
|
||||
146,
|
||||
147,
|
||||
201,
|
||||
204,
|
||||
206,
|
||||
209,
|
||||
210,
|
||||
211,
|
||||
212,
|
||||
214,
|
||||
215,
|
||||
217,
|
||||
220,
|
||||
230
|
||||
],
|
||||
"incheon": [
|
||||
121,
|
||||
122,
|
||||
131,
|
||||
137,
|
||||
150,
|
||||
234,
|
||||
800
|
||||
],
|
||||
"busan": [
|
||||
600,
|
||||
602,
|
||||
603,
|
||||
605,
|
||||
606,
|
||||
607,
|
||||
617,
|
||||
621,
|
||||
623
|
||||
],
|
||||
"daegu": [
|
||||
500,
|
||||
502,
|
||||
503,
|
||||
504,
|
||||
514,
|
||||
516
|
||||
],
|
||||
"gwangju": [
|
||||
400,
|
||||
408,
|
||||
409,
|
||||
410,
|
||||
419
|
||||
],
|
||||
"daejeon": [
|
||||
300,
|
||||
305,
|
||||
314,
|
||||
318
|
||||
],
|
||||
"ulsan": [
|
||||
610,
|
||||
620
|
||||
],
|
||||
"sejong": [
|
||||
320
|
||||
],
|
||||
"gyeonggi": [
|
||||
123,
|
||||
124,
|
||||
125,
|
||||
126,
|
||||
127,
|
||||
128,
|
||||
129,
|
||||
130,
|
||||
132,
|
||||
134,
|
||||
135,
|
||||
138,
|
||||
140,
|
||||
141,
|
||||
142,
|
||||
143,
|
||||
144,
|
||||
149,
|
||||
151,
|
||||
152,
|
||||
200,
|
||||
231,
|
||||
232,
|
||||
233,
|
||||
235,
|
||||
236
|
||||
],
|
||||
"gangwon": [
|
||||
221,
|
||||
222,
|
||||
223,
|
||||
224,
|
||||
225,
|
||||
226,
|
||||
227
|
||||
],
|
||||
"chungbuk": [
|
||||
301,
|
||||
302,
|
||||
303,
|
||||
304,
|
||||
317
|
||||
],
|
||||
"chungnam": [
|
||||
307,
|
||||
308,
|
||||
310,
|
||||
311,
|
||||
312,
|
||||
313,
|
||||
316,
|
||||
319
|
||||
],
|
||||
"jeonbuk": [
|
||||
401,
|
||||
402,
|
||||
403,
|
||||
404,
|
||||
407,
|
||||
418
|
||||
],
|
||||
"jeonnam": [
|
||||
411,
|
||||
412,
|
||||
415,
|
||||
416,
|
||||
417
|
||||
],
|
||||
"gyeongbuk": [
|
||||
505,
|
||||
506,
|
||||
507,
|
||||
508,
|
||||
510,
|
||||
511,
|
||||
512,
|
||||
513,
|
||||
515
|
||||
],
|
||||
"gyeongnam": [
|
||||
608,
|
||||
609,
|
||||
611,
|
||||
612,
|
||||
613,
|
||||
615,
|
||||
624
|
||||
],
|
||||
"jeju": [
|
||||
616
|
||||
],
|
||||
"p_seoul": [
|
||||
116,
|
||||
775
|
||||
],
|
||||
"p_incheon": [
|
||||
172,
|
||||
139
|
||||
],
|
||||
"p_gyeonggi": [
|
||||
696,
|
||||
276,
|
||||
585,
|
||||
133,
|
||||
687,
|
||||
509,
|
||||
581,
|
||||
557,
|
||||
405,
|
||||
727,
|
||||
514,
|
||||
371
|
||||
],
|
||||
"p_busan": [
|
||||
825,
|
||||
644,
|
||||
449
|
||||
],
|
||||
"p_daejeon": [
|
||||
306
|
||||
],
|
||||
"p_sejong": [
|
||||
330,
|
||||
698
|
||||
],
|
||||
"p_gwangju": [
|
||||
256
|
||||
],
|
||||
"p_gyeongbuk": [
|
||||
568
|
||||
],
|
||||
"p_chungnam": [
|
||||
709,
|
||||
294
|
||||
],
|
||||
"p_chungbuk": [
|
||||
203,
|
||||
136
|
||||
],
|
||||
"p_jeonbuk": [
|
||||
586,
|
||||
704
|
||||
]
|
||||
}
|
||||
}
|
||||
57
examples/korea_biz_area_checker.js
Normal file
57
examples/korea_biz_area_checker.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// korea_biz_area_checker.js
|
||||
// Namhyeon Go <gnh1201@catswords.re.kr>, WelsonJS OSS team
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
var Office = require("lib/msoffice");
|
||||
|
||||
function main(args) {
|
||||
// Business Area Code in Korea
|
||||
console.log("> Business Area Code in Korea");
|
||||
var data_biz_areacode = JSON.parse(FILE.readFile("data/korea_business_areacode.json")).data;
|
||||
console.log(JSON.stringify(data_biz_areacode));
|
||||
|
||||
// Open the Microsoft Excel file
|
||||
console.log("> Open the Microsoft Excel file");
|
||||
var excel = new Office.Excel();
|
||||
excel.open("data\\example.xlsx");
|
||||
|
||||
// Retrieve the business area code
|
||||
for (var i = 3; i < 1233; i++) {
|
||||
try {
|
||||
// check the biz area name
|
||||
console.log(">> check the biz area name");
|
||||
var areaname = excel.getCellByPosition(i, 16).getValue();
|
||||
if (!!areaname)
|
||||
continue;
|
||||
|
||||
// check the biz number
|
||||
console.log(">> check the biz number");
|
||||
var biznumber = excel.getCellByPosition(i, 8).getValue();
|
||||
if (!biznumber)
|
||||
continue;
|
||||
|
||||
// match the biznumber to biz area code data
|
||||
console.log(">> match the biznumber to biz area code data: " + biznumber);
|
||||
var matched_areaname = "unknown";
|
||||
for (var k in data_biz_areacode) {
|
||||
var areacode = parseInt(biznumber.substring(0, 3));
|
||||
if (data_biz_areacode[k].indexOf(areacode) > -1) {
|
||||
matched_areaname = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(">> write the matched area name: " + matched_areaname);
|
||||
excel.getCellByPosition(i, 16).setValue(matched_areaname);
|
||||
} catch (e) {
|
||||
excel.getCellByPosition(i, 16).setValue("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
excel.saveAs("example_edited.xlsx");
|
||||
|
||||
excel.close();
|
||||
}
|
||||
|
||||
exports.main = main;
|
||||
|
|
@ -15,6 +15,8 @@ function main(args) {
|
|||
console.error("lib/http: Something wrong");
|
||||
}
|
||||
|
||||
sleep(100000);
|
||||
|
||||
//Toolkit.create();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,11 @@ var HTTPObject = function(engine) {
|
|||
} else if (this.engine == "CURL") {
|
||||
this._interface = SHELL.create();
|
||||
|
||||
// the location of cURL binary
|
||||
// set cURL executable file location
|
||||
var default_curl_path = SYS.getAppDataDir() + "\\curl\\curl.exe";
|
||||
if (FILE.fileExists(default_curl_path)) {
|
||||
this.setBinPath(default_curl_path);
|
||||
} else {
|
||||
var arch = SYS.getArch();
|
||||
if (arch.toLowerCase().indexOf("arm") > -1) {
|
||||
this.setBinPath("bin\\arm64\\curl-" + this.curlVersion + "-win64a-mingw\\bin\\curl.exe");
|
||||
|
|
@ -128,6 +132,7 @@ var HTTPObject = function(engine) {
|
|||
} else {
|
||||
this.setBinPath("bin\\x86\\curl-" + this.curlVersion + "-win32-mingw\\bin\\curl.exe");
|
||||
}
|
||||
}
|
||||
|
||||
// do not clear after calling the `exec`
|
||||
this._interface.setIsPreventClear(true);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
// ovftool.js
|
||||
// Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// Download OVFTool (Open Virtualization Format (OVF) Tool):
|
||||
// https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest
|
||||
//
|
||||
var SYS = require("lib/system");
|
||||
var SHELL = require("lib/shell");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function OVFObject() {
|
||||
this.binPath = "bin\\x64\\VMware-ovftool-4.6.3-24031167-win.x86_64\\ovftool\\ovftool.exe";
|
||||
this.binPath = SYS.getAppDataDir() + "\\ovftool\\ovftool.exe";
|
||||
this.hostname = "";
|
||||
this.port = 443;
|
||||
this.resourceName = "";
|
||||
|
|
@ -66,7 +67,7 @@ function create() {
|
|||
exports.setCredential = setCredential;
|
||||
exports.create = create;
|
||||
|
||||
exports.VERSIONINFO = "Broadcom/VMware OVF Tool interface (ovftool.js) version 0.1.2";
|
||||
exports.VERSIONINFO = "Broadcom/VMware OVF Tool interface (ovftool.js) version 0.1.3";
|
||||
exports.AUTHOR = "gnh1201@catswords.re.kr";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// python3.js
|
||||
// Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
|
|
@ -7,12 +7,17 @@
|
|||
//
|
||||
var SYS = require("lib/system");
|
||||
var SHELL = require("lib/shell");
|
||||
var FILE = require("lib/file");
|
||||
|
||||
function PythonObject() {
|
||||
this.binPath = null;
|
||||
this.version = "3.13.2";
|
||||
|
||||
this.create = function() {
|
||||
var default_python3_path = SYS.getAppDataDir() + "\\python\\python.exe";
|
||||
if (FILE.fileExists(default_python3_path)) {
|
||||
this.setBinPath(default_python3_path);
|
||||
} else {
|
||||
var arch = SYS.getArch();
|
||||
if (arch.toLowerCase().indexOf("arm") > -1) {
|
||||
this.setBinPath("bin\\arm64\\python-" + this.version + "-embed-arm64\\python.exe");
|
||||
|
|
@ -21,6 +26,7 @@ function PythonObject() {
|
|||
} else {
|
||||
this.setBinPath("bin\\x86\\python-" + this.version + "-embed-win32\\python.exe");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.setBinPath = function(binPath) {
|
||||
|
|
@ -45,6 +51,9 @@ function PythonObject() {
|
|||
scriptName
|
||||
].concat(args));
|
||||
};
|
||||
|
||||
// Initialize default Python binary path based on current version and system arch
|
||||
this.create();
|
||||
}
|
||||
|
||||
exports.PythonObject = PythonObject;
|
||||
|
|
@ -57,6 +66,6 @@ exports.execScript = function(scriptName, args) {
|
|||
return (new PythonObject()).execScript(scriptName, args);
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "Python Interface (python3.js) version 0.2.1";
|
||||
exports.VERSIONINFO = "Python Interface (python3.js) version 0.2.2";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ function getEnvString(envName) {
|
|||
})(envName.toUpperCase());
|
||||
}
|
||||
|
||||
function getAppDataDir() {
|
||||
return getEnvString("APPDATA") + "\\WelsonJS";
|
||||
}
|
||||
|
||||
function get32BitFolder() {
|
||||
var base = getEnvString("WINDIR");
|
||||
var syswow64 = base + "\\SysWOW64\\";
|
||||
|
|
@ -198,6 +202,7 @@ function getProcessVersion() {
|
|||
|
||||
exports.createProcess = createProcess;
|
||||
exports.getEnvString = getEnvString;
|
||||
exports.getAppDataDir = getAppDataDir;
|
||||
exports.get32BitFolder = get32BitFolder;
|
||||
exports.isElevated = isElevated;
|
||||
exports.getOS = getOS;
|
||||
|
|
@ -219,6 +224,6 @@ exports.createShortcut = createShortcut;
|
|||
exports.ping = ping;
|
||||
exports.getProcessVersion = getProcessVersion;
|
||||
|
||||
exports.VERSIONINFO = "System Module (system.js) version 0.1.5";
|
||||
exports.VERSIONINFO = "System Module (system.js) version 0.1.6";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
11
lib/wamr.js
11
lib/wamr.js
|
|
@ -1,15 +1,16 @@
|
|||
// wamr.js
|
||||
// Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// WAMR(WebAssembly Micro Runtime) integration for WelsonJS framework
|
||||
// WAMR(WebAssembly Micro Runtime) integration
|
||||
// https://github.com/bytecodealliance/wasm-micro-runtime
|
||||
//
|
||||
var SYS = require("lib/system");
|
||||
var SHELL = require("lib/shell");
|
||||
|
||||
var WAMRObject = function() {
|
||||
this.binPath = "bin\\iwasm";
|
||||
this.binPath = SYS.getAppDataDir() + "\\wamr\\iwasm.exe";
|
||||
|
||||
this.verbose = 0;
|
||||
this.stackSize = 0;
|
||||
|
|
@ -60,3 +61,7 @@ var WAMRObject = function() {
|
|||
exports.create = function() {
|
||||
return new WAMRObject();
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "WAMR(WebAssembly Micro Runtime) integration (wamr.js) version 0.1.1";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
13
setup.iss
13
setup.iss
|
|
@ -25,12 +25,24 @@ DisableWelcomePage=yes
|
|||
DisableDirPage=yes
|
||||
DisableProgramGroupPage=yes
|
||||
LicenseFile=SECURITY.MD
|
||||
ChangesAssociations=yes
|
||||
|
||||
; [Registry]
|
||||
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueData: "URL:{cm:AppName}"; Flags: uninsdeletekey
|
||||
; Root: HKCR; Subkey: "welsonjs"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: ""
|
||||
; Root: HKCR; Subkey: "welsonjs\DefaultIcon"; ValueType: "string"; ValueData: "{app}\app\favicon.ico,0"
|
||||
; Root: HKCR; Subkey: "welsonjs\shell\open\command"; ValueType: "string"; ValueData: "cscript ""{app}\app.js"" uriloader ""%1"""
|
||||
Root: HKCR; Subkey: "WelsonJS.Script"; ValueType: string; ValueData: "WelsonJS Script"; Flags: uninsdeletekey
|
||||
Root: HKCR; Subkey: "WelsonJS.Script\DefaultIcon"; ValueType: string; ValueData: "{app}\app\favicon.ico,0"; Flags: uninsdeletekey
|
||||
Root: HKCR; Subkey: "WelsonJS.Script\shell"; ValueType: string; ValueData: "open"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: "WelsonJS.Script\shell\open"; ValueType: string; ValueData: "Run with WelsonJS"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: "WelsonJS.Script\shell\open\command"; ValueType: string; ValueData: """{app}\bin\x86\WelsonJS.Launcher.exe"" --file ""%1"""; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".js"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".ts"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".re"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".res"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".ls"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
Root: HKCR; Subkey: ".coffee"; ValueType: string; ValueData: "WelsonJS.Script"; Flags: uninsdeletevalue
|
||||
|
||||
[Files]
|
||||
Source: "app.js"; DestDir: "{app}";
|
||||
|
|
@ -72,6 +84,7 @@ Name: "{group}\Uninstall {cm:AppName}"; Filename: "{uninstallexe}"; AfterInstall
|
|||
; Filename: {app}\bin\gtk2-runtime-2.24.33-2021-01-30-ts-win64.exe;
|
||||
; Filename: {app}\bin\nmap-7.92\VC_redist.x86.exe;
|
||||
; Filename: {app}\bin\nmap-7.92\npcap-1.50.exe;
|
||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\afterInstall.ps1"""; WorkingDir: "{app}"; Flags: nowait
|
||||
Filename: {app}\installService.bat; Flags: nowait
|
||||
Filename: {app}\bin\x86\WelsonJS.Launcher.exe; Flags: nowait
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user