Compare commits

...

87 Commits

Author SHA1 Message Date
aee5fb22d0
Merge pull request #245 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add JavaScript CDN servers
2025-05-05 23:44:59 +09:00
14c8b12df7 Add a CDN servers 2025-05-05 23:32:41 +09:00
deed89560b Update ResourceServer.cs 2025-05-05 23:22:02 +09:00
eb32437f96 Update ResourceServer.cs 2025-05-05 21:34:50 +09:00
c95b7a373b Update ResourceServer.cs 2025-05-05 21:33:06 +09:00
302e7ce4fc Add an available CDN servers 2025-05-05 19:13:41 +09:00
a5fc5de78f Update ResourceServer.cs 2025-05-05 17:47:50 +09:00
d362d852ad Add JavaScript CDN servers 2025-05-05 17:38:48 +09:00
2a3f9fb4fa
Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-01 14:32:48 +09:00
944751121c
Merge pull request #243 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add the example to use function calling on LLM
2025-04-27 13:14:27 +09:00
fb420d1116 Add the example to use function calling on LLM 2025-04-27 13:09:03 +09:00
26af578178
Merge pull request #242 from gnh1201/dev
Set throttle to the prompt context
2025-04-27 11:43:52 +09:00
245dd85341 Update editor.html 2025-04-27 11:39:43 +09:00
fb6596fe64 Update editor.html 2025-04-27 11:10:00 +09:00
a42180d244 Set throttle to the prompt context 2025-04-27 10:50:52 +09:00
73b24f9a56
Merge pull request #240 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix bug when use DevTools CORS policy (WebSocket error)
2025-04-22 21:31:37 +09:00
eae2795bbf Update Program.cs 2025-04-22 21:27:23 +09:00
98e73b2372 Fix bug when use the devtools protocol with the remote allow origins (Fix WebSocket error) 2025-04-22 21:26:42 +09:00
2225ab9011
Merge pull request #239 from gnh1201/dev
Improve WelsonJS Editor with React framework
2025-04-18 19:51:56 +09:00
4c0895850b Update the integrity attributes 2025-04-18 19:48:41 +09:00
ea412908ef Update editor.html 2025-04-18 19:31:23 +09:00
05ea48a0be some updates 2025-04-18 19:22:25 +09:00
243ff95198 Migrate to React framework 2025-04-18 01:06:27 +09:00
8341394912
Merge pull request #238 from gnh1201/dev
Forward Whois and DNS query data to LLM services
2025-04-12 14:34:59 +09:00
e5a89c9182 Forward Whois and DNS query data to LLM services
Forward Whois and DNS query data to LLM services (e.g. Server configuration assistant)
2025-04-12 14:24:59 +09:00
df5b8cd9f0
Merge pull request #237 from gnh1201/dev
Add support the Azure AI, Optimize the HTTPClient object uses.
2025-04-11 14:19:55 +09:00
e7b6a87175 Reduce code complexity 2025-04-11 14:15:03 +09:00
5b2863058a Add support the Azure AI, Optimize the HTTPClient object uses. 2025-04-11 13:44:21 +09:00
cd8844afef
Merge pull request #236 from gnh1201/dev
Update the markdown files
2025-04-10 16:34:47 +09:00
b26d979b8d Update the markdown files 2025-04-10 16:12:43 +09:00
5446a1bee0
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:18 +09:00
10101986be
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:09 +09:00
47a5f50712
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:01 +09:00
86517f313c
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:55:48 +09:00
b6d34404b5 Update README.md 2025-04-10 13:50:37 +09:00
88ac0cd31e Update README.md 2025-04-10 13:41:57 +09:00
3e0fd7c532 Update README.md, SECURITY.MD 2025-04-10 13:39:23 +09:00
22d10cd28b
Merge pull request #235 from gnh1201/dev
Update SECURITY.MD
2025-04-10 13:29:19 +09:00
0e95b72b21 Update SECURITY.MD 2025-04-10 13:23:16 +09:00
426a9d7721
Merge pull request #234 from gnh1201/dev
Update 2025-04-10
2025-04-10 02:29:10 +09:00
d42210f922
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-04-10 02:27:42 +09:00
e853003bda
Merge branch 'master' into dev 2025-04-10 02:26:21 +09:00
8ca4faa88a
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 02:23:24 +09:00
f84f2195c3 Revert Cache Compression 2025-04-10 02:12:28 +09:00
1742ca385b Update AzureAi.cs 2025-04-10 02:00:18 +09:00
2a9ebaff51 Update AzureAi.cs 2025-04-10 01:48:33 +09:00
916154499c Some updates 2025-04-09 19:58:41 +09:00
53a84b2349 Update README.md 2025-04-07 14:45:25 +09:00
6e3eb5c1d3 Update README.md 2025-04-07 14:44:03 +09:00
4b4754ae16 Update README.md 2025-04-07 14:43:27 +09:00
a273d6aac6 Update README.md 2025-04-07 14:41:56 +09:00
9e1878628b Update README.md 2025-04-07 14:33:47 +09:00
04ce7fdae5 Update README.md, SECURITY.MD 2025-04-07 14:31:11 +09:00
f7de7bd430 Add Cache Compression 2025-04-06 15:23:19 +09:00
ab8a864519
Update README.md 2025-04-05 23:32:10 +09:00
427f8dded0
Update README.md 2025-04-05 23:24:54 +09:00
a96764f725
Update README.md 2025-04-05 23:24:17 +09:00
46d0244c34
Merge pull request #221 from gnh1201/dev
Add the cached blob #220
2025-04-05 20:13:40 +09:00
2cb3c1c331 Add the cached blob 2025-04-05 20:05:23 +09:00
231e6a56bd
Merge pull request #219 from gnh1201/dev
Change the remote blob server to localhost
2025-04-05 17:47:25 +09:00
295ad2fca8 Update ResourceServer.cs 2025-04-05 17:43:34 +09:00
9ecc93a399 Update ResourceServer.cs 2025-04-05 17:42:44 +09:00
2896cc6bf1 Some updates 2025-04-05 17:27:38 +09:00
be37951807 Add the blob server gateway 2025-04-05 17:10:19 +09:00
d38e26ba67
Merge pull request #218 from gnh1201/dev
Refactor an endpoints of the web based editor
2025-04-05 15:24:50 +09:00
dd85e98c9a Some updates 2025-04-05 15:16:15 +09:00
d8fa8779de Refactor an endpoints of the web based editor 2025-04-05 12:53:28 +09:00
f6fd43ae50
Merge pull request #214 from gnh1201/dev
Add Azure AI service (Azure AI Foundry), Add the AppConfig manager
2025-04-02 11:34:00 +09:00
96dbe7b2cd Add Azure AI service (Azure AI Foundry), Add the AppConfig manager 2025-04-02 11:25:23 +09:00
c1fe39d3cc
Merge pull request #213 from gnh1201/dev
Adapt a code review, SRI, CORS, etc.
2025-03-31 17:41:01 +09:00
56ee12741c some updates 2025-03-31 17:09:28 +09:00
4372bdb09d some updates 2025-03-31 16:59:56 +09:00
b21f967a6a Update bootstrap.bat 2025-03-31 16:31:07 +09:00
40b0b704e3 some updates 2025-03-31 15:06:03 +09:00
9a8ee4d7f9 some updates 2025-03-31 14:50:02 +09:00
4f319d474f some updates 2025-03-31 14:18:03 +09:00
93ed60bcf7 some updates 2025-03-31 14:16:35 +09:00
5d717505f4 Edit the codes from code review result 2025-03-30 22:24:35 +09:00
b0e50d33bc Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-03-30 21:12:10 +09:00
c0f9816000 Update editor.html 2025-03-30 20:50:54 +09:00
00ea473683 set SRI and CORS policy strictly to editor.html 2025-03-30 20:48:03 +09:00
7e9054fb8f
Merge pull request #203 from gnh1201/dev
Revert "Reduce SAS token period to 2 years"
2025-03-27 18:02:51 +09:00
f29a63027f Revert "Reduce SAS token period to 2 years"
This reverts commit e930cf86fd.
2025-03-27 17:55:13 +09:00
3419e62c6a
Merge pull request #202 from gnh1201/dev
Change the blob download server
2025-03-27 17:50:53 +09:00
e930cf86fd Reduce SAS token period to 2 years 2025-03-27 17:42:58 +09:00
c0a27efd8d Update bootstrap.bat 2025-03-27 17:35:10 +09:00
d42539c0a8
Update README.md 2025-03-26 11:44:37 +09:00
28 changed files with 2188 additions and 1198 deletions

114
README.md
View File

