├── .clang-format ├── .gitignore ├── .gitmodules ├── Change Log.txt ├── LICENSE ├── Makefile ├── README.md ├── app ├── low_config.h ├── main.cpp ├── transpile.cpp └── transpile.h ├── examples ├── README.txt └── chat_ws_webserver │ ├── README.md │ ├── index.js │ ├── node_modules │ ├── async-limiter │ │ ├── coverage │ │ │ └── lcov-report │ │ │ │ ├── prettify.js │ │ │ │ └── sorter.js │ │ └── index.js │ └── ws │ │ ├── browser.js │ │ ├── index.js │ │ └── lib │ │ ├── buffer-util.js │ │ ├── constants.js │ │ ├── event-target.js │ │ ├── extension.js │ │ ├── permessage-deflate.js │ │ ├── receiver.js │ │ ├── sender.js │ │ ├── validation.js │ │ ├── websocket-server.js │ │ └── websocket.js │ ├── server.crt │ ├── server.key │ └── www │ ├── favicon.png │ ├── index.html │ └── styles.css ├── lib_js ├── assert.js ├── buffer.js ├── child_process.js ├── console.js ├── crypto.js ├── dgram.js ├── dns.js ├── events.js ├── fs.js ├── http.js ├── https.js ├── init.js ├── internal │ ├── assert.js │ ├── constants.js │ ├── errors.js │ ├── http.js │ ├── querystring.js │ ├── readline.js │ ├── util.js │ └── util │ │ ├── comparisons.js │ │ ├── identifier.js │ │ └── types.js ├── main.js ├── module.js ├── net.js ├── os.js ├── path.js ├── process.js ├── querystring.js ├── readline.js ├── repl.js ├── stream.js ├── string_decoder.js ├── timers.js ├── tls.js ├── tsconfig.json ├── tty.js ├── url.js ├── util.js ├── vm.js └── zlib.js ├── package-lock.json ├── package.json ├── src ├── LowCryptoHash.cpp ├── LowCryptoHash.h ├── LowDNSResolver.cpp ├── LowDNSResolver.h ├── LowDNSWorker.cpp ├── LowDNSWorker.h ├── LowDataCallback.h ├── LowDatagram.cpp ├── LowDatagram.h ├── LowFD.cpp ├── LowFD.h ├── LowFSMisc.cpp ├── LowFSMisc.h ├── LowFile.cpp ├── LowFile.h ├── LowHTTPDirect.cpp ├── LowHTTPDirect.h ├── LowLoopCallback.h ├── LowServerSocket.cpp ├── LowServerSocket.h ├── LowSignalHandler.cpp ├── LowSignalHandler.h ├── LowSocket.cpp ├── LowSocket.h ├── LowSocketDirect.h ├── LowTLSContext.cpp ├── LowTLSContext.h ├── low_alloc.cpp ├── low_alloc.h ├── low_crypto.cpp ├── low_crypto.h ├── low_data_thread.cpp ├── low_data_thread.h ├── low_dgram.cpp ├── low_dgram.h ├── low_dns.cpp ├── low_dns.h ├── low_fs.cpp ├── low_fs.h ├── low_fs_misc.cpp ├── low_fs_misc.h ├── low_http.cpp ├── low_http.h ├── low_loop.cpp ├── low_loop.h ├── low_main.cpp ├── low_main.h ├── low_module.cpp ├── low_module.h ├── low_native.cpp ├── low_native_api.cpp ├── low_native_api.h ├── low_native_aux.cpp ├── low_native_aux.h ├── low_net.cpp ├── low_net.h ├── low_opcua.cpp ├── low_opcua.h ├── low_process.cpp ├── low_process.h ├── low_promise.cpp ├── low_promise.h ├── low_system.cpp ├── low_system.h ├── low_tls.cpp ├── low_tls.h ├── low_web_thread.cpp ├── low_web_thread.h └── sys │ ├── elf32.h │ ├── elf64.h │ └── elf_common.h ├── test ├── README.md ├── bugs │ ├── duk_crash_TR20180627.c │ ├── duk_crash_TR20180706.c │ ├── native_Reflect_contruct.js │ ├── ts_not_valid_es5_TR20180702.js │ └── ts_not_valid_es5_TR20180702.txt ├── tests │ ├── assert_throws_stack.out │ ├── test-assert-throws-stack.js │ ├── test-duplex-inheritance.js │ └── test-pause-stdin.js └── tests_script │ ├── package-lock.json │ ├── package.json │ ├── summary │ ├── .gitignore │ ├── bs-config.js │ ├── index_template.html │ ├── main.tsx │ ├── result.ts │ ├── styles.scss │ ├── testResult.tsx │ ├── testResults.tsx │ ├── tsconfig.json │ ├── types.d.ts │ └── webpack.config.js │ ├── tests.ts │ └── tsconfig.json └── util ├── dist-build.sh ├── dist-loader.c ├── dukc.c ├── root-certs-extract.js └── root-certs.json /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Mozilla 3 | AlwaysBreakAfterDefinitionReturnType: None 4 | AlwaysBreakAfterReturnType: None 5 | AlwaysBreakTemplateDeclarations: 'false' 6 | BreakConstructorInitializers: AfterColon 7 | BreakBeforeBraces: Allman 8 | BreakConstructorInitializersBeforeComma: 'false' 9 | ConstructorInitializerIndentWidth: '4' 10 | Cpp11BracedListStyle: 'true' 11 | IndentWidth: '4' 12 | Language: Cpp 13 | MaxEmptyLinesToKeep: '2' 14 | PointerAlignment: Right 15 | SpaceBeforeAssignmentOperators: 'true' 16 | SpaceBeforeParens: Never 17 | SpaceInEmptyParentheses: 'false' 18 | SpacesInAngles: 'false' 19 | SpacesInParentheses: 'false' 20 | SpacesInSquareBrackets: 'false' 21 | Standard: Cpp11 22 | TabWidth: '4' 23 | UseTab: Never 24 | 25 | ... 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | examples/native/src/native.so 2 | .vscode 3 | .DS_Store 4 | /build 5 | /bin 6 | /lib 7 | /lib_js/build 8 | /lib_js_esp32/build 9 | /dist 10 | /util/dukc 11 | /test/duk_crash 12 | *.d 13 | *.o 14 | /node_modules 15 | /docs 16 | /test/tests_script/node_modules 17 | /test/node/ 18 | /test/compiled/ 19 | /test/tests_script/summary.html 20 | *.scss.d.ts 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/mbedtls"] 2 | path = deps/mbedtls 3 | url = https://github.com/ARMmbed/mbedtls 4 | [submodule "deps/duktape"] 5 | path = deps/duktape 6 | url = https://github.com/svaarala/duktape 7 | [submodule "deps/c-ares"] 8 | path = deps/c-ares 9 | url = https://github.com/c-ares/c-ares.git 10 | [submodule "deps/open62541"] 11 | path = deps/open62541 12 | url = https://github.com/neonious/open62541 13 | [submodule "examples/native/low_native_api"] 14 | path = examples/native/low_native_api 15 | url = https://www.github.com/neonious/low_native_api 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | NEONIOUS PUBLIC LICENSE FOR LOW.JS 2 | 3 | Copyright (C) 2018, 2019 neonious GmbH 4 | 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 7 | software, both in source code and compiled form, and associated documentation files (the 8 | "Software") to 9 | 10 | (1) use the Software, including modifying and merging the Software and using the Software 11 | in running applications, including networked ones, also to 12 | 13 | (2) publish, distribute, sublicense or sell copies of the Software, derived work of the 14 | Software or combined work with the Software, both in source code and compiled form, if 15 | 16 | - this happens under the term of this license (The above copyright notice and this 17 | permission notice, both together: this LICENSE file, must be part of the 18 | distribution and be available to the user in a prominent place, such as the LICENSE 19 | file in the root directory of the software), and 20 | 21 | - the origin of the software is clearly stated as being the Software by neonious, with 22 | a link to https://www.neonious.com/ , and 23 | 24 | - changes in the source code or the behaviour of the compiled programs are clearly 25 | documented (for example via GIT commits or a change log), and 26 | 27 | - the software only has code generic to any architecture and code for the following 28 | architectures: 29 | 30 | ESP32 (any OS) 31 | Linux 32 | Windows 33 | macOS 34 | 35 | For any other architectures, please contact neonious. 36 | 37 | Combining and/or running low.js with a user program consisting of JavaScript files and 38 | native modules based on the low native API never make this a derived or combined work. 39 | 40 | 41 | Unless you explicitly state otherwise, any contribution intentionally submitted for 42 | inclusion in the Software by You shall be under the terms and conditions of this license, 43 | without any additional terms or conditions. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 51 | SOFTWARE. 52 | 53 | 54 | Contact us 55 | 56 | neonious GmbH 57 | Münsterstr. 246 58 | 40470 Düsseldorf 59 | Germany 60 | 61 | Managing Director / CEO 62 | Thomas Rogg 63 | 64 | TEL +49 211 9241 8187 65 | FAX +49 211 9241 8172 66 | 67 | info@neonious.com 68 | District Court Düsseldorf 69 | HRB 83086 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FLAGS = -O3 -DLOW_VERSION="\"`git show -s --format=%cd --date=format:%Y%m%d`_`git rev-parse --short HEAD`\"" 2 | 3 | C = gcc 4 | CFLAGS = $(FLAGS) -Isrc -Iapp -Ideps/duktape/src-low -Ideps/mbedtls/include -Ideps/mbedtls/crypto/include 5 | 6 | CXX = g++ 7 | CXXFLAGS = $(CXXFLAGS_SERV) $(FLAGS) -Isrc -Iapp -Ideps/duktape/src-low -Ideps/mbedtls/include -Ideps/mbedtls/crypto/include -Ideps/open62541/build/src_generated -Ideps/open62541/include -Ideps/open62541/arch -Ideps/open62541/plugins/include -Ideps/open62541/src/client -Ideps/open62541/deps -Ideps/open62541/src --std=c++11 8 | 9 | LD = g++ 10 | LDFLAGS = $(FLAGS) -lm -ldl -lpthread deps/open62541/build/bin/libopen62541.a -lresolv 11 | 12 | OBJECTS_LOW = \ 13 | app/main.o \ 14 | app/transpile.o 15 | OBJECTS = \ 16 | deps/duktape/src-low/duktape.o \ 17 | src/low_main.o \ 18 | src/low_module.o \ 19 | src/low_native.o \ 20 | src/low_native_aux.o \ 21 | src/low_process.o \ 22 | src/low_loop.o \ 23 | src/low_fs.o \ 24 | src/low_fs_misc.o \ 25 | src/low_http.o \ 26 | src/low_net.o \ 27 | src/low_dgram.o \ 28 | src/LowDatagram.o \ 29 | src/low_tls.o \ 30 | src/low_dns.o \ 31 | src/low_crypto.o \ 32 | src/LowCryptoHash.o \ 33 | src/low_data_thread.o \ 34 | src/low_web_thread.o \ 35 | src/low_alloc.o \ 36 | src/low_system.o \ 37 | src/LowFile.o \ 38 | src/LowFSMisc.o \ 39 | src/LowServerSocket.o \ 40 | src/LowSocket.o \ 41 | src/LowFD.o \ 42 | src/LowHTTPDirect.o \ 43 | src/LowSignalHandler.o \ 44 | src/LowDNSWorker.o \ 45 | src/LowDNSResolver.o \ 46 | src/LowTLSContext.o \ 47 | src/low_native_api.o \ 48 | src/low_promise.o \ 49 | src/low_opcua.o 50 | 51 | all: bin/low lib/BUILT 52 | 53 | clean: 54 | rm -rf */*.o */*.d bin/* deps/duktape/src-low lib lib_js/build node_modules util/dukc test/duk_crash 55 | cd deps/c-ares && make clean 56 | cd deps/mbedtls && make clean 57 | cd deps/open62541 && rm -rf build 58 | rm deps/c-ares/configure 59 | 60 | bin/low: $(OBJECTS) $(OBJECTS_LOW) deps/mbedtls/programs/test/benchmark 61 | mkdir -p bin 62 | $(LD) -o bin/low deps/mbedtls/library/*.o deps/mbedtls/crypto/library/*.o deps/c-ares/libcares_la-*.o $(OBJECTS) $(OBJECTS_LOW) $(LDFLAGS) 63 | 64 | obj_lowjs_serv: $(OBJECTS) $(OBJECTS_LOW) deps/mbedtls/programs/test/benchmark util/dukc 65 | 66 | util/dukc: deps/duktape/src-low/duktape.o util/dukc.o 67 | $(LD) -o util/dukc deps/duktape/src-low/duktape.o util/dukc.o $(LDFLAGS) 68 | 69 | test/bugs/duk_crash_TR20180627: deps/duktape/src-low/duktape.o test/bugs/duk_crash_TR20180627.o 70 | $(LD) -o test/bugs/duk_crash_TR20180627 deps/duktape/src-low/duktape.o test/bugs/duk_crash_TR20180627.o $(LDFLAGS) 71 | test/bugs/duk_crash_TR20180706: deps/duktape/src-low/duktape.o test/bugs/duk_crash_TR20180706.o 72 | $(LD) -o test/bugs/duk_crash_TR20180706 deps/duktape/src-low/duktape.o test/bugs/duk_crash_TR20180706.o $(LDFLAGS) 73 | 74 | # Force compilation as C++ so linking works 75 | deps/duktape/src-low/duktape.o: deps/duktape/src-low/duktape.c Makefile 76 | $(CXX) $(CXXFLAGS) -MMD -o $@ -c $< 77 | %.o : %.c Makefile 78 | $(C) $(CFLAGS) -MMD -o $@ -c $< 79 | %.o : %.cpp Makefile deps/c-ares/.libs/libcares.a deps/open62541/build/bin/libopen62541.a 80 | $(CXX) $(CXXFLAGS) -MMD -o $@ -c $< 81 | 82 | -include $(OBJECTS:.o=.d) $(OBJECTS_LOW:.o=.d) 83 | 84 | lib/BUILT: util/dukc node_modules/BUILT $(shell find lib_js) util/root-certs.json 85 | rm -rf lib lib_js/build 86 | cd lib_js && node ../node_modules/typescript/bin/tsc 87 | cp node_modules/\@babel/standalone/babel.min.js lib_js/build/babel.js 88 | mkdir lib 89 | util/dukc lib_js/build lib 90 | cp util/root-certs.json lib/internal 91 | touch lib/BUILT 92 | node_modules/BUILT: package.json 93 | npm install 94 | touch node_modules/BUILT 95 | 96 | deps/duktape/src-low/duktape.c: $(shell find deps/duktape/src-input) 97 | rm -rf deps/duktape/src-low 98 | cd deps/duktape && python tools/configure.py --output-directory=src-low \ 99 | -DDUK_USE_GLOBAL_BUILTIN \ 100 | -DDUK_USE_BOOLEAN_BUILTIN \ 101 | -DDUK_USE_ARRAY_BUILTIN \ 102 | -DDUK_USE_OBJECT_BUILTIN \ 103 | -DDUK_USE_FUNCTION_BUILTIN \ 104 | -DDUK_USE_STRING_BUILTIN \ 105 | -DDUK_USE_NUMBER_BUILTIN \ 106 | -DDUK_USE_DATE_BUILTIN \ 107 | -DDUK_USE_REGEXP_SUPPORT \ 108 | -DDUK_USE_MATH_BUILTIN \ 109 | -DDUK_USE_JSON_BUILTIN \ 110 | -DDUK_USE_BUFFEROBJECT_SUPPORT \ 111 | -DDUK_USE_ENCODING_BUILTINS \ 112 | -DDUK_USE_PERFORMANCE_BUILTIN \ 113 | -DDUK_USE_OBJECT_BUILTIN \ 114 | -DDUK_USE_ES6_PROXY \ 115 | -DDUK_USE_GLOBAL_BINDING \ 116 | -DDUK_USE_SYMBOL_BUILTIN \ 117 | -DDUK_USE_SECTION_B \ 118 | -DDUK_USE_CPP_EXCEPTIONS 119 | 120 | deps/c-ares/configure: 121 | cd deps/c-ares && . ./buildconf 122 | deps/c-ares/Makefile: deps/c-ares/configure 123 | cd deps/c-ares && ./configure 124 | deps/c-ares/.libs/libcares.a: deps/c-ares/Makefile 125 | cd deps/c-ares && make 126 | 127 | deps/mbedtls/programs/test/benchmark: 128 | cd deps/mbedtls && make 129 | 130 | deps/open62541/build/bin/libopen62541.a: 131 | cd deps/open62541 && rm -rf build && mkdir build 132 | cd deps/open62541/build && cmake .. 133 | cd deps/open62541/build && make 134 | 135 | # Builds distribution 136 | dist: all 137 | chmod 755 util/dist-build.sh 138 | util/dist-build.sh 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lowjs 2 | 3 | low.js is a free to use and open sourced port of the JavaScript runtime Node.js with far lower system requirements, allowing it to run on cheap, power-efficient microcontroller boards based on the ESP32-WROVER module. 4 | It also runs on Linux based systems as a smaller, faster booting alternative to Node.JS. 5 | 6 | For more information on low.js, please visit http://www.lowjs.org/ . 7 | 8 | This repository neither includes the ESP32 internals nor the neonious IDE. Thus, most development happens outside of the repository. Thus, see the [Change Log](https://www.neonious.com/documentation/changelog) for more activity. 9 | 10 | 11 | ## First steps 12 | 13 | To try out low.js on a PC, try out the [chat webserver example](https://github.com/neonious/lowjs/tree/master/examples/chat_ws_webserver) in the repository, which you can run with both low.js and Node.js. 14 | 15 | To try out low.js on a ESP32-WROVER, try out the [examples on our homepage](https://www.lowjs.org/examples/getting-started.html) on your own board. 16 | 17 | 18 | ## Compile from source 19 | 20 | In case the [binary distributions](https://www.lowjs.org/downloads.html) do not fit your needs, you can compile from source. 21 | 22 | Before compiling, make sure you have the following software installed: 23 | 24 | make g++ 25 | automake autoconf libtool 26 | cmake 27 | python py-pip 28 | nodejs 29 | npm (if not already installed together with nodejs) 30 | 31 | Note: Node.js is only used to transpile the low.js libs from ES6 to ES5. It is only need for the build process. The binary distributions of low.js available on http://www.lowjs.org/ do not include Node.js, of course - this would defeat the purpose. 32 | 33 | With this software installed, please install pyyaml with pip: 34 | 35 | pip install pyyaml 36 | 37 | The compilation itself can be done with these commands: 38 | 39 | git clone --recurse-submodules https://github.com/neonious/lowjs 40 | cd lowjs 41 | make 42 | 43 | low.js is now built in bin and can be called via bin/low. 44 | 45 | The lib directory is also required for low to work (it accesses it via path_to_bin/../lib) and must be copied when creating a distribution. When creating a distribution, it might also make sense to strip the binary with the strip command, to save some KB. 46 | 47 | 48 | ## Running tests 49 | 50 | Please see the [lowjs test documentation](https://github.com/neonious/lowjs/blob/master/test/README.md). 51 | 52 | 53 | ## License / Authors / Contributions 54 | 55 | We appreciate every person or company who is willing to contribute to low.js and its related products. We will gladly accept any code contribution which helps the cause after an appropriate review. Bug reports and suggestions are also welcome! 56 | 57 | low.js, with exception of the adaption for ESP32, is placed under a permisse free license, allowing you to use low.js commercially and even modify it (see LICENSE file for details). The adaption of low.js for ESP32 is not Open Source, but may be used freely with the lowsync flashing tool. low.js is maintained by neonious, the makers of the neonious one microcontroller board. 58 | 59 | 60 | ### Contact us 61 | 62 | neonious GmbH 63 | Münsterstr. 246 64 | 40470 Düsseldorf 65 | Germany 66 | 67 | https://www.neonious.com/ 68 | info@neonious.com 69 | 70 | TEL +49 211 9241 8187 71 | FAX +49 211 9241 8172 72 | 73 | Managing Director / CEO: Thomas Rogg 74 | District Court Düsseldorf, HRB 83086 75 | 76 | 77 | Node.js is a trademark of Joyent, Inc. (https://www.nodejs.org/). ESP32 and ESP32-WROVER are products by Espressif Systems (https://www.espressif.com/). neonious GmbH is in no way affiliated with these companies. 78 | -------------------------------------------------------------------------------- /app/low_config.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_config.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_CONFIG_H__ 6 | #define __LOW_CONFIG_H__ 7 | 8 | #define LOW_NUM_DATA_THREADS 4 9 | 10 | // Enables dns.resolve API but requires additional library c-ares 11 | #define LOW_INCLUDE_CARES_RESOLVER 1 12 | 13 | #define LOW_USE_SYSTEM_ALLOC 1 14 | 15 | // Poll is superior to select because not limited to FD_SETSIZE sockets 16 | #define LOW_HAS_POLL 1 17 | 18 | #define LOW_HAS_TERMIOS 1 19 | 20 | #define LOW_HAS_STRCASESTR 1 21 | 22 | #define LOW_HAS_SYS_SIGNALS 1 23 | 24 | #define LOW_HAS_UNIX_SOCKET 1 25 | 26 | #define LOW_ESP32_LWIP_SPECIALITIES 0 27 | 28 | #ifndef LOW_LIB_PATH 29 | #define LOW_LIB_PATH "../lib/" 30 | #endif 31 | 32 | #endif /* __LOW_CONFIG_H__ */ 33 | -------------------------------------------------------------------------------- /app/transpile.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // transpile.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "transpile.h" 6 | 7 | #include "low_main.h" 8 | #include "low_module.h" 9 | #include "low_system.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | // Global variables 18 | int transpile_babel_stash, transpile_config_stash; 19 | bool transpile_output; 20 | 21 | extern low_system_t g_low_system; 22 | 23 | 24 | // ----------------------------------------------------------------------------- 25 | // init_transpile 26 | // ----------------------------------------------------------------------------- 27 | 28 | static duk_ret_t init_transpile_safe(duk_context *ctx, void *udata) 29 | { 30 | low_load_module(ctx, "lib:babel", false); 31 | duk_get_prop_string(ctx, 0, "exports"); 32 | transpile_babel_stash = low_add_stash(ctx, 1); 33 | 34 | // see node_modules/@babel/standalone/src/generated/plugins.js for supported plugins 35 | duk_push_string(ctx, "{" 36 | "\"presets\": [\"es2015\", \"stage-3\"]," 37 | "\"plugins\": [\"proposal-object-rest-spread\", \"transform-async-to-generator\"]," 38 | "\"parserOpts\": {\"allowReturnOutsideFunction\": true" 39 | "}}"); 40 | duk_json_decode(ctx, 2); 41 | transpile_config_stash = low_add_stash(ctx, 2); 42 | 43 | return true; 44 | } 45 | 46 | bool init_transpile(low_t *low, bool output) 47 | { 48 | int len = strlen(g_low_system.lib_path); 49 | char babel_path[len + 16]; 50 | sprintf(babel_path, "%sbabel.low", g_low_system.lib_path); 51 | 52 | struct stat st; 53 | if(stat(babel_path, &st) == -1 && errno == ENOENT) 54 | { 55 | fprintf(stderr, "Error: This distribution lakes Babel, transpilation is not possible.\n"); 56 | return false; 57 | } 58 | 59 | duk_context *ctx = low_get_duk_context(low); 60 | if(duk_safe_call( 61 | ctx, 62 | init_transpile_safe, 63 | NULL, 0, 1) != DUK_EXEC_SUCCESS) 64 | { 65 | low_duk_print_error(ctx); 66 | duk_pop(ctx); 67 | return false; 68 | } 69 | duk_pop(ctx); 70 | 71 | low->module_transpile_hook = transpile; 72 | 73 | transpile_output = output; 74 | return true; 75 | } 76 | 77 | 78 | // ----------------------------------------------------------------------------- 79 | // transpile 80 | // ----------------------------------------------------------------------------- 81 | 82 | int transpile(duk_context *ctx) 83 | { 84 | low_push_stash(ctx, transpile_babel_stash, false); 85 | duk_push_string(ctx, "transform"); 86 | duk_dup(ctx, -3); 87 | low_push_stash(ctx, transpile_config_stash, false); 88 | 89 | // [code babel result] 90 | duk_call_prop(ctx, -4, 2); 91 | 92 | // [code babel result codeOut] 93 | duk_get_prop_string(ctx, -1, "code"); 94 | if(transpile_output) 95 | { 96 | // To reset console 97 | low_system_destroy(); 98 | 99 | printf("%s\n", duk_get_string(ctx, -1)); 100 | exit(EXIT_SUCCESS); 101 | } 102 | 103 | duk_remove(ctx, -2); 104 | duk_remove(ctx, -2); 105 | duk_remove(ctx, -2); 106 | 107 | return 1; 108 | } 109 | -------------------------------------------------------------------------------- /app/transpile.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // transpile.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __TRANSPILE_H__ 6 | #define __TRANSPILE_H__ 7 | 8 | #include "low_main.h" 9 | 10 | #include 11 | 12 | bool init_transpile(low_t *low, bool output); 13 | 14 | int transpile(duk_context *ctx); 15 | 16 | #endif /* __TRANSPILE_H__ */ -------------------------------------------------------------------------------- /examples/README.txt: -------------------------------------------------------------------------------- 1 | For more examples, take a look at 2 | 3 | https://github.com/neonious/low_native_api 4 | https://github.com/neonious/lowjs_esp32_examples 5 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/README.md: -------------------------------------------------------------------------------- 1 | Simple webserver with chat functionality via WebSocket made for low.js/Node.JS 2 | 3 | Run with bin/low examples/chat_ws_webserver/index.js from lowjs directory 4 | and then open the links given with the web browser. 5 | 6 | The https link will give a certificate warning, which is correct, because 7 | the certificate is self-signed. 8 | 9 | In node_modules you can find the following modules, transpiled to ES5 via 10 | TypeScript: 11 | 12 | ws: 6.1.0 13 | async_limiter: 1.0.0 14 | 15 | The package.json is NOT included, so a npm install does not replace the 16 | transpiled files with the non-transpiled versions. 17 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/index.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var https = require('https'); 3 | var fs = require('fs'); 4 | var tls = require('tls'); 5 | var path = require('path'); 6 | 7 | var wwwPath = path.join(__dirname, 'www'); 8 | function handleRequest(req, res) { 9 | var url = req.url == '/' ? '/index.html' : req.url; 10 | 11 | // add more as required... 12 | var contentType; 13 | if (url.substr(-4) == '.png') 14 | contentType = 'image/png'; 15 | else if (url.substr(-4) == '.css') 16 | contentType = 'text/css'; 17 | else 18 | contentType = 'text/html'; 19 | res.setHeader("Content-Type", contentType); 20 | 21 | console.log("streaming " + wwwPath + url); 22 | 23 | var stream = fs.createReadStream(wwwPath + url); 24 | stream.on('error', function (err) { 25 | res.statusCode = 404; 26 | res.end(err.message); 27 | }); 28 | stream.pipe(res); 29 | } 30 | 31 | var httpServer = http.createServer(handleRequest).listen(0, function (err) { 32 | if (!err) 33 | console.log('listening on http://localhost:' + httpServer.address().port + '/'); 34 | }); 35 | 36 | var options = { 37 | key: fs.readFileSync(path.join(__dirname, 'server.key')), 38 | cert: fs.readFileSync(path.join(__dirname, 'server.crt')) 39 | }; 40 | var httpsServer = https.createServer(options, handleRequest).listen(0, function (err) { 41 | if (!err) 42 | console.log('listening on https://localhost:' + httpsServer.address().port + '/ with self-signed certificate (warning is OK)'); 43 | }); 44 | 45 | 46 | // ***** WebSocket server for chat 47 | // remove this code to remove chat functionality 48 | 49 | var WebSocket = require('ws'); 50 | var wss = new WebSocket.Server({ noServer: true }); 51 | 52 | wss.on('connection', function connection(ws) { 53 | ws.on('message', function incoming(data) { 54 | console.log("broadcasting message: " + data); 55 | wss.clients.forEach(function each(client) { 56 | if (client !== ws && client.readyState === WebSocket.OPEN) 57 | client.send(data); 58 | }); 59 | }); 60 | }); 61 | function upgradeToWSS(req, socket, head) { 62 | if (req.url === '/Chat') { 63 | console.log("webbrowser connected to chat"); 64 | 65 | wss.handleUpgrade(req, socket, head, function done(ws) { 66 | wss.emit('connection', ws, req); 67 | }); 68 | } else 69 | socket.destroy(); 70 | } 71 | 72 | httpServer.on('upgrade', upgradeToWSS); 73 | httpsServer.on('upgrade', upgradeToWSS); 74 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/async-limiter/coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, currentSort = { 4 | index: 0, 5 | desc: false 6 | }; 7 | // returns the summary table element 8 | function getTable() { return document.querySelector('.coverage-summary table'); } 9 | // returns the thead element of the summary table 10 | function getTableHeader() { return getTable().querySelector('thead tr'); } 11 | // returns the tbody element of the summary table 12 | function getTableBody() { return getTable().querySelector('tbody'); } 13 | // returns the th element for nth column 14 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 15 | // loads all columns 16 | function loadColumns() { 17 | var colNodes = getTableHeader().querySelectorAll('th'), colNode, cols = [], col, i; 18 | for (i = 0; i < colNodes.length; i += 1) { 19 | colNode = colNodes[i]; 20 | col = { 21 | key: colNode.getAttribute('data-col'), 22 | sortable: !colNode.getAttribute('data-nosort'), 23 | type: colNode.getAttribute('data-type') || 'string' 24 | }; 25 | cols.push(col); 26 | if (col.sortable) { 27 | col.defaultDescSort = col.type === 'number'; 28 | colNode.innerHTML = colNode.innerHTML + ''; 29 | } 30 | } 31 | return cols; 32 | } 33 | // attaches a data attribute to every tr element with an object 34 | // of data values keyed by column name 35 | function loadRowData(tableRow) { 36 | var tableCols = tableRow.querySelectorAll('td'), colNode, col, data = {}, i, val; 37 | for (i = 0; i < tableCols.length; i += 1) { 38 | colNode = tableCols[i]; 39 | col = cols[i]; 40 | val = colNode.getAttribute('data-value'); 41 | if (col.type === 'number') { 42 | val = Number(val); 43 | } 44 | data[col.key] = val; 45 | } 46 | return data; 47 | } 48 | // loads all row data 49 | function loadData() { 50 | var rows = getTableBody().querySelectorAll('tr'), i; 51 | for (i = 0; i < rows.length; i += 1) { 52 | rows[i].data = loadRowData(rows[i]); 53 | } 54 | } 55 | // sorts the table using the data for the ith column 56 | function sortByIndex(index, desc) { 57 | var key = cols[index].key, sorter = function (a, b) { 58 | a = a.data[key]; 59 | b = b.data[key]; 60 | return a < b ? -1 : a > b ? 1 : 0; 61 | }, finalSorter = sorter, tableBody = document.querySelector('.coverage-summary tbody'), rowNodes = tableBody.querySelectorAll('tr'), rows = [], i; 62 | if (desc) { 63 | finalSorter = function (a, b) { 64 | return -1 * sorter(a, b); 65 | }; 66 | } 67 | for (i = 0; i < rowNodes.length; i += 1) { 68 | rows.push(rowNodes[i]); 69 | tableBody.removeChild(rowNodes[i]); 70 | } 71 | rows.sort(finalSorter); 72 | for (i = 0; i < rows.length; i += 1) { 73 | tableBody.appendChild(rows[i]); 74 | } 75 | } 76 | // removes sort indicators for current column being sorted 77 | function removeSortIndicators() { 78 | var col = getNthColumn(currentSort.index), cls = col.className; 79 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 80 | col.className = cls; 81 | } 82 | // adds sort indicators for current column being sorted 83 | function addSortIndicators() { 84 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 85 | } 86 | // adds event listeners for all sorter widgets 87 | function enableUI() { 88 | var i, el, ithSorter = function ithSorter(i) { 89 | var col = cols[i]; 90 | return function () { 91 | var desc = col.defaultDescSort; 92 | if (currentSort.index === i) { 93 | desc = !currentSort.desc; 94 | } 95 | sortByIndex(i, desc); 96 | removeSortIndicators(); 97 | currentSort.index = i; 98 | currentSort.desc = desc; 99 | addSortIndicators(); 100 | }; 101 | }; 102 | for (i = 0; i < cols.length; i += 1) { 103 | if (cols[i].sortable) { 104 | el = getNthColumn(i).querySelector('.sorter'); 105 | if (el.addEventListener) { 106 | el.addEventListener('click', ithSorter(i)); 107 | } 108 | else { 109 | el.attachEvent('onclick', ithSorter(i)); 110 | } 111 | } 112 | } 113 | } 114 | // adds sorting functionality to the UI 115 | return function () { 116 | if (!getTable()) { 117 | return; 118 | } 119 | cols = loadColumns(); 120 | loadData(cols); 121 | addSortIndicators(); 122 | enableUI(); 123 | }; 124 | })(); 125 | window.addEventListener('load', addSorting); 126 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/async-limiter/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function Queue(options) { 3 | if (!(this instanceof Queue)) { 4 | return new Queue(options); 5 | } 6 | options = options || {}; 7 | this.concurrency = options.concurrency || Infinity; 8 | this.pending = 0; 9 | this.jobs = []; 10 | this.cbs = []; 11 | this._done = done.bind(this); 12 | } 13 | var arrayAddMethods = [ 14 | 'push', 15 | 'unshift', 16 | 'splice' 17 | ]; 18 | arrayAddMethods.forEach(function (method) { 19 | Queue.prototype[method] = function () { 20 | var methodResult = Array.prototype[method].apply(this.jobs, arguments); 21 | this._run(); 22 | return methodResult; 23 | }; 24 | }); 25 | Object.defineProperty(Queue.prototype, 'length', { 26 | get: function () { 27 | return this.pending + this.jobs.length; 28 | } 29 | }); 30 | Queue.prototype._run = function () { 31 | if (this.pending === this.concurrency) { 32 | return; 33 | } 34 | if (this.jobs.length) { 35 | var job = this.jobs.shift(); 36 | this.pending++; 37 | job(this._done); 38 | this._run(); 39 | } 40 | if (this.pending === 0) { 41 | while (this.cbs.length !== 0) { 42 | var cb = this.cbs.pop(); 43 | process.nextTick(cb); 44 | } 45 | } 46 | }; 47 | Queue.prototype.onDone = function (cb) { 48 | if (typeof cb === 'function') { 49 | this.cbs.push(cb); 50 | this._run(); 51 | } 52 | }; 53 | function done() { 54 | this.pending--; 55 | this._run(); 56 | } 57 | module.exports = Queue; 58 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function () { 3 | throw new Error('ws does not work in the browser. Browser clients must use the native ' + 4 | 'WebSocket object'); 5 | }; 6 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var WebSocket = require('./lib/websocket'); 3 | WebSocket.Server = require('./lib/websocket-server'); 4 | WebSocket.Receiver = require('./lib/receiver'); 5 | WebSocket.Sender = require('./lib/sender'); 6 | module.exports = WebSocket; 7 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/lib/buffer-util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Merges an array of buffers into a new buffer. 4 | * 5 | * @param {Buffer[]} list The array of buffers to concat 6 | * @param {Number} totalLength The total length of buffers in the list 7 | * @return {Buffer} The resulting buffer 8 | * @public 9 | */ 10 | function concat(list, totalLength) { 11 | var target = Buffer.allocUnsafe(totalLength); 12 | var offset = 0; 13 | for (var i = 0; i < list.length; i++) { 14 | var buf = list[i]; 15 | buf.copy(target, offset); 16 | offset += buf.length; 17 | } 18 | return target; 19 | } 20 | /** 21 | * Masks a buffer using the given mask. 22 | * 23 | * @param {Buffer} source The buffer to mask 24 | * @param {Buffer} mask The mask to use 25 | * @param {Buffer} output The buffer where to store the result 26 | * @param {Number} offset The offset at which to start writing 27 | * @param {Number} length The number of bytes to mask. 28 | * @public 29 | */ 30 | function _mask(source, mask, output, offset, length) { 31 | for (var i = 0; i < length; i++) { 32 | output[offset + i] = source[i] ^ mask[i & 3]; 33 | } 34 | } 35 | /** 36 | * Unmasks a buffer using the given mask. 37 | * 38 | * @param {Buffer} buffer The buffer to unmask 39 | * @param {Buffer} mask The mask to use 40 | * @public 41 | */ 42 | function _unmask(buffer, mask) { 43 | // Required until https://github.com/nodejs/node/issues/9006 is resolved. 44 | var length = buffer.length; 45 | for (var i = 0; i < length; i++) { 46 | buffer[i] ^= mask[i & 3]; 47 | } 48 | } 49 | try { 50 | var bufferUtil = require('bufferutil'); 51 | var bu_1 = bufferUtil.BufferUtil || bufferUtil; 52 | module.exports = { 53 | mask: function (source, mask, output, offset, length) { 54 | if (length < 48) 55 | _mask(source, mask, output, offset, length); 56 | else 57 | bu_1.mask(source, mask, output, offset, length); 58 | }, 59 | unmask: function (buffer, mask) { 60 | if (buffer.length < 32) 61 | _unmask(buffer, mask); 62 | else 63 | bu_1.unmask(buffer, mask); 64 | }, 65 | concat: concat 66 | }; 67 | } 68 | catch (e) /* istanbul ignore next */ { 69 | module.exports = { concat: concat, mask: _mask, unmask: _unmask }; 70 | } 71 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/lib/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'], 4 | GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 5 | kStatusCode: Symbol('status-code'), 6 | kWebSocket: Symbol('websocket'), 7 | EMPTY_BUFFER: Buffer.alloc(0), 8 | NOOP: function () { } 9 | }; 10 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/lib/event-target.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = function (d, b) { 4 | extendStatics = Object.setPrototypeOf || 5 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 6 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 7 | return extendStatics(d, b); 8 | } 9 | return function (d, b) { 10 | extendStatics(d, b); 11 | function __() { this.constructor = d; } 12 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 13 | }; 14 | })(); 15 | /** 16 | * Class representing an event. 17 | * 18 | * @private 19 | */ 20 | var Event = /** @class */ (function () { 21 | /** 22 | * Create a new `Event`. 23 | * 24 | * @param {String} type The name of the event 25 | * @param {Object} target A reference to the target to which the event was dispatched 26 | */ 27 | function Event(type, target) { 28 | this.target = target; 29 | this.type = type; 30 | } 31 | return Event; 32 | }()); 33 | /** 34 | * Class representing a message event. 35 | * 36 | * @extends Event 37 | * @private 38 | */ 39 | var MessageEvent = /** @class */ (function (_super) { 40 | __extends(MessageEvent, _super); 41 | /** 42 | * Create a new `MessageEvent`. 43 | * 44 | * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data 45 | * @param {WebSocket} target A reference to the target to which the event was dispatched 46 | */ 47 | function MessageEvent(data, target) { 48 | var _this = _super.call(this, 'message', target) || this; 49 | _this.data = data; 50 | return _this; 51 | } 52 | return MessageEvent; 53 | }(Event)); 54 | /** 55 | * Class representing a close event. 56 | * 57 | * @extends Event 58 | * @private 59 | */ 60 | var CloseEvent = /** @class */ (function (_super) { 61 | __extends(CloseEvent, _super); 62 | /** 63 | * Create a new `CloseEvent`. 64 | * 65 | * @param {Number} code The status code explaining why the connection is being closed 66 | * @param {String} reason A human-readable string explaining why the connection is closing 67 | * @param {WebSocket} target A reference to the target to which the event was dispatched 68 | */ 69 | function CloseEvent(code, reason, target) { 70 | var _this = _super.call(this, 'close', target) || this; 71 | _this.wasClean = target._closeFrameReceived && target._closeFrameSent; 72 | _this.reason = reason; 73 | _this.code = code; 74 | return _this; 75 | } 76 | return CloseEvent; 77 | }(Event)); 78 | /** 79 | * Class representing an open event. 80 | * 81 | * @extends Event 82 | * @private 83 | */ 84 | var OpenEvent = /** @class */ (function (_super) { 85 | __extends(OpenEvent, _super); 86 | /** 87 | * Create a new `OpenEvent`. 88 | * 89 | * @param {WebSocket} target A reference to the target to which the event was dispatched 90 | */ 91 | function OpenEvent(target) { 92 | return _super.call(this, 'open', target) || this; 93 | } 94 | return OpenEvent; 95 | }(Event)); 96 | /** 97 | * Class representing an error event. 98 | * 99 | * @extends Event 100 | * @private 101 | */ 102 | var ErrorEvent = /** @class */ (function (_super) { 103 | __extends(ErrorEvent, _super); 104 | /** 105 | * Create a new `ErrorEvent`. 106 | * 107 | * @param {Object} error The error that generated this event 108 | * @param {WebSocket} target A reference to the target to which the event was dispatched 109 | */ 110 | function ErrorEvent(error, target) { 111 | var _this = _super.call(this, 'error', target) || this; 112 | _this.message = error.message; 113 | _this.error = error; 114 | return _this; 115 | } 116 | return ErrorEvent; 117 | }(Event)); 118 | /** 119 | * This provides methods for emulating the `EventTarget` interface. It's not 120 | * meant to be used directly. 121 | * 122 | * @mixin 123 | */ 124 | var EventTarget = { 125 | /** 126 | * Register an event listener. 127 | * 128 | * @param {String} method A string representing the event type to listen for 129 | * @param {Function} listener The listener to add 130 | * @public 131 | */ 132 | addEventListener: function (method, listener) { 133 | if (typeof listener !== 'function') 134 | return; 135 | function onMessage(data) { 136 | listener.call(this, new MessageEvent(data, this)); 137 | } 138 | function onClose(code, message) { 139 | listener.call(this, new CloseEvent(code, message, this)); 140 | } 141 | function onError(error) { 142 | listener.call(this, new ErrorEvent(error, this)); 143 | } 144 | function onOpen() { 145 | listener.call(this, new OpenEvent(this)); 146 | } 147 | if (method === 'message') { 148 | onMessage._listener = listener; 149 | this.on(method, onMessage); 150 | } 151 | else if (method === 'close') { 152 | onClose._listener = listener; 153 | this.on(method, onClose); 154 | } 155 | else if (method === 'error') { 156 | onError._listener = listener; 157 | this.on(method, onError); 158 | } 159 | else if (method === 'open') { 160 | onOpen._listener = listener; 161 | this.on(method, onOpen); 162 | } 163 | else { 164 | this.on(method, listener); 165 | } 166 | }, 167 | /** 168 | * Remove an event listener. 169 | * 170 | * @param {String} method A string representing the event type to remove 171 | * @param {Function} listener The listener to remove 172 | * @public 173 | */ 174 | removeEventListener: function (method, listener) { 175 | var listeners = this.listeners(method); 176 | for (var i = 0; i < listeners.length; i++) { 177 | if (listeners[i] === listener || listeners[i]._listener === listener) { 178 | this.removeListener(method, listeners[i]); 179 | } 180 | } 181 | } 182 | }; 183 | module.exports = EventTarget; 184 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/node_modules/ws/lib/validation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | try { 3 | var isValidUTF8 = require('utf-8-validate'); 4 | exports.isValidUTF8 = typeof isValidUTF8 === 'object' 5 | ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0 6 | : isValidUTF8; 7 | } 8 | catch (e) /* istanbul ignore next */ { 9 | exports.isValidUTF8 = function () { return true; }; 10 | } 11 | /** 12 | * Checks if a status code is allowed in a close frame. 13 | * 14 | * @param {Number} code The status code 15 | * @return {Boolean} `true` if the status code is valid, else `false` 16 | * @public 17 | */ 18 | exports.isValidStatusCode = function (code) { 19 | return ((code >= 1000 && 20 | code <= 1013 && 21 | code !== 1004 && 22 | code !== 1005 && 23 | code !== 1006) || 24 | (code >= 3000 && code <= 4999)); 25 | }; 26 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC0DCCAbgCCQDiFEBwjK/Q7zANBgkqhkiG9w0BAQsFADAqMREwDwYDVQQKDAhu 3 | ZW9uaW91czEVMBMGA1UEAwwMbmVvbmlvdXMub25lMB4XDTE4MDUxMDE2MTcwNloX 4 | DTI4MDUwNzE2MTcwNlowKjERMA8GA1UECgwIbmVvbmlvdXMxFTATBgNVBAMMDG5l 5 | b25pb3VzLm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKjCzMcr 6 | bFuy6YImpDNPEyYxw+nQAmrITFDS8qSk4L4OPU1MV9Epv9ehLNGFleEnVJVs021W 7 | 5dxy15tznQriI1t2tLU/Mz0gnxenY2UAAOd9njUcjgimehY+/mRbQXGQCkvoeRRs 8 | noAroP1jUJbOMtSFkB2gwCyxFeivWEAqKZJSLI1OAq1BmexoKGPT7QRN5ynWv1TM 9 | zyX0/DGbL+ghWKr2FkueSokiYJNfj9Kl6KbT5nVj+bTZgtSfUSv26EHKZB5NciJv 10 | 2Jl2392sMk8PhkTU7K8L4v6d50bzc8v6X8P5SvPINTdfCo28y0HUc1bIUhVgIQi4 11 | t/Dbc/xCxEo/zNUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEASUFHGGPsAOx6fmCA 12 | CPkvc/Y5ud9+vrleCzGXmUcYikChBTXw3KJQtvpDUfJ12PkLAEwUfhMWD7vholOO 13 | q+DqTzZao9sDFasQg2cpUFhFXj/YL/nWMq3L8rlrccmmKB8Cc/iiUa6e0ukhaoUK 14 | 6MPwwGj7eL5cUXguVgOmlhvgzyfO/SSqc+LKL46l16EB18bpETS07aeW13vKZTeC 15 | d5GVkvhbyn2m63HRsGjikq1NOwmH4Ror6TTb5u/BvBX60dVExpK8spFJSafINPW4 16 | jXqzfSuyaIhVHQyTdpsmQSFf9cdcAwq28eYIYUaMO95QEYmA/95fCnUoCCNteSIV 17 | gX3TQQ== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAqMLMxytsW7LpgiakM08TJjHD6dACashMUNLypKTgvg49TUxX 3 | 0Sm/16Es0YWV4SdUlWzTbVbl3HLXm3OdCuIjW3a0tT8zPSCfF6djZQAA532eNRyO 4 | CKZ6Fj7+ZFtBcZAKS+h5FGyegCug/WNQls4y1IWQHaDALLEV6K9YQCopklIsjU4C 5 | rUGZ7GgoY9PtBE3nKda/VMzPJfT8MZsv6CFYqvYWS55KiSJgk1+P0qXoptPmdWP5 6 | tNmC1J9RK/boQcpkHk1yIm/YmXbf3awyTw+GRNTsrwvi/p3nRvNzy/pfw/lK88g1 7 | N18KjbzLQdRzVshSFWAhCLi38Ntz/ELESj/M1QIDAQABAoIBAAvqLPEG5NCYkhnp 8 | RoCE3bI9ozpXwEPvvkuaiR0Msv1YHgXeFPkkfHHp5DMqvkk2MKeYFllK4FGvHf/Q 9 | qs7A5oQnnlyJiMGREwplfAP+exHc8ZWIXZLIxifZ7LYDJ1ywMbnoQNwrSwl7ixM4 10 | ttDe4AHXKDSfS9Ib8pMKBi4JjAPTgg3LfYcui6mcELqt/sd3Cv1GKNDmIxXpxc5Q 11 | eDy43/bBAJx597GkpLW0mmpmx3EvlrEaRjC0BxCKg/NrTiUnRJW/zfyS6gKOeZWd 12 | mGgNbxrbErW7vNDbrMt742QhRkqyqwvkf10/RRTlLfOaQJz4Bu7AO3912A1diU2q 13 | 1WB+80UCgYEA0fcN5jm9/sEbhgV8n6TBD6Sk5k65Wvqb9g7sQFaixZqtITqu/tuA 14 | 6qua51FN115ATXwJGdhSJfyUFdDSK3Sd4b+21leIv9JoU3c5bYFTV0nn5W7J5rGG 15 | STPRtjMf8nIWH6jOFEBW6nV62euKeUHTKduIkdGNyaM0AMaER/JnMB8CgYEAzcMJ 16 | GQoAKCKEcN1VLKY2j7AQs56BchBpQB0ipnhenNJgHokEwNP0NfudCX50yoWLsUel 17 | KbmMvgXSqPaZcniqgRiT21fFl2VgiS+qCiX9vOEF1st9/ESnw75xa0TUUVNiKOH9 18 | p8/hUpl87iPf2NFeEDnjYr/Ouh40uCL7Au/B1IsCgYEAow/cYo07ierNBlOiipU4 19 | Pn7edeJzvz1b/EdwoTLnbNGIXYMmvtUYFKg7QCR7cKRJCiQnKUQ/4DJ9i0fGwWrq 20 | 5pSuWV5X3Kl6zj+MgQfsAqFqEFvvP1Nld9pfpsGjsPV7SxEdIsso9SNRyoZL34oI 21 | hbxyHtUA6bTuwR9rQjj2fH8CgYEAuw5SqAOybsoqctyUARo9wdTC6jfv3/1RYarb 22 | BFGrWY/bOAdCXfaSLb1HXwkqLa7Idur2GH+Jlnp+r4I3r5xJDUGFsUMS63aLE0xU 23 | nhM5oEtFXqbyKrNTfJ0WSPlyt1hBhX8ldTiD0+6bZ3cPmfGEPOYTdIOA8Sxiqv+K 24 | CHpkUM8CgYATpSv5J+p5xTlcWk2gkX4JTT44EP31RXYRvBzwOm3DiJRB78JU6aOg 25 | 6aqo5/Qv3JqwAz/X2mMcRw+DuuvOXyGYXryqbzr3e82bY4Yp0rFyi1LrM72v6HIT 26 | b72rJqOKu+TZjzvp8qgPcQtiJ/qZsUmPNfXIMVm9IizAsfByg9wL+A== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/www/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neonious/lowjs/3479cc660a73de2b7adbd7b94cc518a17b2c0f89/examples/chat_ws_webserver/www/favicon.png -------------------------------------------------------------------------------- /examples/chat_ws_webserver/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome to low.js! 6 | 7 | 8 | 48 | 49 | 50 | 51 |
52 |

