mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-07 20:26:06 +00:00
Compare commits
87 Commits
Author | SHA1 | Date | |
---|---|---|---|
aee5fb22d0 | |||
14c8b12df7 | |||
deed89560b | |||
eb32437f96 | |||
c95b7a373b | |||
302e7ce4fc | |||
a5fc5de78f | |||
d362d852ad | |||
2a3f9fb4fa | |||
944751121c | |||
fb420d1116 | |||
26af578178 | |||
245dd85341 | |||
fb6596fe64 | |||
a42180d244 | |||
73b24f9a56 | |||
eae2795bbf | |||
98e73b2372 | |||
2225ab9011 | |||
4c0895850b | |||
ea412908ef | |||
05ea48a0be | |||
243ff95198 | |||
8341394912 | |||
e5a89c9182 | |||
df5b8cd9f0 | |||
e7b6a87175 | |||
5b2863058a | |||
cd8844afef | |||
b26d979b8d | |||
5446a1bee0 | |||
10101986be | |||
47a5f50712 | |||
86517f313c | |||
b6d34404b5 | |||
88ac0cd31e | |||
3e0fd7c532 | |||
22d10cd28b | |||
0e95b72b21 | |||
426a9d7721 | |||
d42210f922 | |||
e853003bda | |||
8ca4faa88a | |||
f84f2195c3 | |||
1742ca385b | |||
2a9ebaff51 | |||
916154499c | |||
53a84b2349 | |||
6e3eb5c1d3 | |||
4b4754ae16 | |||
a273d6aac6 | |||
9e1878628b | |||
04ce7fdae5 | |||
f7de7bd430 | |||
ab8a864519 | |||
427f8dded0 | |||
a96764f725 | |||
46d0244c34 | |||
2cb3c1c331 | |||
231e6a56bd | |||
295ad2fca8 | |||
9ecc93a399 | |||
2896cc6bf1 | |||
be37951807 | |||
d38e26ba67 | |||
dd85e98c9a | |||
d8fa8779de | |||
f6fd43ae50 | |||
96dbe7b2cd | |||
c1fe39d3cc | |||
56ee12741c | |||
4372bdb09d | |||
b21f967a6a | |||
40b0b704e3 | |||
9a8ee4d7f9 | |||
4f319d474f | |||
93ed60bcf7 | |||
5d717505f4 | |||
b0e50d33bc | |||
c0f9816000 | |||
00ea473683 | |||
7e9054fb8f | |||
f29a63027f | |||
3419e62c6a | |||
e930cf86fd | |||
c0a27efd8d | |||
d42539c0a8 |
114
README.md
114
README.md
|
@ -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
|
|||

|
||||
|
||||
## 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
|
||||

|
||||
|
@ -139,41 +140,42 @@ The WelsonJS framework suggests the following application release methods:
|
|||

|
||||
|
||||
## 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
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large)
|
||||
|
|
45
SECURITY.MD
45
SECURITY.MD
|
@ -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.
|
||||
|
|
188
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.Designer.cs
generated
188
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal file
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
142
WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.Designer.cs
generated
142
WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
446
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
446
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
42
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal file
42
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
77
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
Normal file
77
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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(" ", ""));
|
60
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal file
60
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
6
data/prompt_function_calling_en.json
Normal file
6
data/prompt_function_calling_en.json
Normal 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`."
|
||||
}
|
||||
]
|
6
data/prompt_function_calling_ko.json
Normal file
6
data/prompt_function_calling_ko.json
Normal 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으로 고정되어야 함."
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user