@ -20,21 +20,22 @@ Now, You can build a Windows desktop app with JavaScript, TypeScript, CoffeeScri
WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + :heart:[Contributions](https://github.com/sponsors/gnh1201)
:kissing_cat: [Download Latest WelsonJS Launcher (ics.catswords.net)](https://ics.catswords.net/welsonjs_launcher_latest.zip)
* :kissing_cat: [Download Latest WelsonJS Launcher (ics.catswords.net)](https://ics.catswords.net/welsonjs_launcher_latest.zip)
* :rocket: [Launch the WelsonJS environment on Microsoft Azure (azuremarketplace.microsoft.com)](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/catswords.catswords-welsonjs-feb2025-02?tab=Overview)
**Note**: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
## Sponsors
- :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201)
- <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> [Open Software Portal](https://oss.kr), Korea National Industry Promotion Agency - Awarded Prize
- <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
- <img src="https://ics.catswords.net/f1security_logo.png" height="32" alt=""/> [F1Security](https://azuremarketplace.microsoft.com/ko-kr/marketplace/apps/1599123192819.uwss?tab=overview) provides web security services designed by [industry-leading experts](https://www.ksecurity.or.kr/kisis/subIndex/469.do).
- <img src="https://ics.catswords.net/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools.
- :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [Coupang](https://link.coupang.com/a/b7HV3V)...)
* :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201), :coffee: [Buy me a coffee](https://buymeacoffee.com/catswords)
* <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> [Open SW Portal](https://oss.kr), NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>
* <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
* <img src="https://ics.catswords.net/f1security_logo.png" height="32" alt=""/> [F1Security<sup>(에프원시큐리티)</sup>](https://f1security.co.kr/) provides [industry-leading](https://www.ksecurity.or.kr/kisis/subIndex/469.do) web security services.
* <img src="https://ics.catswords.net/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools.
* :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [Coupang](https://link.coupang.com/a/b7HV3V)...)
## System Requirements
- **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2)
- For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately.
* **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2)
* For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately.
## Why Choose WelsonJS?
WelsonJS is an advanced JavaScript framework designed to operate in extreme conditions where conventional solutions may fail. Unlike traditional JavaScript frameworks, WelsonJS focuses on executing scripts in constrained environments, ensuring reliable performance even with minimal system resources.
@ -59,23 +60,23 @@ WelsonJS is tailored for developers who need a reliable, lightweight JavaScript
![The structure of the WelsonJS framework can be extended based on whether it operates in a console (command prompt) environment, a GUI (with HTML/CSS) environment, or a service environment, with the `app.js` file at its core.](https://ics.catswords.net/structure.png)
## Specifications
- Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
- **Ready to use on Windows machine immediately. No require additional software installation.**
- **WelsonJS Launcher**: Instance management (You can manage previously run apps), User-defined variable editor (You can pass user-defined variables if needed), [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) (You can edit code without installing an additional editor).
- ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml)
- HTML5, CSS3 compatibility: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr)
- Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout)
- WYSIWYG HTML Editor: [summernote](https://github.com/summernote/summernote)
- Included libraries: [jQuery](https://jquery.com/), [jQuery UI](https://jqueryui.com/), [jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin), [squel](https://github.com/hiddentao/squel), [jsrender](https://github.com/BorisMoore/jsrender), [linq](https://github.com/mihaifm/linq), [pegjs](https://github.com/pegjs/pegjs), [numbers.js](https://github.com/numbers/numbers.js)
- Compatible with modern JavaScript specifications: [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility, [NPM(Node Pacakge Manager)](https://www.npmjs.com/) compatibility
- Support a device debugging protocol clients: [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb)
- RPC(Remote Procedure Call) protocol clients: [gRPC](https://grpc.io/), [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
- Various types of HTTP clients: [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), [Web Proxy, SEO/SERP](https://catswords-oss.rdbl.io/5719744820/1706431912)
- The native toolkit for Windows environments: Write a Windows Service Application with JavaScript, Control a window handle, Cryptography (e.g., [ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do)), [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based [IPC](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5), [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit)
- Generative AI integrations: [Multiple LLM and sLLM](https://catswords-oss.rdbl.io/5719744820/5510319392) (e.g., ChatGPT, Claude, ...)
- Aviation Data integrations: [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [SearchApi Google Flight](https://www.searchapi.io/?via=namhyeon)
- VM infrastucture tool integrations: [OVFTool for Broadcom/VMware infrastructures](https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest)
- Everything you can imagine.
* Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
* **Ready to use on Windows machine immediately. No additional software installation is required.**
* **WelsonJS Launcher**: Manage instances (Like a container), User-defined variable editor, [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) and [React](https://react.dev/) (Pre-embedded rich code editor), [Microsoft Copilot](https://copilot.microsoft.com), and [Azure AI Services](https://azure.microsoft.com/en-us/products/ai-services) on the code editor.
* ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml)
* HTML5 compatibility on the built-in HTML rendering engine: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr)
* Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout)
* WYSIWYG HTML Editor: [summernote](https://github.com/summernote/summernote)
* Included libraries: [jQuery](https://jquery.com/), [jQuery UI](https://jqueryui.com/), [jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin), [squel](https://github.com/hiddentao/squel), [jsrender](https://github.com/BorisMoore/jsrender), [linq](https://github.com/mihaifm/linq), [pegjs](https://github.com/pegjs/pegjs), [numbers.js](https://github.com/numbers/numbers.js)
* Compatible with modern JavaScript specifications: [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility, [NPM(Node Package Manager)](https://www.npmjs.com/) compatibility
* Support a device debugging protocol clients: [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb)
* RPC(Remote Procedure Call) protocol clients: [gRPC](https://grpc.io/), [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
* Various types of HTTP clients: [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), [Web Proxy, SEO/SERP](https://catswords-oss.rdbl.io/5719744820/1706431912)
* The native toolkit for Windows environments: Write a Windows Service Application with JavaScript, Control a window handle, Cryptography (e.g., [ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do)), [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based [IPC](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5), [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit)
* Generative AI integrations: [Multiple LLM and sLLM](https://catswords-oss.rdbl.io/5719744820/5510319392) (e.g., ChatGPT, Claude, ...)
* Aviation Data integrations: [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [SearchApi Google Flight](https://www.searchapi.io/?via=namhyeon)
* VM infrastructure tool integrations: [OVFTool for Broadcom/VMware infrastructures](https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest)
* Everything you can imagine.
## Quick start
@ -119,9 +120,9 @@ ended say()
## How to release my application?
The WelsonJS framework suggests the following application release methods:
- **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779).
- **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included.
- **Copy all directories and files**: This is the simplest and most straightforward method.
* **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779).
* **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included.
* **Copy all directories and files**: This is the simplest and most straightforward method.
## Screenshots
![(Screenshot 1) GUI environment](https://ics.catswords.net/screenshot.png)
@ -139,41 +140,42 @@ The WelsonJS framework suggests the following application release methods:
![(Screenshot 7) Microsoft Monaco Editor on WelsonJS Launcher](https://ics.catswords.net/screenshot7.png)
## Thanks to
- :heart: Artwork (Logo image): [@druidesse](https://github.com/druidesse)
- :heart: Artwork (Cover image): [@_bag0@x.com](https://x.com/_bag0)
- :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment
- :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment
- :sunglasses: Information security companies in Republic of Korea - Use case establishment
- :eyes: [Facebook Group "Javascript Programming"(javascript4u)](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/)
- :eyes: [morioh.com](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css)
- :eyes: CSDN
- :eyes: Qiita - Knowledge-base about WSH environment
- :sunglasses: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
- :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
- :sunglasses: Inspired by the use of Named Shared Memory in an inter-language IPC implementation devised by an unidentified developer.
- :eyes: Fediverse
- :eyes: [Hacker News](https://news.ycombinator.com/item?id=41316782)
- :eyes: [WebToolsWeekly](https://webtoolsweekly.com/archives/issue-585/)
- :eyes: [GeekNews](https://news.hada.io/weekly/202441) in GeekNews Weekly (2024-09-30 ~ 2024-10-06)
- :eyes: [daily.dev](https://app.daily.dev/posts/js-libraries-svg-tools-json-databases-8quregz3a)
- :eyes: [PitchHut](https://www.pitchhut.com/project/proj_Ya136OLSW5at)
- :eyes: [Disquiet](https://dis.qa/nv6T6)
* :heart: Artwork (Logo image): [@druidesse](https://github.com/druidesse)
* :heart: Artwork (Cover image): [@_bag0@x.com](https://x.com/_bag0)
* :heart: Special Contributors: [@hcho3](https://github.com/hcho3), :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201)
* :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment
* :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment
* :sunglasses: Information security companies in Republic of Korea - Use case establishment
* :eyes: [Facebook Group "Javascript Programming"(javascript4u)](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/)
* :eyes: [morioh.com](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css)
* :eyes: CSDN
* :eyes: Qiita - Knowledge-base about WSH environment
* :sunglasses: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
* :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
* :sunglasses: Inspired by the use of Named Shared Memory in a cross-runtime IPC implementation written by the unidentified developer.
* :eyes: Fediverse
* :eyes: [Hacker News](https://news.ycombinator.com/item?id=41316782)
* :eyes: [WebToolsWeekly](https://webtoolsweekly.com/archives/issue-585/)
* :eyes: [GeekNews](https://news.hada.io/weekly/202441) in GeekNews Weekly (2024-09-30 ~ 2024-10-06)
* :eyes: [daily.dev](https://app.daily.dev/posts/js-libraries-svg-tools-json-databases-8quregz3a)
* :eyes: [PitchHut](https://www.pitchhut.com/project/proj_Ya136OLSW5at)
* :eyes: [Disquiet](https://dis.qa/nv6T6)
## Report abuse
- [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
- abuse@catswords.net
* [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
* [abuse@catswords.net](mailto:abuse@catswords.net)
## Join the community
I am always open. Collaboration, opportunities, and community activities are all welcome.
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
- XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
- [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
- [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
## Special channels
- [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean (한국어) region.
- [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.
* [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> region.
* [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.
## License
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large)

View File

@ -9,17 +9,17 @@ This repository contains information on accessing Windows APIs and functions in
## Known Use Cases
WelsonJS is typically used for the following purposes:
* Testing web accessibility and compliance, including adherence to W3C standards (WEB-ARIA, WCAG), national laws (ADA/DDA, GDPR), and other relevant regulations.
* Exploring vulnerabilities of equipment within the local network.
* Improving the availability of VPN or proxy clients.
* Building automation, CI/CD (Continuous Integration/Continuous Delivery), DevOps, and SecOps.
* Asset evaluation (e.g., obtaining purchase history from online shopping and delivery websites).
* Online video streaming quality testing and improvement.
* Office automation and integration with LLM-based AI (e.g., ChatGPT) services.
* Testing web accessibility and compliance, including adherence to W3C standards (WEB-ARIA, WCAG), national laws (ADA/DDA, GDPR), and other relevant regulations.
* Exploring vulnerabilities of equipment within the local network.
* Improving the availability of VPN or proxy clients.
* Building automation, CI/CD (Continuous Integration/Continuous Delivery), DevOps, and SecOps.
* Asset evaluation (e.g., obtaining purchase history from online shopping and delivery websites).
* Online video streaming quality testing and improvement.
* Office automation and integration with LLM-based AI (e.g., ChatGPT) services.
## Notes
1. If you plan to use WelsonJS for a purpose other than those mentioned above, please contact us beforehand.
2. If you are looking for ways to use WelsonJS more efficiently, referencing the [LOLBAS (Living Off The Land Binaries and Scripts)](https://lolbas-project.github.io/) list can be helpful.
1. If you plan to use WelsonJS for a purpose other than those mentioned above, please contact us beforehand.
2. If you are looking for ways to use WelsonJS more efficiently, referencing the [LOLBAS (Living Off The Land Binaries and Scripts)](https://lolbas-project.github.io/) list can be helpful.
## Guidelines
@ -41,22 +41,23 @@ WelsonJS is a project inspired by the requirements of a cloud service provider t
## Alternative Names
This program is also known by the following names. These names are used solely for the purpose of identifying the work and do not impact the license:
- DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384) (CERN/OpenAIRE Zenodo)
- ["284757291"](https://ics.catswords.net/1494315-Certificate%2BSoR-284757291.pdf) (Registered with the [UK Copyright Service](https://copyrightservice.co.uk/))
- ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency, Republic of Korea)
- "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission, Republic of Korea)
- "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea)
* DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384)(2024) (CERN/OpenAIRE Zenodo)
* ["284757291"](https://ics.catswords.net/1494315-Certificate%2BSoR-284757291.pdf)(2024) (Registered with the [UK Copyright Service](https://copyrightservice.co.uk/))
* ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>, Republic of Korea)
* ["2025-02-08-1952"](https://ics.catswords.net/20250410092300005.pdf)(2025) (Technical Data Bailment System (Technology Escrow), "Korea Foundation for Cooperation of Large & Small Business, Rural Affairs"<sup>(대·중소기업·농어업협력재단)</sup>, Republic of Korea)
* "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission<sup>(한국저작권위원회)</sup>, Republic of Korea)
* "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea)
## Report abuse
- [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
- abuse@catswords.net
* [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
* [abuse@catswords.net](mailto:abuse@catswords.net)
## Join the community
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
- XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
- [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
- [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
## Special channels
- [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean (한국어) region.
- [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.
* [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> region.
* [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.

View File

@ -28,11 +28,11 @@
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.listView1 = new System.Windows.Forms.ListView();
this.gbUserDefinedVariables = new System.Windows.Forms.GroupBox();
this.lvUserDefinedVariables = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.gbUpdateUserDefinedVariable = new System.Windows.Forms.GroupBox();
this.checkDeleteVariable = new System.Windows.Forms.CheckBox();
this.btnOk = new System.Windows.Forms.Button();
this.btnOpenFile = new System.Windows.Forms.Button();
@ -41,39 +41,36 @@
this.textSetName = new System.Windows.Forms.TextBox();
this.labelSetValue = new System.Windows.Forms.Label();
this.labelSetName = new System.Windows.Forms.Label();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.gbImportAndExport = new System.Windows.Forms.GroupBox();
this.btnExport = new System.Windows.Forms.Button();
this.btnImport = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.gbUserDefinedVariables.SuspendLayout();
this.gbUpdateUserDefinedVariable.SuspendLayout();
this.gbImportAndExport.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
// gbUserDefinedVariables
//
this.groupBox1.Controls.Add(this.listView1);
this.groupBox1.Location = new System.Drawing.Point(17, 18);
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox1.Size = new System.Drawing.Size(599, 255);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "User-defined variables";
this.gbUserDefinedVariables.Controls.Add(this.lvUserDefinedVariables);
this.gbUserDefinedVariables.Location = new System.Drawing.Point(12, 12);
this.gbUserDefinedVariables.Name = "gbUserDefinedVariables";
this.gbUserDefinedVariables.Size = new System.Drawing.Size(419, 170);
this.gbUserDefinedVariables.TabIndex = 0;
this.gbUserDefinedVariables.TabStop = false;
this.gbUserDefinedVariables.Text = "User-defined variables";
//
// listView1
// lvUserDefinedVariables
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.lvUserDefinedVariables.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(23, 39);
this.listView1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(550, 192);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1_SelectedIndexChanged);
this.lvUserDefinedVariables.HideSelection = false;
this.lvUserDefinedVariables.Location = new System.Drawing.Point(16, 26);
this.lvUserDefinedVariables.Name = "lvUserDefinedVariables";
this.lvUserDefinedVariables.Size = new System.Drawing.Size(386, 129);
this.lvUserDefinedVariables.TabIndex = 0;
this.lvUserDefinedVariables.UseCompatibleStateImageBehavior = false;
this.lvUserDefinedVariables.SelectedIndexChanged += new System.EventHandler(this.lvUserDefinedVariables_SelectedIndexChanged);
//
// columnHeader1
//
@ -83,32 +80,29 @@
//
this.columnHeader2.Text = "Value";
//
// groupBox2
// gbUpdateUserDefinedVariable
//
this.groupBox2.Controls.Add(this.checkDeleteVariable);
this.groupBox2.Controls.Add(this.btnOk);
this.groupBox2.Controls.Add(this.btnOpenFile);
this.groupBox2.Controls.Add(this.btnOpenDirectory);
this.groupBox2.Controls.Add(this.textSetValue);
this.groupBox2.Controls.Add(this.textSetName);
this.groupBox2.Controls.Add(this.labelSetValue);
this.groupBox2.Controls.Add(this.labelSetName);
this.groupBox2.Location = new System.Drawing.Point(17, 282);
this.groupBox2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox2.Size = new System.Drawing.Size(599, 344);
this.groupBox2.TabIndex = 1;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Update the user-defined variable";
this.gbUpdateUserDefinedVariable.Controls.Add(this.checkDeleteVariable);
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOk);
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOpenFile);
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOpenDirectory);
this.gbUpdateUserDefinedVariable.Controls.Add(this.textSetValue);
this.gbUpdateUserDefinedVariable.Controls.Add(this.textSetName);
this.gbUpdateUserDefinedVariable.Controls.Add(this.labelSetValue);
this.gbUpdateUserDefinedVariable.Controls.Add(this.labelSetName);
this.gbUpdateUserDefinedVariable.Location = new System.Drawing.Point(12, 188);
this.gbUpdateUserDefinedVariable.Name = "gbUpdateUserDefinedVariable";
this.gbUpdateUserDefinedVariable.Size = new System.Drawing.Size(419, 229);
this.gbUpdateUserDefinedVariable.TabIndex = 1;
this.gbUpdateUserDefinedVariable.TabStop = false;
this.gbUpdateUserDefinedVariable.Text = "Update the user-defined variable";
//
// checkDeleteVariable
//
this.checkDeleteVariable.AutoSize = true;
this.checkDeleteVariable.Location = new System.Drawing.Point(44, 132);
this.checkDeleteVariable.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.checkDeleteVariable.Location = new System.Drawing.Point(31, 88);
this.checkDeleteVariable.Name = "checkDeleteVariable";
this.checkDeleteVariable.Size = new System.Drawing.Size(178, 22);
this.checkDeleteVariable.Size = new System.Drawing.Size(131, 16);
this.checkDeleteVariable.TabIndex = 7;
this.checkDeleteVariable.Text = "Delete this variable";
this.checkDeleteVariable.UseVisualStyleBackColor = true;
@ -116,10 +110,9 @@
// btnOk
//
this.btnOk.Image = global::WelsonJS.Launcher.Properties.Resources.icon_check_32;
this.btnOk.Location = new System.Drawing.Point(433, 184);
this.btnOk.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnOk.Location = new System.Drawing.Point(303, 123);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(123, 129);
this.btnOk.Size = new System.Drawing.Size(86, 86);
this.btnOk.TabIndex = 6;
this.btnOk.Text = "Ok";
this.btnOk.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
@ -130,11 +123,10 @@
//
this.btnOpenFile.Image = global::WelsonJS.Launcher.Properties.Resources.icon_file_32;
this.btnOpenFile.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnOpenFile.Location = new System.Drawing.Point(44, 254);
this.btnOpenFile.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnOpenFile.Location = new System.Drawing.Point(31, 169);
this.btnOpenFile.Name = "btnOpenFile";
this.btnOpenFile.Padding = new System.Windows.Forms.Padding(16, 0, 0, 0);
this.btnOpenFile.Size = new System.Drawing.Size(287, 60);
this.btnOpenFile.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
this.btnOpenFile.Size = new System.Drawing.Size(201, 40);
this.btnOpenFile.TabIndex = 5;
this.btnOpenFile.Text = "Open the file...";
this.btnOpenFile.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@ -146,11 +138,10 @@
//
this.btnOpenDirectory.Image = global::WelsonJS.Launcher.Properties.Resources.icon_directory_32;
this.btnOpenDirectory.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnOpenDirectory.Location = new System.Drawing.Point(44, 184);
this.btnOpenDirectory.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnOpenDirectory.Location = new System.Drawing.Point(31, 123);
this.btnOpenDirectory.Name = "btnOpenDirectory";
this.btnOpenDirectory.Padding = new System.Windows.Forms.Padding(16, 0, 0, 0);
this.btnOpenDirectory.Size = new System.Drawing.Size(287, 60);
this.btnOpenDirectory.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
this.btnOpenDirectory.Size = new System.Drawing.Size(201, 40);
this.btnOpenDirectory.TabIndex = 4;
this.btnOpenDirectory.Text = "Open the directory...";
this.btnOpenDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@ -160,62 +151,55 @@
//
// textSetValue
//
this.textSetValue.Location = new System.Drawing.Point(140, 82);
this.textSetValue.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.textSetValue.Location = new System.Drawing.Point(98, 55);
this.textSetValue.Name = "textSetValue";
this.textSetValue.Size = new System.Drawing.Size(414, 28);
this.textSetValue.Size = new System.Drawing.Size(291, 21);
this.textSetValue.TabIndex = 3;
//
// textSetName
//
this.textSetName.Location = new System.Drawing.Point(140, 42);
this.textSetName.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.textSetName.Location = new System.Drawing.Point(98, 28);
this.textSetName.Name = "textSetName";
this.textSetName.Size = new System.Drawing.Size(414, 28);
this.textSetName.Size = new System.Drawing.Size(291, 21);
this.textSetName.TabIndex = 2;
//
// labelSetValue
//
this.labelSetValue.AutoSize = true;
this.labelSetValue.Location = new System.Drawing.Point(41, 88);
this.labelSetValue.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.labelSetValue.Location = new System.Drawing.Point(29, 59);
this.labelSetValue.Name = "labelSetValue";
this.labelSetValue.Size = new System.Drawing.Size(89, 18);
this.labelSetValue.Size = new System.Drawing.Size(61, 12);
this.labelSetValue.TabIndex = 1;
this.labelSetValue.Text = "Set value:";
//
// labelSetName
//
this.labelSetName.AutoSize = true;
this.labelSetName.Location = new System.Drawing.Point(41, 46);
this.labelSetName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.labelSetName.Location = new System.Drawing.Point(29, 31);
this.labelSetName.Name = "labelSetName";
this.labelSetName.Size = new System.Drawing.Size(91, 18);
this.labelSetName.Size = new System.Drawing.Size(63, 12);
this.labelSetName.TabIndex = 0;
this.labelSetName.Text = "Set name:";
//
// groupBox3
// gbImportAndExport
//
this.groupBox3.Controls.Add(this.btnExport);
this.groupBox3.Controls.Add(this.btnImport);
this.groupBox3.Location = new System.Drawing.Point(17, 634);
this.groupBox3.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.groupBox3.Size = new System.Drawing.Size(599, 134);
this.groupBox3.TabIndex = 2;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Import and export";
this.gbImportAndExport.Controls.Add(this.btnExport);
this.gbImportAndExport.Controls.Add(this.btnImport);
this.gbImportAndExport.Location = new System.Drawing.Point(12, 423);
this.gbImportAndExport.Name = "gbImportAndExport";
this.gbImportAndExport.Size = new System.Drawing.Size(419, 89);
this.gbImportAndExport.TabIndex = 2;
this.gbImportAndExport.TabStop = false;
this.gbImportAndExport.Text = "Import and export";
//
// btnExport
//
this.btnExport.Image = global::WelsonJS.Launcher.Properties.Resources.icon_export_32;
this.btnExport.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnExport.Location = new System.Drawing.Point(304, 44);
this.btnExport.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnExport.Location = new System.Drawing.Point(213, 29);
this.btnExport.Name = "btnExport";
this.btnExport.Padding = new System.Windows.Forms.Padding(16, 0, 0, 0);
this.btnExport.Size = new System.Drawing.Size(251, 60);
this.btnExport.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
this.btnExport.Size = new System.Drawing.Size(176, 40);
this.btnExport.TabIndex = 6;
this.btnExport.Text = "Export";
this.btnExport.UseVisualStyleBackColor = true;
@ -225,11 +209,10 @@
//
this.btnImport.Image = global::WelsonJS.Launcher.Properties.Resources.icon_import_32;
this.btnImport.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnImport.Location = new System.Drawing.Point(44, 44);
this.btnImport.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnImport.Location = new System.Drawing.Point(31, 29);
this.btnImport.Name = "btnImport";
this.btnImport.Padding = new System.Windows.Forms.Padding(16, 0, 0, 0);
this.btnImport.Size = new System.Drawing.Size(251, 60);
this.btnImport.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
this.btnImport.Size = new System.Drawing.Size(176, 40);
this.btnImport.TabIndex = 5;
this.btnImport.Text = "Import";
this.btnImport.UseVisualStyleBackColor = true;
@ -237,30 +220,29 @@
//
// EnvForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 18F);
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(639, 794);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.ClientSize = new System.Drawing.Size(447, 529);
this.Controls.Add(this.gbImportAndExport);
this.Controls.Add(this.gbUpdateUserDefinedVariable);
this.Controls.Add(this.gbUserDefinedVariables);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.MaximizeBox = false;
this.Name = "EnvForm";
this.Text = "User-defined variables editor";
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.gbUserDefinedVariables.ResumeLayout(false);
this.gbUpdateUserDefinedVariable.ResumeLayout(false);
this.gbUpdateUserDefinedVariable.PerformLayout();
this.gbImportAndExport.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.GroupBox gbUserDefinedVariables;
private System.Windows.Forms.GroupBox gbUpdateUserDefinedVariable;
private System.Windows.Forms.TextBox textSetValue;
private System.Windows.Forms.TextBox textSetName;
private System.Windows.Forms.Label labelSetValue;
@ -269,10 +251,10 @@
private System.Windows.Forms.Button btnOpenFile;
private System.Windows.Forms.Button btnOpenDirectory;
private System.Windows.Forms.CheckBox checkDeleteVariable;
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ListView lvUserDefinedVariables;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.GroupBox gbImportAndExport;
private System.Windows.Forms.Button btnImport;
private System.Windows.Forms.Button btnExport;
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace WelsonJS.Launcher
@ -9,6 +10,7 @@ namespace WelsonJS.Launcher
{
private Dictionary<string, string> userVariables = new Dictionary<string, string>();
private string tempFilePath;
private readonly Encoding defaultEncoding = Encoding.UTF8;
public EnvForm()
{
@ -24,11 +26,11 @@ namespace WelsonJS.Launcher
// Initialize ListView
private void InitializeListView()
{
listView1.View = View.Details;
listView1.FullRowSelect = true;
listView1.Columns[0].Width = 150;
listView1.Columns[1].Width = 220;
listView1.SelectedIndexChanged += ListView1_SelectedIndexChanged;
lvUserDefinedVariables.View = View.Details;
lvUserDefinedVariables.FullRowSelect = true;
lvUserDefinedVariables.Columns[0].Width = 150;
lvUserDefinedVariables.Columns[1].Width = 220;
lvUserDefinedVariables.SelectedIndexChanged += lvUserDefinedVariables_SelectedIndexChanged;
}
// Load user-defined variables from the temporary folder in .env format
@ -86,21 +88,21 @@ namespace WelsonJS.Launcher
// Update ListView with current variables
private void UpdateListView()
{
listView1.Items.Clear();
lvUserDefinedVariables.Items.Clear();
foreach (var variable in userVariables)
{
var item = new ListViewItem(variable.Key);
item.SubItems.Add(variable.Value);
listView1.Items.Add(item);
lvUserDefinedVariables.Items.Add(item);
}
}
// Handle ListView selection change
private void ListView1_SelectedIndexChanged(object sender, EventArgs e)
private void lvUserDefinedVariables_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
if (lvUserDefinedVariables.SelectedItems.Count > 0)
{
var selectedItem = listView1.SelectedItems[0];
var selectedItem = lvUserDefinedVariables.SelectedItems[0];
textSetName.Text = selectedItem.Text;
textSetValue.Text = selectedItem.SubItems[1].Text;
checkDeleteVariable.Checked = false;
@ -166,7 +168,7 @@ namespace WelsonJS.Launcher
}
// Write lines to the file
File.WriteAllLines(tempFilePath, lines);
File.WriteAllLines(tempFilePath, lines, defaultEncoding);
}
catch (Exception ex)
{
@ -185,68 +187,74 @@ namespace WelsonJS.Launcher
// Handle "Open Directory" button click
private void btnOpenDirectory_Click(object sender, EventArgs e)
{
var folderDialog = new FolderBrowserDialog();
if (folderDialog.ShowDialog() == DialogResult.OK)
using (var folderDialog = new FolderBrowserDialog())
{
textSetValue.Text = folderDialog.SelectedPath;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
textSetValue.Text = folderDialog.SelectedPath;
}
}
}
// Handle "Open File" button click
private void btnOpenFile_Click(object sender, EventArgs e)
{
var fileDialog = new OpenFileDialog();
if (fileDialog.ShowDialog() == DialogResult.OK)
using (var fileDialog = new OpenFileDialog())
{
textSetName.Text = Path.GetFileName(fileDialog.FileName);
textSetValue.Text = fileDialog.FileName;
if (fileDialog.ShowDialog() == DialogResult.OK)
{
textSetName.Text = Path.GetFileName(fileDialog.FileName);
textSetValue.Text = fileDialog.FileName;
}
}
}
private void btnImport_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
using (var openFileDialog = new OpenFileDialog())
{
try
openFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
// Load variables from the selected file
string filePath = openFileDialog.FileName;
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
try
{
// Skip empty lines
if (string.IsNullOrWhiteSpace(line)) continue;
// Load variables from the selected file
string filePath = openFileDialog.FileName;
string[] lines = File.ReadAllLines(filePath, defaultEncoding);
int indexOfEquals = line.IndexOf('=');
if (indexOfEquals != -1)
foreach (string line in lines)
{
string key = line.Substring(0, indexOfEquals).Trim();
string value = line.Substring(indexOfEquals + 1).Trim();
// Skip empty lines
if (string.IsNullOrWhiteSpace(line)) continue;
// Remove surrounding quotes if present
if (value.StartsWith("\"") && value.EndsWith("\""))
int indexOfEquals = line.IndexOf('=');
if (indexOfEquals != -1)
{
value = value.Substring(1, value.Length - 2);
string key = line.Substring(0, indexOfEquals).Trim();
string value = line.Substring(indexOfEquals + 1).Trim();
// Remove surrounding quotes if present
if (value.StartsWith("\"") && value.EndsWith("\""))
{
value = value.Substring(1, value.Length - 2);
}
// Unescape double quotes in the value
value = value.Replace("\\\"", "\"");
// Update or add the key-value pair
userVariables[key] = value;
}
// Unescape double quotes in the value
value = value.Replace("\\\"", "\"");
// Update or add the key-value pair
userVariables[key] = value;
}
}
// Save the updated variables to the file
SaveUserVariables();
UpdateListView(); // Refresh the display
}
catch (Exception ex)
{
MessageBox.Show($"Error importing variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Save the updated variables to the file
SaveUserVariables();
UpdateListView(); // Refresh the display
}
catch (Exception ex)
{
MessageBox.Show($"Error importing variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
@ -275,7 +283,7 @@ namespace WelsonJS.Launcher
lines.Add($"{variable.Key}={value}");
}
File.WriteAllLines(filePath, lines);
File.WriteAllLines(filePath, lines, defaultEncoding);
}
catch (Exception ex)
{

View File

@ -28,62 +28,62 @@
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.groupBox1.SuspendLayout();
this.gbMaxScriptStatements = new System.Windows.Forms.GroupBox();
this.btnOkMaxScriptStatements = new System.Windows.Forms.Button();
this.txtMaxScriptStatements = new System.Windows.Forms.TextBox();
this.gbMaxScriptStatements.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
// gbMaxScriptStatements
//
this.groupBox1.Controls.Add(this.button1);
this.groupBox1.Controls.Add(this.textBox1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(290, 67);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "MaxScriptStatements (GUI only)";
this.gbMaxScriptStatements.Controls.Add(this.btnOkMaxScriptStatements);
this.gbMaxScriptStatements.Controls.Add(this.txtMaxScriptStatements);
this.gbMaxScriptStatements.Location = new System.Drawing.Point(12, 12);
this.gbMaxScriptStatements.Name = "gbMaxScriptStatements";
this.gbMaxScriptStatements.Size = new System.Drawing.Size(290, 67);
this.gbMaxScriptStatements.TabIndex = 0;
this.gbMaxScriptStatements.TabStop = false;
this.gbMaxScriptStatements.Text = "MaxScriptStatements (GUI only)";
//
// button1
// btnOkMaxScriptStatements
//
this.button1.Location = new System.Drawing.Point(218, 30);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(57, 21);
this.button1.TabIndex = 1;
this.button1.Text = "Ok";
this.button1.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
this.btnOkMaxScriptStatements.Location = new System.Drawing.Point(218, 30);
this.btnOkMaxScriptStatements.Name = "btnOkMaxScriptStatements";
this.btnOkMaxScriptStatements.Size = new System.Drawing.Size(57, 21);
this.btnOkMaxScriptStatements.TabIndex = 1;
this.btnOkMaxScriptStatements.Text = "Ok";
this.btnOkMaxScriptStatements.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnOkMaxScriptStatements.UseVisualStyleBackColor = true;
this.btnOkMaxScriptStatements.Click += new System.EventHandler(this.btnOkMaxScriptStatements_Click);
//
// textBox1
// txtMaxScriptStatements
//
this.textBox1.Location = new System.Drawing.Point(15, 30);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(197, 21);
this.textBox1.TabIndex = 1;
this.txtMaxScriptStatements.Location = new System.Drawing.Point(15, 30);
this.txtMaxScriptStatements.Name = "txtMaxScriptStatements";
this.txtMaxScriptStatements.Size = new System.Drawing.Size(197, 21);
this.txtMaxScriptStatements.TabIndex = 1;
//
// GlobalSettingsForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(315, 92);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.gbMaxScriptStatements);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
this.MaximizeBox = false;
this.Name = "GlobalSettingsForm";
this.Text = "Global settings...";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.gbMaxScriptStatements.ResumeLayout(false);
this.gbMaxScriptStatements.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.GroupBox gbMaxScriptStatements;
private System.Windows.Forms.TextBox txtMaxScriptStatements;
private System.Windows.Forms.Button btnOkMaxScriptStatements;
}
}

View File

@ -21,28 +21,35 @@ namespace WelsonJS.Launcher
{
if (key != null)
{
object value = key.GetValue(RegistryKey);
if (value != null && value is int maxStatements)
string value = key.GetValue(RegistryKey)?.ToString();
if (value != null && int.TryParse(value, out int maxStatements))
{
textBox1.Text = maxStatements.ToString();
txtMaxScriptStatements.Text = maxStatements.ToString();
}
}
}
}
private void button1_Click(object sender, EventArgs e)
private void btnOkMaxScriptStatements_Click(object sender, EventArgs e)
{
if (uint.TryParse(textBox1.Text, out uint maxStatements))
try
{
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegistryPath))
if (int.TryParse(txtMaxScriptStatements.Text, out int maxStatements))
{
key.SetValue(RegistryKey, (int)maxStatements, RegistryValueKind.DWord);
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegistryPath))
{
key.SetValue(RegistryKey, maxStatements, RegistryValueKind.DWord);
}
MessageBox.Show($"MaxScriptStatements setting has been changed to {maxStatements}.", "Confirmation", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
MessageBox.Show($"MaxScriptStatements setting has been changed to {maxStatements}.", "Confirmation", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
else
{
MessageBox.Show("Please enter a valid number within the DWORD range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show("Please enter a valid number within the DWORD range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show($"An error occurred while trying to change the MaxScriptStatements setting: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}

View File

@ -0,0 +1,25 @@
using System.Net;
using System.Threading.Tasks;
namespace WelsonJS.Launcher
{
/// <summary>
/// Defines a contract for resource tools that can handle specific HTTP requests.
/// </summary>
public interface IResourceTool
{
/// <summary>
/// Determines whether this tool can handle the specified path.
/// </summary>
/// <param name="path">The request path to check.</param>
/// <returns>True if this tool can handle the request; otherwise, false.</returns>
bool CanHandle(string path);
/// <summary>
/// Asynchronously processes the HTTP request for the specified path.
/// </summary>
/// <param name="context">The HTTP listener context containing request and response objects.</param>
/// <param name="path">The request path to handle.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task HandleAsync(HttpListenerContext context, string path);
}
}

View File

@ -28,46 +28,48 @@
/// </summary>
private void InitializeComponent()
{
this.listView1 = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lvInstances = new System.Windows.Forms.ListView();
this.chInstanceId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.chFirstDeployTime = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.btnDelete = new System.Windows.Forms.Button();
this.btnOpenWithExplorer = new System.Windows.Forms.Button();
this.checkBox2 = new System.Windows.Forms.CheckBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.cbInteractiveServiceApp = new System.Windows.Forms.CheckBox();
this.txtUseSpecificScript = new System.Windows.Forms.TextBox();
this.cbUseSpecificScript = new System.Windows.Forms.CheckBox();
this.btnStart = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// listView1
// lvInstances
//
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(12, 12);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(547, 253);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
this.lvInstances.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.chInstanceId,
this.chFirstDeployTime});
this.lvInstances.HideSelection = false;
this.lvInstances.Location = new System.Drawing.Point(8, 8);
this.lvInstances.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.lvInstances.Name = "lvInstances";
this.lvInstances.Size = new System.Drawing.Size(384, 170);
this.lvInstances.TabIndex = 0;
this.lvInstances.UseCompatibleStateImageBehavior = false;
this.lvInstances.View = System.Windows.Forms.View.Details;
//
// columnHeader1
// chInstanceId
//
this.columnHeader1.Text = "Instance ID";
this.columnHeader1.Width = 220;
this.chInstanceId.Text = "Instance ID";
this.chInstanceId.Width = 220;
//
// columnHeader2
// chFirstDeployTime
//
this.columnHeader2.Text = "First Deploy Time";
this.columnHeader2.Width = 160;
this.chFirstDeployTime.Text = "First Deploy Time";
this.chFirstDeployTime.Width = 160;
//
// btnDelete
//
this.btnDelete.Image = global::WelsonJS.Launcher.Properties.Resources.icon_delete_32;
this.btnDelete.Location = new System.Drawing.Point(171, 364);
this.btnDelete.Location = new System.Drawing.Point(120, 243);
this.btnDelete.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(150, 60);
this.btnDelete.Size = new System.Drawing.Size(105, 40);
this.btnDelete.TabIndex = 2;
this.btnDelete.Text = "Delete";
this.btnDelete.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
@ -77,53 +79,52 @@
// btnOpenWithExplorer
//
this.btnOpenWithExplorer.Image = global::WelsonJS.Launcher.Properties.Resources.icon_directory_32;
this.btnOpenWithExplorer.Location = new System.Drawing.Point(327, 364);
this.btnOpenWithExplorer.Location = new System.Drawing.Point(229, 243);
this.btnOpenWithExplorer.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.btnOpenWithExplorer.Name = "btnOpenWithExplorer";
this.btnOpenWithExplorer.Size = new System.Drawing.Size(232, 60);
this.btnOpenWithExplorer.Size = new System.Drawing.Size(162, 40);
this.btnOpenWithExplorer.TabIndex = 3;
this.btnOpenWithExplorer.Text = "Open with Explorer";
this.btnOpenWithExplorer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnOpenWithExplorer.UseVisualStyleBackColor = true;
this.btnOpenWithExplorer.Click += new System.EventHandler(this.btnOpenWithExplorer_Click);
//
// checkBox2
// cbInteractiveServiceApp
//
this.checkBox2.AutoSize = true;
this.checkBox2.Location = new System.Drawing.Point(15, 322);
this.checkBox2.Margin = new System.Windows.Forms.Padding(4);
this.checkBox2.Name = "checkBox2";
this.checkBox2.Size = new System.Drawing.Size(352, 22);
this.checkBox2.TabIndex = 9;
this.checkBox2.Text = "This is an Interactive Service Application";
this.checkBox2.UseVisualStyleBackColor = true;
this.cbInteractiveServiceApp.AutoSize = true;
this.cbInteractiveServiceApp.Location = new System.Drawing.Point(10, 215);
this.cbInteractiveServiceApp.Name = "cbInteractiveServiceApp";
this.cbInteractiveServiceApp.Size = new System.Drawing.Size(254, 16);
this.cbInteractiveServiceApp.TabIndex = 9;
this.cbInteractiveServiceApp.Text = "This is an Interactive Service Application";
this.cbInteractiveServiceApp.UseVisualStyleBackColor = true;
//
// textBox1
// txtUseSpecificScript
//
this.textBox1.Enabled = false;
this.textBox1.Location = new System.Drawing.Point(284, 283);
this.textBox1.Margin = new System.Windows.Forms.Padding(4);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(155, 28);
this.textBox1.TabIndex = 8;
this.txtUseSpecificScript.Enabled = false;
this.txtUseSpecificScript.Location = new System.Drawing.Point(199, 189);
this.txtUseSpecificScript.Name = "txtUseSpecificScript";
this.txtUseSpecificScript.Size = new System.Drawing.Size(110, 21);
this.txtUseSpecificScript.TabIndex = 8;
//
// checkBox1
// cbUseSpecificScript
//
this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(15, 288);
this.checkBox1.Margin = new System.Windows.Forms.Padding(4);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(256, 22);
this.checkBox1.TabIndex = 7;
this.checkBox1.Text = "I want to use specific script ";
this.checkBox1.UseVisualStyleBackColor = true;
this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
this.cbUseSpecificScript.AutoSize = true;
this.cbUseSpecificScript.Location = new System.Drawing.Point(10, 192);
this.cbUseSpecificScript.Name = "cbUseSpecificScript";
this.cbUseSpecificScript.Size = new System.Drawing.Size(184, 16);
this.cbUseSpecificScript.TabIndex = 7;
this.cbUseSpecificScript.Text = "I want to use specific script ";
this.cbUseSpecificScript.UseVisualStyleBackColor = true;
this.cbUseSpecificScript.CheckedChanged += new System.EventHandler(this.cbUseSpecificScript_CheckedChanged);
//
// btnStart
//
this.btnStart.Image = global::WelsonJS.Launcher.Properties.Resources.icon_start_32;
this.btnStart.Location = new System.Drawing.Point(15, 364);
this.btnStart.Location = new System.Drawing.Point(10, 243);
this.btnStart.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(150, 60);
this.btnStart.Size = new System.Drawing.Size(105, 40);
this.btnStart.TabIndex = 1;
this.btnStart.Text = "Start";
this.btnStart.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
@ -132,18 +133,19 @@
//
// InstancesForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 18F);
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(573, 444);
this.ClientSize = new System.Drawing.Size(401, 296);
this.Controls.Add(this.btnStart);
this.Controls.Add(this.listView1);
this.Controls.Add(this.lvInstances);
this.Controls.Add(this.btnDelete);
this.Controls.Add(this.checkBox1);
this.Controls.Add(this.checkBox2);
this.Controls.Add(this.cbUseSpecificScript);
this.Controls.Add(this.cbInteractiveServiceApp);
this.Controls.Add(this.btnOpenWithExplorer);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.txtUseSpecificScript);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.MaximizeBox = false;
this.Name = "InstancesForm";
this.Text = "Instances";
@ -155,14 +157,14 @@
#endregion
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.ListView lvInstances;
private System.Windows.Forms.Button btnDelete;
private System.Windows.Forms.Button btnOpenWithExplorer;
private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.CheckBox cbInteractiveServiceApp;
private System.Windows.Forms.TextBox txtUseSpecificScript;
private System.Windows.Forms.CheckBox cbUseSpecificScript;
private System.Windows.Forms.ColumnHeader chInstanceId;
private System.Windows.Forms.ColumnHeader chFirstDeployTime;
private System.Windows.Forms.Button btnStart;
}
}

View File

@ -20,7 +20,7 @@ namespace WelsonJS.Launcher
private void InstancesForm_Load(object sender, EventArgs e)
{
listView1.Items.Clear();
lvInstances.Items.Clear();
LoadInstances(Program.GetAppDataPath());
LoadInstances(Path.GetTempPath());
}
@ -48,7 +48,7 @@ namespace WelsonJS.Launcher
if (firstDeployTime != null)
{
listView1.Items.Add(new ListViewItem(new[]
lvInstances.Items.Add(new ListViewItem(new[]
{
Path.GetFileName(dir),
firstDeployTime
@ -62,11 +62,11 @@ namespace WelsonJS.Launcher
private void btnStart_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
if (lvInstances.SelectedItems.Count > 0)
{
scriptName = textBox1.Text;
scriptName = txtUseSpecificScript.Text;
string instanceId = listView1.SelectedItems[0].Text;
string instanceId = lvInstances.SelectedItems[0].Text;
string workingDirectory = Program.GetWorkingDirectory(instanceId, true);
Task.Run(() =>
@ -74,7 +74,7 @@ namespace WelsonJS.Launcher
try
{
// Run the appliction
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, checkBox1.Checked, checkBox2.Checked);
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, cbUseSpecificScript.Checked, cbInteractiveServiceApp.Checked);
}
catch (Exception ex)
{
@ -90,9 +90,9 @@ namespace WelsonJS.Launcher
private void btnDelete_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
if (lvInstances.SelectedItems.Count > 0)
{
string instanceId = listView1.SelectedItems[0].Text;
string instanceId = lvInstances.SelectedItems[0].Text;
string workingDirectory = Program.GetWorkingDirectory(instanceId, false);
if (!Directory.Exists(workingDirectory))
@ -104,7 +104,7 @@ namespace WelsonJS.Launcher
{
Directory.Delete(workingDirectory, true);
listView1.Items.Clear();
lvInstances.Items.Clear();
LoadInstances(Program.GetAppDataPath());
LoadInstances(Path.GetTempPath());
}
@ -117,9 +117,9 @@ namespace WelsonJS.Launcher
private void btnOpenWithExplorer_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
if (lvInstances.SelectedItems.Count > 0)
{
string instanceId = listView1.SelectedItems[0].Text;
string instanceId = lvInstances.SelectedItems[0].Text;
string workingDirectory = Program.GetWorkingDirectory(instanceId, true);
if (Directory.Exists(workingDirectory))
@ -133,9 +133,9 @@ namespace WelsonJS.Launcher
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
private void cbUseSpecificScript_CheckedChanged(object sender, EventArgs e)
{
textBox1.Enabled = checkBox1.Checked;
txtUseSpecificScript.Enabled = cbUseSpecificScript.Checked;
}
}
}

View File

@ -29,13 +29,13 @@
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.btnRunFromZipFile = new System.Windows.Forms.Button();
this.btnRunFromExternalLink = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.textBox1 = new System.Windows.Forms.TextBox();
this.checkBox2 = new System.Windows.Forms.CheckBox();
this.cbUseSpecificScript = new System.Windows.Forms.CheckBox();
this.txtUseSpecificScript = new System.Windows.Forms.TextBox();
this.cbInteractiveServiceApp = new System.Windows.Forms.CheckBox();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.userdefinedVariablesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -43,7 +43,7 @@
this.runAsAdministratorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.globalSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.startCodeEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openMicrosoftCopilotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openCopilotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.openLauncherToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@ -53,29 +53,29 @@
this.contextMenuStrip1.SuspendLayout();
this.SuspendLayout();
//
// button1
// btnRunFromZipFile
//
this.button1.Image = global::WelsonJS.Launcher.Properties.Resources.icon_zip_128;
this.button1.Location = new System.Drawing.Point(24, 67);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(200, 200);
this.button1.TabIndex = 0;
this.button1.Text = "From ZIP file...";
this.button1.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
this.btnRunFromZipFile.Image = global::WelsonJS.Launcher.Properties.Resources.icon_zip_128;
this.btnRunFromZipFile.Location = new System.Drawing.Point(24, 67);
this.btnRunFromZipFile.Name = "btnRunFromZipFile";
this.btnRunFromZipFile.Size = new System.Drawing.Size(200, 200);
this.btnRunFromZipFile.TabIndex = 0;
this.btnRunFromZipFile.Text = "From ZIP file...";
this.btnRunFromZipFile.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
this.btnRunFromZipFile.UseVisualStyleBackColor = true;
this.btnRunFromZipFile.Click += new System.EventHandler(this.btnRunFromZipFile_Click);
//
// button2
// btnRunFromExternalLink
//
this.button2.Image = global::WelsonJS.Launcher.Properties.Resources.icon_link_128;
this.button2.Location = new System.Drawing.Point(230, 67);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(200, 200);
this.button2.TabIndex = 1;
this.button2.Text = "From external link...";
this.button2.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
this.btnRunFromExternalLink.Image = global::WelsonJS.Launcher.Properties.Resources.icon_link_128;
this.btnRunFromExternalLink.Location = new System.Drawing.Point(230, 67);
this.btnRunFromExternalLink.Name = "btnRunFromExternalLink";
this.btnRunFromExternalLink.Size = new System.Drawing.Size(200, 200);
this.btnRunFromExternalLink.TabIndex = 1;
this.btnRunFromExternalLink.Text = "From external link...";
this.btnRunFromExternalLink.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
this.btnRunFromExternalLink.UseVisualStyleBackColor = true;
this.btnRunFromExternalLink.Click += new System.EventHandler(this.btnRunFromExternalLink_Click);
//
// label1
//
@ -97,34 +97,34 @@
this.linkLabel1.Text = "https://github.com/gnh1201/welsonjs";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// checkBox1
// cbUseSpecificScript
//
this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(26, 281);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(184, 16);
this.checkBox1.TabIndex = 4;
this.checkBox1.Text = "I want to use specific script ";
this.checkBox1.UseVisualStyleBackColor = true;
this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
this.cbUseSpecificScript.AutoSize = true;
this.cbUseSpecificScript.Location = new System.Drawing.Point(26, 281);
this.cbUseSpecificScript.Name = "cbUseSpecificScript";
this.cbUseSpecificScript.Size = new System.Drawing.Size(184, 16);
this.cbUseSpecificScript.TabIndex = 4;
this.cbUseSpecificScript.Text = "I want to use specific script ";
this.cbUseSpecificScript.UseVisualStyleBackColor = true;
this.cbUseSpecificScript.CheckedChanged += new System.EventHandler(this.cbUseSpecificScript_CheckedChanged);
//
// textBox1
// txtUseSpecificScript
//
this.textBox1.Enabled = false;
this.textBox1.Location = new System.Drawing.Point(214, 278);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(110, 21);
this.textBox1.TabIndex = 5;
this.txtUseSpecificScript.Enabled = false;
this.txtUseSpecificScript.Location = new System.Drawing.Point(214, 278);
this.txtUseSpecificScript.Name = "txtUseSpecificScript";
this.txtUseSpecificScript.Size = new System.Drawing.Size(110, 21);
this.txtUseSpecificScript.TabIndex = 5;
//
// checkBox2
// cbInteractiveServiceApp
//
this.checkBox2.AutoSize = true;
this.checkBox2.Location = new System.Drawing.Point(26, 305);
this.checkBox2.Name = "checkBox2";
this.checkBox2.Size = new System.Drawing.Size(254, 16);
this.checkBox2.TabIndex = 6;
this.checkBox2.Text = "This is an Interactive Service Application";
this.checkBox2.UseVisualStyleBackColor = true;
this.cbInteractiveServiceApp.AutoSize = true;
this.cbInteractiveServiceApp.Location = new System.Drawing.Point(26, 305);
this.cbInteractiveServiceApp.Name = "cbInteractiveServiceApp";
this.cbInteractiveServiceApp.Size = new System.Drawing.Size(254, 16);
this.cbInteractiveServiceApp.TabIndex = 6;
this.cbInteractiveServiceApp.Text = "This is an Interactive Service Application";
this.cbInteractiveServiceApp.UseVisualStyleBackColor = true;
//
// menuStrip1
//
@ -144,7 +144,7 @@
this.runAsAdministratorToolStripMenuItem,
this.globalSettingsToolStripMenuItem,
this.startCodeEditorToolStripMenuItem,
this.openMicrosoftCopilotToolStripMenuItem});
this.openCopilotToolStripMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(62, 20);
this.settingsToolStripMenuItem.Text = "Settings";
@ -152,44 +152,44 @@
// userdefinedVariablesToolStripMenuItem
//
this.userdefinedVariablesToolStripMenuItem.Name = "userdefinedVariablesToolStripMenuItem";
this.userdefinedVariablesToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.userdefinedVariablesToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.userdefinedVariablesToolStripMenuItem.Text = "User-defined variables";
this.userdefinedVariablesToolStripMenuItem.Click += new System.EventHandler(this.userdefinedVariablesToolStripMenuItem_Click);
//
// instancesToolStripMenuItem
//
this.instancesToolStripMenuItem.Name = "instancesToolStripMenuItem";
this.instancesToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.instancesToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.instancesToolStripMenuItem.Text = "Instances";
this.instancesToolStripMenuItem.Click += new System.EventHandler(this.instancesToolStripMenuItem_Click);
//
// runAsAdministratorToolStripMenuItem
//
this.runAsAdministratorToolStripMenuItem.Name = "runAsAdministratorToolStripMenuItem";
this.runAsAdministratorToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.runAsAdministratorToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.runAsAdministratorToolStripMenuItem.Text = "Run as Administrator...";
this.runAsAdministratorToolStripMenuItem.Click += new System.EventHandler(this.runAsAdministratorToolStripMenuItem_Click);
//
// globalSettingsToolStripMenuItem
//
this.globalSettingsToolStripMenuItem.Name = "globalSettingsToolStripMenuItem";
this.globalSettingsToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.globalSettingsToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.globalSettingsToolStripMenuItem.Text = "Global settings...";
this.globalSettingsToolStripMenuItem.Click += new System.EventHandler(this.globalSettingsToolStripMenuItem_Click);
//
// startCodeEditorToolStripMenuItem
//
this.startCodeEditorToolStripMenuItem.Name = "startCodeEditorToolStripMenuItem";
this.startCodeEditorToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.startCodeEditorToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.startCodeEditorToolStripMenuItem.Text = "Start the code editor...";
this.startCodeEditorToolStripMenuItem.Click += new System.EventHandler(this.startCodeEditorToolStripMenuItem_Click);
//
// openMicrosoftCopilotToolStripMenuItem
// openCopilotToolStripMenuItem
//
this.openMicrosoftCopilotToolStripMenuItem.Name = "openMicrosoftCopilotToolStripMenuItem";
this.openMicrosoftCopilotToolStripMenuItem.Size = new System.Drawing.Size(210, 22);
this.openMicrosoftCopilotToolStripMenuItem.Text = "Open Microsoft Copilot...";
this.openMicrosoftCopilotToolStripMenuItem.Click += new System.EventHandler(this.openMicrosoftCopilotToolStripMenuItem_Click);
this.openCopilotToolStripMenuItem.Name = "openCopilotToolStripMenuItem";
this.openCopilotToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
this.openCopilotToolStripMenuItem.Text = "Open the Copilot...";
this.openCopilotToolStripMenuItem.Click += new System.EventHandler(this.openCopilotToolStripMenuItem_Click);
//
// notifyIcon1
//
@ -230,13 +230,13 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(461, 382);
this.Controls.Add(this.checkBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.checkBox1);
this.Controls.Add(this.cbInteractiveServiceApp);
this.Controls.Add(this.txtUseSpecificScript);
this.Controls.Add(this.cbUseSpecificScript);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.btnRunFromExternalLink);
this.Controls.Add(this.btnRunFromZipFile);
this.Controls.Add(this.menuStrip1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
@ -254,13 +254,13 @@
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button btnRunFromZipFile;
private System.Windows.Forms.Button btnRunFromExternalLink;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.CheckBox cbUseSpecificScript;
private System.Windows.Forms.TextBox txtUseSpecificScript;
private System.Windows.Forms.CheckBox cbInteractiveServiceApp;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem userdefinedVariablesToolStripMenuItem;
@ -273,7 +273,7 @@
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openCodeEditorToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openLauncherToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openMicrosoftCopilotToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem openCopilotToolStripMenuItem;
}
}

View File

@ -5,7 +5,6 @@ using System.IO.Compression;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows.Forms;
using WelsonJS.Launcher.Tools;
namespace WelsonJS.Launcher
{
@ -62,43 +61,54 @@ namespace WelsonJS.Launcher
private void EnableUI()
{
label1.Text = "Choose the location of WelsonJS application package.";
button1.Enabled = true;
button2.Enabled = true;
checkBox1.Enabled = true;
checkBox2.Enabled = true;
if (checkBox1.Checked)
btnRunFromZipFile.Enabled = true;
btnRunFromExternalLink.Enabled = true;
cbUseSpecificScript.Enabled = true;
cbInteractiveServiceApp.Enabled = true;
if (cbUseSpecificScript.Checked)
{
textBox1.Enabled = true;
txtUseSpecificScript.Enabled = true;
}
}
private void DisableUI()
{
label1.Text = "Please wait...";
button1.Enabled = false;
button2.Enabled = false;
checkBox1.Enabled = false;
checkBox2.Enabled = false;
textBox1.Enabled = false;
btnRunFromZipFile.Enabled = false;
btnRunFromExternalLink.Enabled = false;
cbUseSpecificScript.Enabled = false;
cbInteractiveServiceApp.Enabled = false;
txtUseSpecificScript.Enabled = false;
}
private void button2_Click(object sender, EventArgs e)
private void SafeInvoke(Action action)
{
MessageBox.Show("Comming soon...!");
}
private void button1_Click(object sender, EventArgs e)
{
string filePath = OpenFileDialog();
if (filePath != null)
if (InvokeRequired)
{
string fileExtension = Path.GetExtension(filePath);
if (fileExtension != ".zip")
{
MessageBox.Show("It doesn't seems to a ZIP file.");
}
else
Invoke(action);
}
else
{
action();
}
}
private void btnRunFromExternalLink_Click(object sender, EventArgs e)
{
MessageBox.Show("Coming soon...!");
}
private void btnRunFromZipFile_Click(object sender, EventArgs e)
{
using (var openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "zip files (*.zip)|*.zip|All files (*.*)|*.*";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
ExtractAndRun(filePath);
}
}
@ -108,7 +118,7 @@ namespace WelsonJS.Launcher
{
instanceId = Guid.NewGuid().ToString();
workingDirectory = Program.GetWorkingDirectory(instanceId);
scriptName = textBox1.Text;
scriptName = txtUseSpecificScript.Text;
Task.Run(() =>
{
@ -130,15 +140,18 @@ namespace WelsonJS.Launcher
workingDirectory = Program.GetWorkingDirectory(instanceId, true);
// Run the appliction
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, checkBox1.Checked, checkBox2.Checked);
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, cbUseSpecificScript.Checked, cbInteractiveServiceApp.Checked);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
SafeInvoke(() =>
{
MessageBox.Show("Error: " + ex.Message);
});
}
// Enable UI
label1.Invoke((MethodInvoker)delegate {
SafeInvoke(() => {
EnableUI();
});
});
@ -161,22 +174,6 @@ namespace WelsonJS.Launcher
}
}
private string OpenFileDialog()
{
string filePath = null;
using (OpenFileDialog fileDialog = new OpenFileDialog())
{
if (fileDialog.ShowDialog() == DialogResult.OK)
{
// Get the path of specified file
filePath = fileDialog.FileName;
}
}
return filePath;
}
private bool IsInAdministrator()
{
try
@ -190,14 +187,14 @@ namespace WelsonJS.Launcher
}
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
private void cbUseSpecificScript_CheckedChanged(object sender, EventArgs e)
{
textBox1.Enabled = checkBox1.Checked;
txtUseSpecificScript.Enabled = cbUseSpecificScript.Checked;
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Process.Start("https://github.com/gnh1201/welsonjs");
Program.OpenWebBrowser(Program.GetAppConfig("RepositoryUrl"));
}
private void userdefinedVariablesToolStripMenuItem_Click(object sender, EventArgs e)
@ -245,10 +242,7 @@ namespace WelsonJS.Launcher
private void startCodeEditorToolStripMenuItem_Click(object sender, EventArgs e)
{
if (Program.resourceServer == null)
{
Program.resourceServer = new ResourceServer("http://localhost:3000/", "editor.html");
}
Program.StartResourceServer();
if (!Program.resourceServer.IsRunning())
{
@ -273,9 +267,9 @@ namespace WelsonJS.Launcher
}
}
private void openMicrosoftCopilotToolStripMenuItem_Click(object sender, EventArgs e)
private void openCopilotToolStripMenuItem_Click(object sender, EventArgs e)
{
Program.OpenWebBrowser("https://copilot.microsoft.com/");
Program.OpenWebBrowser(Program.GetAppConfig("CopilotUrl"));
}
}
}

View File

@ -4,7 +4,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using WelsonJS.Launcher.Tools;
using System.Configuration;
namespace WelsonJS.Launcher
{
@ -138,13 +138,27 @@ namespace WelsonJS.Launcher
return workingDirectory;
}
public static void StartResourceServer()
{
lock(typeof(Program))
{
if (resourceServer == null)
{
resourceServer = new ResourceServer(GetAppConfig("ResourceServerPrefix"), "editor.html");
}
}
}
public static void OpenWebBrowser(string url)
{
Uri resourceServerUri = new Uri(GetAppConfig("ResourceServerPrefix"));
Uri devToolsUri = new Uri(GetAppConfig("DevToolsPrefix"));
string userDataDir = Path.Combine(GetAppDataPath(), "EdgeUserProfile");
string remoteAllowOrigins = "http://localhost:3000";
string remoteAllowOrigins = $"{resourceServerUri.Scheme}://{resourceServerUri.Host}:{resourceServerUri.Port}";
int remoteDebuggingPort = devToolsUri.Port;
string[] arguments = {
$"\"{url}\"",
"--remote-debugging-port=9222",
$"--remote-debugging-port={remoteDebuggingPort}",
$"--remote-allow-origins={remoteAllowOrigins}", // for security reason
$"--user-data-dir=\"{userDataDir}\""
};
@ -156,5 +170,22 @@ namespace WelsonJS.Launcher
UseShellExecute = true
});
}
public static string GetAppConfig(string key)
{
string value = ConfigurationManager.AppSettings[key];
if (!string.IsNullOrEmpty(value))
{
return value;
}
value = Properties.Resources.ResourceManager.GetString(key);
if (!string.IsNullOrEmpty(value))
{
return value;
}
return null;
}
}
}

View File

@ -60,6 +60,105 @@ namespace WelsonJS.Launcher.Properties {
}
}
/// <summary>
/// https://ajax.aspnetcdn.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string AspNetCdnPrefix {
get {
return ResourceManager.GetString("AspNetCdnPrefix", resourceCulture);
}
}
/// <summary>
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string AzureAiServiceApiKey {
get {
return ResourceManager.GetString("AzureAiServiceApiKey", resourceCulture);
}
}
/// <summary>
/// 2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string AzureAiServiceApiVersion {
get {
return ResourceManager.GetString("AzureAiServiceApiVersion", resourceCulture);
}
}
/// <summary>
/// https://ai-catswords656881030318.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string AzureAiServicePrefix {
get {
return ResourceManager.GetString("AzureAiServicePrefix", resourceCulture);
}
}
/// <summary>
/// https://catswords.blob.core.windows.net/welsonjs/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string BlobStoragePrefix {
get {
return ResourceManager.GetString("BlobStoragePrefix", resourceCulture);
}
}
/// <summary>
/// https://cdnjs.cloudflare.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string CdnJsPrefix {
get {
return ResourceManager.GetString("CdnJsPrefix", resourceCulture);
}
}
/// <summary>
/// https://copilot.microsoft.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string CopilotUrl {
get {
return ResourceManager.GetString("CopilotUrl", resourceCulture);
}
}
/// <summary>
/// http://localhost:9222/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string DevToolsPrefix {
get {
return ResourceManager.GetString("DevToolsPrefix", resourceCulture);
}
}
/// <summary>
/// 1.1.1.1과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string DnsServerAddress {
get {
return ResourceManager.GetString("DnsServerAddress", resourceCulture);
}
}
/// <summary>
/// https://esm.run/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string EsmRunPrefix {
get {
return ResourceManager.GetString("EsmRunPrefix", resourceCulture);
}
}
/// <summary>
/// https://esm.sh/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string EsmShPrefix {
get {
return ResourceManager.GetString("EsmShPrefix", resourceCulture);
}
}
/// <summary>
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
/// </summary>
@ -70,6 +169,15 @@ namespace WelsonJS.Launcher.Properties {
}
}
/// <summary>
/// https://ajax.googleapis.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string GoogleApisPrefix {
get {
return ResourceManager.GetString("GoogleApisPrefix", resourceCulture);
}
}
/// <summary>
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
/// </summary>
@ -159,5 +267,104 @@ namespace WelsonJS.Launcher.Properties {
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// https://code.jquery.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string JqueryCdnPrefix {
get {
return ResourceManager.GetString("JqueryCdnPrefix", resourceCulture);
}
}
/// <summary>
/// https://cdn.jsdelivr.net/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string JsDeliverPrefix {
get {
return ResourceManager.GetString("JsDeliverPrefix", resourceCulture);
}
}
/// <summary>
/// https://polyfill-fastly.io/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string PolyfillPrefix {
get {
return ResourceManager.GetString("PolyfillPrefix", resourceCulture);
}
}
/// <summary>
/// https://raw.githubusercontent.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string RawGitHubPrefix {
get {
return ResourceManager.GetString("RawGitHubPrefix", resourceCulture);
}
}
/// <summary>
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string RepositoryUrl {
get {
return ResourceManager.GetString("RepositoryUrl", resourceCulture);
}
}
/// <summary>
/// http://localhost:3000/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string ResourceServerPrefix {
get {
return ResourceManager.GetString("ResourceServerPrefix", resourceCulture);
}
}
/// <summary>
/// https://www.skypack.dev/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string SkypackPrefix {
get {
return ResourceManager.GetString("SkypackPrefix", resourceCulture);
}
}
/// <summary>
/// https://unpkg.com/과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string UnpkgPrefix {
get {
return ResourceManager.GetString("UnpkgPrefix", resourceCulture);
}
}
/// <summary>
/// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string WhoisClientAddress {
get {
return ResourceManager.GetString("WhoisClientAddress", resourceCulture);
}
}
/// <summary>
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string WhoisReferrerUrl {
get {
return ResourceManager.GetString("WhoisReferrerUrl", resourceCulture);
}
}
/// <summary>
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
/// </summary>
internal static string WhoisServerUrl {
get {
return ResourceManager.GetString("WhoisServerUrl", resourceCulture);
}
}
}
}

View File

@ -148,4 +148,73 @@
<data name="icon_start_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\icon_start_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="CopilotUrl" xml:space="preserve">
<value>https://copilot.microsoft.com/</value>
</data>
<data name="RepositoryUrl" xml:space="preserve">
<value>https://github.com/gnh1201/welsonjs</value>
</data>
<data name="ResourceServerPrefix" xml:space="preserve">
<value>http://localhost:3000/</value>
</data>
<data name="DevToolsPrefix" xml:space="preserve">
<value>http://localhost:9222/</value>
</data>
<data name="AzureAiServiceApiKey" xml:space="preserve">
<value />
</data>
<data name="AzureAiServicePrefix" xml:space="preserve">
<value>https://ai-catswords656881030318.services.ai.azure.com/</value>
</data>
<data name="DnsServerAddress" xml:space="preserve">
<value>1.1.1.1</value>
</data>
<data name="WhoisClientAddress" xml:space="preserve">
<value>141.101.82.1</value>
</data>
<data name="WhoisReferrerUrl" xml:space="preserve">
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp</value>
</data>
<data name="WhoisServerUrl" xml:space="preserve">
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc</value>
</data>
<data name="BlobStoragePrefix" xml:space="preserve">
<value>https://catswords.blob.core.windows.net/welsonjs/</value>
</data>
<data name="AzureAiServiceApiVersion" xml:space="preserve">
<value>2024-05-01-preview</value>
</data>
<data name="CdnJsPrefix" xml:space="preserve">
<value>https://cdnjs.cloudflare.com/</value>
</data>
<data name="EsmRunPrefix" xml:space="preserve">
<value>https://esm.run/</value>
</data>
<data name="EsmShPrefix" xml:space="preserve">
<value>https://esm.sh/</value>
</data>
<data name="JqueryCdnPrefix" xml:space="preserve">
<value>https://code.jquery.com/</value>
</data>
<data name="JsDeliverPrefix" xml:space="preserve">
<value>https://cdn.jsdelivr.net/</value>
</data>
<data name="SkypackPrefix" xml:space="preserve">
<value>https://www.skypack.dev/</value>
</data>
<data name="UnpkgPrefix" xml:space="preserve">
<value>https://unpkg.com/</value>
</data>
<data name="AspNetCdnPrefix" xml:space="preserve">
<value>https://ajax.aspnetcdn.com/</value>
</data>
<data name="GoogleApisPrefix" xml:space="preserve">
<value>https://ajax.googleapis.com/</value>
</data>
<data name="PolyfillPrefix" xml:space="preserve">
<value>https://polyfill-fastly.io/</value>
</data>
<data name="RawGitHubPrefix" xml:space="preserve">
<value>https://raw.githubusercontent.com/</value>
</data>
</root>

View File

@ -0,0 +1,446 @@
// ResourceServer.cs
// A resource server of WelsonJS Editor (WelsonJS.Launcher)
// Namhyeon Go <abuse@catswords.net>
// https://github.com/gnh1201/welsonjs
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WelsonJS.Launcher
{
public class ResourceServer
{
private readonly HttpListener _listener;
private CancellationTokenSource _cts;
private Task _serverTask;
private bool _isRunning;
private string _prefix;
private string _resourceName;
private List<IResourceTool> _tools = new List<IResourceTool>();
private readonly HttpClient _httpClient = new HttpClient();
private static readonly string _defaultMimeType = "application/octet-stream";
private static readonly Regex _nodePackageRegex = new Regex(@"^[^/@]+@[^/]+/", RegexOptions.Compiled);
private static readonly List<string[]> CDN_PREFIXES = new List<string[]> {
new[] { "ajax/libs/" },
new[] { "npm/", "gh/", "wp/" },
new[] { "jquery/" },
new[] { "polyfill/" },
new[] { "ajax/" }, // https://learn.microsoft.com/en-us/aspnet/ajax/cdn/overview
new[] { "raw/gh/"}
};
private enum CDN_TYPES: int
{
Cloudflare = 0,
JsDeliver = 1,
Jquery = 2,
Polyfill = 3,
Microsoft = 4,
GitHub = 5
};
public ResourceServer(string prefix, string resourceName)
{
_prefix = prefix;
_listener = new HttpListener();
_listener.Prefixes.Add(prefix);
_resourceName = resourceName;
_httpClient.Timeout = TimeSpan.FromSeconds(30);
// Add resource tools
_tools.Add(new ResourceTools.Completion(this, _httpClient));
_tools.Add(new ResourceTools.Settings(this, _httpClient));
_tools.Add(new ResourceTools.DevTools(this, _httpClient));
_tools.Add(new ResourceTools.DnsQuery(this, _httpClient));
_tools.Add(new ResourceTools.Tfa(this, _httpClient));
_tools.Add(new ResourceTools.Whois(this, _httpClient));
}
public string GetPrefix()
{
return _prefix;
}
public void Start()
{
if (_isRunning) return;
_isRunning = true;
_cts = new CancellationTokenSource();
_listener.Start();
// Open the web browser
Program.OpenWebBrowser(_prefix);
// Run a task with cancellation token
_serverTask = Task.Run(() => ListenLoop(_cts.Token));
}
public void Stop()
{
_isRunning = false;
_cts.Cancel();
_listener.Stop();
MessageBox.Show("Server stopped.");
}
public bool IsRunning()
{
return _isRunning;
}
private async Task ListenLoop(CancellationToken token)
{
while (!token.IsCancellationRequested && _isRunning)
{
try
{
await ProcessRequest(await _listener.GetContextAsync());
}
catch (Exception ex)
{
if (token.IsCancellationRequested || !_isRunning) break;
MessageBox.Show($"Error: {ex.Message}");
}
}
}
private async Task ProcessRequest(HttpListenerContext context)
{
string path = context.Request.Url.AbsolutePath.TrimStart('/');
// Serve from a resource name
if (String.IsNullOrEmpty(path))
{
ServeResource(context, GetResource(_resourceName), "text/html");
return;
}
// Serve the favicon.ico file
if ("favicon.ico".Equals(path, StringComparison.OrdinalIgnoreCase))
{
ServeResource(context, GetResource("favicon"), "image/x-icon");
return;
}
// Serve from a resource tool
foreach (var tool in _tools)
{
if (tool.CanHandle(path))
{
await tool.HandleAsync(context, path);
return;
}
}
// Serve from the blob server
if (await ServeBlob(context, path)) return;
// Fallback to serve from a resource name
ServeResource(context, GetResource(_resourceName), "text/html");
}
private async Task<bool> ServeBlob(HttpListenerContext context, string path, string prefix = null)
{
byte[] data;
string mimeType;
if (!String.IsNullOrEmpty(prefix))
{
string url = $"{prefix}{path}";
try
{
using (var client = new HttpClient())
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.UserAgent.ParseAdd(context.Request.UserAgent);
HttpResponseMessage response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
Trace.TraceError($"Failed to serve blob. URL: {url}, Status: {response.StatusCode}");
return false;
}
data = await response.Content.ReadAsByteArrayAsync();
mimeType = response.Content.Headers.ContentType?.MediaType ?? _defaultMimeType;
ServeResource(context, data, mimeType);
_ = TrySaveCachedBlob(path, data, mimeType);
return true;
}
}
catch (Exception ex)
{
Trace.TraceError($"Failed to serve blob. URL: {url}, Exception: {ex.Message}");
return false;
}
}
else
{
// use the cached data
if (TryGetCachedBlob(path, out mimeType, true))
{
if (TryGetCachedBlob(path, out data))
{
if (String.IsNullOrEmpty(mimeType))
{
mimeType = _defaultMimeType;
}
ServeResource(context, data, mimeType);
return true;
}
}
// use CDN sources
if (await TryServeFromCdn(context, path))
{
return true;
}
}
return false;
}
private async Task<bool> TryServeFromCdn(HttpListenerContext context, string path)
{
bool isNodePackageExpression = _nodePackageRegex.IsMatch(path);
bool isPrefixMatched(CDN_TYPES type)
{
if (CDN_PREFIXES[(int)type].Any(prefix => path.StartsWith(prefix)))
{
return true;
}
return false;
}
var sources = new (bool isMatch, string configKey, Func<string, string> transform)[]
{
(isPrefixMatched(CDN_TYPES.Cloudflare), "CdnJsPrefix", p => p), // Libraries from Cloudflare
(isPrefixMatched(CDN_TYPES.Cloudflare), "GoogleApisPrefix", p => p), // Libraries from Google
(isNodePackageExpression, "UnpkgPrefix", p => p),
(isNodePackageExpression, "SkypackPrefix", p => p),
(isNodePackageExpression, "EsmShPrefix", p => p),
(isNodePackageExpression, "EsmRunPrefix", p => p),
(isPrefixMatched(CDN_TYPES.JsDeliver), "JsDeliverPrefix", p => p),
(isPrefixMatched(CDN_TYPES.Jquery), "JqueryCdnPrefix", p => p.Substring("jquery/".Length)),
(isPrefixMatched(CDN_TYPES.Polyfill), "CdnJsPrefix", p => p), // polyfill.js from Cloudflare
(isPrefixMatched(CDN_TYPES.Polyfill), "PolyfillPrefix", p => p.Substring("polyfill/".Length)), // polyfill.js from Fastly
(isPrefixMatched(CDN_TYPES.Microsoft), "AspNetCdnPrefix", p => p), // Libraries from Microsoft
(isPrefixMatched(CDN_TYPES.GitHub), "RawGitHubPrefix", p => p.Substring("raw/gh/".Length)),
(true, "BlobStoragePrefix", p => p) // fallback
};
foreach (var (isMatch, configKey, transform) in sources)
{
if (isMatch)
{
string prefix = Program.GetAppConfig(configKey);
if (await ServeBlob(context, transform(path), prefix))
{
return true;
}
}
}
return false;
}
private string GetCachedBlobPath(string path)
{
// Get a hash from the path
string hashedPath;
using (MD5 md5 = MD5.Create())
{
byte[] bHashedPath = md5.ComputeHash(Encoding.UTF8.GetBytes(path));
hashedPath = BitConverter.ToString(bHashedPath).Replace("-", "").ToLowerInvariant();
}
// Get a sub-directory paths from the hashed path
string[] subDirectoryPaths = new string[] {
hashedPath.Substring(0, 2),
hashedPath.Substring(2, 2),
hashedPath.Substring(4, 2)
};
// Return the cache path
return Path.Combine(Program.GetAppDataPath(), "BlobCache", String.Join("\\", subDirectoryPaths), hashedPath);
}
private bool TryGetCachedBlob(string path, out byte[] data, bool isMetadata = false)
{
string cachePath = GetCachedBlobPath(path);
if (isMetadata)
{
cachePath = $"{cachePath}.meta";
}
try
{
if (File.Exists(cachePath))
{
data = File.ReadAllBytes(cachePath);
return true;
}
}
catch (Exception ex)
{
Trace.TraceError($"Cache Read Error: {ex.Message}");
}
data = null;
return false;
}
private bool TryGetCachedBlob(string path, out string data, bool isMetadata = false)
{
byte[] bData;
if (TryGetCachedBlob(path, out bData, isMetadata))
{
data = Encoding.UTF8.GetString(bData);
return true;
}
data = null;
return false;
}
private async Task<bool> TrySaveCachedBlob(string path, byte[] data, string mimeType)
{
await Task.Delay(0);
try
{
string cachePath = GetCachedBlobPath(path);
string cacheDirectory = Path.GetDirectoryName(cachePath);
// Is exists the cached blob directory
if (!Directory.Exists(cacheDirectory))
{
Directory.CreateDirectory(cacheDirectory);
}
// Save the cache
File.WriteAllBytes(cachePath, data);
// Save the cache meta
File.WriteAllBytes($"{cachePath}.meta", Encoding.UTF8.GetBytes(mimeType));
return true;
}
catch (Exception ex)
{
Trace.TraceError($"Error: {ex.Message}");
return false;
}
}
public void ServeResource(HttpListenerContext context)
{
ServeResource(context, "<error>Not Found</error>", "application/xml", 404);
}
public void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
{
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
if (data == null) {
data = Encoding.UTF8.GetBytes(xmlHeader + "\r\n<error>Could not find the resource.</error>");
mimeType = "application/xml";
statusCode = 404;
}
context.Response.StatusCode = statusCode;
context.Response.ContentType = mimeType;
context.Response.ContentLength64 = data.Length;
using (Stream outputStream = context.Response.OutputStream)
{
outputStream.Write(data, 0, data.Length);
}
}
public void ServeResource(HttpListenerContext context, string data, string mimeType = "text/html", int statusCode = 200)
{
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
if (data == null)
{
data = xmlHeader + "\r\n<error>Could not find the resource.</error>";
mimeType = "application/xml";
statusCode = 404;
}
else if (mimeType == "application/xml" && !data.StartsWith("<?xml"))
{
data = xmlHeader + "\r\n" + data;
}
ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
}
private byte[] GetResource(string resourceName)
{
// Try to fetch embedded resource.
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
if (data != null) return data;
// Fallback: Try to fetch resource from ResourceManager.
return GetResourceFromManager(resourceName);
}
private byte[] GetEmbeddedResource(string fullResourceName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
{
if (stream != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
return null;
}
private byte[] GetResourceFromManager(string resourceName)
{
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
switch (resourceObject)
{
case byte[] resourceBytes:
return resourceBytes;
case System.Drawing.Icon icon:
return ConvertIconToBytes(icon);
default:
return null;
}
}
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
{
using (MemoryStream memoryStream = new MemoryStream())
{
icon.Save(memoryStream);
return memoryStream.ToArray();
}
}
}
}

View File

@ -3,29 +3,75 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Net.Http;
namespace WelsonJS.Launcher.Tools
namespace WelsonJS.Launcher.ResourceTools
{
public class ExecutablesCollector
public class Completion : IResourceTool
{
private List<string> executables = new List<string>();
private readonly ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "completion/";
private List<string> Executables = new List<string>();
public ExecutablesCollector()
public Completion(ResourceServer server, HttpClient httpClient)
{
Server = server;
_httpClient = httpClient;
new Task(() =>
{
executables.AddRange(GetInstalledSoftwareExecutables());
executables.AddRange(GetExecutablesFromPath());
executables.AddRange(GetExecutablesFromNetFx());
Executables.AddRange(GetInstalledSoftwareExecutables());
Executables.AddRange(GetExecutablesFromPath());
Executables.AddRange(GetExecutablesFromNetFx());
}).Start();
}
public List<string> GetExecutables()
public bool CanHandle(string path)
{
return executables;
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
await Task.Delay(0);
string word = path.Substring(Prefix.Length);
try
{
CompletionItem[] completionItems = Executables
.Where(exec => exec.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) > -1)
.Take(100) // Limit the number of results
.Select(exec => new CompletionItem
{
Label = Path.GetFileName(exec),
Kind = "Text",
Documentation = $"An executable file: {exec}",
InsertText = exec
})
.ToArray();
XElement response = new XElement("suggestions",
completionItems.Select(item => new XElement("item",
new XElement("label", item.Label),
new XElement("kind", item.Kind),
new XElement("documentation", item.Documentation),
new XElement("insertText", item.InsertText)
))
);
Server.ServeResource(context, response.ToString(), "application/xml");
}
catch (Exception ex)
{
Server.ServeResource(context, $"<error>Failed to process completion request. {ex.Message}</error>", "application/xml", 500);
}
}
private List<string> GetInstalledSoftwareExecutables()
@ -157,4 +203,12 @@ namespace WelsonJS.Launcher.Tools
return executables;
}
}
public class CompletionItem
{
public string Label { get; set; }
public string Kind { get; set; }
public string Documentation { get; set; }
public string InsertText { get; set; }
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace WelsonJS.Launcher.ResourceTools
{
public class DevTools : IResourceTool
{
private ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "devtools/";
public DevTools(ResourceServer server, HttpClient httpClient)
{
Server = server;
_httpClient = httpClient;
}
public bool CanHandle(string path)
{
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
string endpoint = path.Substring(Prefix.Length);
try
{
string url = Program.GetAppConfig("DevToolsPrefix") + endpoint;
string data = await _httpClient.GetStringAsync(url);
Server.ServeResource(context, data, "application/json");
}
catch (Exception ex)
{
Server.ServeResource(context, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500);
}
}
}
}

View File

@ -1,22 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace WelsonJS.Launcher.Tools
namespace WelsonJS.Launcher.ResourceTools
{
public class DnsQuery
public class DnsQuery : IResourceTool
{
private static readonly Random _random = new Random();
private readonly string _dnsServer;
private readonly ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "dns-query/";
private string DnsServer;
private const int DnsPort = 53;
private const int Timeout = 5000;
private static readonly Random _random = new Random();
public DnsQuery(string dnsServer = "8.8.8.8")
public DnsQuery(ResourceServer server, HttpClient httpClient)
{
_dnsServer = dnsServer;
Server = server;
_httpClient = httpClient;
DnsServer = Program.GetAppConfig("DnsServerAddress");
}
public bool CanHandle(string path)
{
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
await Task.Delay(0);
string query = path.Substring(Prefix.Length);
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
{
Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
return;
}
try
{
Dictionary<string, List<string>> allRecords = QueryAll(query);
StringBuilder result = new StringBuilder();
foreach (var recordType in allRecords.Keys)
{
result.AppendLine($"\n{recordType} Records:");
foreach (var record in allRecords[recordType])
{
result.AppendLine(record);
}
}
string data = result.ToString();
Server.ServeResource(context, data, "text/plain", 200);
}
catch (Exception ex)
{
Server.ServeResource(context, $"<error>Failed to process DNS query. {ex.Message}</error>", "application/xml", 500);
}
}
public List<string> QueryA(string domain) => QueryDns(domain, 1);
@ -62,7 +110,7 @@ namespace WelsonJS.Launcher.Tools
}
// Basic domain format validation
if (domain.Length > 255 ||
if (domain.Length > 255 ||
!domain.Split('.').All(part => part.Length > 0 && part.Length <= 63))
{
records.Add("Error: Invalid domain format");
@ -71,17 +119,18 @@ namespace WelsonJS.Launcher.Tools
try
{
UdpClient udpClient = new UdpClient(_dnsServer, DnsPort);
udpClient.Client.ReceiveTimeout = Timeout;
using (UdpClient udpClient = new UdpClient(DnsServer, DnsPort))
{
udpClient.Client.ReceiveTimeout = Timeout;
byte[] request = CreateDnsQuery(domain, type);
udpClient.Send(request, request.Length);
byte[] request = CreateDnsQuery(domain, type);
udpClient.Send(request, request.Length);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
byte[] response = udpClient.Receive(ref remoteEP);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
byte[] response = udpClient.Receive(ref remoteEP);
records.AddRange(ParseDnsResponse(response, type));
udpClient.Close();
records.AddRange(ParseDnsResponse(response, type));
}
}
catch (Exception ex)
{

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Resources;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace WelsonJS.Launcher.ResourceTools
{
public class Settings : IResourceTool
{
private readonly ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "settings";
public Settings(ResourceServer server, HttpClient httpClient)
{
Server = server;
_httpClient = httpClient;
}
public bool CanHandle(string path)
{
return path.Equals(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
await Task.Delay(0);
// Get current namespace (e.g., WelsonJS.Launcher)
string ns = typeof(Program).Namespace;
// Build resource base name (e.g., WelsonJS.Launcher.Properties.Resources)
string resourceBaseName = ns + ".Properties.Resources";
// Load resource strings using ResourceManager
var resourceManager = new ResourceManager(resourceBaseName, Assembly.GetExecutingAssembly());
var resourceSet = resourceManager.GetResourceSet(
System.Globalization.CultureInfo.CurrentCulture,
true,
true
);
var resourceStrings = new Dictionary<string, string>();
foreach (System.Collections.DictionaryEntry entry in resourceSet)
{
if (entry.Value is string strValue)
{
resourceStrings[(string)entry.Key] = strValue;
}
}
// Load settings from app.config
var appConfig = ConfigurationManager.AppSettings.AllKeys
.ToDictionary(k => k, k => ConfigurationManager.AppSettings[k]);
// Merge by starting with resourceStrings and letting app.config override
var finalConfig = new Dictionary<string, string>(resourceStrings);
foreach (var kv in appConfig)
{
finalConfig[kv.Key] = kv.Value;
}
// Generate XML using XElement
XElement xml = new XElement("settings",
finalConfig.Select(kv => new XElement(kv.Key, kv.Value))
);
Server.ServeResource(context, xml.ToString(), "application/xml");
}
}
}

View File

@ -2,13 +2,45 @@
using System.Linq;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using System.Net.Http;
namespace WelsonJS.Launcher.Tools
namespace WelsonJS.Launcher.ResourceTools
{
public class Tfa
public class Tfa : IResourceTool
{
private readonly ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "tfa/";
private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public Tfa(ResourceServer server, HttpClient httpClient)
{
Server = server;
_httpClient = httpClient;
}
public bool CanHandle(string path)
{
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
await Task.Delay(0);
string endpoint = path.Substring(Prefix.Length);
if (endpoint.Equals("pubkey"))
{
Server.ServeResource(context, GetPubKey(), "text/plain", 200);
return;
}
Server.ServeResource(context);
}
public int GetOtp(string key)
{
byte[] binaryKey = DecodeBase32(key.Replace(" ", ""));

View File

@ -0,0 +1,60 @@
using System.Net;
using System.Threading.Tasks;
using System;
using System.Net.Http;
using System.Text;
namespace WelsonJS.Launcher.ResourceTools
{
public class Whois : IResourceTool
{
private readonly ResourceServer Server;
private readonly HttpClient _httpClient;
private const string Prefix = "whois/";
public Whois(ResourceServer server, HttpClient httpClient)
{
Server = server;
_httpClient = httpClient;
}
public bool CanHandle(string path)
{
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
}
public async Task HandleAsync(HttpListenerContext context, string path)
{
string query = path.Substring(Prefix.Length);
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
{
Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
return;
}
string clientAddress = Program.GetAppConfig("WhoisClientAddress");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl"))
{
Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip={clientAddress}", Encoding.UTF8, "application/x-www-form-urlencoded")
};
request.Headers.Add("Accept", "*/*");
request.Headers.Add("User-Agent", context.Request.UserAgent);
_httpClient.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl"));
try
{
HttpResponseMessage response = await _httpClient.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
}
catch (Exception ex)
{
Server.ServeResource(context, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
}
}
}
}

View File

@ -1,375 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
namespace WelsonJS.Launcher.Tools
{
public class ResourceServer
{
private readonly HttpListener _listener;
private CancellationTokenSource _cts;
private Task _serverTask;
private bool _isRunning;
private string _prefix;
private string _resourceName;
private ExecutablesCollector _executablesCollector;
public ResourceServer(string prefix, string resourceName)
{
_prefix = prefix;
_listener = new HttpListener();
_listener.Prefixes.Add(prefix);
_resourceName = resourceName;
_executablesCollector = new ExecutablesCollector();
}
public string GetPrefix()
{
return _prefix;
}
public void Start()
{
if (_isRunning) return;
_isRunning = true;
_cts = new CancellationTokenSource();
_listener.Start();
// Open the web browser
Program.OpenWebBrowser(_prefix);
// Run a task with cancellation token
_serverTask = Task.Run(() => ListenLoop(_cts.Token));
}
public void Stop()
{
_isRunning = false;
_cts.Cancel();
_listener.Stop();
MessageBox.Show("Server stopped.");
}
public bool IsRunning()
{
return _isRunning;
}
private async Task ListenLoop(CancellationToken token)
{
while (!token.IsCancellationRequested && _isRunning)
{
try
{
await ProcessRequest(await _listener.GetContextAsync());
}
catch (Exception ex)
{
if (token.IsCancellationRequested || !_isRunning) break;
MessageBox.Show($"Error: {ex.Message}");
}
}
}
private async Task ProcessRequest(HttpListenerContext context)
{
string path = context.Request.Url.AbsolutePath.TrimStart('/');
// Serve the favicon.ico file
if ("favicon.ico".Equals(path, StringComparison.OrdinalIgnoreCase))
{
ServeResource(context, GetResource("favicon"), "image/x-icon");
return;
}
// Serve the code completion (word suggestion)
const string completionPrefix = "completion/";
if (path.StartsWith(completionPrefix, StringComparison.OrdinalIgnoreCase))
{
ServeCompletion(context, path.Substring(completionPrefix.Length));
return;
}
// Serve the DevTools Protocol
const string devtoolsPrefix = "devtools/";
if (path.StartsWith(devtoolsPrefix, StringComparison.OrdinalIgnoreCase))
{
await ServeDevTools(context, path.Substring(devtoolsPrefix.Length));
return;
}
// Serve WHOIS request (use KRNIC server)
const string whoisPrefix = "whois/";
if (path.StartsWith(whoisPrefix, StringComparison.OrdinalIgnoreCase))
{
await ServeWhoisRequest(context, path.Substring(whoisPrefix.Length));
return;
}
// Serve DNS Query request (use Google DNS server)
const string dnsQueryPrefix = "dns-query/";
if (path.StartsWith(dnsQueryPrefix, StringComparison.OrdinalIgnoreCase))
{
ServeDnsQueryRequest(context, path.Substring(dnsQueryPrefix.Length));
return;
}
// Serve TFA request
const string tfaPrefix = "tfa/";
if (path.StartsWith(tfaPrefix, StringComparison.OrdinalIgnoreCase))
{
ServeTfaRequest(context, path.Substring(tfaPrefix.Length));
return;
}
// Serve a resource
ServeResource(context, GetResource(_resourceName), "text/html");
}
private void ServeCompletion(HttpListenerContext context, string word)
{
try
{
List<string> executables = _executablesCollector.GetExecutables();
CompletionItem[] completionItems = executables
.Where(exec => exec.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) > -1)
.Take(100) // Limit the number of results
.Select(exec => new CompletionItem
{
Label = Path.GetFileName(exec),
Kind = "Text",
Documentation = $"An executable file: {exec}",
InsertText = exec
})
.ToArray();
XElement response = new XElement("suggestions",
completionItems.Select(item => new XElement("item",
new XElement("label", item.Label),
new XElement("kind", item.Kind),
new XElement("documentation", item.Documentation),
new XElement("insertText", item.InsertText)
))
);
ServeResource(context, response.ToString(), "application/xml");
}
catch (Exception ex)
{
ServeResource(context, $"<error>Failed to process completion request. {ex.Message}</error>", "application/xml", 500);
}
}
private async Task ServeDevTools(HttpListenerContext context, string endpoint)
{
try
{
using (HttpClient client = new HttpClient())
{
string url = "http://localhost:9222/" + endpoint;
string data = await client.GetStringAsync(url);
ServeResource(context, data, "application/json");
}
}
catch (Exception ex)
{
ServeResource(context, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500);
}
}
private async Task ServeWhoisRequest(HttpListenerContext context, string query)
{
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
{
ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
return;
}
string whoisServerUrl = "https://xn--c79as89aj0e29b77z.xn--3e0b707e";
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(10);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{whoisServerUrl}/kor/whois.jsc")
{
Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip=141.101.82.1", Encoding.UTF8, "application/x-www-form-urlencoded")
};
request.Headers.Add("Accept", "*/*");
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.3124.77");
client.DefaultRequestHeaders.Referrer = new Uri($"{whoisServerUrl}/kor/whois/whois.jsp");
try
{
HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
}
catch (Exception ex)
{
ServeResource(context, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
}
}
}
private void ServeDnsQueryRequest(HttpListenerContext context, string query)
{
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
{
ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
return;
}
try
{
DnsQuery dns = new DnsQuery();
Dictionary<string, List<string>> allRecords = dns.QueryAll(query);
StringBuilder result = new StringBuilder();
foreach (var recordType in allRecords.Keys)
{
result.AppendLine($"\n{recordType} Records:");
foreach (var record in allRecords[recordType])
{
result.AppendLine(record);
}
}
string data = result.ToString();
ServeResource(context, data, "text/plain", 200);
}
catch (Exception ex)
{
ServeResource(context, $"<error>Failed to process DNS query. {ex.Message}</error>", "application/xml", 500);
}
}
private void ServeTfaRequest(HttpListenerContext context, string endpoint)
{
Tfa _tfa = new Tfa();
if (endpoint.Equals("pubkey"))
{
ServeResource(context, _tfa.GetPubKey(), "text/plain", 200);
return;
}
ServeResource(context);
}
private void ServeResource(HttpListenerContext context)
{
ServeResource(context, "<error>Not Found</error>", "application/xml", 404);
}
private void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
{
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
if (data == null) {
data = Encoding.UTF8.GetBytes(xmlHeader + "\r\n<error>Could not find the resource.</error>");
mimeType = "application/xml";
statusCode = 404;
}
context.Response.StatusCode = statusCode;
context.Response.ContentType = mimeType;
context.Response.ContentLength64 = data.Length;
using (Stream outputStream = context.Response.OutputStream)
{
outputStream.Write(data, 0, data.Length);
}
}
private void ServeResource(HttpListenerContext context, string data, string mimeType = "text/html", int statusCode = 200)
{
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
if (data == null)
{
data = xmlHeader + "\r\n<error>Could not find the resource.</error>";
mimeType = "application/xml";
statusCode = 404;
}
else if (mimeType == "application/xml" && !data.StartsWith("<?xml"))
{
data = xmlHeader + "\r\n" + data;
}
ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
}
private byte[] GetResource(string resourceName)
{
// Try to fetch embedded resource.
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
if (data != null) return data;
// Fallback: Try to fetch resource from ResourceManager.
return GetResourceFromManager(resourceName);
}
private byte[] GetEmbeddedResource(string fullResourceName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
{
if (stream != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
return null;
}
private byte[] GetResourceFromManager(string resourceName)
{
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
switch (resourceObject)
{
case byte[] resourceBytes:
return resourceBytes;
case System.Drawing.Icon icon:
return ConvertIconToBytes(icon);
default:
return null;
}
}
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
{
using (MemoryStream memoryStream = new MemoryStream())
{
icon.Save(memoryStream);
return memoryStream.ToArray();
}
}
}
public class CompletionItem
{
public string Label { get; set; }
public string Kind { get; set; }
public string Documentation { get; set; }
public string InsertText { get; set; }
}
}

View File

@ -57,6 +57,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
@ -72,14 +73,19 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="Tools\DnsQuery.cs" />
<Compile Include="IResourceTool.cs" />
<Compile Include="ResourceTools\Settings.cs" />
<Compile Include="ResourceTools\Completion.cs" />
<Compile Include="ResourceTools\DevTools.cs" />
<Compile Include="ResourceTools\DnsQuery.cs" />
<Compile Include="ResourceTools\Tfa.cs" />
<Compile Include="ResourceTools\Whois.cs" />
<Compile Include="EnvForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="EnvForm.Designer.cs">
<DependentUpon>EnvForm.cs</DependentUpon>
</Compile>
<Compile Include="Tools\ExecutablesCollector.cs" />
<Compile Include="InstancesForm.cs">
<SubType>Form</SubType>
</Compile>
@ -100,8 +106,7 @@
<Compile Include="GlobalSettingsForm.Designer.cs">
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
</Compile>
<Compile Include="Tools\ResourceServer.cs" />
<Compile Include="Tools\Tfa.cs" />
<Compile Include="ResourceServer.cs" />
<EmbeddedResource Include="EnvForm.resx">
<DependentUpon>EnvForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -1,3 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
<appSettings>
<add key="ResourceServerPrefix" value="http://localhost:3000/"/>
<add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/>
<add key="CopilotUrl" value="https://copilot.microsoft.com/"/>
<add key="DevToolsPrefix" value="http://localhost:9222/"/>
<add key="AzureAiServicePrefix" value="https://ai-catswords656881030318.services.ai.azure.com/"/>
<add key="AzureAiServiceApiKey" value=""/>
<add key="AzureAiServiceApiVersion" value="2024-05-01-preview"/>
<add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/>
<add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/>
<add key="WhoisClientAddress" value="141.101.82.1"/>
<add key="DnsServerAddress" value="1.1.1.1"/>
<add key="BlobStoragePrefix" value="https://catswords.blob.core.windows.net/welsonjs/"/>
<add key="CdnJsPrefix" value="https://cdnjs.cloudflare.com/"/>
<add key="JsDeliverPrefix" value="https://cdn.jsdelivr.net/"/>
<add key="UnpkgPrefix" value="https://unpkg.com/"/>
<add key="SkypackPrefix" value="https://www.skypack.dev/"/>
<add key="EsmShPrefix" value="https://esm.sh/"/>
<add key="EsmRunPrefix" value="https://esm.run/"/>
<add key="JqueryCdnPrefix" value="https://code.jquery.com/"/>
<add key="AspNetCdnPrefix" value="https://ajax.aspnetcdn.com/"/>
<add key="GoogleApisPrefix" value="https://ajax.googleapis.com/"/>
<add key="RawGitHubPrefix" value="https://raw.githubusercontent.com/"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>

View File

@ -2,12 +2,15 @@
<html>
<head>
<title>WelsonJS Editor</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" href="https://cdn.metroui.org.ua/dev/metro.css">
<link rel="stylesheet" href="https://cdn.metroui.org.ua/dev/icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.css">
<meta name="title" content="WelsonJS Editor">
<meta name="description" content="WelsonJS can build a Windows app on the Windows built-in JavaScript engine.">
<meta name="keywords" content="ecmascript, javascript, windows">
<meta name="robots" content="noindex, nofollow">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="language" content="English">
<meta name="author" content="Namhyeon Go (abuse@catswords.net)">
<style>
html, body {
html, body, #app, #app > .app {
margin: 0;
padding: 0;
width: 100%;
@ -17,12 +20,17 @@
#container {
border: 1px solid grey;
height: calc(100% - 139px);
height: calc(100% - 167px);
display: flex;
overflow: hidden;
}
#fileInput {
display: none;
#editor {
flex: 3;
}
#promptEditor {
flex: 1;
}
.banner {
@ -34,331 +42,556 @@
</style>
</head>
<body>
<nav data-role="ribbonmenu">
<ul class="tabs-holder">
<li class="static"><a href="#">WelsonJS</a></li>
<li><a href="#editor-tab">Editor</a></li>
</ul>
<div class="content-holder">
<div class="section" id="editor-tab">
<div class="group">
<button id="btnOpenFile" class="ribbon-button">
<span class="icon mif-folder-open"></span>
<span class="caption">Open File</span>
</button>
<button id="btnSaveFile" class="ribbon-button">
<span class="icon mif-floppy-disks"></span>
<span class="caption">Save File</span>
</button>
<button id="btnGenerate" class="ribbon-button">
<span class="icon mif-rocket"></span>
<span class="caption">Generate</span>
</button>
<button id="btnSponsor" class="ribbon-button">
<span class="icon mif-heart"></span>
<span class="caption">Sponsor</span>
</button>
<span class="title">Common</span>
</div>
<div class="group">
<button id="btnWhois" class="ribbon-button">
<span class="icon mif-earth"></span>
<span class="caption">Whois</span>
</button>
<button id="btnDnsQuery" class="ribbon-button">
<span class="icon mif-earth"></span>
<span class="caption">DNS</span>
</button>
<span class="title">Network tools</span>
</div>
</div>
</div>
</nav>
<div id="container"></div>
<input type="file" id="fileInput">
<div class="banner"><a href="https://github.com/gnh1201/welsonjs">WelsonJS</a> Code Editor powered by <a href="https://github.com/microsoft/monaco-editor">Microsoft Monaco Editor</a>.</div>
<div id="app"></div>
<script>
var require = {
paths: {
vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs'
vs: 'http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs'
}
};
</script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/4.5.1/fxparser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.4/purify.min.js"></script>
<script src="https://cdn.metroui.org.ua/dev/metro.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.js"></script>
<script src="http://localhost:3000/ajax/libs/lodash/4.17.21/lodash.min.js" integrity="sha384-H6KKS1H1WwuERMSm+54dYLzjg0fKqRK5ZRyASdbrI/lwrCc6bXEmtGYr5SwvP1pZ" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.js" integrity="sha384-NdVVc20Tze856ZAWEoJNCk0mL4zJrGztRwULc5Hz25HUXQQgYtmjFtgVAxR4p5dD" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/axios/1.8.4/axios.min.js" integrity="sha384-06w+raHvkSL3+E7mbQ2X6DZwI5A3veU8Ba+NLrAPxxRGw4Xy78sihHDHQMustMM4" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/fast-xml-parser/4.5.1/fxparser.min.js" integrity="sha384-ae/HepOQ8hiJ/VA6yGwPMGXQXOkT/lJpjlcQ7EUgibUcfnBltuozgNj4IgOZ9QLc" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/dompurify/3.2.4/purify.min.js" integrity="sha384-eEu5CTj3qGvu9PdJuS+YlkNi7d2XxQROAFYOr59zgObtlcux1ae1Il3u7jvdCSWu" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/loader.js" integrity="sha384-pHG02SG8pId94Np3AbPmBEJ1yPqaH0IkJGLSNGXYmuGhkazT8Lr/57WYpbkGjJtu" crossorigin="anonymous"></script>
<script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.js" integrity="sha384-fj9z+NUc93I3woCCy5IRQfrQ8Amu1E27tllwgb5gz3d9Vr1ymS13xcF6two3e4KH" crossorigin="anonymous"></script>
<script>
var editor;
var currentFileName = "sayhello.js";
var serverBaseUrl = "http://localhost:3000";
function loadResource(url, mimeType, integrity) {
mimeType = mimeType || 'application/javascript';
function resizeEditor() {
if (editor) {
var ribbonHeight = document.querySelector('nav').offsetHeight;
var bannerHeight = document.querySelector('.banner').offsetHeight;
var containerHeight = document.documentElement.clientHeight - ribbonHeight - bannerHeight;
document.getElementById('container').style.height = containerHeight + 'px';
editor.layout();
}
return new Promise((resolve, reject) => {
let el;
if (mimeType === 'text/css') {
el = document.createElement('link');
el.rel = 'stylesheet';
el.type = mimeType;
el.href = url;
} else {
el = document.createElement('script');
el.type = mimeType;
el.src = url;
}
if (integrity) {
el.integrity = integrity;
el.crossOrigin = 'anonymous';
}
el.onload = resolve;
el.onerror = reject;
(mimeType === 'text/css' ? document.head : document.body).appendChild(el);
});
}
function getSuggestions(word, range) {
return axios.get(`${serverBaseUrl}/completion/${encodeURIComponent(word)}`)
.then(function (response) {
var parser = new XMLParser();
var result = parser.parse(response.data);
Promise.all([
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/metro.css", "text/css", "sha384-4XgOiXH2ZMaWt5s5B35yKi7EAOabhZvx7wO8Jr71q2vZ+uONdRza/6CsK2kpyocd"),
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/icons.css", "text/css", "sha384-FuLND994etg+RtnpPSPMyNBvL+fEz+xGhbN61WUWuDEeZ+wJzcQ8SGqAMuI5hWrt"),
loadResource("http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.css", "text/css", "sha384-06yHXpYRlHEPaR4AS0fB/W+lMN09Zh5e1XMtfkNQdHV38OlhfkOEW5M+pCj3QskC"),
loadResource("http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.css", "text/css", "sha384-cj1rYBc4/dVYAknZMTkVCDRL6Knzugf32igVqsuFW0iRWFHKH8Ci8+ekC8gNsFZ+")
]).then(() => {
const _e = React.createElement;
if (!result.suggestions || !result.suggestions.item) {
function Button({ id, icon, caption, onClick }) {
return _e(
'button',
{ id, className: 'ribbon-button', onClick },
_e('span', { className: `icon ${icon}` }),
_e('span', { className: 'caption' }, caption)
);
}
function Group({ title, buttons }) {
return _e(
'div',
{ className: 'group' },
buttons.map((btn, index) =>
_e(Button, { key: index, ...btn })
),
_e('span', { className: 'title' }, title)
);
}
function RibbonMenu({
onOpenFileClick, onSaveFileClick, onCopliotClick, onAzureAiClick,
onSavePromptClick, onLoadPromptClick, onQueryWhoisClick, onQueryDnsClick
}) {
const fileButtons = [
{
id: 'btnOpenFile',
icon: 'mif-folder-open',
caption: 'Open File',
onClick: onOpenFileClick
},
{
id: 'btnSaveFile',
icon: 'mif-floppy-disks',
caption: 'Save File',
onClick: onSaveFileClick
}
];
const aiButtons = [
{ id: 'btnCopilot', icon: 'mif-rocket', caption: 'Copilot', onClick: onCopliotClick },
{ id: 'btnAzureAi', icon: 'mif-rocket', caption: 'Azure AI', onClick: onAzureAiClick },
{ id: 'btnSavePrompt', icon: 'mif-floppy-disks', caption: 'Save', onClick: onSavePromptClick },
{ id: 'btnLoadPrompt', icon: 'mif-file-upload', caption: 'Load', onClick: onLoadPromptClick }
];
const networkToolsButtons = [
{ id: 'btnWhois', icon: 'mif-earth', caption: 'Whois', onClick: onQueryWhoisClick },
{ id: 'btnDnsQuery', icon: 'mif-earth', caption: 'DNS', onClick: onQueryDnsClick }
];
return _e(
'nav',
{ 'className': 'ribbon-menu' },
_e('ul', { className: 'tabs-holder' },
_e('li', { className: 'static' }, _e('a', { href: '#heading-tab' }, 'WelsonJS')),
_e('li', { className: 'active' }, _e('a', { href: '#editor-tab' }, 'Editor'))
),
_e('div', { className: 'content-holder' },
_e('div', { className: 'section active', id: 'editor-tab' },
_e(Group, { title: 'File', buttons: fileButtons }),
_e(Group, { title: 'Generative AI', buttons: aiButtons }),
_e(Group, { title: 'Network tools', buttons: networkToolsButtons })
)
)
);
}
function Editor({ editorRef }) {
const containerRef = React.useRef(null);
React.useEffect(() => {
if (!containerRef.current)
return;
require(['vs/editor/editor.main'], () => {
const instance = monaco.editor.create(containerRef.current, {
value: ['// lib/sayhello.js', 'function say() {', ' console.log("hello");', '}', '', 'exports.say = say;', '', 'exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1";', 'exports.AUTHOR = "abuse@catswords.net";', 'exports.global = global;', 'exports.require = global.require;'].join('\n'),
language: 'javascript'
});
editorRef.current = instance;
});
}, []);
return _e('div', { id: 'editor', ref: containerRef });
}
function PromptEditor({ promptEditorRef, promptMessagesRef }) {
const containerRef = React.useRef(null);
React.useEffect(() => {
if (!containerRef.current)
return;
const invoke = () => {
try {
if (promptEditorRef.current) {
const updated = promptEditorRef.current.get();
promptMessagesRef.current = updated;
} else {
throw new Error("promptEditorRef.current is null");
}
} catch (e) {
console.error("Invalid JSON structure", e);
}
};
const throttledInvoke = _.throttle(invoke, 300, {
leading: true,
trailing: true
});
const options = {
onChange: throttledInvoke
};
const instance = new JSONEditor(containerRef.current, options);
instance.set(promptMessagesRef.current);
promptEditorRef.current = instance;
return () => {
if (instance) {
throttledInvoke.flush();
throttledInvoke.cancel();
instance.destroy();
}
};
}, []);
return _e('div', { id: 'promptEditor', ref: containerRef });
}
function App() {
const serverPrefix = "http://localhost:3000/";
const editorRef = React.useRef(null);
const promptEditorRef = React.useRef(null);
const settingsRef = React.useRef({});
const fileNameRef = React.useRef('sayhello.js');
const promptMessagesRef = React.useRef([]);
const fetchSettings = () => axios.get(`${serverPrefix}settings`)
.then(response => {
const parser = new XMLParser();
const result = parser.parse(response.data);
settingsRef.current = result.settings;
});
const resizeEditor = () => {
if (editorRef.current) {
const ribbon = document.querySelector('nav')?.offsetHeight || 0;
const banner = document.querySelector('.banner')?.offsetHeight || 0;
const h = document.documentElement.clientHeight - ribbon - banner;
const editorDiv = document.getElementById('editor');
if (editorDiv) editorDiv.style.height = h + 'px';
if (editorRef.current) editorRef.current.layout();
}
};
const getSuggestions = (word) => axios.get(`${serverPrefix}completion/${encodeURIComponent(word)}`)
.then(response => {
const parser = new XMLParser();
const result = parser.parse(response.data);
if (!result.suggestions || !result.suggestions.item) {
return {
suggestions: []
};
}
const items = Array.isArray(result.suggestions.item) ? result.suggestions.item : [result.suggestions.item];
const suggestions = items.map(function (item) {
return {
label: item.label,
kind: monaco.languages.CompletionItemKind.Text,
documentation: item.documentation || "",
insertText: '"' + item.insertText + '"',
range: range
};
});
return {
suggestions: suggestions
};
})
.catch(function () {
return {
suggestions: []
};
}
var items = Array.isArray(result.suggestions.item) ? result.suggestions.item : [result.suggestions.item];
var suggestions = items.map(function (item) {
return {
label: item.label,
kind: monaco.languages.CompletionItemKind.Text,
documentation: item.documentation || "",
insertText: '"' + item.insertText + '"',
range: range
};
});
return {
suggestions: suggestions
};
})
.catch(function () {
return {
suggestions: []
};
});
}
require(["vs/editor/editor.main"], function () {
editor = monaco.editor.create(document.getElementById('container'), {
value: ['// lib/sayhello.js', 'function say() {', ' console.log("hello");', '}', '', 'exports.say = say;', '', 'exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1";', 'exports.AUTHOR = "abuse@catswords.net";', 'exports.global = global;', 'exports.require = global.require;'].join('\n'),
language: 'javascript'
});
const pushPromptMessage = (role, content) => {
promptMessagesRef.current.push({
role: role,
content: content
});
promptEditorRef.current.set(promptMessagesRef.current);
};
monaco.languages.registerCompletionItemProvider('javascript', {
provideCompletionItems: function (model, position) {
var word = model.getWordUntilPosition(position);
var range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn
const navigate = (href) => {
const a = document.createElement("a");
a.href = href;
a.target = "_blank";
document.body.appendChild(a);
a.click();
};
const appendTextToEditor = (text) => {
const editor = editorRef.current;
const position = editor.getPosition();
const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
editor.executeEdits('', [{
range: range,
text: "\n" + text,
forceMoveMarkers: true
}]);
resizeEditor();
};
const openFile = () => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.onchange = () => {
const file = fileInput.files[0];
if (!file)
return;
const reader = new FileReader();
reader.onload = (e) => {
const fileName = file.name;
const ext = fileName.split('.').pop().toLowerCase();
const langMap = {
js: 'javascript', ts: 'typescript', html: 'html',
css: 'css', json: 'json', py: 'python', java: 'java',
c: 'c', cpp: 'cpp', cs: 'csharp', php: 'php',
rb: 'ruby', go: 'go', rs: 'rust'
};
const lang = langMap[ext] || 'plaintext';
monaco.editor.setModelLanguage(editorRef.current.getModel(), lang);
editorRef.current.setValue(e.target.result);
fileNameRef.current = fileName;
};
reader.readAsText(file);
};
fileInput.click();
};
const saveFile = () => {
const text = editorRef.current.getValue();
const fileName = prompt("Enter file name:", fileNameRef.current);
if (!fileName)
return;
const blob = new Blob([text], { type: 'text/plain' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileNameRef.current;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
const sendMessageToCopilot = () => {
const promptMessage = prompt("Enter a prompt message:", '');
if (!promptMessage || promptMessage.trim() == '') {
alert("A prompt message is required.");
return;
}
appendTextToEditor(`\n// ${promptMessage}... Generating text with Copilot...`);
pushPromptMessage("user", promptMessage);
(async () => {
const targetWsUrl = await getTargetByUrl('copilot.microsoft.com');
if (targetWsUrl) {
await _sendMessageToCopilot(targetWsUrl, promptMessage);
} else {
alert("Microsoft Copilot not running. Please visit copilot.microsoft.com first.");
}
})();
};
const _sendMessageToCopilot = async (wsUrl, promptMessage) => {
const socket = new WebSocket(wsUrl);
const steps = [
{
id: 1,
method: 'Input.insertText',
params: {
text: promptMessage
}
},
{
id: 2,
method: 'Input.dispatchKeyEvent',
params: {
type: 'keyDown',
key: 'Enter',
code: 'Enter'
}
},
{
id: 3,
method: 'Runtime.evaluate',
params: {
expression: '((e)=>e[e.length-1].querySelector("code")?.innerText||e[e.length-1].innerText)(document.querySelectorAll("[data-content=ai-message]"))'
}
}
];
socket.onopen = () => {
steps.forEach((step) => {
if (step.id == 3) {
setTimeout(() => {
socket.send(JSON.stringify(step));
}, 9000);
} else {
socket.send(JSON.stringify(step));
}
});
};
return getSuggestions(word.word, range);
}
});
});
socket.onmessage = (event) => {
const response = JSON.parse(event.data);
console.log("Sent successfully:", response.result);
window.addEventListener('resize', resizeEditor);
if (response.id == 3) {
const responseContent = response.result.result.value;
function getFileLanguage(fileName) {
var extension = fileName.split('.').pop().toLowerCase();
var languageMap = {
'js': 'javascript',
'ts': 'typescript',
'html': 'html',
'css': 'css',
'json': 'json',
'py': 'python',
'java': 'java',
'c': 'c',
'cpp': 'cpp',
'cs': 'csharp',
'php': 'php',
'rb': 'ruby',
'go': 'go',
'rs': 'rust'
};
return languageMap[extension] || 'plaintext';
}
appendTextToEditor("/*\n" + responseContent + "\n*/");
pushPromptMessage("assistant", responseContent);
function navigate(href) {
var a = document.createElement("a");
a.href = href;
a.target = "_blank";
document.body.appendChild(a);
a.click();
}
socket.close();
}
};
};
function appendTextToEditor(text) {
const position = editor.getPosition();
const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
editor.executeEdits("my-source", [{
range: range,
text: "\n" + text,
forceMoveMarkers: true
}]);
resizeEditor();
}
const getTargetByUrl = async (urlPart) => {
const response = await fetch(`${serverPrefix}devtools/json`);
const targets = await response.json();
document.getElementById("fileInput").onchange = function (event) {
var file = event.target.files[0];
if (!file) return;
const target = targets.find(target => target.url.includes(urlPart));
currentFileName = file.name;
var reader = new FileReader();
reader.onload = function (e) {
var language = getFileLanguage(file.name);
monaco.editor.setModelLanguage(editor.getModel(), language);
editor.setValue(e.target.result);
};
reader.readAsText(file);
};
document.getElementById("btnOpenFile").onclick = function () {
document.getElementById('fileInput').click();
};
document.getElementById("btnSaveFile").onclick = function () {
var text = editor.getValue();
var fileName = prompt("Enter file name:", currentFileName);
if (!fileName) return;
currentFileName = fileName;
var blob = new Blob([text], { type: 'text/plain' });
var a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
document.getElementById("btnSponsor").onclick = function () {
navigate('https://github.com/sponsors/gnh1201');
};
document.getElementById("btnGenerate").onclick = function () {
const promptMessage = prompt("Enter a prompt message:", '');
if (!promptMessage || promptMessage.trim() == '') {
alert("A prompt message is required.");
return;
}
appendTextToEditor(`\n//${promptMessage}... Thinking with Generative AI...`);
(async function () {
const targetWsUrl = await getTargetByUrl('copilot.microsoft.com');
if (targetWsUrl) {
await sendPromptMessage(targetWsUrl, promptMessage);
} else {
alert("Microsoft Copilot not running. Please visit copilot.microsoft.com first.");
}
})();
};
document.getElementById("btnWhois").onclick = function () {
const hostname = prompt("Enter a hostname or IP address:", '');
if (!hostname || hostname.trim() == '') {
alert("A hostname or IP address is required.");
return;
}
axios.get(`${serverBaseUrl}/whois/${hostname}`).then(response => {
const responseText = DOMPurify.sanitize(response.data, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
appendTextToEditor(`/*\n${responseText}\n*/`);
}).catch(error => {
console.error(error);
});
};
document.getElementById("btnDnsQuery").onclick = function () {
const hostname = prompt("Enter a hostname or IP address:", '');
if (!hostname || hostname.trim() == '') {
alert("A hostname or IP address is required.");
return;
}
axios.get(`${serverBaseUrl}/dns-query/${hostname}`).then(response => {
const responseText = response.data;
appendTextToEditor(`/*\n${responseText}\n*/`);
}).catch(error => {
console.error(error);
});
};
async function getTargetByUrl(urlPart) {
const response = await fetch(`${serverBaseUrl}/devtools/json`);
const targets = await response.json();
const target = targets.find(target => target.url.includes(urlPart));
if (target) {
console.log(`Found target: ${target.title} (${target.id})`);
return target.webSocketDebuggerUrl;
} else {
console.log('Target not found');
return null;
}
}
async function sendPromptMessage(wsUrl, promptMessage) {
const socket = new WebSocket(wsUrl);
const steps = [
{
id: 1,
method: 'Input.insertText',
params: {
text: promptMessage
}
},
{
id: 2,
method: 'Input.dispatchKeyEvent',
params: {
type: 'keyDown',
key: 'Enter',
code: 'Enter'
}
},
{
id: 3,
method: 'Runtime.evaluate',
params: {
expression: '((e)=>e[e.length-1].querySelector("code")?.innerText||e[e.length-1].innerText)(document.querySelectorAll("[data-content=ai-message]"))'
}
}
];
socket.onopen = () => {
steps.forEach((step) => {
if (step.id == 3) {
setTimeout(() => {
socket.send(JSON.stringify(step));
}, 9000);
if (target) {
console.log(`Found target: ${target.title} (${target.id})`);
return target.webSocketDebuggerUrl;
} else {
socket.send(JSON.stringify(step));
console.log('Target not found');
return null;
}
});
};
};
socket.onmessage = (event) => {
const response = JSON.parse(event.data);
console.log("Sent successfully:", response.result);
const sendMessageToAzureAi = () => {
const promptMessage = prompt("Enter a prompt message:", '');
if (!promptMessage || promptMessage.trim() == '') {
alert("A prompt message is required.");
return;
}
if (response.id == 3) {
appendTextToEditor(response.result.result.value);
socket.close();
}
};
}
appendTextToEditor(`\n// ${promptMessage}... Generating text with Azure AI...`);
pushPromptMessage("user", promptMessage);
const apiKey = settingsRef.current.AzureAiServiceApiKey;
const url = `${settingsRef.current.AzureAiServicePrefix}models/chat/completions?api-version=${settingsRef.current.AzureAiServiceApiVersion}`;
const data = {
messages: promptMessagesRef.current,
max_tokens: 2048,
temperature: 0.8,
top_p: 0.1,
presence_penalty: 0,
frequency_penalty: 0,
model: 'Phi-4'
};
axios.post(url, data, {
headers: {
'Content-Type': 'application/json',
'api-key': apiKey
}
}).then(response => {
response.data.choices.forEach(x => {
const responseContent = x.message.content;
pushPromptMessage("assistant", responseContent);
const responseText = DOMPurify.sanitize(responseContent, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
appendTextToEditor(`/*\n${responseText}\n*/`);
});
})
.catch(error => {
console.error('Error:', error.response?.data || error.message);
});
};
const savePromptMessages = () => {
const text = JSON.stringify(promptMessagesRef.current, null, 4);
const blob = new Blob([text], { type: 'text/plain' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = "prompt.json";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
const loadPromptMessages = () => {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
fileInput.onchange = function (event) {
const file = event.target.files[0];
if (!file)
return;
let reader = new FileReader();
reader.onload = function (e) {
promptMessagesRef.current = JSON.parse(e.target.result);
promptEditorRef.current.set(promptMessagesRef.current);
appendTextToEditor("\n//Prompt loaded successfully.");
};
reader.readAsText(file);
};
fileInput.click();
};
const queryWhois = () => {
const hostname = prompt("Enter a hostname or IP address:", '');
if (!hostname || hostname.trim() == '') {
appendTextToEditor("\n// A hostname or IP address is required.");
return;
}
axios.get(`${serverPrefix}whois/${hostname}`).then(response => {
const responseText = DOMPurify.sanitize(response.data, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
appendTextToEditor(`/*\n${responseText}\n*/`);
pushPromptMessage("system", responseText);
}).catch(error => {
console.error(error);
});
};
const queryDns = () => {
const hostname = prompt("Enter a hostname or IP address:", '');
if (!hostname || hostname.trim() == '') {
appendTextToEditor("\n// A hostname or IP address is required.");
return;
}
axios.get(`${serverPrefix}dns-query/${hostname}`).then(response => {
const responseText = response.data;
appendTextToEditor(`/*\n${responseText}\n*/`);
pushPromptMessage("system", responseText);
}).catch(error => {
console.error(error);
});
};
React.useEffect(() => {
window.addEventListener('resize', () => {
resizeEditor();
});
window.dispatchEvent(new Event('resize'));
}, []);
fetchSettings();
return _e('div', { className: 'app' },
_e(RibbonMenu, {
onOpenFileClick: openFile,
onSaveFileClick: saveFile,
onCopliotClick: sendMessageToCopilot,
onAzureAiClick: sendMessageToAzureAi,
onSavePromptClick: savePromptMessages,
onLoadPromptClick: loadPromptMessages,
onQueryWhoisClick: queryWhois,
onQueryDnsClick: queryDns
}),
_e('div', { id: 'container' },
_e(Editor, { editorRef }),
_e(PromptEditor, { promptEditorRef, promptMessagesRef })
),
_e('div', { className: 'banner' }, _e('a', { href: 'https://github.com/gnh1201/welsonjs' }, 'WelsonJS'), ' Editor powered by Metro UI, Monaco Editor, and JSONEditor.'),
);
}
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
root.render(_e(App));
});
</script>
</body>
</html>

View File

@ -5,8 +5,8 @@ REM Source code available: https://github.com/gnh1201/welsonjs
pushd %~dp0
:: Define variables
set TOOLKIT_URL=https://ics.catswords.net/welsonjs_toolkit.cab
set TOOLKIT_PATH=%APPDATA%\welsonjs\welsonjs_toolkit.cab
set TOOLKIT_URL=https://catswords.blob.core.windows.net/welsonjs/welsonjs_toolkit_latest.cab
set TOOLKIT_PATH=%APPDATA%\welsonjs\welsonjs_toolkit_latest.cab
set TOOLKIT_EXTRACT_PATH=%APPDATA%\welsonjs
set REGASM_PATH=%WINDIR%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe
set LOCAL_TOOLKIT_DLL=bin\x86\WelsonJS.Toolkit.dll

View File

@ -0,0 +1,6 @@
[
{
"role": "system",
"content": "If external information is required, provide the response according to the given conditions:\n\n* The type field should specify the search type (e.g., weather, location, stock, news, keyword), and the query field should specify the search target.\n* For types that require location information, request location information first.\n* The format must be in JSON-RPC 2.0.\n* The method should always be fixed as `get_search`."
}
]

View File

@ -0,0 +1,6 @@
[
{
"role": "system",
"content": "외부 정보가 필요한 경우 주어진 조건에 맞는 응답을 보내줘.\n\n* type 필드에 검색 유형(예: weather, location, stock, news, keyword), query 필드에 검색 대상을 지정\n* 위치 정보가 필요한 유형은 위치 정보를 먼저 요청\n* JSON-RPC 2.0 형식이여야 함.\n* method는 get_search으로 고정되어야 함."
}
]