Welcome to low.js!

53 | 54 |

This page is served by the JavaScript program you just started.

55 |

Add files to www directory to serve them, too!
(Do not forget to add mime type in 56 | handleRequest() first.)

57 | 58 |

Chat with everybody else having this website open:
(uses 59 | WebSockets)

60 |

61 |

63 |

64 |

Chat window:
(Own messages are grey.)

65 |
66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/chat_ws_webserver/www/styles.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | * { 6 | font-size: 14pt; 7 | font-family: Arial, Helvetica, sans-serif; 8 | text-align: center; 9 | } 10 | 11 | body { 12 | position: absolute; 13 | left: 0; 14 | top: 0; 15 | width: 100%; 16 | height: 100%; 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: center; 20 | align-items: center; 21 | } 22 | body>div { 23 | background: #eeeeff; 24 | box-shadow: 0 0 220px 125px #eeeeff; 25 | max-width: 790px; 26 | border-radius: 30px; 27 | padding: 20px; 28 | } 29 | 30 | 31 | small { 32 | font-size: 12pt; 33 | } 34 | 35 | input[type=text] { 36 | border: 1px solid black; 37 | width: 460px; 38 | text-align: left; 39 | padding: 5px; 40 | } 41 | input[type=submit] { 42 | -webkit-appearance: none; 43 | margin-left: 5px; 44 | } 45 | 46 | a { 47 | text-decoration: none; 48 | } 49 | a:hover { 50 | color: #8888ff; 51 | } 52 | 53 | .welcome { 54 | font-size: 30pt; 55 | font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif; 56 | letter-spacing: 5px; 57 | } 58 | #messages { 59 | background-color: white; 60 | padding: 5px; 61 | width: 460px; 62 | height: 100px; 63 | border: 1px solid black; 64 | text-align: left; 65 | overflow-y: scroll; 66 | } -------------------------------------------------------------------------------- /lib_js/buffer.js: -------------------------------------------------------------------------------- 1 | Buffer = ((oldFunc) => { 2 | let newBuffer = function (...args) { 3 | if(typeof args[0] === 'string' && (args[1] == 'hex' || args[1] == 'base64')) 4 | return oldFunc.call(this, Duktape.dec(args[1], args[0])); 5 | else if(args[0].slice && typeof args[1] !== 'string' && args[2] !== undefined) 6 | // Workaround: DukTape does not allow slicing in constructor 7 | return oldFunc.call(this, args[0].slice(args[1], args[1] + args[2])); 8 | else 9 | return oldFunc.call(this, ...args); 10 | } 11 | newBuffer.byteLength = oldFunc.byteLength; 12 | newBuffer.compare = oldFunc.compare; 13 | newBuffer.concat = oldFunc.concat; 14 | newBuffer.isBuffer = oldFunc.isBuffer; 15 | newBuffer.isEncoding = oldFunc.isEncoding; 16 | newBuffer.poolSize = oldFunc.poolSize; 17 | newBuffer.prototype = oldFunc.prototype; 18 | 19 | // Not implemented by DukTape 20 | newBuffer.from = (...args) => { return new newBuffer(...args); } 21 | newBuffer.allocUnsafe = newBuffer.alloc = (...args) => { return new newBuffer(...args); } 22 | return newBuffer; 23 | })(Buffer); 24 | 25 | Buffer.prototype.toString = ((oldFunc) => { 26 | return function (encoding, b, c) { 27 | if (encoding == 'hex' || encoding == 'base64') 28 | return Duktape.enc(encoding, this); 29 | else 30 | return oldFunc.call(this, encoding, b, c); 31 | } 32 | })(Buffer.prototype.toString); 33 | 34 | exports.Buffer = Buffer; 35 | -------------------------------------------------------------------------------- /lib_js/child_process.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export function exec() { 4 | throw new Error('Not supported.'); 5 | } 6 | 7 | export function execSync() { 8 | throw new Error('Not supported.'); 9 | } 10 | 11 | export function spawn() { 12 | throw new Error('Not supported.'); 13 | } 14 | 15 | export function spawnSync() { 16 | throw new Error('Not supported.'); 17 | } 18 | -------------------------------------------------------------------------------- /lib_js/crypto.js: -------------------------------------------------------------------------------- 1 | 'use script'; 2 | 3 | let native = require('native'); 4 | 5 | // TODO: make Hash a transform stream 6 | class Hash { 7 | constructor(type, key) { 8 | this._native = native.createCryptoHash(this, type, key); 9 | } 10 | 11 | update(data, encoding) { 12 | if (typeof data === 'string') 13 | data = Buffer.from(data, encoding); 14 | 15 | native.cryptoHashUpdate(this._native, data); 16 | return this; 17 | } 18 | 19 | digest(encoding) { 20 | let val = native.cryptoHashDigest(this._native); 21 | if (encoding) 22 | return val.toString(encoding); 23 | else 24 | return val; 25 | } 26 | } 27 | 28 | exports.randomBytes = native.randomBytes; 29 | 30 | exports.createHash = function (type) { 31 | return new Hash(type); 32 | } 33 | 34 | exports.createHmac = function (type, key) { 35 | return new Hash(type, key); 36 | } 37 | 38 | exports.randomFillSync = function(buffer, offset, size) { 39 | if(offset === undefined) 40 | offset = 0; 41 | if(size === undefined) 42 | size = buffer.length - offset; 43 | 44 | let buf = native.randomBytes(size); 45 | buf.copy(buffer, offset); 46 | } 47 | 48 | // TODO: use second core 49 | exports.randomFill = function(buffer, offset, size, callback) { 50 | if(callback === undefined) { 51 | if(size === undefined) { 52 | callback = offset; 53 | offset = undefined; 54 | } else { 55 | callback = size; 56 | size = undefined; 57 | } 58 | } 59 | 60 | if(offset === undefined) 61 | offset = 0; 62 | if(size === undefined) 63 | size = buffer.length - offset; 64 | 65 | let buf = native.randomBytes(size); 66 | buf.copy(buffer, offset); 67 | 68 | process.nextTick(() => { 69 | callback(null, buffer); 70 | }); 71 | } -------------------------------------------------------------------------------- /lib_js/internal/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isWindows = process.platform === 'win32'; 4 | 5 | module.exports = { 6 | // Alphabet chars. 7 | CHAR_UPPERCASE_A: 65, /* A */ 8 | CHAR_LOWERCASE_A: 97, /* a */ 9 | CHAR_UPPERCASE_Z: 90, /* Z */ 10 | CHAR_LOWERCASE_Z: 122, /* z */ 11 | 12 | // Non-alphabetic chars. 13 | CHAR_DOT: 46, /* . */ 14 | CHAR_FORWARD_SLASH: 47, /* / */ 15 | CHAR_BACKWARD_SLASH: 92, /* \ */ 16 | CHAR_VERTICAL_LINE: 124, /* | */ 17 | CHAR_COLON: 58, /* : */ 18 | CHAR_QUESTION_MARK: 63, /* ? */ 19 | CHAR_UNDERSCORE: 95, /* _ */ 20 | CHAR_LINE_FEED: 10, /* \n */ 21 | CHAR_CARRIAGE_RETURN: 13, /* \r */ 22 | CHAR_TAB: 9, /* \t */ 23 | CHAR_FORM_FEED: 12, /* \f */ 24 | CHAR_EXCLAMATION_MARK: 33, /* ! */ 25 | CHAR_HASH: 35, /* # */ 26 | CHAR_SPACE: 32, /* */ 27 | CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ 28 | CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ 29 | CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ 30 | CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ 31 | CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ 32 | CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ 33 | CHAR_LEFT_CURLY_BRACKET: 123, /* { */ 34 | CHAR_RIGHT_CURLY_BRACKET: 125, /* } */ 35 | CHAR_HYPHEN_MINUS: 45, /* - */ 36 | CHAR_PLUS: 43, /* + */ 37 | CHAR_DOUBLE_QUOTE: 34, /* " */ 38 | CHAR_SINGLE_QUOTE: 39, /* ' */ 39 | CHAR_PERCENT: 37, /* % */ 40 | CHAR_SEMICOLON: 59, /* ; */ 41 | CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ 42 | CHAR_GRAVE_ACCENT: 96, /* ` */ 43 | CHAR_AT: 64, /* @ */ 44 | CHAR_AMPERSAND: 38, /* & */ 45 | CHAR_EQUAL: 61, /* = */ 46 | 47 | // Digits 48 | CHAR_0: 48, /* 0 */ 49 | CHAR_9: 57, /* 9 */ 50 | 51 | EOL: isWindows ? '\r\n' : '\n' 52 | }; 53 | -------------------------------------------------------------------------------- /lib_js/internal/querystring.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | 'use strict'; 23 | 24 | const hexTable = new Array(256); 25 | for (var i = 0; i < 256; ++i) 26 | hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); 27 | 28 | const isHexTable = [ 29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 47 32 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 33 | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 - 79 34 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 95 35 | 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96 - 111 36 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112 - 127 37 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ... 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // ... 256 45 | ]; 46 | 47 | function encodeStr(str, noEscapeTable, hexTable) { 48 | const len = str.length; 49 | if (len === 0) 50 | return ''; 51 | 52 | let out = ''; 53 | let lastPos = 0; 54 | 55 | for (let i = 0; i < len; i++) { 56 | let c = str.charCodeAt(i); 57 | 58 | // ASCII 59 | if (c < 0x80) { 60 | if (noEscapeTable[c] === 1) 61 | continue; 62 | if (lastPos < i) 63 | out += str.slice(lastPos, i); 64 | lastPos = i + 1; 65 | out += hexTable[c]; 66 | continue; 67 | } 68 | 69 | if (lastPos < i) 70 | out += str.slice(lastPos, i); 71 | 72 | // Multi-byte characters ... 73 | if (c < 0x800) { 74 | lastPos = i + 1; 75 | out += hexTable[0xC0 | (c >> 6)] + 76 | hexTable[0x80 | (c & 0x3F)]; 77 | continue; 78 | } 79 | if (c < 0xD800 || c >= 0xE000) { 80 | lastPos = i + 1; 81 | out += hexTable[0xE0 | (c >> 12)] + 82 | hexTable[0x80 | ((c >> 6) & 0x3F)] + 83 | hexTable[0x80 | (c & 0x3F)]; 84 | continue; 85 | } 86 | // Surrogate pair 87 | ++i; 88 | 89 | // This branch should never happen because all URLSearchParams entries 90 | // should already be converted to USVString. But, included for 91 | // completion's sake anyway. 92 | if (i >= len) 93 | throw new ERR_INVALID_URI(); 94 | 95 | const c2 = str.charCodeAt(i) & 0x3FF; 96 | 97 | lastPos = i + 1; 98 | c = 0x10000 + (((c & 0x3FF) << 10) | c2); 99 | out += hexTable[0xF0 | (c >> 18)] + 100 | hexTable[0x80 | ((c >> 12) & 0x3F)] + 101 | hexTable[0x80 | ((c >> 6) & 0x3F)] + 102 | hexTable[0x80 | (c & 0x3F)]; 103 | } 104 | if (lastPos === 0) 105 | return str; 106 | if (lastPos < len) 107 | return out + str.slice(lastPos); 108 | return out; 109 | } 110 | 111 | module.exports = { 112 | encodeStr, 113 | hexTable, 114 | isHexTable 115 | }; 116 | -------------------------------------------------------------------------------- /lib_js/internal/util/types.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ReflectApply = Reflect.apply; 4 | 5 | // This function is borrowed from the function with the same name on V8 Extras' 6 | // `utils` object. V8 implements Reflect.apply very efficiently in conjunction 7 | // with the spread syntax, such that no additional special case is needed for 8 | // function calls w/o arguments. 9 | // Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156 10 | function uncurryThis(func) { 11 | return (thisArg, ...args) => ReflectApply(func, thisArg, args); 12 | } 13 | 14 | // Cached to make sure no userland code can tamper with it. 15 | const isArrayBufferView = ArrayBuffer.isView; 16 | 17 | function isUint8Array(value) { 18 | return value instanceof Uint8Array; 19 | } 20 | 21 | function isUint8ClampedArray(value) { 22 | return value instanceof Uint8ClampedArray; 23 | } 24 | 25 | function isUint16Array(value) { 26 | return value instanceof Uint16Array; 27 | } 28 | 29 | function isUint32Array(value) { 30 | return value instanceof Uint32Array; 31 | } 32 | 33 | function isInt8Array(value) { 34 | return value instanceof Int8Array; 35 | } 36 | 37 | function isInt16Array(value) { 38 | return value instanceof Int16Array; 39 | } 40 | 41 | function isInt32Array(value) { 42 | return value instanceof Int32Array; 43 | } 44 | 45 | function isFloat32Array(value) { 46 | return value instanceof Float32Array; 47 | } 48 | 49 | function isFloat64Array(value) { 50 | return value instanceof Float64Array; 51 | } 52 | 53 | function isBigInt64Array(value) { 54 | return value instanceof BigInt64Array; 55 | } 56 | 57 | function isBigUint64Array(value) { 58 | return value instanceof BigUint64Array; 59 | } 60 | 61 | function isAnyArrayBuffer(value) { return false; } 62 | function isArgumentsObject(value) { return false; } 63 | function isDataView(value) { return value instanceof DataView; } 64 | function isExternal(value) { return false; } 65 | function isMap(value) { return value instanceof Map; } 66 | function isMapIterator(value) { return false; } 67 | function isPromise(value) { return value instanceof Promise; } 68 | function isSet(value) { return value instanceof Set; } 69 | function isSetIterator(value) { return false; } 70 | function isWeakMap(value) { return value instanceof WeakMap; } 71 | function isWeakSet(value) { return value instanceof WeakSet; } 72 | function isRegExp(value) { return value instanceof RegExp; } 73 | function isDate(value) { return value instanceof Date; } 74 | function isTypedArray(value) { return false; } 75 | function isModuleNamespaceObject(value) { return false; } 76 | // TODO: check list of util/types 77 | 78 | module.exports = { 79 | isArrayBufferView, 80 | isTypedArray, 81 | isUint8Array, 82 | isUint8ClampedArray, 83 | isUint16Array, 84 | isUint32Array, 85 | isInt8Array, 86 | isInt16Array, 87 | isInt32Array, 88 | isFloat32Array, 89 | isFloat64Array, 90 | isBigInt64Array, 91 | isBigUint64Array, 92 | isAnyArrayBuffer, 93 | isArgumentsObject, 94 | isDataView, 95 | isExternal, 96 | isMap, 97 | isMapIterator, 98 | isPromise, 99 | isSet, 100 | isSetIterator, 101 | isWeakMap, 102 | isWeakSet, 103 | isRegExp, 104 | isDate, 105 | isModuleNamespaceObject 106 | }; 107 | -------------------------------------------------------------------------------- /lib_js/main.js: -------------------------------------------------------------------------------- 1 | require('repl').start(); 2 | -------------------------------------------------------------------------------- /lib_js/module.js: -------------------------------------------------------------------------------- 1 | // Note: we are skipping init.js and main.js, because both are modules which cannot be require()-ed 2 | exports.builtinModules = [ 3 | 'assert', 4 | 'buffer', 5 | 'console', 6 | 'crypto', 7 | 'dgram', 8 | 'dns', 9 | 'events', 10 | 'fs', 11 | 'http', 12 | 'https', 13 | 'module', 14 | 'net', 15 | 'path', 16 | 'process', 17 | 'querystring', 18 | 'readline', 19 | 'repl', 20 | 'stream', 21 | 'string_decoder', 22 | 'tls', 23 | 'tty', 24 | 'url', 25 | 'util', 26 | 'vm', 27 | 'zlib' 28 | ] 29 | if (process.platform == 'esp32') { 30 | exports.builtinModules.push('gpio'); 31 | exports.builtinModules.push('i2c'); 32 | exports.builtinModules.push('lowsys'); 33 | exports.builtinModules.push('sdcard'); 34 | exports.builtinModules.push('signal'); 35 | exports.builtinModules.push('spi'); 36 | exports.builtinModules.push('uart'); 37 | } -------------------------------------------------------------------------------- /lib_js/os.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const native = require('native'); 4 | 5 | export let EOL = '\n'; 6 | 7 | export function arch() { 8 | return process.arch; 9 | } 10 | 11 | export function platform() { 12 | return process.platform; 13 | } 14 | 15 | export function freemem() { 16 | return native.osInfo().freemem; 17 | } 18 | 19 | export function totalmem() { 20 | return native.osInfo().totalmem; 21 | } 22 | 23 | export function uptime() { 24 | return native.osInfo().uptime; 25 | } 26 | 27 | // TODO: fake below here 28 | exports.constants = { 29 | }; 30 | 31 | export function homedir() { 32 | return "/"; 33 | } 34 | 35 | export function tmpdir() { 36 | if (process.platform == 'esp32') { 37 | return "/"; 38 | } else { 39 | return "/tmp"; 40 | } 41 | } 42 | 43 | export function hostname() { 44 | return "host"; 45 | } 46 | 47 | export function loadavg() { 48 | return [0, 0, 0]; 49 | } 50 | 51 | export function endianness() { 52 | return 'LE'; 53 | } 54 | 55 | export function networkInterfaces() { 56 | return {}; 57 | } 58 | 59 | export function release() { 60 | return process.platform; 61 | } 62 | 63 | export function type() { 64 | return process.platform; 65 | } 66 | 67 | export function cpus() { 68 | return [{}]; // todo need this so that tests work 69 | } 70 | 71 | export function networkInterfaces() { 72 | return {}; // todo need this so that tests work 73 | } 74 | 75 | export function userInfo() { 76 | return {}; 77 | } 78 | -------------------------------------------------------------------------------- /lib_js/process.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Re-export process as a native module 4 | module.exports = process; 5 | -------------------------------------------------------------------------------- /lib_js/string_decoder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class StringDecoder { 4 | constructor(encoding) { 5 | this._textDecoder = new TextDecoder(encoding); 6 | } 7 | 8 | write(buf) { 9 | return this._textDecoder.decode(buf, { 'stream': true }); 10 | } 11 | 12 | end(buf) { 13 | return this._textDecoder.decode(buf); 14 | } 15 | } 16 | 17 | exports.StringDecoder = StringDecoder; 18 | -------------------------------------------------------------------------------- /lib_js/timers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | setTimeout, 5 | setInterval, 6 | setImmediate, 7 | clearTimeout, 8 | clearInterval, 9 | clearImmediate 10 | }; 11 | -------------------------------------------------------------------------------- /lib_js/tls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let native = require('native'); 4 | let net = require('net'); 5 | let socket = require('stream'); 6 | 7 | class Server extends net.Server { 8 | constructor(options, acceptCallback) { 9 | if (!acceptCallback && typeof options === 'function') { 10 | acceptCallback = options; 11 | options = {}; 12 | } 13 | if (!options) 14 | options = {}; 15 | if(!options.ca) 16 | options.ca = module.exports.rootCertificates; 17 | 18 | options.secureContext = native.createTLSContext(options, true); 19 | super(options); 20 | } 21 | } 22 | 23 | class TLSSocket extends net.Socket { 24 | constructor(options, secureConnectCallback) { 25 | if (!secureConnectCallback && typeof options === 'function') { 26 | secureConnectCallback = options; 27 | options = {}; 28 | } 29 | if (!options) 30 | options = {}; 31 | if(!options.ca) 32 | options.ca = module.exports.rootCertificates; 33 | 34 | options.secureContext = native.createTLSContext(options, false); 35 | super(options); 36 | } 37 | } 38 | 39 | function createServer(options, acceptCallback) { 40 | return new Server(options, acceptCallback); 41 | } 42 | 43 | function connect(...args) { 44 | let normalized = normalizeArgs(args); 45 | let options = normalized[0]; 46 | 47 | let socket = new TLSSocket(options); 48 | let cb = normalized[1]; 49 | if(cb) 50 | socket.once('connect', cb); 51 | if (options.timeout) 52 | socket.setTimeout(options.timeout); 53 | return TLSSocket.prototype.connect.call(socket, options); 54 | } 55 | // Returns an array [options, cb], where options is an object, 56 | // cb is either a function or null. 57 | // Used to normalize arguments of Socket.prototype.connect() and 58 | // Server.prototype.listen(). Possible combinations of parameters: 59 | // (options[...][, cb]) 60 | // (path[...][, cb]) 61 | // ([port][, host][...][, cb]) 62 | // For Socket.prototype.connect(), the [...] part is ignored 63 | // For Server.prototype.listen(), the [...] part is [, backlog] 64 | // but will not be handled here (handled in listen()) 65 | let normalizedArgsSymbol = Symbol(); 66 | function isPipeName(s) { 67 | return typeof s === 'string' && toNumber(s) === false; 68 | } 69 | function normalizeArgs(args) { 70 | let arr; 71 | 72 | if (args.length === 0) { 73 | arr = [{}, null]; 74 | arr[normalizedArgsSymbol] = true; 75 | return arr; 76 | } 77 | 78 | const arg0 = args[0]; 79 | let options = {}; 80 | if (typeof arg0 === 'object' && arg0 !== null) { 81 | // (options[...][, cb]) 82 | options = arg0; 83 | } else if (isPipeName(arg0)) { 84 | // (path[...][, cb]) 85 | options.path = arg0; 86 | } else { 87 | // ([port][, host][...][, cb]) 88 | options.port = arg0; 89 | if (args.length > 1 && typeof args[1] === 'string') { 90 | options.host = args[1]; 91 | } 92 | } 93 | 94 | let cb = args[args.length - 1]; 95 | if (typeof cb !== 'function') 96 | arr = [options, null]; 97 | else 98 | arr = [options, cb]; 99 | 100 | arr[normalizedArgsSymbol] = true; 101 | return arr; 102 | } 103 | 104 | function createSecureContext(options) { 105 | if (!options) 106 | options = {}; 107 | if(!options.ca) 108 | options.ca = module.exports.rootCertificates; 109 | 110 | return native.createTLSContext(options); 111 | } 112 | 113 | let rootCerts; 114 | 115 | module.exports = { 116 | Server, 117 | createSecureContext, 118 | createServer, 119 | connect, 120 | get rootCertificates() { 121 | if(!rootCerts) 122 | rootCerts = require('internal/root-certs.json'); 123 | 124 | return rootCerts; 125 | } 126 | } -------------------------------------------------------------------------------- /lib_js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": false, 4 | "module": "commonjs", 5 | "target": "ES5", 6 | "allowJs": true, 7 | "rootDir": "./", 8 | "baseUrl": "./", 9 | "outDir": "./build", 10 | "noStrictGenericChecks": true, 11 | "skipLibCheck": true, 12 | "strictFunctionTypes": false, 13 | "lib": [ 14 | "es2015", 15 | "dom" 16 | ] 17 | }, 18 | "exclude": [ 19 | "./build/**" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /lib_js/tty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let native = require('native'); 4 | let net = require('net'); 5 | 6 | let OSRelease; 7 | 8 | const COLORS_2 = 1; 9 | const COLORS_16 = 4; 10 | const COLORS_256 = 8; 11 | const COLORS_16m = 24; 12 | 13 | // Some entries were taken from `dircolors` 14 | // (https://linux.die.net/man/1/dircolors). The corresponding terminals might 15 | // support more than 16 colors, but this was not tested for. 16 | // 17 | // Copyright (C) 1996-2016 Free Software Foundation, Inc. Copying and 18 | // distribution of this file, with or without modification, are permitted 19 | // provided the copyright notice and this notice are preserved. 20 | const TERM_ENVS = [ 21 | 'Eterm', 22 | 'cons25', 23 | 'console', 24 | 'cygwin', 25 | 'dtterm', 26 | 'gnome', 27 | 'hurd', 28 | 'jfbterm', 29 | 'konsole', 30 | 'kterm', 31 | 'mlterm', 32 | 'putty', 33 | 'st', 34 | 'terminator' 35 | ]; 36 | 37 | const TERM_ENVS_REG_EXP = [ 38 | /ansi/, 39 | /color/, 40 | /linux/, 41 | /^con[0-9]*x[0-9]/, 42 | /^rxvt/, 43 | /^screen/, 44 | /^xterm/, 45 | /^vt100/ 46 | ]; 47 | 48 | class ReadStream extends net.Socket { 49 | isTTY = true; 50 | isRaw = false; 51 | 52 | constructor(fd) { 53 | super({ 54 | fd, 55 | readable: true, 56 | writable: false 57 | }); 58 | } 59 | 60 | setRawMode(mode) { 61 | this.isRaw = !!mode; 62 | native.setsockopt(this._socketFD, undefined, undefined, undefined, this.isRaw); 63 | } 64 | } 65 | 66 | class WriteStream extends net.Socket { 67 | isTTY = true; 68 | 69 | constructor(fd) { 70 | super({ 71 | fd, 72 | readable: false, 73 | writable: true 74 | }); 75 | } 76 | 77 | // The `getColorDepth` API got inspired by multiple sources such as 78 | // https://github.com/chalk/supports-color, 79 | // https://github.com/isaacs/color-support. 80 | getColorDepth(env = process.env) { 81 | if (env.NODE_DISABLE_COLORS || env.TERM === 'dumb' && !env.COLORTERM) { 82 | return COLORS_2; 83 | } 84 | 85 | if (process.platform === 'win32') { 86 | // Lazy load for startup performance. 87 | if (OSRelease === undefined) { 88 | const { release } = require('os'); 89 | OSRelease = release().split('.'); 90 | } 91 | // Windows 10 build 10586 is the first Windows release that supports 256 92 | // colors. Windows 10 build 14931 is the first release that supports 93 | // 16m/TrueColor. 94 | if (+OSRelease[0] >= 10) { 95 | const build = +OSRelease[2]; 96 | if (build >= 14931) 97 | return COLORS_16m; 98 | if (build >= 10586) 99 | return COLORS_256; 100 | } 101 | 102 | return COLORS_16; 103 | } 104 | 105 | if (env.TMUX) { 106 | return COLORS_256; 107 | } 108 | 109 | if (env.CI) { 110 | if ('TRAVIS' in env || 'CIRCLECI' in env || 'APPVEYOR' in env || 111 | 'GITLAB_CI' in env || env.CI_NAME === 'codeship') { 112 | return COLORS_256; 113 | } 114 | return COLORS_2; 115 | } 116 | 117 | if ('TEAMCITY_VERSION' in env) { 118 | return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 119 | COLORS_16 : COLORS_2; 120 | } 121 | 122 | switch (env.TERM_PROGRAM) { 123 | case 'iTerm.app': 124 | if (!env.TERM_PROGRAM_VERSION || 125 | /^[0-2]\./.test(env.TERM_PROGRAM_VERSION)) { 126 | return COLORS_256; 127 | } 128 | return COLORS_16m; 129 | case 'HyperTerm': 130 | case 'Hyper': 131 | case 'MacTerm': 132 | return COLORS_16m; 133 | case 'Apple_Terminal': 134 | return COLORS_256; 135 | } 136 | 137 | if (env.TERM) { 138 | if (/^xterm-256/.test(env.TERM)) 139 | return COLORS_256; 140 | 141 | const termEnv = env.TERM.toLowerCase(); 142 | 143 | for (const term of TERM_ENVS) { 144 | if (termEnv === term) { 145 | return COLORS_16; 146 | } 147 | } 148 | for (const term of TERM_ENVS_REG_EXP) { 149 | if (term.test(termEnv)) { 150 | return COLORS_16; 151 | } 152 | } 153 | } 154 | 155 | if (env.COLORTERM) 156 | return COLORS_16; 157 | 158 | return COLORS_2; 159 | } 160 | } 161 | 162 | function isatty(fd) { 163 | return process.stdout.isTTY && (fd == 0 || fd == 1 || fd == 2); 164 | } 165 | 166 | // Backwards-compat 167 | let readline; 168 | 169 | WriteStream.prototype.cursorTo = function (x, y) { 170 | if (readline === undefined) readline = require('readline'); 171 | readline.cursorTo(this, x, y); 172 | }; 173 | WriteStream.prototype.moveCursor = function (dx, dy) { 174 | if (readline === undefined) readline = require('readline'); 175 | readline.moveCursor(this, dx, dy); 176 | }; 177 | WriteStream.prototype.clearLine = function (dir) { 178 | if (readline === undefined) readline = require('readline'); 179 | readline.clearLine(this, dir); 180 | }; 181 | WriteStream.prototype.clearScreenDown = function () { 182 | if (readline === undefined) readline = require('readline'); 183 | readline.clearScreenDown(this); 184 | }; 185 | WriteStream.prototype.getWindowSize = function () { 186 | return [this.columns, this.rows]; 187 | }; 188 | 189 | module.exports = { ReadStream, WriteStream, isatty }; -------------------------------------------------------------------------------- /lib_js/vm.js: -------------------------------------------------------------------------------- 1 | let native = require('native'); 2 | 3 | class Script { 4 | constructor(code, options) { 5 | this._func = native.compile(code); 6 | if (options && options.filename) 7 | this._filename = options.filename; 8 | } 9 | 10 | runInNewContext(sandbox, options) { 11 | createContext(sandbox, options); 12 | return runInContext(sandbox, options); 13 | } 14 | 15 | runInContext(sandbox, options) { 16 | if (options && options.filename) 17 | this._func.fileName = options.filename; 18 | else 19 | this._func.fileName = this._filename; 20 | 21 | if (sandbox._vmIsRunning) 22 | sandbox._vmIsRunning++; 23 | else { 24 | sandbox._vmIsRunning = 1; 25 | Object.setPrototypeOf(sandbox, global); 26 | } 27 | 28 | let res = native.runInContext(this._func, sandbox, options ? options.timeout : undefined, options ? !!options.breakOnSigint : undefined); 29 | if (!--sandbox._vmIsRunning) { 30 | delete sandbox._vmIsRunning; 31 | Object.setPrototypeOf(sandbox, null); 32 | } 33 | 34 | return res; 35 | } 36 | 37 | runInThisContext(options) { 38 | if (options && options.filename) 39 | this._func.fileName = options.filename; 40 | else 41 | this._func.fileName = this._filename; 42 | 43 | let res = native.runInContext(this._func, global, options ? options.timeout : undefined, options ? !!options.breakOnSigint : undefined); 44 | return res; 45 | } 46 | 47 | createCachedData() { 48 | // returning bogus data does not break anything 49 | // currently not supported, but we might in the future 50 | return new Buffer(1); 51 | } 52 | } 53 | 54 | function createScript(code, options) { 55 | return new Script(code, options); 56 | } 57 | 58 | function createContext(sandbox) { 59 | if (!sandbox) 60 | sandbox = {}; 61 | sandbox._vmIsContext = true; 62 | return sandbox; 63 | } 64 | 65 | function isContext(sandbox) { 66 | return !!sandbox._vmIsContext; 67 | } 68 | 69 | function runInContext(code, sandbox, options) { 70 | let script = new Script(code, options); 71 | return script.runInContext(sandbox, options); 72 | } 73 | 74 | function runInNewContext(code, sandbox, options) { 75 | let script = new Script(code, options); 76 | createContext(sandbox, options); 77 | return script.runInContext(sandbox, options); 78 | } 79 | 80 | function runInThisContext(code, options) { 81 | let script = new Script(code, options); 82 | return script.runInThisContext(options); 83 | } 84 | 85 | module.exports = { 86 | Script, 87 | createScript, 88 | createContext, 89 | isContext, 90 | runInContext, 91 | runInNewContext, 92 | runInThisContext 93 | }; -------------------------------------------------------------------------------- /lib_js/zlib.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neonious/lowjs/3479cc660a73de2b7adbd7b94cc518a17b2c0f89/lib_js/zlib.js -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lowjs", 3 | "version": "1.6.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/standalone": { 8 | "version": "7.6.4", 9 | "resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.6.4.tgz", 10 | "integrity": "sha512-ikqLCCQ3iSaRhkE1xgVc6+f49s+ZbMu8gvaW1VNJdKE+pQMAp+2CALy4rRKopaLfYWULvtfeKrs4suICO64/dg==", 11 | "dev": true 12 | }, 13 | "arrify": { 14 | "version": "1.0.1", 15 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 16 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 17 | "dev": true 18 | }, 19 | "buffer-from": { 20 | "version": "1.1.1", 21 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 22 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 23 | "dev": true 24 | }, 25 | "diff": { 26 | "version": "3.5.0", 27 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 28 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 29 | "dev": true 30 | }, 31 | "make-error": { 32 | "version": "1.3.6", 33 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 34 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 35 | "dev": true 36 | }, 37 | "minimist": { 38 | "version": "1.2.5", 39 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 40 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 41 | "dev": true 42 | }, 43 | "mkdirp": { 44 | "version": "0.5.5", 45 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 46 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 47 | "dev": true, 48 | "requires": { 49 | "minimist": "^1.2.5" 50 | } 51 | }, 52 | "source-map": { 53 | "version": "0.6.1", 54 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 55 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 56 | "dev": true 57 | }, 58 | "source-map-support": { 59 | "version": "0.5.19", 60 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 61 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 62 | "dev": true, 63 | "requires": { 64 | "buffer-from": "^1.0.0", 65 | "source-map": "^0.6.0" 66 | } 67 | }, 68 | "ts-node": { 69 | "version": "7.0.1", 70 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", 71 | "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", 72 | "dev": true, 73 | "requires": { 74 | "arrify": "^1.0.0", 75 | "buffer-from": "^1.1.0", 76 | "diff": "^3.1.0", 77 | "make-error": "^1.1.1", 78 | "minimist": "^1.2.0", 79 | "mkdirp": "^0.5.1", 80 | "source-map-support": "^0.5.6", 81 | "yn": "^2.0.0" 82 | } 83 | }, 84 | "typescript": { 85 | "version": "3.1.6", 86 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", 87 | "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", 88 | "dev": true 89 | }, 90 | "yn": { 91 | "version": "2.0.0", 92 | "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", 93 | "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", 94 | "dev": true 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lowjs", 3 | "version": "1.6.1", 4 | "description": "The Node.JS port for embedded devices.", 5 | "author": "neonious GmbH", 6 | "scripts": { 7 | "test": "cd test/tests_script && ts-node tests.ts" 8 | }, 9 | "devDependencies": { 10 | "@babel/standalone": "7.6.4", 11 | "ts-node": "^7.0.1", 12 | "typescript": "3.1.6" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LowCryptoHash.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowCryptoHash.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "LowCryptoHash.h" 6 | 7 | #include "mbedtls/md_internal.h" 8 | 9 | 10 | // ----------------------------------------------------------------------------- 11 | // LowCryptoHash::LowCryptoHash 12 | // ----------------------------------------------------------------------------- 13 | 14 | LowCryptoHash::LowCryptoHash(low_t *low, 15 | const mbedtls_md_info_t *info, 16 | unsigned char *key, 17 | int key_len) : 18 | mLow(low), 19 | mIndex(-1), mHMAC(key ? true : false), mOutputSize(info->size) 20 | { 21 | mbedtls_md_init(&mContext); 22 | 23 | int res = mbedtls_md_setup(&mContext, info, mHMAC ? 1 : 0); 24 | if(res != 0) 25 | duk_generic_error(mLow->duk_ctx, "mbedtls error code #%d", res); 26 | 27 | res = mHMAC ? mbedtls_md_hmac_starts(&mContext, key, key_len) 28 | : mbedtls_md_starts(&mContext); 29 | if(res != 0) 30 | duk_generic_error(mLow->duk_ctx, "mbedtls error code #%d", res); 31 | } 32 | 33 | // ----------------------------------------------------------------------------- 34 | // LowCryptoHash::~LowCryptoHash 35 | // ----------------------------------------------------------------------------- 36 | 37 | LowCryptoHash::~LowCryptoHash() 38 | { 39 | mbedtls_md_free(&mContext); 40 | 41 | if(mIndex >= 0) 42 | { 43 | if(mIndex >= mLow->cryptoHashes.size() || 44 | mLow->cryptoHashes[mIndex] != this) 45 | printf("assertion error at LowCryptoHash\n"); 46 | 47 | mLow->cryptoHashes[mIndex] = NULL; 48 | } 49 | } 50 | 51 | // ----------------------------------------------------------------------------- 52 | // LowCryptoHash::Update 53 | // ----------------------------------------------------------------------------- 54 | 55 | void LowCryptoHash::Update(unsigned char *data, int len) 56 | { 57 | int res = mHMAC ? mbedtls_md_hmac_update(&mContext, data, len) 58 | : mbedtls_md_update(&mContext, data, len); 59 | if(res != 0) 60 | duk_generic_error(mLow->duk_ctx, "mbedtls error code #%d", res); 61 | } 62 | 63 | // ----------------------------------------------------------------------------- 64 | // LowCryptoHash::Digest 65 | // ----------------------------------------------------------------------------- 66 | 67 | void LowCryptoHash::Digest(unsigned char *data, int len) 68 | { 69 | int res = mHMAC ? mbedtls_md_hmac_finish(&mContext, data) 70 | : mbedtls_md_finish(&mContext, data); 71 | if(res != 0) 72 | duk_generic_error(mLow->duk_ctx, "mbedtls error code #%d", res); 73 | } -------------------------------------------------------------------------------- /src/LowCryptoHash.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowCryptoHash.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWCRYPTOHASH_H__ 6 | #define __LOWCRYPTOHASH_H__ 7 | 8 | #include "low_main.h" 9 | 10 | #include "mbedtls/md.h" 11 | 12 | using namespace std; 13 | 14 | class LowCryptoHash 15 | { 16 | public: 17 | LowCryptoHash(low_t *low, 18 | const mbedtls_md_info_t *info, 19 | unsigned char *key, 20 | int key_len); 21 | ~LowCryptoHash(); 22 | 23 | void SetIndex(int index) { mIndex = index; } 24 | 25 | void Update(unsigned char *data, int len); 26 | void Digest(unsigned char *data, int len); 27 | 28 | int OutputSize() { return mOutputSize; } 29 | 30 | private: 31 | low_t *mLow; 32 | int mIndex; 33 | 34 | mbedtls_md_context_t mContext; 35 | 36 | bool mHMAC; 37 | int mOutputSize; 38 | }; 39 | 40 | #endif /* __LOWCRYPTOHASH_H__ */ -------------------------------------------------------------------------------- /src/LowDNSResolver.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowDNSResolver.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWDNSRESOLVER_H__ 6 | #define __LOWDNSRESOLVER_H__ 7 | 8 | #include "LowLoopCallback.h" 9 | 10 | #include "../deps/c-ares/ares.h" 11 | 12 | struct low_t; 13 | 14 | class LowDNSResolver 15 | { 16 | friend class LowDNSResolver_Query; 17 | friend class LowDNSResolver_GetHostByAddr; 18 | 19 | public: 20 | LowDNSResolver(low_t *low); 21 | virtual ~LowDNSResolver(); 22 | 23 | bool Init(); 24 | void Cancel(); 25 | 26 | struct ares_addr_port_node *GetServers(int &err); 27 | int SetServers(struct ares_addr_port_node *list); 28 | 29 | ares_channel &Channel() { return mChannel; } 30 | bool IsActive() { return mActiveQueries != 0; } 31 | 32 | static int AresErr(int err); 33 | 34 | private: 35 | low_t *mLow; 36 | 37 | ares_channel mChannel; 38 | int mIndex, mActiveQueries; 39 | }; 40 | 41 | class LowDNSResolver_Query : public LowLoopCallback 42 | { 43 | public: 44 | LowDNSResolver_Query(LowDNSResolver *resolver); 45 | virtual ~LowDNSResolver_Query(); 46 | 47 | void Resolve(const char *hostname, const char *type, bool ttl, int refIndex, int callIndex); 48 | 49 | protected: 50 | virtual bool OnLoop(); 51 | 52 | private: 53 | void Callback(int status, int timeouts, unsigned char *abuf, int alen); 54 | static void CallbackStatic(void *arg, int status, int timeouts, unsigned char *abuf, int alen) 55 | { 56 | ((LowDNSResolver_Query *)arg)->Callback(status, timeouts, abuf, alen); 57 | } 58 | 59 | private: 60 | LowDNSResolver *mResolver; 61 | low_t *mLow; 62 | ares_channel mChannel; 63 | 64 | bool mTTL; 65 | int mDNSType; 66 | 67 | int mRefID, mCallID, mError; 68 | const char *mSyscall; 69 | 70 | unsigned char *mData; 71 | int mLen; 72 | 73 | void *mDataFree, *mAresFree; 74 | struct hostent *mHostFree; 75 | }; 76 | 77 | class LowDNSResolver_GetHostByAddr : public LowLoopCallback 78 | { 79 | public: 80 | LowDNSResolver_GetHostByAddr(LowDNSResolver *resolver); 81 | virtual ~LowDNSResolver_GetHostByAddr(); 82 | 83 | int Resolve(const char *hostname, int refIndex, int callIndex); 84 | 85 | protected: 86 | virtual bool OnLoop(); 87 | 88 | private: 89 | void Callback(int status, int timeouts, struct hostent *hostent); 90 | static void CallbackStatic(void *arg, int status, int timeouts, struct hostent *hostent) 91 | { 92 | ((LowDNSResolver_GetHostByAddr *)arg)->Callback(status, timeouts, hostent); 93 | } 94 | 95 | private: 96 | LowDNSResolver *mResolver; 97 | low_t *mLow; 98 | ares_channel mChannel; 99 | 100 | int mRefID, mCallID, mError; 101 | const char *mSyscall; 102 | 103 | char **mResult; 104 | }; 105 | 106 | #endif /* __LOWDNSRESOLVER_H__ */ 107 | -------------------------------------------------------------------------------- /src/LowDNSWorker.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowDNSWorker.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWDNSWORKER_H__ 6 | #define __LOWDNSWORKER_H__ 7 | 8 | #include "LowLoopCallback.h" 9 | #include "LowDataCallback.h" 10 | 11 | #include 12 | 13 | struct low_t; 14 | 15 | class LowDNSWorker : public LowLoopCallback, public LowDataCallback 16 | { 17 | public: 18 | LowDNSWorker(low_t *low); 19 | virtual ~LowDNSWorker(); 20 | 21 | bool Lookup(const char *host, int family, int hints, int callIndex); 22 | bool LookupService(const char *ip, int port, int callIndex); 23 | 24 | protected: 25 | virtual bool OnLoop(); 26 | virtual bool OnData(); 27 | 28 | private: 29 | low_t *mLow; 30 | 31 | char mIP[INET_ADDRSTRLEN]; 32 | char mHost[64], mService[64]; 33 | int mFamily, mHints, mPort, mCallID; 34 | bool mLookupService; 35 | int mError; 36 | 37 | struct addrinfo *mResult; 38 | }; 39 | 40 | #endif /* __LOWDNSWORKER_H__ */ -------------------------------------------------------------------------------- /src/LowDataCallback.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowDataCallback.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWDATACALLBACK_H__ 6 | #define __LOWDATACALLBACK_H__ 7 | 8 | struct low_t; 9 | 10 | class LowDataCallback 11 | { 12 | friend void *low_data_thread_main(void *arg); 13 | friend bool low_reset(low_t *low); 14 | friend void low_data_set_callback(low_t *low, 15 | LowDataCallback *callback, int priority); 16 | friend void low_data_clear_callback(low_t *low, 17 | LowDataCallback *callback); 18 | 19 | public: 20 | LowDataCallback(low_t *low) 21 | : mLow(low), mNext(nullptr), mInDataThread(false), mDataClearOnReset(true) 22 | { 23 | } 24 | virtual ~LowDataCallback() { low_data_clear_callback(mLow, this); } 25 | 26 | protected: 27 | virtual bool OnData() = 0; 28 | 29 | private: 30 | low_t *mLow; 31 | LowDataCallback *mNext; 32 | 33 | bool mInDataThread; 34 | 35 | protected: 36 | bool mDataClearOnReset; 37 | }; 38 | 39 | #endif /* __LOWDATACALLBACK_H__ */ -------------------------------------------------------------------------------- /src/LowDatagram.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowDatagram.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWDATAGRAM_H__ 6 | #define __LOWDATAGRAM_H__ 7 | 8 | #include "LowFD.h" 9 | #include "LowLoopCallback.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | class LowDatagram 16 | : public LowFD 17 | , public LowLoopCallback 18 | { 19 | public: 20 | LowDatagram(low_t *low); 21 | virtual ~LowDatagram(); 22 | 23 | bool Bind(struct sockaddr *addr, int addrLen, int callIndex, int &err, 24 | const char *&syscall, bool reuseAddr); 25 | void Send(int bufferIndex, const char *address, int port, int callIndex); 26 | 27 | void Read(int pos, unsigned char *data, int len, int callIndex) {} 28 | void Write(int pos, unsigned char *data, int len, int callIndex) {} 29 | bool Close(int callIndex); 30 | 31 | protected: 32 | virtual bool OnEvents(short events); 33 | virtual bool OnLoop(); 34 | 35 | private: 36 | low_t *mLow; 37 | 38 | int mMessageCallID, mFamily; 39 | 40 | unsigned char *mSendData; 41 | struct sockaddr_in6 mSendAddr; 42 | int mSendLen, mSendErr; 43 | int mSendBufferID, mSendCallID; 44 | 45 | unsigned char mRecvData[1500]; 46 | struct sockaddr_in6 mRecvAddr; 47 | socklen_t mRecvAddrLen; 48 | int mRecvLen, mRecvErr; 49 | bool mHasRecv; 50 | }; 51 | 52 | #endif /* __LOWDATAGRAM_H__ */ -------------------------------------------------------------------------------- /src/LowFD.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowFD.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "LowFD.h" 6 | #include "LowServerSocket.h" 7 | 8 | 9 | // ----------------------------------------------------------------------------- 10 | // LowFD::~LowFD 11 | // ----------------------------------------------------------------------------- 12 | 13 | LowFD::~LowFD() 14 | { 15 | if(mAdvertisedFD >= 0) 16 | mLow->fds.erase(mAdvertisedFD); 17 | low_web_clear_poll(mLow, this); 18 | 19 | if(mLow->reset_accepts && mAdvertisedFD >= 0 /* make sure we are in code thread */) 20 | { 21 | mLow->reset_accepts = false; 22 | for(auto iter = mLow->fds.begin(); iter != mLow->fds.end(); iter++) 23 | { 24 | if(iter->second->FDType() == LOWFD_TYPE_SERVER && iter->second->FD() >= 0 25 | && !((LowServerSocket *)iter->second)->WaitForNotTooManyConnections()) 26 | low_web_set_poll_events(mLow, iter->second, POLLIN); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/LowFD.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowFD.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWFD_H__ 6 | #define __LOWFD_H__ 7 | 8 | #include "low_main.h" 9 | #include "low_web_thread.h" 10 | 11 | enum LowFDType 12 | { 13 | LOWFD_TYPE_FILE, 14 | LOWFD_TYPE_SERVER, 15 | LOWFD_TYPE_SOCKET, 16 | LOWFD_TYPE_DATAGRAM, 17 | LOWFD_TYPE_NATIVE_API, 18 | LOWFD_TYPE_CUSTOM 19 | }; 20 | 21 | class LowFD 22 | { 23 | friend void *low_web_thread_main(void *arg); 24 | friend bool low_reset(low_t *low); 25 | friend void low_web_set_poll_events(low_t *low, LowFD *fd, 26 | short events); 27 | friend void low_web_clear_poll(low_t *low, LowFD *fd); 28 | friend void low_web_mark_delete(low_t *low, LowFD *fd); 29 | 30 | public: 31 | LowFD(low_t *low, LowFDType type, int fd = -1) 32 | : mLow(low), mFD(fd), mAdvertisedFD(-1), mFDType(type), 33 | mMarkDelete(false), mPollIndex(-1), mPollEvents(0), 34 | mNextChanged(nullptr), mFDClearOnReset(true) 35 | { 36 | } 37 | virtual ~LowFD(); 38 | 39 | virtual void Read(int pos, unsigned char *data, int len, int callIndex) = 0; 40 | virtual void Write(int pos, unsigned char *data, int len, 41 | int callIndex) = 0; 42 | virtual bool Close(int callIndex) = 0; 43 | 44 | LowFDType FDType() { return mFDType; } 45 | int &FD() { return mFD; } 46 | int PollEvents() { return mPollEvents; } 47 | 48 | void SetFD(int fd) { mFD = fd; } 49 | void AdvertiseFD() 50 | { 51 | if(mAdvertisedFD >= 0) 52 | mLow->fds.erase(mAdvertisedFD); 53 | mAdvertisedFD = mFD; 54 | if(mAdvertisedFD >= 0) 55 | mLow->fds[mAdvertisedFD] = this; 56 | } 57 | 58 | protected: 59 | virtual bool OnEvents(short events) { return true; } 60 | 61 | private: 62 | low_t *mLow; 63 | 64 | int mFD, mAdvertisedFD; 65 | LowFDType mFDType; 66 | bool mMarkDelete; 67 | 68 | int mPollIndex; 69 | short mPollEvents; 70 | 71 | LowFD *mNextChanged; 72 | 73 | protected: 74 | bool mFDClearOnReset; 75 | }; 76 | 77 | #endif /* __LOWFD_H__ */ 78 | -------------------------------------------------------------------------------- /src/LowFSMisc.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowFSMisc.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWFSMisc_H__ 6 | #define __LOWFSMisc_H__ 7 | 8 | #include "LowDataCallback.h" 9 | #include "LowLoopCallback.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | struct low_t; 17 | 18 | enum 19 | { 20 | 21 | LOWFSMISC_PHASE_RENAME, 22 | LOWFSMISC_PHASE_UNLINK, 23 | LOWFSMISC_PHASE_STAT, 24 | LOWFSMISC_PHASE_ACCESS, 25 | LOWFSMISC_PHASE_READDIR, 26 | LOWFSMISC_PHASE_MKDIR, 27 | LOWFSMISC_PHASE_RMDIR 28 | }; 29 | 30 | class LowFSMisc 31 | : public LowDataCallback 32 | , public LowLoopCallback 33 | { 34 | public: 35 | LowFSMisc(low_t *low); 36 | virtual ~LowFSMisc(); 37 | 38 | void Rename(const char *old_name, const char *new_name); 39 | void Unlink(const char *file_name); 40 | void Stat(const char *file_name); 41 | 42 | void Access(const char *file_name, int mode); 43 | void ReadDir(const char *file_name, bool withFileTypes); 44 | void MkDir(const char *file_name, bool recursive, int mode); 45 | void RmDir(const char *file_name); 46 | 47 | void Run(int callIndex = 0); 48 | 49 | protected: 50 | void ReadDir(); 51 | 52 | virtual bool OnData(); 53 | virtual bool OnLoop(); 54 | 55 | private: 56 | low_t *mLow; 57 | char *mOldName; 58 | char *mNewName; 59 | 60 | struct stat mStat; 61 | bool mWithFileTypes, mRecursive; 62 | int mMode; 63 | 64 | int mCallID; 65 | 66 | int mPhase, mError; 67 | char *mFileEntries; 68 | }; 69 | 70 | #endif /* __LOWFSMISC_H__ */ 71 | -------------------------------------------------------------------------------- /src/LowFile.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowFile.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWFILE_H__ 6 | #define __LOWFILE_H__ 7 | 8 | #include "LowDataCallback.h" 9 | #include "LowFD.h" 10 | #include "LowLoopCallback.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | struct low_t; 17 | 18 | enum 19 | { 20 | LOWFILE_PHASE_OPENING, 21 | LOWFILE_PHASE_READY, 22 | LOWFILE_PHASE_READING, 23 | LOWFILE_PHASE_WRITING, 24 | LOWFILE_PHASE_FSTAT, 25 | LOWFILE_PHASE_CLOSING 26 | }; 27 | 28 | class LowFile 29 | : public LowFD 30 | , public LowDataCallback 31 | , public LowLoopCallback 32 | { 33 | public: 34 | LowFile(low_t *low, const char *path, int flags, int callIndex); 35 | virtual ~LowFile(); 36 | 37 | void Read(int pos, unsigned char *data, int len, int callIndex); 38 | void Write(int pos, unsigned char *data, int len, int callIndex); 39 | void FStat(int callIndex); 40 | bool Close(int callIndex); 41 | 42 | bool FinishPhase(); 43 | 44 | protected: 45 | virtual bool OnData(); 46 | virtual bool OnLoop(); 47 | 48 | private: 49 | low_t *mLow; 50 | char *mPath; 51 | int mFlags; 52 | 53 | unsigned char *mData; 54 | int mPos, mLen; 55 | struct stat mStat; 56 | int mCallID; 57 | 58 | int mPhase, mError; 59 | const char *mSyscall; 60 | bool mDataDone, mClose; 61 | }; 62 | 63 | #endif /* __LOWFILE_H__ */ -------------------------------------------------------------------------------- /src/LowHTTPDirect.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowHTTPDirect.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWHTTPDIRECT_H__ 6 | #define __LOWHTTPDIRECT_H__ 7 | 8 | #include "LowLoopCallback.h" 9 | #include "LowSocketDirect.h" 10 | 11 | #include 12 | 13 | #include "low_config.h" 14 | #if LOW_ESP32_LWIP_SPECIALITIES 15 | #include 16 | #else 17 | #include 18 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 19 | 20 | using namespace std; 21 | 22 | enum LowHTTPDirect_Phase 23 | { 24 | LOWHTTPDIRECT_PHASE_FIRSTLINE1, 25 | LOWHTTPDIRECT_PHASE_FIRSTLINE2, 26 | LOWHTTPDIRECT_PHASE_FIRSTLINE3, 27 | LOWHTTPDIRECT_PHASE_HEADER_KEY, 28 | LOWHTTPDIRECT_PHASE_HEADER_VALUE, 29 | LOWHTTPDIRECT_PHASE_CHUNK_HEADER, 30 | LOWHTTPDIRECT_PHASE_BODY, 31 | LOWHTTPDIRECT_PHASE_SENDING_RESPONSE 32 | }; 33 | 34 | enum LowHTTPDirect_ParamDataType 35 | { 36 | LOWHTTPDIRECT_PARAMDATA_HEADER = 0, 37 | LOWHTTPDIRECT_PARAMDATA_TRAILER 38 | }; 39 | 40 | struct LowHTTPDirect_ParamData 41 | { 42 | LowHTTPDirect_ParamData *next; 43 | LowHTTPDirect_ParamDataType type; 44 | int size; 45 | char data[10240]; 46 | }; 47 | 48 | class LowSocket; 49 | class LowHTTPDirect 50 | : public LowSocketDirect 51 | , public LowLoopCallback 52 | { 53 | public: 54 | LowHTTPDirect(low_t *low, bool isServer); 55 | virtual ~LowHTTPDirect(); 56 | 57 | virtual void SetSocket(LowSocket *socket); 58 | void Detach(bool pushRemainingRead = false); 59 | 60 | void SetRequestCallID(int callID); 61 | void Read(unsigned char *data, int len, int callIndex); 62 | 63 | void WriteHeaders(const char *txt, int index, int len, bool isChunked); 64 | void Write(unsigned char *data, int len, int bufferIndex, int callIndex); 65 | 66 | protected: 67 | void Init(); 68 | 69 | virtual bool OnLoop(); 70 | 71 | virtual bool OnSocketData(unsigned char *data, int len); 72 | bool SocketData(unsigned char *data, int len, bool inLoop); 73 | 74 | void DoWrite(); 75 | virtual bool OnSocketWrite(); 76 | 77 | private: 78 | low_t *mLow; 79 | bool mIsServer, mDetached; 80 | 81 | LowSocket *mSocket; 82 | int mRequestCallID, mReadCallID, mWriteCallID; 83 | 84 | pthread_mutex_t mMutex; 85 | LowHTTPDirect_Phase mPhase; 86 | bool mIsRequest; 87 | int mBytesRead; 88 | int mBytesWritten; 89 | 90 | bool mShutdown, mClosed, mEraseNextN, mAtTrailer; 91 | 92 | bool mNoBodyDefault, mChunkedEncoding; 93 | 94 | int mContentLen, mDataLen; 95 | 96 | LowHTTPDirect_ParamData *mParamFirst, *mParamLast; 97 | unsigned char *mParamCurrent; 98 | int mParamStart, mChunkedParamStart, mParamPos, mParamPosNonSpace; 99 | 100 | char mChunkedHeaderLine[10]; 101 | bool mIsContentLengthHeader, mIsTransferEncodingHeader; 102 | 103 | unsigned char *mRemainingRead; 104 | int mRemainingReadLen; 105 | 106 | unsigned char *mReadData; 107 | int mReadPos, mReadLen; 108 | 109 | char mWriteChunkedHeaderLine[10]; 110 | struct iovec mWriteBuffers[3]; 111 | int mWriteBufferStashID[3]; 112 | int mWritePos, mWriteLen; 113 | uint8_t mWriteBufferCount, mWriteBufferStashInvalidCount; 114 | bool mWriting, mWriteDone, mWriteChunkedEncoding; 115 | 116 | bool mReadError, mWriteError, mHTTPError; 117 | }; 118 | 119 | #endif /* __LOWHTTPDIRECT_H__ */ -------------------------------------------------------------------------------- /src/LowLoopCallback.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowLoopCallback.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWLOOPCALLBACK_H__ 6 | #define __LOWLOOPCALLBACK_H__ 7 | 8 | #include "low_loop.h" 9 | 10 | class LowLoopCallback 11 | { 12 | friend duk_ret_t low_loop_run_safe(duk_context *ctx, void *udata); 13 | friend bool low_reset(low_t *low); 14 | friend void low_loop_set_callback(low_t *low, 15 | LowLoopCallback *callback); 16 | friend void low_loop_clear_callback(low_t *low, 17 | LowLoopCallback *callback); 18 | friend duk_ret_t low_fs_open_sync(duk_context *ctx); 19 | friend duk_ret_t low_fs_close_sync(duk_context *ctx); 20 | friend duk_ret_t low_fs_waitdone(duk_context *ctx); 21 | 22 | public: 23 | LowLoopCallback(low_t *low) 24 | : mLow(low), mNext(nullptr), mLoopClearOnReset(true) 25 | { 26 | } 27 | virtual ~LowLoopCallback() { low_loop_clear_callback(mLow, this); } 28 | 29 | protected: 30 | virtual bool OnLoop() = 0; 31 | 32 | private: 33 | low_t *mLow; 34 | LowLoopCallback *mNext; 35 | 36 | protected: 37 | bool mLoopClearOnReset; 38 | }; 39 | 40 | #endif /* __LOWLOOPCALLBACK_H__ */ 41 | -------------------------------------------------------------------------------- /src/LowServerSocket.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowServerSocket.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWSERVERSOCKET_H__ 6 | #define __LOWSERVERSOCKET_H__ 7 | 8 | #include "LowFD.h" 9 | 10 | struct low_t; 11 | 12 | class LowServerSocket : public LowFD 13 | { 14 | public: 15 | LowServerSocket(low_t *low, bool isHTTP, LowTLSContext *secureContext); 16 | virtual ~LowServerSocket(); 17 | 18 | bool Listen(struct sockaddr *addr, int addrLen, int callIndex, int &err, 19 | const char *&syscall); 20 | 21 | void Read(int pos, unsigned char *data, int len, int callIndex) {} 22 | void Write(int pos, unsigned char *data, int len, int callIndex) {} 23 | bool Close(int callIndex); 24 | 25 | void Connections(int count, int max); 26 | bool WaitForNotTooManyConnections() { return mWaitForNotTooManyConnections; } 27 | 28 | protected: 29 | virtual bool OnEvents(short events); 30 | 31 | private: 32 | low_t *mLow; 33 | bool mIsHTTP; 34 | 35 | int mFamily, mAcceptCallID; 36 | 37 | LowTLSContext *mSecureContext; 38 | 39 | bool mWaitForNotTooManyConnections, mTrackTooManyConnections; 40 | }; 41 | 42 | #endif /* __LOWSERVERSOCKET_H__ */ -------------------------------------------------------------------------------- /src/LowSignalHandler.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowSignalHandler.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "LowSignalHandler.h" 6 | 7 | #include "low_main.h" 8 | #include "low_system.h" 9 | #include "low_config.h" 10 | 11 | #include 12 | 13 | 14 | // ----------------------------------------------------------------------------- 15 | // LowSignalHandler::LowSignalHandler 16 | // ----------------------------------------------------------------------------- 17 | 18 | LowSignalHandler::LowSignalHandler(low_t *low, int signal) 19 | : LowLoopCallback(low), mLow(low), mSignal(signal) 20 | { 21 | const char *name; 22 | switch(signal) 23 | { 24 | case SIGUSR1: 25 | name = "SIGUSR1"; 26 | break; 27 | case SIGUSR2: 28 | name = "SIGUSR2"; 29 | break; 30 | case SIGPIPE: 31 | name = "SIGPIPE"; 32 | break; 33 | case SIGWINCH: 34 | name = "SIGWINCH"; 35 | break; 36 | case SIGTERM: 37 | name = "SIGTERM"; 38 | break; 39 | case SIGINT: 40 | name = "SIGINT"; 41 | break; 42 | case SIGHUP: 43 | name = "SIGHUP"; 44 | break; 45 | default: 46 | name = NULL; 47 | } 48 | mName = name; 49 | 50 | low_loop_set_callback(low, this); 51 | } 52 | 53 | // ----------------------------------------------------------------------------- 54 | // LowSignalHandler::LowSignalHandler 55 | // ----------------------------------------------------------------------------- 56 | 57 | LowSignalHandler::LowSignalHandler(low_t *low, const char *name) 58 | : LowLoopCallback(low), mLow(low), mName(name), mSignal(0) 59 | { 60 | low_loop_set_callback(low, this); 61 | } 62 | 63 | // ----------------------------------------------------------------------------- 64 | // LowSignalHandler::OnLoop 65 | // ----------------------------------------------------------------------------- 66 | 67 | #include "low_process.h" 68 | 69 | bool LowSignalHandler::OnLoop() 70 | { 71 | if(!mName) 72 | return false; 73 | 74 | low_push_stash(mLow->duk_ctx, mLow->signal_call_id, false); 75 | duk_push_string(mLow->duk_ctx, "emit"); 76 | duk_push_string(mLow->duk_ctx, mName); 77 | duk_call_prop(mLow->duk_ctx, -3, 1); 78 | if(!duk_require_boolean(mLow->duk_ctx, -1) && 79 | (mSignal == SIGTERM || mSignal == SIGINT || mSignal == SIGHUP)) 80 | { 81 | #if LOW_HAS_SYS_SIGNALS 82 | // Go back to default handler 83 | struct sigaction action; 84 | memset(&action, 0, sizeof(action)); 85 | sigemptyset(&action.sa_mask); 86 | action.sa_flags = SA_RESTART; 87 | action.sa_handler = SIG_DFL; 88 | sigaction(mSignal, &action, NULL); 89 | 90 | // Exit 91 | low_system_destroy(); 92 | raise(mSignal); 93 | #else 94 | while(true) 95 | { 96 | } 97 | #endif /* LOW_HAS_SYS_SIGNALS */ 98 | } 99 | 100 | return false; 101 | } 102 | -------------------------------------------------------------------------------- /src/LowSignalHandler.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowSignalHandler.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWSIGNALHANDLER_H__ 6 | #define __LOWSIGNALHANDLER_H__ 7 | 8 | #include "LowLoopCallback.h" 9 | 10 | class LowSignalHandler : public LowLoopCallback 11 | { 12 | public: 13 | LowSignalHandler(low_t *low, int signal); 14 | LowSignalHandler(low_t *low, const char *name); 15 | 16 | protected: 17 | virtual bool OnLoop(); 18 | 19 | private: 20 | low_t *mLow; 21 | const char *mName; 22 | int mSignal; 23 | }; 24 | 25 | #endif /* __LOWSIGNALHANDLER_H__ */ -------------------------------------------------------------------------------- /src/LowSocket.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowSocket.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWSOCKET_H__ 6 | #define __LOWSOCKET_H__ 7 | 8 | #include "LowFD.h" 9 | #include "LowLoopCallback.h" 10 | 11 | #include 12 | #include 13 | 14 | #include "mbedtls/ssl.h" 15 | 16 | enum LowSocketType 17 | { 18 | LOWSOCKET_TYPE_STDINOUT, 19 | LOWSOCKET_TYPE_ACCEPTED, 20 | LOWSOCKET_TYPE_CONNECTED 21 | }; 22 | 23 | const int LOWSOCKET_TRIGGER_READ = 1; 24 | const int LOWSOCKET_TRIGGER_WRITE = 2; 25 | 26 | struct low_t; 27 | 28 | class LowSocketDirect; 29 | class LowSocket 30 | : public LowFD 31 | , public LowLoopCallback 32 | { 33 | public: 34 | LowSocket(low_t *low, int fd); // LOWSOCKET_TYPE_STDINOUT 35 | LowSocket(low_t *low, 36 | int fd, 37 | struct sockaddr *remoteAddr, 38 | int acceptCallID, 39 | LowSocketDirect *direct, 40 | int directType, 41 | LowTLSContext *tlsContext, 42 | bool clearOnReset = true); // LOWSOCKET_TYPE_ACCEPTED 43 | LowSocket(low_t *low, 44 | LowSocketDirect *direct, 45 | int directType, 46 | LowTLSContext *tlsContext, 47 | char *host, 48 | bool clearOnReset = true); // LOWSOCKET_TYPE_CONNECTED 49 | virtual ~LowSocket(); 50 | 51 | bool Connect(struct sockaddr *remoteAddr, 52 | int remoteAddrLen, 53 | int callIndex, 54 | int &err, 55 | const char *&syscall); 56 | 57 | void Read(int pos, unsigned char *data, int len, int callIndex); 58 | void Write(int pos, unsigned char *data, int len, int callIndex); 59 | void Shutdown(int callIndex); // JS version 60 | int Shutdown(); 61 | bool Close(int callIndex = -1); 62 | 63 | void KeepAlive(bool enable, int secs); 64 | void NoDelay(bool enable); 65 | 66 | void SetDirect(LowSocketDirect *direct, 67 | int type, 68 | bool fromWebThread = false); 69 | LowSocketDirect *GetDirect(int &type); 70 | void TriggerDirect(int trigger); 71 | 72 | // for direct 73 | int write(const unsigned char *data, int len); 74 | int writev(const struct iovec *iov, int iovcnt); 75 | 76 | void SetError(bool write, int error, bool ssl); 77 | void PushError(int call); 78 | 79 | bool IsConnected() { return mConnected; } 80 | 81 | protected: 82 | virtual bool OnEvents(short events); 83 | virtual bool OnLoop(); 84 | 85 | bool InitSocket(struct sockaddr *remoteAddr); 86 | bool CallAcceptConnect(int callIndex, bool onStash); 87 | 88 | int DoRead(unsigned char *data, int len); 89 | int DoWrite(); 90 | 91 | private: 92 | low_t *mLow; 93 | LowSocketType mType; 94 | short mLastEvents; 95 | 96 | int mNodeFamily; 97 | char mRemoteHost[INET6_ADDRSTRLEN]; 98 | int mRemotePort; 99 | 100 | int mAcceptConnectCallID, mAcceptConnectErrno, mCloseCallID; 101 | bool mAcceptConnectError, mAcceptConnectErrnoSSL, mConnected, mClosed, 102 | mDestroyed; 103 | const char *mAcceptConnectSyscall; 104 | 105 | unsigned char *mReadData, *mDirectReadData, *mWriteData; 106 | int mReadLen, mReadCallID, mReadPos, mReadErrno; 107 | int mWriteLen, mWriteCallID, mWritePos, mWriteErrno; 108 | bool mReadErrnoSSL, mWriteErrnoSSL; 109 | 110 | LowSocketDirect *mDirect; 111 | int mDirectType; 112 | bool mDirectReadEnabled, mDirectWriteEnabled; 113 | 114 | LowTLSContext *mTLSContext; 115 | mbedtls_ssl_context *mSSL; 116 | char *mHost; 117 | bool mSSLWantRead, mSSLWantWrite; 118 | 119 | bool mIsWebThreadOnly; 120 | }; 121 | 122 | #endif /* __LOWSOCKET_H__ */ -------------------------------------------------------------------------------- /src/LowSocketDirect.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowSocketDirect.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOWSOCKETDIRECT_H__ 6 | #define __LOWSOCKETDIRECT_H__ 7 | 8 | class LowSocket; 9 | class LowSocketDirect 10 | { 11 | friend class LowSocket; 12 | 13 | protected: 14 | virtual ~LowSocketDirect() {} 15 | 16 | virtual void SetSocket(LowSocket *socket) = 0; 17 | 18 | virtual void OnSocketConnected() {} 19 | virtual bool OnSocketData(unsigned char *data, int len) = 0; 20 | virtual bool OnSocketWrite() = 0; 21 | }; 22 | 23 | #endif /* __LOWSOCKETDIRECT_H__ */ -------------------------------------------------------------------------------- /src/LowTLSContext.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // LowTLSContext.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "LowTLSContext.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "mbedtls/debug.h" 11 | 12 | void add_stats(int index, bool add); 13 | 14 | 15 | // ----------------------------------------------------------------------------- 16 | // LowTLSContext::LowTLSContext 17 | // ----------------------------------------------------------------------------- 18 | 19 | static void my_debug(void *ctx, int level, const char *file, int line, 20 | const char *str) 21 | { 22 | const char *p, *basename; 23 | (void)ctx; 24 | 25 | /* Extract basename from file */ 26 | for(p = basename = file; *p != '\0'; p++) 27 | { 28 | if(*p == '/' || *p == '\\') 29 | { 30 | basename = p + 1; 31 | } 32 | } 33 | 34 | printf("%s:%04d: |%d| %s", basename, line, level, str); 35 | } 36 | 37 | LowTLSContext::LowTLSContext(low_t *low, const char *cert, int certLen, 38 | const char *key, int keyLen, const char *ca, 39 | int caLen, bool isServer) 40 | : mLow(low), mRef(1), mIndex(-1), mIsOK(false), mHasCert(false), mHasCA(false) 41 | { 42 | int ret; 43 | 44 | #if LOW_ESP32_LWIP_SPECIALITIES 45 | add_stats(4, true); 46 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 47 | 48 | if(!cert || !key) 49 | cert = key = NULL; 50 | 51 | mbedtls_ssl_config_init(&conf); 52 | mbedtls_entropy_init(&entropy); 53 | mbedtls_ctr_drbg_init(&ctr_drbg); 54 | 55 | ret = mbedtls_ssl_config_defaults( 56 | &conf, isServer ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, 57 | MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); 58 | if(ret != 0) 59 | return; 60 | /* 61 | mbedtls_ssl_conf_dbg(&conf, my_debug, NULL); 62 | mbedtls_debug_set_threshold(4); 63 | */ 64 | const char *pers = "low.js"; 65 | ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 66 | (const unsigned char *)pers, strlen(pers)); 67 | if(ret != 0) 68 | return; 69 | 70 | mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); 71 | 72 | if(cert) 73 | { 74 | mbedtls_x509_crt_init(&srvcert); 75 | 76 | mHasCert = true; 77 | mbedtls_pk_init(&pkey); 78 | 79 | ret = mbedtls_x509_crt_parse(&srvcert, (unsigned char *)cert, certLen); 80 | if(ret != 0) 81 | return; 82 | 83 | ret = 84 | mbedtls_pk_parse_key(&pkey, (unsigned char *)key, keyLen, NULL, 0); 85 | if(ret != 0) 86 | return; 87 | } 88 | if(ca) 89 | { 90 | mbedtls_x509_crt_init(&cacert); 91 | 92 | mHasCA = true; 93 | 94 | ret = mbedtls_x509_crt_parse(&cacert, (unsigned char *)ca, caLen); 95 | if(ret != 0) 96 | return; 97 | 98 | mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); 99 | } 100 | else 101 | { 102 | // We have nothing to verify... 103 | mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE); 104 | } 105 | 106 | if(cert) 107 | { 108 | ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey); 109 | if(ret != 0) 110 | return; 111 | } 112 | 113 | mIsOK = true; 114 | } 115 | 116 | 117 | // ----------------------------------------------------------------------------- 118 | // LowTLSContext::~LowTLSContext 119 | // ----------------------------------------------------------------------------- 120 | 121 | LowTLSContext::~LowTLSContext() 122 | { 123 | #if LOW_ESP32_LWIP_SPECIALITIES 124 | add_stats(4, false); 125 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 126 | 127 | if(mIndex >= 0) 128 | mLow->tlsContexts[mIndex] = NULL; 129 | 130 | if(mHasCA) 131 | mbedtls_x509_crt_free(&cacert); 132 | if(mHasCert) 133 | { 134 | mbedtls_x509_crt_free(&srvcert); 135 | mbedtls_pk_free(&pkey); 136 | } 137 | mbedtls_ssl_config_free(&conf); 138 | mbedtls_ctr_drbg_free(&ctr_drbg); 139 | mbedtls_entropy_free(&entropy); 140 | } 141 | 142 | 143 | // ----------------------------------------------------------------------------- 144 | // LowTLSContext::AddRef 145 | // ----------------------------------------------------------------------------- 146 | 147 | void LowTLSContext::AddRef() 148 | { 149 | pthread_mutex_lock(&mLow->ref_mutex); 150 | mRef++; 151 | pthread_mutex_unlock(&mLow->ref_mutex); 152 | } 153 | 154 | 155 | // ----------------------------------------------------------------------------- 156 | // LowTLSContext::DecRef 157 | // ----------------------------------------------------------------------------- 158 | 159 | void LowTLSContext::DecRef() 160 | { 161 | pthread_mutex_lock(&mLow->ref_mutex); 162 | if(!--mRef) 163 | { 164 | pthread_mutex_unlock(&mLow->ref_mutex); 165 | delete this; 166 | return; 167 | } 168 | pthread_mutex_unlock(&mLow->ref_mutex); 169 | } -------------------------------------------------------------------------------- /src/LowTLSContext.h: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // LowTLSContext.h 4 | // ----------------------------------------------------------------------------- 5 | 6 | #ifndef __LOWTLSCONTEXT_H__ 7 | #define __LOWTLSCONTEXT_H__ 8 | 9 | #include "low_main.h" 10 | 11 | #include "mbedtls/certs.h" 12 | #include "mbedtls/ctr_drbg.h" 13 | #include "mbedtls/entropy.h" 14 | #include "mbedtls/error.h" 15 | #include "mbedtls/net_sockets.h" 16 | #include "mbedtls/ssl.h" 17 | #include "mbedtls/x509.h" 18 | #include "mbedtls/x509_crt.h" 19 | 20 | using namespace std; 21 | 22 | class LowTLSContext 23 | { 24 | public: 25 | LowTLSContext(low_t *low, 26 | const char *cert = NULL, 27 | int certLen = 0, 28 | const char *key = NULL, 29 | int keyLen = 0, 30 | const char *ca = NULL, 31 | int caLen = 0, 32 | bool isServer = false); 33 | ~LowTLSContext(); 34 | 35 | bool IsOK() { return mIsOK; } 36 | 37 | void SetIndex(int index) { mIndex = index; } 38 | void AddRef(); 39 | void DecRef(); 40 | 41 | mbedtls_ssl_config &GetSSLConfig() { return conf; } 42 | 43 | private: 44 | low_t *mLow; 45 | int mRef; 46 | int mIndex; 47 | 48 | mbedtls_entropy_context entropy; 49 | mbedtls_ctr_drbg_context ctr_drbg; 50 | mbedtls_ssl_config conf; 51 | mbedtls_x509_crt srvcert, cacert; 52 | mbedtls_pk_context pkey; 53 | 54 | bool mIsOK, mHasCert, mHasCA; 55 | }; 56 | 57 | #endif /* __LOWTLSCONTEXT_H__ */ -------------------------------------------------------------------------------- /src/low_alloc.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_alloc.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "low_alloc.h" 6 | 7 | #include "low_main.h" 8 | #include "low_system.h" 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #if LOW_ESP32_LWIP_SPECIALITIES || defined(LOWJS_SERV) 18 | 19 | extern bool gAllocFailed; 20 | 21 | #endif /* LOW_ESP32_LWIP_SPECIALITIES || defined(LOWJS_SERV) */ 22 | #if LOW_ESP32_LWIP_SPECIALITIES 23 | 24 | extern "C" bool alloc_use_fund(); 25 | extern void *gRainyDayFund; 26 | 27 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 28 | 29 | 30 | // ----------------------------------------------------------------------------- 31 | // low_duk_alloc 32 | // ----------------------------------------------------------------------------- 33 | 34 | void *low_duk_alloc(void *udata, duk_size_t size) 35 | { 36 | low_t *low = (low_t *)udata; 37 | 38 | #if LOW_ESP32_LWIP_SPECIALITIES 39 | low->in_gc = true; 40 | void *ptr = low_alloc(size); 41 | low->in_gc = false; 42 | return ptr; 43 | #else 44 | if(size > 0xFFFFFFF0 - low->heap_size) 45 | return NULL; 46 | 47 | if(!low->in_gc && low->heap_size + size > low->max_heap_size) 48 | { 49 | low->in_gc = true; 50 | duk_gc(low->duk_ctx, 0); 51 | low->in_gc = false; 52 | 53 | #ifdef LOWJS_SERV 54 | if(low->heap_size + size + 4 > low->max_heap_size) 55 | { 56 | gAllocFailed = true; 57 | low->duk_flag_stop = 1; 58 | } 59 | #else 60 | if(low->heap_size + size + 4 > low->max_heap_size) 61 | { 62 | fprintf(stderr, "Reached memory limit of %d MB, aborting. If the device has more memory, configure the low.js memory limit with --max-old-space-size.\n", (int)(low->max_heap_size / (1024 * 1024))); 63 | _exit(1); 64 | } 65 | #endif /* LOWJS_SERV */ 66 | } 67 | 68 | unsigned int *ptr = (unsigned int *)low_alloc(size + 4); 69 | if(!ptr) 70 | return NULL; 71 | 72 | low->heap_size += size + 4; 73 | *ptr = (unsigned int)size; 74 | return (void *)(ptr + 1); 75 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 76 | } 77 | 78 | 79 | // ----------------------------------------------------------------------------- 80 | // low_duk_realloc 81 | // ----------------------------------------------------------------------------- 82 | 83 | void *low_duk_realloc(void *udata, void *data, duk_size_t size) 84 | { 85 | low_t *low = (low_t *)udata; 86 | 87 | #if LOW_ESP32_LWIP_SPECIALITIES 88 | low->in_gc = true; 89 | void *ptr = low_realloc(data, size); 90 | low->in_gc = false; 91 | return ptr; 92 | #else 93 | if(!data) 94 | return low_duk_alloc(udata, size); 95 | 96 | unsigned int *ptr = ((unsigned int *)data) - 1; 97 | size_t old_size = (size_t)*ptr; 98 | 99 | if(size > 0xFFFFFFF0 - (low->heap_size - old_size)) 100 | return NULL; 101 | 102 | if(!low->in_gc && low->heap_size - old_size + size > low->max_heap_size) 103 | { 104 | low->in_gc = true; 105 | duk_gc(low->duk_ctx, 0); 106 | low->in_gc = false; 107 | 108 | #ifdef LOWJS_SERV 109 | if(low->heap_size - old_size + size > low->max_heap_size) 110 | { 111 | gAllocFailed = true; 112 | low->duk_flag_stop = 1; 113 | } 114 | #else 115 | if(low->heap_size - old_size + size > low->max_heap_size) 116 | { 117 | fprintf(stderr, "Reached memory limit of %d MB, aborting.\n", (int)(low->max_heap_size / (1024 * 1024))); 118 | _exit(1); 119 | } 120 | #endif /* LOWJS_SERV */ 121 | } 122 | 123 | ptr = (unsigned int *)low_realloc(ptr, size + 4); 124 | if(!ptr) 125 | return NULL; 126 | 127 | low->heap_size += size - old_size; 128 | *ptr = (unsigned int)size; 129 | return (void *)(ptr + 1); 130 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 131 | } 132 | 133 | 134 | // ----------------------------------------------------------------------------- 135 | // low_duk_free 136 | // ----------------------------------------------------------------------------- 137 | 138 | void low_duk_free(void *udata, void *data) 139 | { 140 | #if LOW_ESP32_LWIP_SPECIALITIES 141 | low_free(data); 142 | #else 143 | if(!data) 144 | return; 145 | 146 | low_t *low = (low_t *)udata; 147 | unsigned int *ptr = ((unsigned int *)data) - 1; 148 | 149 | low->heap_size -= ((size_t)*ptr) + 4; 150 | low_free(ptr); 151 | #endif /* !LOW_ESP32_LWIP_SPECIALITIES */ 152 | } 153 | 154 | 155 | 156 | // ----------------------------------------------------------------------------- 157 | // low_alloc_throw 158 | // ----------------------------------------------------------------------------- 159 | 160 | void *low_alloc_throw(duk_context *ctx, size_t size) 161 | { 162 | void *data = low_alloc(size); 163 | if(!data) 164 | { 165 | low_push_error(ctx, ENOMEM, "malloc"); 166 | duk_throw(ctx); 167 | } 168 | return data; 169 | } 170 | 171 | 172 | // ----------------------------------------------------------------------------- 173 | // low_strdup 174 | // ----------------------------------------------------------------------------- 175 | 176 | char *low_strdup(const char *str) 177 | { 178 | int len = str ? strlen(str) : 0; 179 | char *dup = (char *)low_alloc(len + 1); 180 | 181 | if(dup) 182 | { 183 | if(len) 184 | memcpy(dup, str, len + 1); 185 | else 186 | *dup = '\0'; 187 | } 188 | 189 | return dup; 190 | } 191 | 192 | 193 | // ----------------------------------------------------------------------------- 194 | // low_strcat 195 | // ----------------------------------------------------------------------------- 196 | 197 | char *low_strcat(const char *str1, const char *str2) 198 | { 199 | int len1 = str1 ? strlen(str1) : 0; 200 | int len2 = str2 ? strlen(str2) : 0; 201 | char *dup = (char *)low_alloc(len1 + len2 + 1); 202 | 203 | if(dup) 204 | { 205 | if(len1) 206 | memcpy(dup, str1, len1); 207 | if(len2) 208 | memcpy(dup + len1, str2, len2); 209 | dup[len1 + len2] = '\0'; 210 | } 211 | 212 | return dup; 213 | } 214 | 215 | 216 | // ----------------------------------------------------------------------------- 217 | // operator new / operator delete 218 | // ----------------------------------------------------------------------------- 219 | 220 | void *operator new(size_t size, duk_context *ctx) { return low_alloc_throw(ctx, size); } 221 | void *operator new[](size_t size, duk_context *ctx) { return low_alloc_throw(ctx, size); } 222 | -------------------------------------------------------------------------------- /src/low_alloc.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_alloc.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_ALLOC_H__ 6 | #define __LOW_ALLOC_H__ 7 | 8 | #include "low_config.h" 9 | 10 | #include 11 | #include 12 | 13 | void *low_duk_alloc(void *udata, duk_size_t size); 14 | void *low_duk_realloc(void *udata, void *ptr, duk_size_t size); 15 | void low_duk_free(void *udata, void *ptr); 16 | 17 | #if LOW_USE_SYSTEM_ALLOC 18 | #include 19 | 20 | #define low_alloc malloc 21 | #define low_calloc calloc 22 | #define low_realloc realloc 23 | #define low_free free 24 | 25 | extern "C" 26 | { 27 | char *low_strdup(const char *str); 28 | char *low_strcat(const char *str1, const char *str2); 29 | 30 | void *low_alloc_throw(duk_context *ctx, size_t size); 31 | } 32 | #else 33 | #ifdef __cplusplus 34 | extern "C" 35 | { 36 | #endif /* __cplusplus */ 37 | void *low_alloc(size_t size); 38 | void *low_calloc(size_t num, size_t size); 39 | void *low_realloc(void *ptr, size_t size); 40 | void low_free(void *ptr); 41 | 42 | char *low_strdup(const char *str); 43 | char *low_strcat(const char *str1, const char *str2); 44 | 45 | void *low_alloc_throw(duk_context *ctx, size_t size); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif /* __cplusplus */ 50 | #endif /* LOW_USE_SYSTEM_ALLOC */ 51 | 52 | #ifdef __cplusplus 53 | #include 54 | 55 | void *operator new(size_t size, duk_context *ctx); 56 | void *operator new[](size_t size, duk_context *ctx); 57 | 58 | #endif /* __cplusplus */ 59 | 60 | #endif /* __LOW_ALLOC_H__ */ 61 | -------------------------------------------------------------------------------- /src/low_crypto.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_crypto.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "low_crypto.h" 6 | #include "LowCryptoHash.h" 7 | 8 | #include "low_alloc.h" 9 | 10 | 11 | // ----------------------------------------------------------------------------- 12 | // low_crypto_create_hash 13 | // ----------------------------------------------------------------------------- 14 | 15 | duk_ret_t low_crypto_create_hash(duk_context *ctx) 16 | { 17 | low_t *low = duk_get_low_context(ctx); 18 | 19 | const char *type = duk_require_string(ctx, 1); 20 | 21 | int len = strlen(type); 22 | char *typeUpper = (char *)low_alloc_throw(ctx, len + 1); 23 | for(int i = 0; i < len; i++) 24 | typeUpper[i] = toupper((unsigned)type[i]); 25 | typeUpper[len] = 0; 26 | const mbedtls_md_info_t *info = mbedtls_md_info_from_string(typeUpper); 27 | low_free(typeUpper); 28 | 29 | if(!info) 30 | duk_reference_error( 31 | low->duk_ctx, "unsupported hashing algorithm %s!", type); 32 | 33 | unsigned char *key = NULL; 34 | duk_size_t key_len; 35 | if(!duk_is_undefined(ctx, 2)) 36 | { 37 | key = (unsigned char *)duk_get_buffer_data(ctx, 2, &key_len); 38 | if(!key) 39 | { 40 | key = (unsigned char *)duk_require_string(ctx, 2); 41 | key_len = strlen((char *)key); 42 | } 43 | } 44 | 45 | LowCryptoHash *hash = new LowCryptoHash(low, info, key, key_len); 46 | 47 | int index; 48 | for(index = 0; index < low->cryptoHashes.size(); index++) 49 | if(!low->cryptoHashes[index]) 50 | { 51 | low->cryptoHashes[index] = hash; 52 | break; 53 | } 54 | if(index == low->cryptoHashes.size()) 55 | low->cryptoHashes.push_back(hash); 56 | hash->SetIndex(index); 57 | 58 | duk_push_int(low->duk_ctx, index); 59 | duk_push_c_function(ctx, low_crypto_hash_finalizer, 1); 60 | duk_set_finalizer(ctx, 0); 61 | 62 | return 1; 63 | } 64 | 65 | // ----------------------------------------------------------------------------- 66 | // low_crypto_hash_finalizer 67 | // ----------------------------------------------------------------------------- 68 | 69 | duk_ret_t low_crypto_hash_finalizer(duk_context *ctx) 70 | { 71 | low_t *low = duk_get_low_context(ctx); 72 | 73 | duk_get_prop_string(ctx, 0, "_native"); 74 | int index = duk_require_int(ctx, -1); 75 | 76 | if(index < 0 || index >= low->cryptoHashes.size()) 77 | duk_reference_error(ctx, "crypto hash not found"); 78 | 79 | delete low->cryptoHashes[index]; 80 | return 0; 81 | } 82 | 83 | 84 | // ----------------------------------------------------------------------------- 85 | // low_crypto_hash_update 86 | // ----------------------------------------------------------------------------- 87 | 88 | duk_ret_t low_crypto_hash_update(duk_context *ctx) 89 | { 90 | low_t *low = duk_get_low_context(ctx); 91 | 92 | int index = duk_require_int(ctx, 0); 93 | if(index < 0 || index >= low->cryptoHashes.size()) 94 | duk_reference_error(ctx, "crypto hash not found"); 95 | 96 | duk_size_t len; 97 | auto buffer = duk_require_buffer_data(ctx, 1, &len); 98 | 99 | low->cryptoHashes[index]->Update((unsigned char *)buffer, len); 100 | return 0; 101 | } 102 | 103 | 104 | // ----------------------------------------------------------------------------- 105 | // low_crypto_hash_digest 106 | // ----------------------------------------------------------------------------- 107 | 108 | duk_ret_t low_crypto_hash_digest(duk_context *ctx) 109 | { 110 | low_t *low = duk_get_low_context(ctx); 111 | 112 | int index = duk_require_int(ctx, 0); 113 | if(index < 0 || index >= low->cryptoHashes.size()) 114 | duk_reference_error(ctx, "crypto hash not found"); 115 | 116 | int len = low->cryptoHashes[index]->OutputSize(); 117 | auto buffer = low_push_buffer(ctx, len); 118 | 119 | low->cryptoHashes[index]->Digest((unsigned char *)buffer, len); 120 | return 1; 121 | } 122 | 123 | 124 | // ----------------------------------------------------------------------------- 125 | // low_crypto_random_bytes 126 | // ----------------------------------------------------------------------------- 127 | 128 | duk_ret_t low_crypto_random_bytes(duk_context *ctx) 129 | { 130 | int len = duk_require_int(ctx, 0); 131 | if(!duk_is_undefined(ctx, 1)) 132 | duk_reference_error(ctx, "crypto.randomBytes async version not implemented yet"); 133 | 134 | unsigned char *buffer = (unsigned char *)low_push_buffer(ctx, len); 135 | for(int i = 0; i < len; i++) 136 | buffer[i] = rand(); 137 | 138 | return 1; 139 | } 140 | -------------------------------------------------------------------------------- /src/low_crypto.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_crypto.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_CRYPTO_H__ 6 | #define __LOW_CRYPTO_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_crypto_create_hash(duk_context *ctx); 11 | duk_ret_t low_crypto_hash_finalizer(duk_context *ctx); 12 | 13 | duk_ret_t low_crypto_hash_update(duk_context *ctx); 14 | duk_ret_t low_crypto_hash_digest(duk_context *ctx); 15 | 16 | duk_ret_t low_crypto_random_bytes(duk_context *ctx); 17 | 18 | #endif /* __LOW_CRYPTO_H__ */ -------------------------------------------------------------------------------- /src/low_data_thread.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_data_thread.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_DATA_THREAD_H__ 6 | #define __LOW_DATA_THREAD_H__ 7 | 8 | enum 9 | { 10 | LOW_DATA_THREAD_PRIORITY_READ = 0, 11 | LOW_DATA_THREAD_PRIORITY_MODIFY 12 | }; 13 | 14 | struct low_t; 15 | class LowDataCallback; 16 | 17 | void *low_data_thread_main(void *arg); 18 | 19 | void low_data_set_callback(low_t *low, LowDataCallback *callback, 20 | int priority); 21 | void low_data_clear_callback(low_t *low, LowDataCallback *callback); 22 | 23 | #endif /* __LOW_DATA_THREAD_H__ */ -------------------------------------------------------------------------------- /src/low_dgram.cpp: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_dgram.cpp 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include "low_dgram.h" 7 | #include "low_system.h" 8 | 9 | #include "LowDatagram.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | // ----------------------------------------------------------------------------- 18 | // low_dgram_bind 19 | // ----------------------------------------------------------------------------- 20 | 21 | duk_ret_t low_dgram_bind(duk_context *ctx) 22 | { 23 | low_t *low = duk_get_low_context(ctx); 24 | 25 | const char *address = duk_require_string(ctx, 0); 26 | int port = duk_require_int(ctx, 1); 27 | int family = duk_require_int(ctx, 2); 28 | bool reuseAddr = duk_require_boolean(ctx, 3); 29 | // 4 = listening cb 30 | // 5 = message cb 31 | 32 | int addrLen = family == 4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); 33 | unsigned char addrBuf[addrLen]; 34 | sockaddr *addr = (sockaddr *)addrBuf; 35 | memset(addr, 0, addrLen); 36 | 37 | if(family == 4) 38 | { 39 | sockaddr_in *addr_in = (sockaddr_in *)addr; 40 | 41 | addr_in->sin_family = AF_INET; 42 | if(inet_pton(AF_INET, address, &addr_in->sin_addr) != 1) 43 | { 44 | int err = errno; 45 | duk_dup(low->duk_ctx, 4); 46 | low_push_error(ctx, err, "inet_pton"); 47 | low_call_next_tick(low->duk_ctx, 1); 48 | return 0; 49 | } 50 | addr_in->sin_port = htons(port); 51 | } 52 | else 53 | { 54 | sockaddr_in6 *addr_in6 = (sockaddr_in6 *)addr; 55 | 56 | addr_in6->sin6_family = AF_INET6; 57 | if(inet_pton(AF_INET6, address, &addr_in6->sin6_addr) != 1) 58 | { 59 | int err = errno; 60 | duk_dup(low->duk_ctx, 4); 61 | low_push_error(ctx, err, "inet_pton"); 62 | low_call_next_tick(low->duk_ctx, 1); 63 | return 0; 64 | } 65 | addr_in6->sin6_port = htons(port); 66 | } 67 | 68 | LowDatagram *datagram = 69 | new LowDatagram(low); 70 | if(!datagram) 71 | { 72 | duk_dup(low->duk_ctx, 4); 73 | low_push_error(ctx, ENOMEM, "malloc"); 74 | low_call_next_tick(low->duk_ctx, 1); 75 | return 0; 76 | } 77 | 78 | int err; 79 | const char *syscall; 80 | if(!datagram->Bind(addr, addrLen, 5, err, syscall, reuseAddr)) 81 | { 82 | delete datagram; 83 | 84 | duk_dup(ctx, 4); 85 | low_push_error(ctx, err, syscall); 86 | low_call_next_tick(ctx, 1); 87 | } 88 | else 89 | { 90 | duk_dup(ctx, 4); 91 | duk_push_null(ctx); 92 | duk_push_int(ctx, datagram->FD()); 93 | if(family == 4) 94 | duk_push_int(ctx, ntohs(((struct sockaddr_in *)addr)->sin_port)); 95 | else 96 | duk_push_int(ctx, ntohs(((struct sockaddr_in6 *)addr)->sin6_port)); 97 | low_call_next_tick(ctx, 3); 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | 104 | // ----------------------------------------------------------------------------- 105 | // low_dgram_send 106 | // ----------------------------------------------------------------------------- 107 | 108 | duk_ret_t low_dgram_send(duk_context *ctx) 109 | { 110 | low_t *low = duk_get_low_context(ctx); 111 | 112 | int fd = duk_require_int(ctx, 0); 113 | // 1 = array of buffers 114 | const char *address = duk_require_string(ctx, 2); 115 | int port = duk_require_int(ctx, 3); 116 | // 4 = callback 117 | 118 | auto iter = low->fds.find(fd); 119 | if(iter == low->fds.end()) 120 | duk_reference_error(ctx, "file descriptor not found"); 121 | if(iter->second->FDType() != LOWFD_TYPE_DATAGRAM) 122 | duk_reference_error(ctx, "file descriptor is not a datagram socket"); 123 | LowDatagram *datagram = (LowDatagram *)iter->second; 124 | 125 | datagram->Send(1, address, port, 4); 126 | return 0; 127 | } -------------------------------------------------------------------------------- /src/low_dgram.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_dgram.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_DGRAM_H__ 6 | #define __LOW_DGRAM_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_dgram_bind(duk_context *ctx); 11 | duk_ret_t low_dgram_send(duk_context *ctx); 12 | 13 | #endif /* __LOW_DGRAM_H__ */ -------------------------------------------------------------------------------- /src/low_dns.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_dns.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_DNS_H__ 6 | #define __LOW_DNS_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_dns_lookup(duk_context *ctx); 11 | duk_ret_t low_dns_lookup_service(duk_context *ctx); 12 | 13 | duk_ret_t low_dns_new_resolver(duk_context *ctx); 14 | duk_ret_t low_dns_resolver_cancel(duk_context *ctx); 15 | duk_ret_t low_dns_resolver_get_servers(duk_context *ctx); 16 | duk_ret_t low_dns_resolver_set_servers(duk_context *ctx); 17 | duk_ret_t low_dns_resolver_resolve(duk_context *ctx); 18 | duk_ret_t low_dns_resolver_gethostbyaddr(duk_context *ctx); 19 | 20 | duk_ret_t low_dns_resolver_finalizer(duk_context *ctx); 21 | 22 | #endif /* __LOW_DNS_H__ */ -------------------------------------------------------------------------------- /src/low_fs.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_fs.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_FS_H__ 6 | #define __LOW_FS_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_fs_open(duk_context *ctx); 11 | duk_ret_t low_fs_open_sync(duk_context *ctx); 12 | 13 | duk_ret_t low_fs_close(duk_context *ctx); 14 | duk_ret_t low_fs_close_sync(duk_context *ctx); 15 | 16 | duk_ret_t low_fs_read(duk_context *ctx); 17 | duk_ret_t low_fs_write(duk_context *ctx); 18 | duk_ret_t low_fs_fstat(duk_context *ctx); 19 | 20 | duk_ret_t low_fs_waitdone(duk_context *ctx); 21 | duk_ret_t low_fs_file_pos(duk_context *ctx); 22 | 23 | bool low_fs_resolve(char *res, 24 | int res_len, 25 | const char *base, 26 | const char *add, 27 | const char *add_node_modules_at = NULL 28 | #if LOW_ESP32_LWIP_SPECIALITIES || defined(LOWJS_SERV) 29 | , bool add_esp_base = true 30 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 31 | ); 32 | 33 | #endif /* __LOW_FS_H__ */ -------------------------------------------------------------------------------- /src/low_fs_misc.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_fs_misc.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_FS_MISC_H__ 6 | #define __LOW_FS_MISC_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_fs_rename(duk_context *ctx); 11 | duk_ret_t low_fs_unlink(duk_context *ctx); 12 | duk_ret_t low_fs_stat(duk_context *ctx); 13 | duk_ret_t low_fs_access(duk_context *ctx); 14 | duk_ret_t low_fs_readdir(duk_context *ctx); 15 | duk_ret_t low_fs_mkdir(duk_context *ctx); 16 | duk_ret_t low_fs_rmdir(duk_context *ctx); 17 | 18 | duk_ret_t low_fs_rename_sync(duk_context *ctx); 19 | duk_ret_t low_fs_unlink_sync(duk_context *ctx); 20 | duk_ret_t low_fs_stat_sync(duk_context *ctx); 21 | duk_ret_t low_fs_access_sync(duk_context *ctx); 22 | duk_ret_t low_fs_readdir_sync(duk_context *ctx); 23 | duk_ret_t low_fs_mkdir_sync(duk_context *ctx); 24 | duk_ret_t low_fs_rmdir_sync(duk_context *ctx); 25 | 26 | #endif /* __LOW_FS_MISC_H__ */ 27 | -------------------------------------------------------------------------------- /src/low_http.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_http.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "low_http.h" 6 | 7 | #include "LowHTTPDirect.h" 8 | #include "LowSocket.h" 9 | 10 | #include "low_alloc.h" 11 | #include "low_main.h" 12 | #include "low_system.h" 13 | 14 | #include 15 | 16 | // ----------------------------------------------------------------------------- 17 | // low_http_get_request 18 | // ----------------------------------------------------------------------------- 19 | 20 | duk_ret_t low_http_get_request(duk_context *ctx) 21 | { 22 | low_t *low = duk_get_low_context(ctx); 23 | 24 | int socketFD = duk_require_int(ctx, 0); 25 | auto iter = low->fds.find(socketFD); 26 | if(iter == low->fds.end()) 27 | return 0; 28 | 29 | if(iter->second->FDType() != LOWFD_TYPE_SOCKET) 30 | duk_reference_error(ctx, "file descriptor is not a socket"); 31 | LowSocket *socket = (LowSocket *)iter->second; 32 | 33 | int directType; 34 | LowHTTPDirect *direct = (LowHTTPDirect *)socket->GetDirect(directType); 35 | if(direct && directType == 0) 36 | { 37 | // Server version 38 | direct->SetRequestCallID(low_add_stash(ctx, 1)); 39 | } 40 | else if(!direct) 41 | { 42 | // Client version 43 | direct = new LowHTTPDirect(low, false); 44 | if(!direct) 45 | { 46 | duk_dup(ctx, 1); 47 | low_push_error(ctx, ENOMEM, "malloc"); 48 | low_call_next_tick(ctx, 1); 49 | return 0; 50 | } 51 | 52 | socket->SetDirect(direct, 0); 53 | direct->SetRequestCallID(low_add_stash(ctx, 1)); 54 | } 55 | else 56 | duk_reference_error( 57 | ctx, "file descriptor is already acquired by direct object"); 58 | 59 | return 0; 60 | } 61 | 62 | // ----------------------------------------------------------------------------- 63 | // low_http_detach 64 | // ----------------------------------------------------------------------------- 65 | 66 | duk_ret_t low_http_detach(duk_context *ctx) 67 | { 68 | low_t *low = duk_get_low_context(ctx); 69 | 70 | int socketFD = duk_require_int(ctx, 0); 71 | auto iter = low->fds.find(socketFD); 72 | if(iter == low->fds.end()) 73 | return 0; 74 | 75 | if(iter->second->FDType() != LOWFD_TYPE_SOCKET) 76 | duk_reference_error(ctx, "file descriptor is not a socket"); 77 | LowSocket *socket = (LowSocket *)iter->second; 78 | 79 | int directType; 80 | LowHTTPDirect *direct = (LowHTTPDirect *)socket->GetDirect(directType); 81 | if(!direct) 82 | return 1; 83 | if(directType != 0) 84 | duk_reference_error(ctx, "file descriptor is not an HTTP stream"); 85 | 86 | direct->Detach(true); 87 | return 1; 88 | } 89 | 90 | // ----------------------------------------------------------------------------- 91 | // low_http_read 92 | // ----------------------------------------------------------------------------- 93 | 94 | duk_ret_t low_http_read(duk_context *ctx) 95 | { 96 | low_t *low = duk_get_low_context(ctx); 97 | 98 | int socketFD = duk_require_int(ctx, 0); 99 | duk_size_t buf_len; 100 | unsigned char *buf = 101 | (unsigned char *)duk_require_buffer_data(ctx, 1, &buf_len); 102 | 103 | auto iter = low->fds.find(socketFD); 104 | if(iter == low->fds.end()) 105 | return 0; 106 | 107 | if(iter->second->FDType() != LOWFD_TYPE_SOCKET) 108 | duk_reference_error(ctx, "file descriptor is not a socket"); 109 | LowSocket *socket = (LowSocket *)iter->second; 110 | 111 | int directType; 112 | LowHTTPDirect *http = (LowHTTPDirect *)socket->GetDirect(directType); 113 | if(!http || directType != 0) 114 | { 115 | duk_push_error_object(ctx, DUK_ERR_ERROR, "file descriptor is not HTTP stream / HTTP error"); 116 | low_call_next_tick(low->duk_ctx, 1); 117 | return 0; 118 | } 119 | 120 | http->Read(buf, buf_len, 2); 121 | return 0; 122 | } 123 | 124 | // ----------------------------------------------------------------------------- 125 | // low_http_write 126 | // ----------------------------------------------------------------------------- 127 | 128 | duk_ret_t low_http_write(duk_context *ctx) 129 | { 130 | low_t *low = duk_get_low_context(ctx); 131 | 132 | int socketFD = duk_require_int(ctx, 0); 133 | duk_size_t buf_len = 0; 134 | unsigned char *buf = 135 | duk_is_null(ctx, 1) 136 | ? NULL 137 | : (unsigned char *)duk_require_buffer_data(ctx, 1, &buf_len); 138 | 139 | auto iter = low->fds.find(socketFD); 140 | if(iter == low->fds.end()) 141 | return 0; 142 | 143 | if(iter->second->FDType() != LOWFD_TYPE_SOCKET) 144 | duk_reference_error(ctx, "file descriptor is not a socket"); 145 | LowSocket *socket = (LowSocket *)iter->second; 146 | 147 | int directType; 148 | LowHTTPDirect *http = (LowHTTPDirect *)socket->GetDirect(directType); 149 | if(!http || directType != 0) 150 | { 151 | duk_push_error_object(ctx, DUK_ERR_ERROR, "file descriptor is not HTTP stream / HTTP error"); 152 | low_call_next_tick(low->duk_ctx, 1); 153 | return 0; 154 | } 155 | 156 | http->Write(buf, buf_len, 1, 2); 157 | return 0; 158 | } 159 | 160 | // ----------------------------------------------------------------------------- 161 | // low_http_write_head 162 | // ----------------------------------------------------------------------------- 163 | 164 | duk_ret_t low_http_write_head(duk_context *ctx) 165 | { 166 | low_t *low = duk_get_low_context(ctx); 167 | 168 | int socketFD = duk_require_int(ctx, 0); 169 | const char *headers = duk_require_string(ctx, 1); 170 | int len = duk_require_int(ctx, 2); 171 | bool isChunked = duk_require_boolean(ctx, 3); 172 | 173 | auto iter = low->fds.find(socketFD); 174 | if(iter == low->fds.end()) 175 | return 0; 176 | 177 | if(iter->second->FDType() != LOWFD_TYPE_SOCKET) 178 | duk_reference_error(ctx, "file descriptor is not a socket"); 179 | LowSocket *socket = (LowSocket *)iter->second; 180 | 181 | int directType; 182 | LowHTTPDirect *http = (LowHTTPDirect *)socket->GetDirect(directType); 183 | if(!http || directType != 0) 184 | { 185 | duk_push_error_object(ctx, DUK_ERR_ERROR, "file descriptor is not HTTP stream / HTTP error"); 186 | low_call_next_tick(low->duk_ctx, 1); 187 | return 0; 188 | } 189 | 190 | http->WriteHeaders(headers, 1, len, isChunked); 191 | return 0; 192 | } -------------------------------------------------------------------------------- /src/low_http.h: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_http.h 4 | // ----------------------------------------------------------------------------- 5 | 6 | #ifndef __LOW_HTTP_H__ 7 | #define __LOW_HTTP_H__ 8 | 9 | #include "duktape.h" 10 | 11 | duk_ret_t low_http_get_request(duk_context *ctx); 12 | duk_ret_t low_http_detach(duk_context *ctx); 13 | 14 | duk_ret_t low_http_read(duk_context *ctx); 15 | 16 | duk_ret_t low_http_write(duk_context *ctx); 17 | duk_ret_t low_http_write_head(duk_context *ctx); 18 | 19 | #endif /* __LOW_HTTP_H__ */ -------------------------------------------------------------------------------- /src/low_loop.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_loop.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_LOOP_H__ 6 | #define __LOW_LOOP_H__ 7 | 8 | #include "duktape.h" 9 | 10 | struct low_t; 11 | 12 | struct low_chore_t 13 | { 14 | int stamp, interval; 15 | unsigned char oneshot, ref; 16 | 17 | // If oneshot == 2, C version 18 | void (*call)(duk_context *ctx, void *data); 19 | void *data; 20 | }; 21 | 22 | class LowLoopCallback; 23 | 24 | bool low_loop_run(low_t *low); 25 | duk_ret_t low_loop_run_safe(duk_context *ctx, void *udata); 26 | 27 | duk_ret_t low_loop_chore_ref(duk_context *ctx); 28 | duk_ret_t low_loop_run_ref(duk_context *ctx); 29 | 30 | duk_ret_t low_loop_set_chore(duk_context *ctx); 31 | duk_ret_t low_loop_clear_chore(duk_context *ctx); 32 | 33 | extern "C" int low_set_timeout(duk_context *ctx, int index, int delay, void (*call)(duk_context *ctx, void *userdata), void *userdata); 34 | extern "C" void low_clear_timeout(duk_context *ctx, int index); 35 | 36 | void low_loop_set_callback( 37 | low_t *low, 38 | LowLoopCallback *callback); // may be called from other thread 39 | void low_loop_clear_callback( 40 | low_t *low, 41 | LowLoopCallback *callback); // must be called from main thread 42 | 43 | extern "C" void low_call_next_tick(duk_context *ctx, int num_args); 44 | int low_call_next_tick_js(duk_context *ctx); 45 | 46 | void low_loop_wait(duk_context *ctx, int millisecs); 47 | 48 | #endif /* __LOW_LOOP_H__ */ -------------------------------------------------------------------------------- /src/low_main.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_main.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_MAIN_H__ 6 | #define __LOW_MAIN_H__ 7 | 8 | #include "low_alloc.h" 9 | #include "low_config.h" 10 | #include "low_loop.h" 11 | 12 | #if LOW_ESP32_LWIP_SPECIALITIES 13 | #include 14 | #include 15 | #include 16 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | class LowLoopCallback; 25 | class LowDataCallback; 26 | class LowFD; 27 | class LowDNSResolver; 28 | class LowTLSContext; 29 | class LowCryptoHash; 30 | 31 | struct low_t 32 | { 33 | uint8_t duk_flag_stop; 34 | bool destroying; 35 | duk_context *duk_ctx, *next_tick_ctx; 36 | 37 | #if !LOW_ESP32_LWIP_SPECIALITIES 38 | unsigned int heap_size, max_heap_size; 39 | #endif /* !LOW_ESP32_LWIP_SPECIALITIES */ 40 | bool in_gc, disallow_native; 41 | 42 | int run_ref, last_stash_index; 43 | 44 | int signal_call_id; 45 | bool in_uncaught_exception; 46 | 47 | map chores; 48 | multimap chore_times; 49 | int last_chore_time; 50 | 51 | #if LOW_ESP32_LWIP_SPECIALITIES 52 | TaskHandle_t data_thread[LOW_NUM_DATA_THREADS]; 53 | TaskHandle_t web_thread; 54 | SemaphoreHandle_t loop_thread_sema; 55 | #else 56 | pthread_t data_thread[LOW_NUM_DATA_THREADS]; 57 | pthread_t web_thread; 58 | pthread_cond_t loop_thread_cond; 59 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 60 | pthread_mutex_t loop_thread_mutex; 61 | 62 | LowLoopCallback *loop_callback_first, *loop_callback_last; 63 | 64 | pthread_mutex_t data_thread_mutex; 65 | pthread_cond_t data_thread_cond, data_thread_done_cond; 66 | LowDataCallback *data_callback_first[2], *data_callback_last[2]; 67 | bool data_thread_done; 68 | 69 | pthread_mutex_t web_thread_mutex; 70 | pthread_cond_t web_thread_done_cond; 71 | #if !LOW_ESP32_LWIP_SPECIALITIES 72 | int web_thread_pipe[2]; 73 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 74 | LowFD *web_changed_first, *web_changed_last; 75 | bool web_thread_done; 76 | bool reset_accepts; 77 | 78 | map> fds; 79 | 80 | #if LOW_INCLUDE_CARES_RESOLVER 81 | vector resolvers; 82 | int resolvers_active; 83 | pthread_mutex_t resolvers_mutex; 84 | #endif /* LOW_INCLUDE_CARES_RESOLVER */ 85 | vector tlsContexts; 86 | vector cryptoHashes; 87 | 88 | pthread_mutex_t ref_mutex; 89 | 90 | #if LOW_ESP32_LWIP_SPECIALITIES || defined(LOWJS_SERV) 91 | char *cwd; 92 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 93 | 94 | int (*module_transpile_hook)(duk_context *ctx); 95 | }; 96 | 97 | typedef enum 98 | { 99 | LOW_THREAD_CODE, 100 | LOW_THREAD_WORKER, 101 | LOW_THREAD_IMMEDIATE 102 | } low_thread; 103 | 104 | low_t *low_init(); 105 | bool low_lib_init(low_t *low); 106 | void low_destroy(low_t *low); 107 | 108 | duk_context *low_get_duk_context(low_t *low); 109 | low_t *duk_get_low_context(duk_context *ctx); 110 | 111 | bool low_reset(low_t *low); 112 | 113 | extern "C" void low_call_thread(duk_context *ctx, low_thread thread, int priority, void (*func)(duk_context *ctx, void *userdata), void *userdata); 114 | extern "C" low_thread low_get_current_thread(duk_context *ctx); 115 | 116 | extern "C" int low_add_stash(duk_context *ctx, int index); 117 | extern "C" void low_remove_stash(duk_context *ctx, int index); 118 | extern "C" void low_push_stash(duk_context *ctx, int index, bool remove); 119 | 120 | extern "C" void *low_push_buffer(duk_context *ctx, int len); 121 | 122 | void low_duk_print_error(duk_context *ctx); 123 | 124 | #endif /* __LOW_MAIN_H__ */ 125 | -------------------------------------------------------------------------------- /src/low_module.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_module.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_MODULE_H__ 6 | #define __LOW_MODULE_H__ 7 | 8 | #include "duktape.h" 9 | 10 | struct low_t; 11 | 12 | #define LOW_MODULE_FLAG_GLOBAL 1 13 | #define LOW_MODULE_FLAG_JSON 2 14 | #define LOW_MODULE_FLAG_DUK_FORMAT 4 15 | #define LOW_MODULE_FLAG_NATIVE 8 16 | 17 | void low_module_init(duk_context *ctx); 18 | 19 | bool low_module_main(low_t *low, const char *path); 20 | 21 | bool low_module_make_native(low_t *low, 22 | const char *name, 23 | void (*setup_cb)(low_t *main, void *data), 24 | void *setup_cb_data); 25 | 26 | duk_ret_t low_module_require(duk_context *ctx); 27 | duk_ret_t low_module_resolve(duk_context *ctx); 28 | duk_ret_t low_module_make(duk_context *ctx); 29 | 30 | extern "C" void low_load_module(duk_context *ctx, const char *path, bool parent_on_stack); 31 | bool low_module_resolve_c(duk_context *ctx, 32 | const char *module_id, 33 | const char *parent_id, 34 | char *res_id); 35 | 36 | #endif /* __LOW_MODULE_H__ */ -------------------------------------------------------------------------------- /src/low_native.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_native.cpp 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "low_crypto.h" 6 | #include "low_dns.h" 7 | #include "low_fs.h" 8 | #include "low_fs_misc.h" 9 | #include "low_http.h" 10 | #include "low_loop.h" 11 | #include "low_module.h" 12 | #include "low_native_aux.h" 13 | #include "low_net.h" 14 | #include "low_dgram.h" 15 | #include "low_process.h" 16 | #include "low_tls.h" 17 | 18 | // The methods of the module 'native', accessable by files in lib_js directory 19 | duk_function_list_entry g_low_native_methods[] = { 20 | {"gc", low_gc, 0}, 21 | {"processInfo", low_process_info, 1}, 22 | {"osInfo", low_os_info, 0}, 23 | {"ttyInfo", low_tty_info, 0}, 24 | {"hrtime", low_hrtime, 1}, 25 | {"compile", low_compile, 1}, 26 | {"runInContext", low_run_in_context, 4}, 27 | {"compare", low_compare, 2}, 28 | {"setChore", low_loop_set_chore, 3}, 29 | {"clearChore", low_loop_clear_chore, 1}, 30 | {"choreRef", low_loop_chore_ref, 2}, 31 | {"runRef", low_loop_run_ref, 1}, 32 | {"open", low_fs_open, 4}, 33 | {"openSync", low_fs_open_sync, 3}, 34 | {"close", low_fs_close, 2}, 35 | {"closeSync", low_fs_close_sync, 1}, 36 | {"read", low_fs_read, 6}, 37 | {"write", low_fs_write, 6}, 38 | {"fstat", low_fs_fstat, 2}, 39 | {"stat", low_fs_stat, 2}, 40 | {"rename", low_fs_rename, 3}, 41 | {"unlink", low_fs_unlink, 2}, 42 | {"access", low_fs_access, 3}, 43 | {"readdir", low_fs_readdir, 3}, 44 | {"mkdir", low_fs_mkdir, 3}, 45 | {"rmdir", low_fs_rmdir, 2}, 46 | {"statSync", low_fs_stat_sync, 1}, 47 | {"renameSync", low_fs_rename_sync, 2}, 48 | {"unlinkSync", low_fs_unlink_sync, 1}, 49 | {"accessSync", low_fs_access_sync, 2}, 50 | {"readdirSync", low_fs_readdir_sync, 2}, 51 | {"mkdirSync", low_fs_mkdir_sync, 2}, 52 | {"rmdirSync", low_fs_rmdir_sync, 1}, 53 | {"waitDone", low_fs_waitdone, 1}, 54 | {"file_pos", low_fs_file_pos, 1}, 55 | {"bind", low_dgram_bind, 6}, 56 | {"send", low_dgram_send, 5}, 57 | {"listen", low_net_listen, 7}, 58 | {"connect", low_net_connect, 6}, 59 | {"setsockopt", low_net_setsockopt, 5}, 60 | {"shutdown", low_net_shutdown, 2}, 61 | {"netConnections", low_net_connections, 3}, 62 | {"isIP", low_is_ip, 1}, 63 | {"lookup", low_dns_lookup, 4}, 64 | {"lookupService", low_dns_lookup_service, 3}, 65 | {"newResolver", low_dns_new_resolver, 1}, 66 | {"resolverCancel", low_dns_resolver_cancel, 1}, 67 | {"resolverGetServers", low_dns_resolver_get_servers, 1}, 68 | {"resolverSetServers", low_dns_resolver_set_servers, 2}, 69 | {"resolverResolve", low_dns_resolver_resolve, 5}, 70 | {"resolverGetHostByAddr", low_dns_resolver_gethostbyaddr, 3}, 71 | {"httpGetRequest", low_http_get_request, 2}, 72 | {"httpDetach", low_http_detach, 1}, 73 | {"httpRead", low_http_read, 3}, 74 | {"httpWrite", low_http_write, 3}, 75 | {"httpWriteHead", low_http_write_head, 4}, 76 | {"createTLSContext", low_tls_create_context, 2}, 77 | {"makeModule", low_module_make, 2}, 78 | {"createCryptoHash", low_crypto_create_hash, 3}, 79 | {"cryptoHashUpdate", low_crypto_hash_update, 2}, 80 | {"cryptoHashDigest", low_crypto_hash_digest, 1}, 81 | {"randomBytes", low_crypto_random_bytes, 2}, 82 | {NULL, NULL, 0}}; 83 | -------------------------------------------------------------------------------- /src/low_native_api.h: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_native_api.h 4 | // ----------------------------------------------------------------------------- 5 | 6 | #ifndef __LOW_NATIVE_API_H__ 7 | #define __LOW_NATIVE_API_H__ 8 | 9 | #include 10 | 11 | void *native_api_load(const char *data, unsigned int size, const char **err, bool *err_malloc); 12 | int native_api_call(duk_context *ctx); 13 | 14 | void native_api_unload_all(); 15 | 16 | #endif /* __LOW_NATIVE_API_H__ */ 17 | -------------------------------------------------------------------------------- /src/low_native_aux.cpp: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_native_aux.cpp 4 | // ----------------------------------------------------------------------------- 5 | 6 | #include "low_native_aux.h" 7 | 8 | #include "low_config.h" 9 | #include "low_main.h" 10 | 11 | #if LOW_ESP32_LWIP_SPECIALITIES 12 | #include "lwip/sockets.h" 13 | #endif /* LOW_ESP32_LWIP_SPECIALITIES */ 14 | 15 | #include 16 | #include 17 | 18 | // ----------------------------------------------------------------------------- 19 | // low_compare 20 | // ----------------------------------------------------------------------------- 21 | 22 | duk_ret_t low_compare(duk_context *ctx) 23 | { 24 | duk_size_t a_len, b_len; 25 | unsigned char *a = (unsigned char *)duk_require_buffer_data(ctx, 0, &a_len); 26 | unsigned char *b = (unsigned char *)duk_require_buffer_data(ctx, 1, &b_len); 27 | 28 | if(a_len < b_len) 29 | duk_push_int(ctx, -1); 30 | else if(a_len > b_len) 31 | duk_push_int(ctx, 1); 32 | else 33 | duk_push_int(ctx, memcmp(a, b, a_len)); 34 | return 1; 35 | } 36 | 37 | // ----------------------------------------------------------------------------- 38 | // low_is_ip 39 | // ----------------------------------------------------------------------------- 40 | 41 | duk_ret_t low_is_ip(duk_context *ctx) 42 | { 43 | const char *ip = duk_require_string(ctx, 0); 44 | 45 | bool isIPv4 = false; 46 | for(int i = 0; ip[i]; i++) 47 | { 48 | if(ip[i] == '.') 49 | { 50 | isIPv4 = true; 51 | break; 52 | } 53 | } 54 | 55 | unsigned char buf[16]; 56 | if(inet_pton(isIPv4 ? AF_INET : AF_INET6, ip, buf) != 1) 57 | { 58 | duk_push_int(ctx, 0); 59 | return 1; 60 | } 61 | 62 | duk_push_int(ctx, isIPv4 ? 4 : 6); 63 | return 1; 64 | } 65 | 66 | // ----------------------------------------------------------------------------- 67 | // low_compile 68 | // ----------------------------------------------------------------------------- 69 | 70 | duk_ret_t low_compile(duk_context *ctx) 71 | { 72 | // If we compile here, Duktape uses global object from compilation 73 | // So all we can do is save it 74 | duk_push_object(ctx); 75 | duk_dup(ctx, 0); 76 | duk_put_prop_string(ctx, -2, "code"); 77 | 78 | return 1; 79 | } 80 | 81 | // ----------------------------------------------------------------------------- 82 | // low_run_in_context 83 | // ----------------------------------------------------------------------------- 84 | 85 | duk_ret_t low_run_in_context_safe(duk_context *ctx, void *udata) 86 | { 87 | // TODO: cache compilation 88 | duk_get_prop_string(ctx, 0, "code"); 89 | duk_get_prop_string(ctx, 0, "fileName"); 90 | duk_compile(ctx, 0); 91 | 92 | duk_call(ctx, 0); 93 | return 1; 94 | } 95 | 96 | duk_ret_t low_run_in_context(duk_context *ctx) 97 | { 98 | low_t *low = duk_get_low_context(ctx); 99 | 100 | duk_push_global_object(low->duk_ctx); // 4 101 | 102 | duk_dup(low->duk_ctx, 1); 103 | duk_set_global_object(low->duk_ctx); 104 | duk_dup(low->duk_ctx, 0); 105 | 106 | if(duk_safe_call(low->duk_ctx, low_run_in_context_safe, NULL, 1, 1) != 107 | DUK_EXEC_SUCCESS) 108 | { 109 | duk_dup(low->duk_ctx, 4); 110 | duk_set_global_object(low->duk_ctx); 111 | 112 | duk_throw(ctx); 113 | return 0; 114 | } 115 | 116 | duk_dup(low->duk_ctx, 4); 117 | duk_set_global_object(low->duk_ctx); 118 | 119 | return 1; 120 | } 121 | -------------------------------------------------------------------------------- /src/low_native_aux.h: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_native_aux.cpp 4 | // ----------------------------------------------------------------------------- 5 | 6 | #ifndef __LOW_NATIVE_AUX_H__ 7 | #define __LOW_NATIVE_AUX_H__ 8 | 9 | #include "duktape.h" 10 | 11 | duk_ret_t low_compare(duk_context *ctx); 12 | duk_ret_t low_is_ip(duk_context *ctx); 13 | 14 | duk_ret_t low_compile(duk_context *ctx); 15 | duk_ret_t low_run_in_context(duk_context *ctx); 16 | 17 | #endif /* __LOW_NATIVE_AUX_H__ */ -------------------------------------------------------------------------------- /src/low_net.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_net.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_NET_H__ 6 | #define __LOW_NET_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_net_listen(duk_context *ctx); 11 | duk_ret_t low_net_connect(duk_context *ctx); 12 | duk_ret_t low_net_setsockopt(duk_context *ctx); 13 | duk_ret_t low_net_shutdown(duk_context *ctx); 14 | duk_ret_t low_net_connections(duk_context *ctx); 15 | 16 | #endif /* __LOW_NET_H__ */ -------------------------------------------------------------------------------- /src/low_opcua.h: -------------------------------------------------------------------------------- 1 | 2 | // ----------------------------------------------------------------------------- 3 | // low_opcua.h 4 | // ----------------------------------------------------------------------------- 5 | 6 | #ifndef __LOW_OPCUA_H__ 7 | #define __LOW_OPCUA_H__ 8 | 9 | #include "duktape.h" 10 | 11 | #include "low_main.h" 12 | #include "LowLoopCallback.h" 13 | #include "LowFD.h" 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #define LOW_OPCUA_WRITEBUFFER_SIZE 1024 22 | bool low_register_opcua(low_t *low); 23 | 24 | int opcua_uaclient_constructor(duk_context *ctx); 25 | int opcua_uaclient_destroy(duk_context *ctx); 26 | int opcua_uaclient_node(duk_context *ctx); 27 | 28 | int opcua_uaclient_create_subscription(duk_context *ctx); 29 | int opcua_uaclient_destroy_subscription(duk_context *ctx); 30 | int opcua_uaclient_subscription_add(duk_context *ctx); 31 | int opcua_uaclient_subscription_remove(duk_context *ctx); 32 | 33 | void opcua_fill_node(duk_context *ctx); 34 | 35 | int opcua_uaclient_lookup_props(duk_context *ctx); 36 | int opcua_uaclient_subnode(duk_context *ctx); 37 | int opcua_uaclient_children(duk_context *ctx); 38 | 39 | int opcua_uaclient_read(duk_context *ctx); 40 | int opcua_uaclient_write(duk_context *ctx); 41 | int opcua_uaclient_call(duk_context *ctx); 42 | 43 | #define LOWOPCTASK_TYPE_DESTROY 0 44 | #define LOWOPCTASK_TYPE_LOOKUP_PROPS 1 45 | #define LOWOPCTASK_TYPE_SUBNODE 2 46 | #define LOWOPCTASK_TYPE_CHILDREN 3 47 | #define LOWOPCTASK_TYPE_READ 4 48 | #define LOWOPCTASK_TYPE_WRITE 5 49 | #define LOWOPCTASK_TYPE_CALL 6 50 | #define LOWOPCTASK_TYPE_CREATE_SUBSCRIPTION 7 51 | #define LOWOPCTASK_TYPE_DESTROY_SUBSCRIPTION 8 52 | #define LOWOPCTASK_TYPE_SUBSCRIPTION_ADD 9 53 | #define LOWOPCTASK_TYPE_SUBSCRIPTION_REMOVE 10 54 | 55 | struct LowOPCUATask 56 | { 57 | class LowOPCUA *opcua; 58 | int id, type; 59 | int objStashIndex, objStashIndex2, clientHandle; 60 | int callbackStashIndex, timeoutChoreIndex; 61 | void *result; 62 | const UA_DataType *resultType; 63 | }; 64 | 65 | struct UA_Client; 66 | class LowOPCUA : public LowLoopCallback, public LowFD 67 | { 68 | public: 69 | LowOPCUA(low_t *low, struct UA_Client *client, int thisIndex, int timeoutMS, const char *url); 70 | virtual ~LowOPCUA(); 71 | 72 | void DisconnectAndDetach(int callbackStashIndex); 73 | void AddAsyncRequestAndUnlock(int type, unsigned int reqID, const UA_DataType *resultType, int objStaskIndex, int callbackStashIndex, int objStashIndex2 = 0, int clientHandle = 0); 74 | 75 | // Not used (we do not advertise the FD, only used in web_thread) 76 | virtual void Read(int pos, unsigned char *data, int len, int callIndex) {} 77 | virtual void Write(int pos, unsigned char *data, int len, 78 | int callIndex) {} 79 | virtual bool Close(int callIndex) { return true; } 80 | 81 | static int OnSend(void *data, unsigned char *buf, int size); 82 | 83 | protected: 84 | static void OnConnect(struct UA_Client *client, void *userdata, uint32_t requestId, void *data); 85 | 86 | static void OnTimeout(duk_context *ctx, void *data); 87 | 88 | static void OnTaskTimeout(duk_context *ctx, void *data); 89 | static UA_StatusCode OnPublishNotification(struct UA_Client *client, UA_ExtensionObject *msg, void *data); 90 | 91 | virtual bool OnLoop(); 92 | virtual bool OnEvents(short events); 93 | 94 | void PushVariant(UA_Variant *variant); 95 | 96 | private: 97 | low_t *mLow; 98 | int mTimeoutMS; 99 | int mThisIndex; 100 | 101 | int mChoreIndex; 102 | 103 | unsigned char *mWriteBuffer, *mWriteBufferLast; 104 | int mWriteBufferRead, mWriteBufferLastLen; 105 | 106 | bool mGoToLoop; 107 | 108 | std::map > mMonitoredItems; 109 | std::queue mDataChangeNotifications; 110 | 111 | public: 112 | static void OnTaskCallback( 113 | UA_Client *client, void *userdata, unsigned int reqID, void *responsedata); 114 | 115 | struct UA_Client *mClient; 116 | std::map mTasks; 117 | pthread_mutex_t mMutex; 118 | int mConnectState, mDisabledState, mDetachedState, mError; 119 | int mLastClientHandle; 120 | }; 121 | 122 | #endif /* __LOW_OPCUA_H__ */ 123 | -------------------------------------------------------------------------------- /src/low_process.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_process.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_PROCESS_H__ 6 | #define __LOW_PROCESS_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_gc(duk_context *ctx); 11 | duk_ret_t low_hrtime(duk_context *ctx); 12 | 13 | duk_ret_t low_process_exit(duk_context *ctx); 14 | duk_ret_t low_process_info(duk_context *ctx); 15 | duk_ret_t low_os_info(duk_context *ctx); 16 | 17 | duk_ret_t low_tty_info(duk_context *ctx); 18 | 19 | #endif /* __LOW_PROCESS_H__ */ -------------------------------------------------------------------------------- /src/low_promise.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_promise.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_PROMISE_H__ 6 | #define __LOW_PROMISE_H__ 7 | 8 | #include "duktape.h" 9 | #include "low_main.h" 10 | 11 | bool low_register_promise(low_t *low); 12 | 13 | int promise_constructor(duk_context *ctx); 14 | 15 | int promise_param_resolve(duk_context *ctx); 16 | int promise_param_reject(duk_context *ctx); 17 | int promise_handle_thens(duk_context *ctx); 18 | 19 | int promise_all(duk_context *ctx); 20 | int promise_all_resolved(duk_context *ctx); 21 | int promise_all_rejected(duk_context *ctx); 22 | int promise_race(duk_context *ctx); 23 | 24 | int promise_resolve(duk_context *ctx); 25 | int promise_reject(duk_context *ctx); 26 | 27 | int promise_catch(duk_context *ctx); 28 | int promise_then(duk_context *ctx); 29 | void promise_then_catch(duk_context *ctx, bool isCatch); 30 | 31 | #endif /* __LOW_PROMISE_H__ */ 32 | -------------------------------------------------------------------------------- /src/low_system.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_system.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_SYSTEM_H__ 6 | #define __LOW_SYSTEM_H__ 7 | 8 | #include "low_config.h" 9 | 10 | #include "duktape.h" 11 | 12 | #if LOW_HAS_TERMIOS 13 | #include 14 | #endif /* LOW_HAS_TERMIOS */ 15 | 16 | #define LOW_EUNKNOWN 0 17 | 18 | // 1-to-1 from c-ares, but with negative number 19 | #define LOW_ENODATA -1 20 | #define LOW_EFORMERR -2 21 | #define LOW_ESERVFAIL -3 22 | #define LOW_ENOTFOUND -4 23 | #define LOW_ENOTIMP -5 24 | #define LOW_EREFUSED -6 25 | #define LOW_EBADQUERY -7 26 | #define LOW_EBADNAME -8 27 | #define LOW_EBADFAMILY -9 28 | #define LOW_EBADRESP -10 29 | #define LOW_ECONNREFUSED -11 30 | #define LOW_ETIMEOUT -12 31 | #define LOW_EOF -13 32 | #define LOW_EFILE -14 33 | #define LOW_ENOMEM -15 34 | #define LOW_EDESTRUCTION -16 35 | #define LOW_EBADSTR -17 36 | #define LOW_EBADFLAGS -18 37 | #define LOW_ENONAME -19 38 | #define LOW_EBADHINTS -20 39 | #define LOW_ENOTINITIALIZED -21 40 | #define LOW_ELOADIPHLPAPI -22 41 | #define LOW_EADDRGETNETWORKPARAMS -23 42 | #define LOW_ECANCELLED -24 43 | 44 | #define LOW_NUM_ERROR_CODES 25 45 | 46 | struct low_system_t 47 | { 48 | #if !LOW_ESP32_LWIP_SPECIALITIES 49 | int argc; 50 | const char **argv; 51 | 52 | char *main_module_path; 53 | char *lib_path; 54 | 55 | int signal_pipe_fd; 56 | #endif /* !LOW_ESP32_LWIP_SPECIALITIES */ 57 | 58 | #if LOW_HAS_TERMIOS 59 | bool isatty, raw_mode; 60 | struct termios orig_termios; 61 | #endif /* LOW_HAS_TERMIOS */ 62 | }; 63 | 64 | extern "C" 65 | { 66 | bool low_system_init(int argc, const char *argv[]); 67 | void low_system_destroy(); 68 | } 69 | 70 | bool low_set_raw_mode(bool mode); 71 | int low_tick_count(); 72 | 73 | extern "C" void low_push_error(duk_context *ctx, int error, const char *syscall); 74 | 75 | void low_error_errno(); 76 | void low_error(const char *txt); 77 | 78 | #endif /* __LOW_SYSTEM_H__ */ 79 | -------------------------------------------------------------------------------- /src/low_tls.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_tls.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_TLS_H__ 6 | #define __LOW_TLS_H__ 7 | 8 | #include "duktape.h" 9 | 10 | duk_ret_t low_tls_create_context(duk_context *ctx); 11 | duk_ret_t low_tls_context_finalizer(duk_context *ctx); 12 | 13 | #endif /* __LOW_TLS_H__ */ -------------------------------------------------------------------------------- /src/low_web_thread.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // low_web_thread.h 3 | // ----------------------------------------------------------------------------- 4 | 5 | #ifndef __LOW_WEB_THREAD_H__ 6 | #define __LOW_WEB_THREAD_H__ 7 | 8 | #include 9 | 10 | #if LOW_HAS_POLL 11 | #include 12 | #else 13 | #define POLLIN 0x01 14 | #define POLLOUT 0x04 15 | #define POLLERR 0x08 16 | #define POLLHUP 0x10 17 | #endif /* LOW_HAS_POLL */ 18 | 19 | struct low_t; 20 | class LowFD; 21 | 22 | void *low_web_thread_main(void *arg); 23 | void low_web_thread_break(low_t *low); 24 | 25 | void low_web_set_poll_events(low_t *low, LowFD *fd, short events); 26 | 27 | void low_web_clear_poll(low_t *low, 28 | LowFD *fd); // only call from not-web thread 29 | void low_web_mark_delete(low_t *low, LowFD *fd); 30 | 31 | #endif /* __LOW_WEB_THREAD_H__ */ 32 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Running tests 2 | 3 | ## How to run 4 | 5 | Prerequisite: 6 | 7 | npm install 8 | cd test/tests_script && npm install 9 | 10 | Be sure your working directory is the project root before continuing. 11 | 12 | It is recommended to run a single test file first, like: 13 | 14 | npm run test -- run node/parallel/test-fs-close.js 15 | 16 | You may see compile errors for some files, but as long as the program says it has written a summary file at the end, everything is good. 17 | 18 | In order to run more tests: 19 | 20 | npm run test -- run node/parallel/test-fs-*.js 21 | 22 | Glob patterns are interpreted relative to the test/compiled directory that is created/updated when running the test runner. See the section 'How it works' for more information. 23 | 24 | Or to run all tests, just do. This can take a very long time: 25 | 26 | npm run test -- run 27 | 28 | Results from test files are cached in the os's temp directory until the test runner successfully completes and writes all cached results into the created summary html file, in which case the cache is cleared. 29 | 30 | This means that aborting a test run and running anew, will result in the runner fetching the results for completed tests from the cache. 31 | 32 | To forcefully clear the cache before running the test runner, use the --clear option, e.g.: 33 | 34 | npm run test -- run --clear 35 | 36 | ## How it works 37 | 38 | The test runner script does the following (pseudocode): 39 | 40 | // First, transform all test files so they can be run in lowjs: 41 | 42 | if test/node does not exist: 43 | clone official node repository to test/node 44 | 45 | nodeTestFiles = test/node/test 46 | ourCustomTestFiles = test/tests 47 | 48 | for each sourceFile in nodeTestFiles and ourCustomTestFiles, recursively: 49 | if sourceFile in nodeTestFiles 50 | destFile = test/compiled/node/ 51 | else 52 | destFile = test/compiled/ 53 | if destFile exists and sourceFile not newer than destFile: 54 | continue, nothing changed 55 | if file is javascript: 56 | if file contains '// Flags:' (tests node command-line switches): 57 | continue, irrelevant for lowjs for now 58 | else 59 | transform sourceFile to es5 60 | write output to destFile 61 | else 62 | copy sourceFile to destFile 63 | 64 | // Of course we need to compile lowjs via make. make will only compile the changed parts, so subsequent make calls should be fast enough: 65 | 66 | run make in project directory 67 | 68 | // Now we need to actually run the test files: 69 | 70 | If no glob patterns have been specified on the command line, all files named test-*.js and test.js in test/compiled are selected (recursively) for testing. 71 | 72 | for each test file: 73 | run file with node, so we have a reference result 74 | if node failed on test file: 75 | continue, no need to test with lowjs 76 | run test file with lowjs 77 | 78 | All test results are written to a summary html file at the end of the run. The location is printed to stdout. Each test result (one per test file) is annotated in the html file. The following information is stored alongside each test result: 79 | * the output and exit code of the test, if any 80 | * information about es5 transformation failure, if applicable 81 | * did node fail or did lowjs fail? If node failed, lowjs was not tested, and the cause should be determined why node failed. Maybe the node version is outdated. At the time of this writing node v10.8 is preferred. Maybe the test itsself is buggy or not suitable for specific node versions. 82 | * timeout: the test timed out and had to be killed. The timeout interval is hardcoded in the test runner. 83 | * crash: the lowjs/node process recieved a signal, indicating that the test crashed and did not end on its own accord. 84 | * error: the test returned a non-zero result code, e.g. an error was thrown, due to a failed assertion or another error. 85 | * ok: test process ended normally with exit code zero. 86 | -------------------------------------------------------------------------------- /test/bugs/duk_crash_TR20180627.c: -------------------------------------------------------------------------------- 1 | /* 2 | * duk_crash.c 3 | * 4 | * Creates Duktape heap, attachs fake debugger which resumes and then does infinite recursion 5 | * Should produce fatal error, but crashes the current Duktape version 6 | * 7 | * Tested with Duktape commit 26f00693780c976b4e490af68c022bccba9d80c0 8 | * and the following configuration: 9 | -DDUK_USE_EXEC_TIMEOUT_CHECK=\*\(unsigned\ char\ \*\) \ 10 | -DDUK_USE_INTERRUPT_COUNTER \ 11 | -DDUK_USE_FATAL_HANDLER \ 12 | -DDUK_USE_DEBUGGER_SUPPORT \ 13 | -DDUK_USE_DEBUGGER_PAUSE_UNCAUGHT \ 14 | -DDUK_USE_DEBUGGER_INSPECT \ 15 | -DDUK_USE_DEBUGGER_THROW_NOTIFY \ 16 | -DDUK_USE_GLOBAL_BUILTIN \ 17 | -DDUK_USE_BOOLEAN_BUILTIN \ 18 | -DDUK_USE_ARRAY_BUILTIN \ 19 | -DDUK_USE_OBJECT_BUILTIN \ 20 | -DDUK_USE_FUNCTION_BUILTIN \ 21 | -DDUK_USE_STRING_BUILTIN \ 22 | -DDUK_USE_NUMBER_BUILTIN \ 23 | -DDUK_USE_DATE_BUILTIN \ 24 | -DDUK_USE_REGEXP_SUPPORT \ 25 | -DDUK_USE_MATH_BUILTIN \ 26 | -DDUK_USE_JSON_BUILTIN \ 27 | -DDUK_USE_BUFFEROBJECT_SUPPORT \ 28 | -DDUK_USE_ENCODING_BUILTINS \ 29 | -DDUK_USE_PERFORMANCE_BUILTIN \ 30 | -DDUK_USE_OBJECT_BUILTIN \ 31 | -DDUK_USE_ES6_PROXY \ 32 | -DDUK_USE_GLOBAL_BINDING \ 33 | -DDUK_USE_SYMBOL_BUILTIN \ 34 | -DDUK_USE_SECTION_B 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include "duktape.h" 42 | 43 | /* 44 | * We fake a debugger here, which directly sends the resume command, and nothing more 45 | */ 46 | 47 | int sent_resume = 0; 48 | 49 | duk_size_t read_cb(void *udata, char *buffer, duk_size_t length) 50 | { 51 | if(sent_resume == 3) 52 | { 53 | printf("Asking for more data after resume! Unexpected result, exiting!\n"); 54 | exit(EXIT_FAILURE); 55 | } 56 | 57 | int at = 0; 58 | if(length && sent_resume == 0) 59 | { 60 | buffer[at++] = 0x01; /* DUK_DBG_IB_REQUEST */ 61 | length--; 62 | sent_resume = 1; 63 | } 64 | if(length && sent_resume == 1) 65 | { 66 | buffer[at++] = (char)0x80 | 0x13; /* DUK_DBG_CMD_RESUME */ 67 | length--; 68 | sent_resume = 2; 69 | } 70 | if(length && sent_resume == 2) 71 | { 72 | buffer[at++] = 0x00; /* DUK_DBG_IB_EOM */ 73 | length--; 74 | sent_resume = 3; 75 | } 76 | 77 | return at; 78 | } 79 | 80 | duk_size_t write_cb(void *udata, const char *buffer, duk_size_t length) 81 | { 82 | return length; 83 | } 84 | 85 | duk_size_t peek_cb(void *udata) 86 | { 87 | return 3 - sent_resume; 88 | } 89 | 90 | void detached_cb(duk_context *ctx, void *udata) 91 | { 92 | printf("Debugger detached! Unexpected result, exiting!\n"); 93 | exit(EXIT_FAILURE); 94 | } 95 | 96 | void fatal_cb(void *udata, const char *msg) 97 | { 98 | if(strcmp(msg, "uncaught: 'callstack limit'") == 0) 99 | { 100 | printf("Test passed!\n"); 101 | exit(EXIT_SUCCESS); 102 | } 103 | else 104 | { 105 | printf("%s. Unexpected result, exiting!\n", msg); 106 | exit(EXIT_FAILURE); 107 | } 108 | } 109 | 110 | int main() 111 | { 112 | char byte = 0; // we use DDUK_USE_EXEC_TIMEOUT_CHECK=\*\(unsigned\ char\ \*\) 113 | // but you do not need to use this to reproduce the bug 114 | duk_context *ctx = duk_create_heap(NULL, NULL, NULL, &byte, fatal_cb); 115 | 116 | duk_debugger_attach(ctx, read_cb, write_cb, peek_cb, NULL, NULL, NULL, detached_cb, NULL); 117 | duk_eval_string(ctx, "function a() { a(); } a();"); 118 | 119 | printf("Did not hit fatal handler. Unexpected result, exiting!\n"); 120 | return EXIT_FAILURE; 121 | } 122 | -------------------------------------------------------------------------------- /test/bugs/duk_crash_TR20180706.c: -------------------------------------------------------------------------------- 1 | /* 2 | * duk_crash.c 3 | * 4 | * Should result into Maximum call stack size exceeded 5 | * But results into Segmentation fault 6 | * 7 | * Tested with Duktape commit 26f00693780c976b4e490af68c022bccba9d80c0 8 | * and the following configuration: 9 | -DDUK_USE_EXEC_TIMEOUT_CHECK=\*\(unsigned\ char\ \*\) \ 10 | -DDUK_USE_INTERRUPT_COUNTER \ 11 | -DDUK_USE_FATAL_HANDLER \ 12 | -DDUK_USE_DEBUGGER_SUPPORT \ 13 | -DDUK_USE_DEBUGGER_PAUSE_UNCAUGHT \ 14 | -DDUK_USE_DEBUGGER_INSPECT \ 15 | -DDUK_USE_DEBUGGER_THROW_NOTIFY \ 16 | -DDUK_USE_GLOBAL_BUILTIN \ 17 | -DDUK_USE_BOOLEAN_BUILTIN \ 18 | -DDUK_USE_ARRAY_BUILTIN \ 19 | -DDUK_USE_OBJECT_BUILTIN \ 20 | -DDUK_USE_FUNCTION_BUILTIN \ 21 | -DDUK_USE_STRING_BUILTIN \ 22 | -DDUK_USE_NUMBER_BUILTIN \ 23 | -DDUK_USE_DATE_BUILTIN \ 24 | -DDUK_USE_REGEXP_SUPPORT \ 25 | -DDUK_USE_MATH_BUILTIN \ 26 | -DDUK_USE_JSON_BUILTIN \ 27 | -DDUK_USE_BUFFEROBJECT_SUPPORT \ 28 | -DDUK_USE_ENCODING_BUILTINS \ 29 | -DDUK_USE_PERFORMANCE_BUILTIN \ 30 | -DDUK_USE_OBJECT_BUILTIN \ 31 | -DDUK_USE_ES6_PROXY \ 32 | -DDUK_USE_GLOBAL_BINDING \ 33 | -DDUK_USE_SYMBOL_BUILTIN \ 34 | -DDUK_USE_SECTION_B 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include "duktape.h" 42 | 43 | void fatal_cb(void *udata, const char *msg) 44 | { 45 | if(strcmp(msg, "uncaught: 'callstack limit'") == 0) 46 | { 47 | printf("Test passed!\n"); 48 | exit(EXIT_SUCCESS); 49 | } 50 | else 51 | { 52 | printf("%s. Unexpected result, exiting!\n", msg); 53 | exit(EXIT_FAILURE); 54 | } 55 | } 56 | 57 | int main() 58 | { 59 | char byte = 0; // we use DDUK_USE_EXEC_TIMEOUT_CHECK=\*\(unsigned\ char\ \*\) 60 | // but you do not need to use this to reproduce the bug 61 | duk_context *ctx = duk_create_heap(NULL, NULL, NULL, &byte, fatal_cb); 62 | 63 | duk_eval_string(ctx, "function AClass() {} \ 64 | Object.defineProperty(AClass, Symbol.hasInstance, { \ 65 | value: function (object) { \ 66 | return object instanceof this; \ 67 | } \ 68 | }); \ 69 | var w = new AClass(); \ 70 | w instanceof AClass; \ 71 | "); 72 | 73 | printf("No fatal handler called. Unexpected result, exiting!\n"); 74 | return EXIT_FAILURE; 75 | } 76 | -------------------------------------------------------------------------------- /test/bugs/native_Reflect_contruct.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The following code, created by Babel, currently makes DukTape output 3 | * "unsupported" if DukTape's Reflect.construct is used. To work around 4 | * this, Reflect.construct is deleted in init.js 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // BABEL INTERNAL HELPERS 10 | 11 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 12 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 13 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 14 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 15 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 16 | function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } 17 | function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } 18 | function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } 19 | function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } 20 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 21 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 22 | 23 | // ACTUAL CODE STARTS HERE 24 | 25 | var FileNotFoundError = function (_Error) { 26 | _inherits(FileNotFoundError, _Error); 27 | 28 | function FileNotFoundError(file, type) { 29 | var _this; 30 | 31 | _classCallCheck(this, FileNotFoundError); 32 | 33 | _this = _possibleConstructorReturn(this, _getPrototypeOf(FileNotFoundError).call(this, 'File not found: ' + file + ', type "' + type + '"')); 34 | _this.name = 'FileNotFoundError'; 35 | _this.file = file; 36 | _this.type = type; 37 | return _this; 38 | } 39 | 40 | return FileNotFoundError; 41 | }(_wrapNativeSuper(Error)); 42 | 43 | // DukTape error "unsupported" 44 | new FileNotFoundError('filename', 'type'); 45 | -------------------------------------------------------------------------------- /test/bugs/ts_not_valid_es5_TR20180702.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | * This broke some Node.JS library code: 5 | * The following valid ES6 is not transpiled to valid ES5 6 | * with TypeScript (it keeps the functions as they are, but 7 | * ES5 strict mode forbids functions at the top of ifs, breaks Duktape) 8 | * Babel does it correctly, however. 9 | * Will not be fixed soon according to TS issues. 10 | */ 11 | 12 | if(a()) { 13 | function b() { 14 | console.log("X"); 15 | } 16 | b(); 17 | } else { 18 | function b() { 19 | console.log("X"); 20 | } 21 | b(); 22 | } 23 | -------------------------------------------------------------------------------- /test/bugs/ts_not_valid_es5_TR20180702.txt: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | * This broke some Node.JS library code: 5 | * The following valid ES6 is not transpiled to valid ES5 6 | * with TypeScript (it keeps the functions as they are, but 7 | * ES5 strict mode forbids functions at the top of ifs, breaks Duktape) 8 | * Babel does it correctly, however. 9 | * Will not be fixed soon according to TS issues. 10 | */ 11 | 12 | if(a()) { 13 | function b() { 14 | console.log("X"); 15 | } 16 | b(); 17 | } else { 18 | function b() { 19 | console.log("X"); 20 | } 21 | b(); 22 | } 23 | -------------------------------------------------------------------------------- /test/tests/assert_throws_stack.out: -------------------------------------------------------------------------------- 1 | assert.js:* 2 | throw err; 3 | ^ 4 | 5 | AssertionError [ERR_ASSERTION]: Input A expected to strictly deep-equal input B: 6 | + expected - actual 7 | 8 | - Comparison {} 9 | + Comparison { 10 | + bar: true 11 | + } 12 | at Object. (*assert_throws_stack.js:*:*) 13 | at * 14 | at * 15 | at * 16 | at * 17 | at * 18 | at * 19 | at * 20 | at * 21 | -------------------------------------------------------------------------------- /test/tests/test-assert-throws-stack.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert').strict; 4 | assert.throws(function() { throw new Error('foo'); }, { bar: true }); 5 | -------------------------------------------------------------------------------- /test/tests/test-duplex-inheritance.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var stream = require('stream'); 3 | var net = require('net'); 4 | function AClass() { 5 | } 6 | assert((new stream.Duplex) instanceof stream.Readable, "Duplex not instance of Readable"); 7 | assert((new stream.Duplex) instanceof stream.Writable, "Duplex not instance of Writable"); 8 | assert((new net.Socket) instanceof stream.Readable, "Socket not instance of Readable"); 9 | assert((new net.Socket) instanceof stream.Writable, "Socket not instance of Writable"); 10 | assert(!((new AClass) instanceof stream.Readable), "AClass instance of Readable"); 11 | assert(!((new AClass) instanceof stream.Writable), "AClass instance of Writable"); 12 | -------------------------------------------------------------------------------- /test/tests/test-pause-stdin.js: -------------------------------------------------------------------------------- 1 | // Should exit 2 | process.stdin.on('data', function(c) {}); 3 | process.stdin.pause(); 4 | -------------------------------------------------------------------------------- /test/tests_script/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "scripts": { 7 | "build_summary": "cd summary && webpack --mode production && html-inline -i build/index.html -o ../summary.html -b build", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "dependencies": { 12 | "@babel/core": "^7.6.4", 13 | "@babel/preset-env": "^7.6.3", 14 | "chalk": "^2.4.1", 15 | "classnames": "^2.2.6", 16 | "execa": "^0.10.0", 17 | "fs-extra": "^7.0.0", 18 | "fs-readdir-recursive": "^1.1.0", 19 | "globby": "^8.0.1", 20 | "html-inline": "^1.2.0", 21 | "lodash": "^4.17.10", 22 | "react": "^16.4.2", 23 | "react-dom": "^16.4.2", 24 | "regenerator-runtime": "^0.13.3", 25 | "typescript": "^3.0.1", 26 | "yargs": "^15.3.1" 27 | }, 28 | "devDependencies": { 29 | "@types/classnames": "^2.2.6", 30 | "@types/execa": "^0.9.0", 31 | "@types/fs-extra": "^5.0.4", 32 | "@types/fs-readdir-recursive": "^1.0.0", 33 | "@types/globby": "^8.0.0", 34 | "@types/lodash": "^4.14.116", 35 | "@types/react": "^16.4.11", 36 | "@types/react-dom": "^16.0.7", 37 | "@types/yargs": "^11.1.1", 38 | "autoprefixer": "^9.1.1", 39 | "browser-sync": "^2.26.12", 40 | "clean-webpack-plugin": "^0.1.19", 41 | "css-loader": "^1.0.0", 42 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 43 | "html-webpack-plugin": "^3.2.0", 44 | "node-sass": "^4.14.1", 45 | "postcss-loader": "^3.0.0", 46 | "sass-loader": "^7.1.0", 47 | "source-map-support": "^0.5.8", 48 | "style-loader": "^0.22.1", 49 | "ts-loader": "^4.5.0", 50 | "ts-node": "^7.0.1", 51 | "typings-for-css-modules-loader": "^1.7.0", 52 | "webpack": "^4.43.0", 53 | "webpack-cli": "^3.1.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/tests_script/summary/.gitignore: -------------------------------------------------------------------------------- 1 | /data.json 2 | /build/ -------------------------------------------------------------------------------- /test/tests_script/summary/bs-config.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | |-------------------------------------------------------------------------- 4 | | Browser-sync config file 5 | |-------------------------------------------------------------------------- 6 | | 7 | | For up-to-date information about the options: 8 | | http://www.browsersync.io/docs/options/ 9 | | 10 | | There are more options than you see here, these are just the ones that are 11 | | set internally. See the website for more info. 12 | | 13 | | 14 | */ 15 | module.exports = { 16 | "ui": { 17 | "port": 3001 18 | }, 19 | "files": ['build/**/*'], 20 | "watchEvents": [ 21 | "add", "change", "unlink" 22 | ], 23 | "watch": false, 24 | "ignore": [], 25 | "single": false, 26 | "watchOptions": { 27 | "ignoreInitial": true 28 | }, 29 | "server": "./build", 30 | "proxy": false, 31 | "port": 3000, 32 | "middleware": false, 33 | "serveStatic": [], 34 | "ghostMode": { 35 | "clicks": true, 36 | "scroll": true, 37 | "location": true, 38 | "forms": { 39 | "submit": true, 40 | "inputs": true, 41 | "toggles": true 42 | } 43 | }, 44 | "logLevel": "info", 45 | "logPrefix": "Browsersync", 46 | "logConnections": false, 47 | "logFileChanges": true, 48 | "logSnippet": true, 49 | "rewriteRules": [], 50 | "open": "local", 51 | "browser": "default", 52 | "cors": false, 53 | "xip": false, 54 | "hostnameSuffix": false, 55 | "reloadOnRestart": false, 56 | "notify": true, 57 | "scrollProportionally": true, 58 | "scrollThrottle": 0, 59 | "scrollRestoreTechnique": "window.name", 60 | "scrollElements": [], 61 | "scrollElementMapping": [], 62 | "reloadDelay": 0, 63 | "reloadDebounce": 500, 64 | "reloadThrottle": 0, 65 | "plugins": [], 66 | "injectChanges": true, 67 | "startPath": null, 68 | "minify": true, 69 | "host": null, 70 | "localOnly": false, 71 | "codeSync": true, 72 | "timestamps": true, 73 | "clientEvents": [ 74 | "scroll", 75 | "scroll:element", 76 | "input:text", 77 | "input:toggles", 78 | "form:submit", 79 | "form:reset", 80 | "click" 81 | ], 82 | "socket": { 83 | "socketIoOptions": { 84 | "log": false 85 | }, 86 | "socketIoClientConfig": { 87 | "reconnectionAttempts": 50 88 | }, 89 | "path": "/browser-sync/socket.io", 90 | "clientPath": "/browser-sync", 91 | "namespace": "/browser-sync", 92 | "clients": { 93 | "heartbeatTimeout": 5000 94 | } 95 | }, 96 | "tagNames": { 97 | "less": "link", 98 | "scss": "link", 99 | "css": "link", 100 | "jpg": "img", 101 | "jpeg": "img", 102 | "png": "img", 103 | "svg": "img", 104 | "gif": "img", 105 | "js": "script" 106 | }, 107 | "injectNotification": false 108 | }; -------------------------------------------------------------------------------- /test/tests_script/summary/index_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= htmlWebpackPlugin.options.title %> 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /test/tests_script/summary/main.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { TestResultsComp } from './testResults'; 4 | import { TestResult } from './result'; 5 | import data from './data.json'; 6 | 7 | let prio = { 8 | ok: 0, 9 | transpile_failed: 1, 10 | error: 2, 11 | timeout: 3, 12 | crashed: 4 13 | } 14 | let results = data as TestResult[]; 15 | results = results.sort((r1, r2) => prio[r1.resultType] > prio[r2.resultType] ? -1 : prio[r1.resultType] === prio[r2.resultType] ? r1.file < r2.file ? -1 : 1 : 1); 16 | 17 | ReactDOM.render(, document.getElementById('app')) -------------------------------------------------------------------------------- /test/tests_script/summary/result.ts: -------------------------------------------------------------------------------- 1 | 2 | export type ResultType = 'ok' | 'error' | 'crashed' | 'timeout' | 'transpile_failed'; 3 | 4 | export interface TestResult { 5 | file: string; 6 | output: string; 7 | code: number | null; 8 | signal: string | null; 9 | resultType: ResultType; 10 | nodeFailed: boolean; 11 | } -------------------------------------------------------------------------------- /test/tests_script/summary/styles.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | background-color: lightgrey; 3 | width: 100px; 4 | height: 20px; 5 | border-radius: 3px; 6 | cursor: pointer; 7 | margin-bottom: 30px; 8 | margin-left: 10px; 9 | margin-right: 10px; 10 | padding: 10px; 11 | display: flex; 12 | box-shadow: 1px 1px 3px 3px grey; 13 | justify-content: center; 14 | align-items: center; 15 | &:hover { 16 | background-color: lighten(lightgrey, 5%); 17 | } 18 | } 19 | 20 | .buttons { 21 | display: flex; 22 | } 23 | 24 | .results-container { 25 | align-items: center; 26 | display: flex; 27 | flex-direction: column; 28 | } 29 | 30 | .results { 31 | max-width: 1600px; 32 | margin: auto; 33 | font-family: 'Courier New', Courier, monospace; 34 | display: flex; 35 | flex-direction: column; 36 | .result { 37 | margin: 2px; 38 | border: 1px solid darkgray; 39 | display: flex; 40 | flex-direction: column; 41 | &.open { 42 | display: block; 43 | } 44 | &.closed { 45 | display: block; 46 | } 47 | $summaryColor:lightgrey; 48 | .summary { 49 | padding: 5px; 50 | justify-content: space-between; 51 | cursor: pointer; 52 | display: flex; 53 | &:hover { 54 | filter: brightness(105%); 55 | } 56 | .file { 57 | display: block; 58 | flex: 1 1 auto; 59 | } 60 | .node-failed { 61 | font-weight: bold; 62 | flex: 0 0 120px; 63 | } 64 | .status-string { 65 | user-select: none; 66 | flex: 0 0 90px; 67 | text-align: right; 68 | } 69 | } 70 | .detail { 71 | padding: 5px; 72 | .row { 73 | padding: 5px; 74 | display: flex; 75 | .header { 76 | flex: 0 0 100px; 77 | font-weight: bold; 78 | } 79 | .text { 80 | border: 1px solid #eee; 81 | padding: 4px; 82 | flex: 1 1 auto; 83 | overflow: auto; 84 | white-space: pre-wrap; 85 | } 86 | } 87 | } 88 | } 89 | $okColor:rgb(209, 252, 209); 90 | $failColor:rgb(255, 251, 193); 91 | .ok { 92 | background-color: $okColor; 93 | } 94 | .error { 95 | background-color: $failColor; 96 | } 97 | .crashed { 98 | background-color: rgb(255, 181, 181); 99 | } 100 | .timeout { 101 | background-color: rgb(162, 184, 255); 102 | } 103 | .transpile_failed { 104 | background-color: rgb(162, 249, 255); 105 | } 106 | } -------------------------------------------------------------------------------- /test/tests_script/summary/testResult.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import classNames from 'classnames'; 3 | import * as s from './styles.scss'; 4 | import { TestResult } from './result'; 5 | 6 | export interface TestResultProps { 7 | result: TestResult; 8 | open: boolean; 9 | toggleOpen(): void; 10 | } 11 | 12 | export class TestResultComp extends React.PureComponent { 13 | constructor(props: TestResultProps) { 14 | super(props); 15 | } 16 | 17 | render() { 18 | const { toggleOpen, open, result: { file, output, code, signal, resultType, nodeFailed } } = this.props; 19 | const statusClass = s[resultType]; 20 | 21 | return
25 |
{ 26 | toggleOpen(); 27 | }}> 28 |
{file}
29 |
{nodeFailed ? 'NODE FAILED' : null}
30 |
{resultType.toUpperCase()}
31 |
32 | { 33 | open ? 34 |
35 |
36 |
37 | Output 38 |
39 |
40 | {output} 41 |
42 |
43 | {typeof code === 'number' ?
44 |
45 | Exit code 46 |
47 |
48 | {code} 49 |
50 |
: null} 51 | {signal ?
52 |
53 | Signal 54 |
55 |
56 | {signal} 57 |
58 |
: null} 59 |
60 | : null 61 | } 62 |
63 | 64 | } 65 | } -------------------------------------------------------------------------------- /test/tests_script/summary/testResults.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { TestResultComp } from './testResult'; 3 | import * as s from './styles.scss'; 4 | import { TestResult } from './result'; 5 | import { chain } from 'lodash'; 6 | 7 | interface ResultsProps { 8 | results: TestResult[]; 9 | } 10 | 11 | interface ResultsState { 12 | open: { 13 | [file: string]: boolean; 14 | } 15 | } 16 | 17 | export class TestResultsComp extends React.PureComponent { 18 | 19 | constructor(props: ResultsProps) { 20 | super(props); 21 | this.state = { open: {} }; 22 | } 23 | 24 | render() { 25 | const { results } = this.props; 26 | return
27 |

Test results

28 | 37 |
38 | { 39 | results.map((r, i) => { 40 | return { 41 | this.setState(s => ({ open: { ...s.open, [r.file]: !s.open[r.file] } })) 42 | }} open={!!this.state.open[r.file]} result={r} key={i} /> 43 | }) 44 | } 45 |
46 |
47 | } 48 | } -------------------------------------------------------------------------------- /test/tests_script/summary/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "moduleResolution": "node", 5 | "target": "es6", 6 | "jsx": "react", 7 | } 8 | } -------------------------------------------------------------------------------- /test/tests_script/summary/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.scss'; 2 | declare module '*.json'; -------------------------------------------------------------------------------- /test/tests_script/summary/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path') 3 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const autoprefixer = require('autoprefixer'); 6 | const ExtractTextPlugin = require("extract-text-webpack-plugin"); 7 | 8 | const mainConfig = (env, options) => { 9 | 10 | const mode = options.mode; 11 | const isProduction = mode === 'production'; 12 | const outDir = 'build'; 13 | const extractSass = new ExtractTextPlugin({ 14 | filename: `styles.[chunkhash].css`, 15 | disable: true 16 | }); 17 | const getExtract = (arg) => { 18 | return extractSass.extract({ 19 | use: [ 20 | arg, 21 | { 22 | loader: "postcss-loader", 23 | options: { 24 | plugins: () => [autoprefixer({ 25 | browsers: [ 26 | 'last 3 version', 27 | 'ie >= 10' 28 | ] 29 | })] 30 | } 31 | }, 32 | { loader: "sass-loader" } 33 | ], 34 | fallback: "style-loader" 35 | }); 36 | } 37 | return { 38 | entry: { 39 | main: './main.tsx' 40 | }, 41 | output: { 42 | filename: "[name].bundle.js", 43 | path: path.resolve(`${__dirname}/${outDir}`) 44 | }, 45 | resolve: { 46 | extensions: [".ts", ".tsx", ".js", ".json"] 47 | }, 48 | module: { 49 | rules: [ 50 | { 51 | test: /\.tsx?$/, 52 | loader: "ts-loader" 53 | }, 54 | { 55 | test: /\.(css|sass|scss)$/, 56 | use: getExtract({ 57 | loader: "typings-for-css-modules-loader", 58 | options: { 59 | namedExport: true, 60 | camelCase: true, 61 | modules: true, 62 | localIdentName: '[local]--[hash:base64:5]', 63 | minimize: isProduction 64 | } 65 | }) 66 | }, 67 | ] 68 | }, 69 | plugins: [ 70 | new CleanWebpackPlugin(outDir), 71 | new HtmlWebpackPlugin({ 72 | title: 'Test results', 73 | filename: 'index.html', 74 | minify: isProduction ? { 75 | collapseWhitespace: true, 76 | collapseInlineTagWhitespace: true, 77 | removeComments: true, 78 | removeRedundantAttributes: true 79 | } : false, 80 | template: 'index_template.html', 81 | isProduction 82 | }), 83 | new webpack.WatchIgnorePlugin([ 84 | /scss\.d\.ts$/ 85 | ]), 86 | extractSass 87 | ] 88 | }; 89 | } 90 | 91 | module.exports = mainConfig; -------------------------------------------------------------------------------- /test/tests_script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "strict": false, 5 | "moduleResolution": "node", 6 | "target": "es6", 7 | "esModuleInterop": true, 8 | }, 9 | "files": [ 10 | "tests.ts", 11 | "summary/result.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /util/dist-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIST_NAME=lowjs-`uname | tr A-Z a-z`-`uname -m`-`git show -s --format=%cd --date=format:%Y%m%d`_`git rev-parse --short HEAD` 4 | 5 | # Cleanup 6 | rm -rf dist $DIST_NAME $DIST_NAME.tar $DIST_NAME.tar.gz 7 | 8 | # Build directory 9 | mkdir $DIST_NAME 10 | 11 | if [ `uname -s` = Linux ] 12 | then 13 | cp -r LICENSE README.md $DIST_NAME 14 | 15 | mkdir $DIST_NAME/{bin,lib} 16 | cp bin/low $DIST_NAME/lib/low-exe 17 | gcc util/dist-loader.c -o $DIST_NAME/bin/low -static -O3 18 | strip $DIST_NAME/bin/low 19 | strip $DIST_NAME/lib/low-exe 20 | deps=$(ldd bin/low | awk 'BEGIN{ORS=" "}$1 ~/^\//{print $1}$3~/^\//{print $3}' | sed 's/,$/\n/') 21 | for dep in $deps 22 | do 23 | cp "$dep" $DIST_NAME/lib 24 | done 25 | 26 | if [ ! -f $DIST_NAME/lib/ld-musl* ] 27 | then 28 | echo "This system is not based on musl (like Alpine Linux)." 29 | echo 30 | echo "A distribution with glibc does not work everywhere, as glibc opens config files on the" 31 | echo "system on its own. Please build on a different system." 32 | echo 33 | echo "Creating distribution failed!" 34 | 35 | rm -rf $DIST_NAME 36 | exit 1 37 | fi 38 | 39 | mv $DIST_NAME/lib/ld-musl* lib/ld-musl.so 40 | chmod 755 $DIST_NAME/lib/* 41 | cp -r lib/* $DIST_NAME/lib 42 | else 43 | cp -r bin lib LICENSE README.md $DIST_NAME 44 | strip $DIST_NAME/bin/low 45 | fi 46 | 47 | rm $DIST_NAME/lib/BUILT 48 | 49 | # Tar and zip 50 | tar -c $DIST_NAME > $DIST_NAME.tar 51 | gzip $DIST_NAME.tar 52 | mkdir dist 53 | mv $DIST_NAME.tar.gz dist 54 | rm -rf $DIST_NAME $DIST_NAME.tar 55 | -------------------------------------------------------------------------------- /util/dist-loader.c: -------------------------------------------------------------------------------- 1 | // loader to be able to distribute dynamic libs with executable 2 | // used when creating distributable with make dist 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | char ldPath[] = "../lib"; 12 | char ld[] = "../lib/ld-musl.so"; 13 | char bin[] = "../lib/low-exe"; 14 | char fName[1024]; 15 | char argv0[32]; 16 | sprintf(argv0, "/proc/%d/exe", getpid()); 17 | memset(fName, 0, sizeof(fName)); 18 | readlink(argv0, fName, sizeof(fName) - 1); 19 | int i; 20 | for(i = strlen(fName); i > 0; i--) 21 | if(fName[i - 1] == '/') 22 | break; 23 | char *path = malloc(i + sizeof(ld)); 24 | memcpy(path, fName, i); 25 | strcpy(path + i, ldPath); 26 | setenv("LD_LIBRARY_PATH", path, 1); 27 | strcpy(path + i, ld); 28 | char **argvNew = malloc((argc + 3) * sizeof(char *)); 29 | argvNew[0] = path; 30 | argvNew[1] = malloc(i + sizeof(bin)); 31 | memcpy(argvNew[1], fName, i); 32 | strcpy(argvNew[1] + i, bin); 33 | for(i = 0; i < argc; i++) 34 | argvNew[i + 2] = argv[i]; 35 | argvNew[argc + 2] = NULL; 36 | execv(path, argvNew); 37 | fprintf(stderr, "Cannot execute low main binary!\n"); 38 | return EXIT_FAILURE; 39 | } 40 | -------------------------------------------------------------------------------- /util/dukc.c: -------------------------------------------------------------------------------- 1 | // low.js Duktape precompiler 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "duktape.h" 12 | 13 | // Stubs, used by DukTape to call lowjs_esp32 14 | // Are unused in POSIX version of lowjs 15 | char user_lock_debugstream(char lock, char block) 16 | { 17 | return 0; 18 | } 19 | void user_broken_debugstream() {} 20 | #ifdef __cplusplus 21 | extern "C" 22 | #endif /* __cplusplus */ 23 | int neoniousGetStackFree() 24 | { 25 | return 10000000; 26 | } 27 | void code_print_error() {} 28 | void code_watchdog_event_loop() {} 29 | void code_gc() {} 30 | 31 | int pathStartLen; 32 | 33 | static void fatal_handler(void *udata, const char *msg) 34 | { 35 | fprintf(stderr, "%s\n", msg); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | char handle1(const char *fPathIn, const char *fPathOut) 40 | { 41 | // Get file name 42 | int pos = strlen(fPathIn); 43 | char file_name[pos + 5]; 44 | int end = pos; 45 | for(; pos > 0; pos--) 46 | { 47 | if(fPathIn[pos] == '.') 48 | end = pos; 49 | if(fPathIn[pos - 1] == '/' || fPathIn[pos - 1] == '\\') 50 | break; 51 | } 52 | pos = pathStartLen + 1; 53 | 54 | memcpy(file_name, "lib:", 4); 55 | memcpy(file_name + 4, fPathIn + pos, end - pos); 56 | file_name[4 + end - pos] = '\0'; 57 | 58 | printf("+ %s...\n", file_name); 59 | 60 | // Read in file 61 | FILE *f = fopen(fPathIn, "r"); 62 | if(!f) 63 | { 64 | fprintf(stderr, "Cannot open '%s' for reading!\n", fPathIn); 65 | fclose(f); 66 | return 0; 67 | } 68 | 69 | int len; 70 | if(fseek(f, 0, SEEK_END) < 0 || (len = ftell(f)) < 0 || 71 | fseek(f, 0, SEEK_SET) < 0) 72 | { 73 | fprintf(stderr, "Cannot get file size of '%s'!\n", fPathIn); 74 | fclose(f); 75 | return 0; 76 | } 77 | 78 | char *data = (char *)malloc(1024 + len); 79 | if(!data) 80 | { 81 | fprintf(stderr, "Memory full!\n"); 82 | fclose(f); 83 | return 0; 84 | } 85 | 86 | // Add CommonJS wrapper 87 | strcpy(data, "function(exports,require,module,__filename,__dirname){"); 88 | pos = strlen(data); 89 | 90 | if(len && fread(data + pos, len, 1, f) != 1) 91 | { 92 | fprintf(stderr, "Cannot read '%s'!\n", fPathIn); 93 | fclose(f); 94 | return 0; 95 | } 96 | 97 | strcpy(data + pos + len, "}"); 98 | len += pos + 1; 99 | 100 | // Setup DukTape 101 | duk_context *heap = duk_create_heap(NULL, NULL, NULL, NULL, fatal_handler); 102 | if(!heap) 103 | { 104 | fprintf(stderr, "Cannot create DukTape heap!\n"); 105 | return 0; 106 | } 107 | 108 | duk_push_string(heap, file_name); 109 | duk_compile_lstring_filename( 110 | heap, DUK_COMPILE_FUNCTION | DUK_COMPILE_STRICT, data, len); 111 | free(data); 112 | duk_dump_function(heap); 113 | 114 | duk_size_t outLen = 0; 115 | data = (char *)duk_get_buffer_data(heap, 0, &outLen); 116 | if(!data || !outLen) 117 | { 118 | fprintf(stderr, "DukTape error!\n"); 119 | return 0; 120 | } 121 | 122 | f = fopen(fPathOut, "w"); 123 | if(!f) 124 | { 125 | fprintf(stderr, "Cannot open '%s' for writing!\n", fPathOut); 126 | return 0; 127 | } 128 | if(fwrite(data, outLen, 1, f) != 1) 129 | { 130 | fprintf(stderr, "Cannot write '%s'!\n", fPathOut); 131 | fclose(f); 132 | return 0; 133 | } 134 | fclose(f); 135 | 136 | return 1; 137 | } 138 | 139 | char handle_dir(const char *pathIn, const char *pathOut) 140 | { 141 | DIR *dir = opendir(pathIn); 142 | if(!dir) 143 | { 144 | fprintf(stderr, "Cannot open '%s' for traversing!\n", pathIn); 145 | return 0; 146 | } 147 | 148 | int lenIn = strlen(pathIn); 149 | int lenOut = strlen(pathOut); 150 | struct dirent *ent; 151 | 152 | while((ent = readdir(dir)) != NULL) 153 | { 154 | if(ent->d_name[0] == '.') 155 | continue; 156 | 157 | int len = strlen(ent->d_name); 158 | char pathInFile[lenIn + strlen(ent->d_name) + 2]; 159 | sprintf(pathInFile, "%s/%s", pathIn, ent->d_name); 160 | char pathOutFile[lenOut + strlen(ent->d_name) + 5]; 161 | sprintf(pathOutFile, "%s/%s", pathOut, ent->d_name); 162 | 163 | if(ent->d_type == DT_DIR) 164 | { 165 | mkdir(pathOutFile, 0755); 166 | if(!handle_dir(pathInFile, pathOutFile)) 167 | return 0; 168 | } 169 | else 170 | { 171 | int pos = strlen(pathOutFile); 172 | for(; pos > 0; pos--) 173 | { 174 | if(pathOutFile[pos] == '.') 175 | { 176 | strcpy(pathOutFile + pos, ".low"); 177 | } 178 | if(pathOutFile[pos - 1] == '/' || pathOutFile[pos - 1] == '\\') 179 | break; 180 | } 181 | 182 | if(!handle1(pathInFile, pathOutFile)) 183 | return 0; 184 | } 185 | } 186 | closedir(dir); 187 | return 1; 188 | } 189 | 190 | int main(int argc, char **argv) 191 | { 192 | if(argc != 3) 193 | { 194 | fprintf(stderr, "Syntax: %s in-dir out-dir\n", argc ? argv[0] : "dukc"); 195 | return EXIT_FAILURE; 196 | } 197 | 198 | pathStartLen = strlen(argv[1]); 199 | if(!handle_dir(argv[1], argv[2])) 200 | return EXIT_FAILURE; 201 | 202 | return EXIT_SUCCESS; 203 | } 204 | -------------------------------------------------------------------------------- /util/root-certs-extract.js: -------------------------------------------------------------------------------- 1 | // Extracts root certs from Node.JS, to make sure low.js uses the same root certs than Node.JS does 2 | // Requires Node > 12.3 3 | 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const tls = require('tls'); 7 | 8 | // Certs are joined to 1 string, allows fast path in low_tls.cpp 9 | let certs = tls.rootCertificates.join('\n').replace(new RegExp('\n\n', 'g'), '\n'); 10 | 11 | fs.writeFileSync(path.join(__dirname, 'root-certs.json'), JSON.stringify([certs])); 12 | --------------------------------------------------------------------------------