Browse Source

Signed-off-by: caner <5658514@qq.com>

caner 3 years ago
parent
commit
1a71235c8e

+ 2 - 29
.gitignore

@@ -1,30 +1,3 @@
-# ---> Node
-# Logs
-logs
-*.log
-npm-debug.log*
-
-# Runtime data
-pids
-*.pid
-*.seed
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directory
-# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
 node_modules
-
+npm-debug.log
+package-lock.json

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "src/kcp"]
+	path = src/kcp
+	url = git@github.com:skywind3000/kcp.git

+ 20 - 0
.travis.yml

@@ -0,0 +1,20 @@
+language: node_js
+node_js:
+    - "12"
+    - "10"
+    - "8"
+git:
+    submodules: false
+before_install:
+    - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
+    - git submodule update --init --recursive
+before_script:
+    - npm install -g grunt-cli
+env:
+    - CXX=g++-4.8
+addons:
+    apt:
+        sources:
+            - ubuntu-toolchain-r-test
+        packages:
+            - g++-4.8

+ 10 - 5
LICENSE

@@ -1,8 +1,13 @@
-MIT License
-Copyright (c) <year> <copyright holders>
+Copyright 2021 leenjewel
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
 
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+    http://www.apache.org/licenses/LICENSE-2.0
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 140 - 2
README.md

@@ -1,3 +1,141 @@
-# node-kcp
+node-kcp
+======================================
 
-kcp 协议
+[![Build Status][1]][2]
+
+[1]: https://api.travis-ci.org/leenjewel/node-kcp.svg?branch=master
+[2]: https://travis-ci.org/leenjewel/node-kcp
+
+
+[KCP Protocol](https://github.com/skywind3000/kcp) for Node.js
+
+### Test
+```
+1. win10 vistduio 2017 
+2. node 16.15.1
+```
+
+## HowTo
+
+### Build:
+
+```
+npm install -g node-gyp
+
+node-gyp configure
+
+git clone git@github.com:leenjewel/node-kcp
+
+cd node-kcp
+
+git submodule init
+
+git submodule update
+
+node-gyp build
+```
+
+## Example:
+
+### Install by npm
+
+```
+npm install node-kcp
+```
+
+### udpserver.js
+
+```
+var kcp = require('node-kcp');
+var dgram = require('dgram');
+var server = dgram.createSocket('udp4');
+var clients = {};
+var interval = 200;
+
+var output = function(data, size, context) {
+    server.send(data, 0, size, context.port, context.address);
+};
+
+server.on('error', (err) => {
+    console.log(`server error:\n${err.stack}`);
+    server.close();
+});
+
+server.on('message', (msg, rinfo) => {
+    var k = rinfo.address+'_'+rinfo.port;
+    if (undefined === clients[k]) {
+        var context = {
+            address : rinfo.address,
+            port : rinfo.port
+        };
+        var kcpobj = new kcp.KCP(123, context);
+        kcpobj.nodelay(0, interval, 0, 0);
+        kcpobj.output(output);
+        clients[k] = kcpobj;
+    }
+    var kcpobj = clients[k];
+    kcpobj.input(msg);
+});
+
+server.on('listening', () => {
+    var address = server.address();
+    console.log(`server listening ${address.address} : ${address.port}`);
+    setInterval(() => {
+        for (var k in clients) {
+            var kcpobj = clients[k];
+        	kcpobj.update(Date.now());
+        	var recv = kcpobj.recv();
+        	if (recv) {
+            	console.log(`server recv ${recv} from ${kcpobj.context().address}:${kcpobj.context().port}`);
+           		kcpobj.send('RE-'+recv);
+       	 	}
+       	}
+    }, interval);
+});
+
+server.bind(41234);
+
+```
+
+### udpclient.js
+
+```
+var kcp = require('node-kcp');
+var kcpobj = new kcp.KCP(123, {address: '127.0.0.1', port: 41234});
+var dgram = require('dgram');
+var client = dgram.createSocket('udp4');
+var msg = 'hello world';
+var idx = 1;
+var interval = 200;
+
+kcpobj.nodelay(0, interval, 0, 0);
+
+kcpobj.output((data, size, context) => {
+    client.send(data, 0, size, context.port, context.address);
+});
+
+client.on('error', (err) => {
+    console.log(`client error:\n${err.stack}`);
+    client.close();
+});
+
+client.on('message', (msg, rinfo) => {
+    kcpobj.input(msg);
+});
+
+setInterval(() => {
+    kcpobj.update(Date.now());
+    var recv = kcpobj.recv();
+    if (recv) {
+        console.log(`client recv ${recv}`);
+        kcpobj.send(msg+(idx++));
+    }
+}, interval);
+
+kcpobj.send(msg+(idx++));
+
+```
+
+## About Pomelo and Pomelo-kcp
+
+If you want to use [node-kcp](https://github.com/leenjewel/node-kcp) in [pomelo](https://github.com/NetEase/pomelo/) server, you need [pomelo-kcp](https://github.com/leenjewel/pomelo-kcp)

+ 15 - 0
binding.gyp

@@ -0,0 +1,15 @@
+{
+    "targets": [
+        {
+            "target_name": "kcp",
+            "include_dirs": [
+                "<!(node -e \"require('nan')\")"
+            ],
+            "sources": [
+                "src/kcp/ikcp.c",
+                "src/kcpobject.cc",
+                "src/node-kcp.cc"
+            ]
+        }
+    ]
+}

BIN
build/Release/kcp.exp


BIN
build/Release/kcp.iobj


BIN
build/Release/kcp.ipdb


BIN
build/Release/kcp.lib


BIN
build/Release/kcp.node


BIN
build/Release/kcp.pdb


BIN
build/Release/obj/kcp/kcp.tlog/CL.command.1.tlog


BIN
build/Release/obj/kcp/kcp.tlog/CL.read.1.tlog


BIN
build/Release/obj/kcp/kcp.tlog/CL.write.1.tlog


+ 2 - 0
build/Release/obj/kcp/kcp.tlog/kcp.lastbuildstate

@@ -0,0 +1,2 @@
+#TargetFrameworkVersion=v4.0:PlatformToolSet=v141:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native64Bit:WindowsTargetPlatformVersion=10.0.17763.0
+Release|x64|C:\Users\Caner\Desktop\node-kcp\build\|

BIN
build/Release/obj/kcp/kcp.tlog/kcp.write.1u.tlog


BIN
build/Release/obj/kcp/kcp.tlog/link.command.1.tlog


BIN
build/Release/obj/kcp/kcp.tlog/link.read.1.tlog


BIN
build/Release/obj/kcp/kcp.tlog/link.write.1.tlog


BIN
build/Release/obj/kcp/src/kcp/ikcp.obj


BIN
build/Release/obj/kcp/src/kcpobject.obj


BIN
build/Release/obj/kcp/src/node-kcp.obj


BIN
build/Release/obj/kcp/win_delay_load_hook.obj


+ 19 - 0
build/binding.sln

@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2015
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kcp", "kcp.vcxproj", "{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Release|x64 = Release|x64
+		Debug|x64 = Debug|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}.Release|x64.ActiveCfg = Release|x64
+		{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}.Release|x64.Build.0 = Release|x64
+		{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}.Debug|x64.ActiveCfg = Debug|x64
+		{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}.Debug|x64.Build.0 = Debug|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 362 - 0
build/config.gypi

@@ -0,0 +1,362 @@
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+  "target_defaults": {
+    "cflags": [],
+    "default_configuration": "Release",
+    "defines": [],
+    "include_dirs": [],
+    "libraries": [],
+    "msbuild_toolset": "v141",
+    "msvs_windows_target_platform_version": "10.0.17763.0"
+  },
+  "variables": {
+    "asan": 0,
+    "coverage": "false",
+    "dcheck_always_on": 0,
+    "debug_nghttp2": "false",
+    "debug_node": "false",
+    "enable_lto": "false",
+    "enable_pgo_generate": "false",
+    "enable_pgo_use": "false",
+    "error_on_warn": "false",
+    "force_dynamic_crt": 0,
+    "host_arch": "x64",
+    "icu_data_in": "..\\..\\deps\\icu-tmp\\icudt70l.dat",
+    "icu_endianness": "l",
+    "icu_gyp_path": "tools/icu/icu-generic.gyp",
+    "icu_path": "deps/icu-small",
+    "icu_small": "false",
+    "icu_ver_major": "70",
+    "is_debug": 0,
+    "llvm_version": "0.0",
+    "napi_build_version": "8",
+    "nasm_version": "2.15",
+    "node_byteorder": "little",
+    "node_debug_lib": "false",
+    "node_enable_d8": "false",
+    "node_install_corepack": "true",
+    "node_install_npm": "true",
+    "node_library_files": [
+      "lib/assert.js",
+      "lib/async_hooks.js",
+      "lib/buffer.js",
+      "lib/child_process.js",
+      "lib/cluster.js",
+      "lib/console.js",
+      "lib/constants.js",
+      "lib/crypto.js",
+      "lib/dgram.js",
+      "lib/diagnostics_channel.js",
+      "lib/dns.js",
+      "lib/domain.js",
+      "lib/events.js",
+      "lib/fs.js",
+      "lib/http.js",
+      "lib/http2.js",
+      "lib/https.js",
+      "lib/inspector.js",
+      "lib/module.js",
+      "lib/net.js",
+      "lib/os.js",
+      "lib/path.js",
+      "lib/perf_hooks.js",
+      "lib/process.js",
+      "lib/punycode.js",
+      "lib/querystring.js",
+      "lib/readline.js",
+      "lib/repl.js",
+      "lib/stream.js",
+      "lib/string_decoder.js",
+      "lib/sys.js",
+      "lib/timers.js",
+      "lib/tls.js",
+      "lib/trace_events.js",
+      "lib/tty.js",
+      "lib/url.js",
+      "lib/util.js",
+      "lib/v8.js",
+      "lib/vm.js",
+      "lib/wasi.js",
+      "lib/worker_threads.js",
+      "lib/zlib.js",
+      "lib/_http_agent.js",
+      "lib/_http_client.js",
+      "lib/_http_common.js",
+      "lib/_http_incoming.js",
+      "lib/_http_outgoing.js",
+      "lib/_http_server.js",
+      "lib/_stream_duplex.js",
+      "lib/_stream_passthrough.js",
+      "lib/_stream_readable.js",
+      "lib/_stream_transform.js",
+      "lib/_stream_wrap.js",
+      "lib/_stream_writable.js",
+      "lib/_tls_common.js",
+      "lib/_tls_wrap.js",
+      "lib/assert/strict.js",
+      "lib/dns/promises.js",
+      "lib/fs/promises.js",
+      "lib/internal/abort_controller.js",
+      "lib/internal/assert.js",
+      "lib/internal/async_hooks.js",
+      "lib/internal/blob.js",
+      "lib/internal/blocklist.js",
+      "lib/internal/buffer.js",
+      "lib/internal/child_process.js",
+      "lib/internal/cli_table.js",
+      "lib/internal/constants.js",
+      "lib/internal/dgram.js",
+      "lib/internal/dtrace.js",
+      "lib/internal/encoding.js",
+      "lib/internal/errors.js",
+      "lib/internal/error_serdes.js",
+      "lib/internal/event_target.js",
+      "lib/internal/fixed_queue.js",
+      "lib/internal/freelist.js",
+      "lib/internal/freeze_intrinsics.js",
+      "lib/internal/heap_utils.js",
+      "lib/internal/histogram.js",
+      "lib/internal/http.js",
+      "lib/internal/idna.js",
+      "lib/internal/inspector_async_hook.js",
+      "lib/internal/js_stream_socket.js",
+      "lib/internal/linkedlist.js",
+      "lib/internal/net.js",
+      "lib/internal/options.js",
+      "lib/internal/priority_queue.js",
+      "lib/internal/promise_hooks.js",
+      "lib/internal/querystring.js",
+      "lib/internal/repl.js",
+      "lib/internal/socketaddress.js",
+      "lib/internal/socket_list.js",
+      "lib/internal/stream_base_commons.js",
+      "lib/internal/timers.js",
+      "lib/internal/trace_events_async_hooks.js",
+      "lib/internal/tty.js",
+      "lib/internal/url.js",
+      "lib/internal/util.js",
+      "lib/internal/v8_prof_polyfill.js",
+      "lib/internal/v8_prof_processor.js",
+      "lib/internal/validators.js",
+      "lib/internal/watchdog.js",
+      "lib/internal/worker.js",
+      "lib/internal/assert/assertion_error.js",
+      "lib/internal/assert/calltracker.js",
+      "lib/internal/bootstrap/environment.js",
+      "lib/internal/bootstrap/loaders.js",
+      "lib/internal/bootstrap/node.js",
+      "lib/internal/bootstrap/pre_execution.js",
+      "lib/internal/bootstrap/switches/does_not_own_process_state.js",
+      "lib/internal/bootstrap/switches/does_own_process_state.js",
+      "lib/internal/bootstrap/switches/is_main_thread.js",
+      "lib/internal/bootstrap/switches/is_not_main_thread.js",
+      "lib/internal/child_process/serialization.js",
+      "lib/internal/cluster/child.js",
+      "lib/internal/cluster/primary.js",
+      "lib/internal/cluster/round_robin_handle.js",
+      "lib/internal/cluster/shared_handle.js",
+      "lib/internal/cluster/utils.js",
+      "lib/internal/cluster/worker.js",
+      "lib/internal/console/constructor.js",
+      "lib/internal/console/global.js",
+      "lib/internal/crypto/aes.js",
+      "lib/internal/crypto/certificate.js",
+      "lib/internal/crypto/cipher.js",
+      "lib/internal/crypto/diffiehellman.js",
+      "lib/internal/crypto/dsa.js",
+      "lib/internal/crypto/ec.js",
+      "lib/internal/crypto/hash.js",
+      "lib/internal/crypto/hashnames.js",
+      "lib/internal/crypto/hkdf.js",
+      "lib/internal/crypto/keygen.js",
+      "lib/internal/crypto/keys.js",
+      "lib/internal/crypto/mac.js",
+      "lib/internal/crypto/pbkdf2.js",
+      "lib/internal/crypto/random.js",
+      "lib/internal/crypto/rsa.js",
+      "lib/internal/crypto/scrypt.js",
+      "lib/internal/crypto/sig.js",
+      "lib/internal/crypto/util.js",
+      "lib/internal/crypto/webcrypto.js",
+      "lib/internal/crypto/x509.js",
+      "lib/internal/debugger/inspect.js",
+      "lib/internal/debugger/inspect_client.js",
+      "lib/internal/debugger/inspect_repl.js",
+      "lib/internal/dns/promises.js",
+      "lib/internal/dns/utils.js",
+      "lib/internal/fs/dir.js",
+      "lib/internal/fs/promises.js",
+      "lib/internal/fs/read_file_context.js",
+      "lib/internal/fs/rimraf.js",
+      "lib/internal/fs/streams.js",
+      "lib/internal/fs/sync_write_stream.js",
+      "lib/internal/fs/utils.js",
+      "lib/internal/fs/watchers.js",
+      "lib/internal/fs/cp/cp-sync.js",
+      "lib/internal/fs/cp/cp.js",
+      "lib/internal/http2/compat.js",
+      "lib/internal/http2/core.js",
+      "lib/internal/http2/util.js",
+      "lib/internal/legacy/processbinding.js",
+      "lib/internal/main/check_syntax.js",
+      "lib/internal/main/eval_stdin.js",
+      "lib/internal/main/eval_string.js",
+      "lib/internal/main/inspect.js",
+      "lib/internal/main/print_help.js",
+      "lib/internal/main/prof_process.js",
+      "lib/internal/main/repl.js",
+      "lib/internal/main/run_main_module.js",
+      "lib/internal/main/worker_thread.js",
+      "lib/internal/modules/package_json_reader.js",
+      "lib/internal/modules/run_main.js",
+      "lib/internal/modules/cjs/helpers.js",
+      "lib/internal/modules/cjs/loader.js",
+      "lib/internal/modules/esm/assert.js",
+      "lib/internal/modules/esm/create_dynamic_module.js",
+      "lib/internal/modules/esm/fetch_module.js",
+      "lib/internal/modules/esm/formats.js",
+      "lib/internal/modules/esm/get_format.js",
+      "lib/internal/modules/esm/get_source.js",
+      "lib/internal/modules/esm/handle_process_exit.js",
+      "lib/internal/modules/esm/initialize_import_meta.js",
+      "lib/internal/modules/esm/load.js",
+      "lib/internal/modules/esm/loader.js",
+      "lib/internal/modules/esm/module_job.js",
+      "lib/internal/modules/esm/module_map.js",
+      "lib/internal/modules/esm/resolve.js",
+      "lib/internal/modules/esm/translators.js",
+      "lib/internal/perf/event_loop_delay.js",
+      "lib/internal/perf/event_loop_utilization.js",
+      "lib/internal/perf/nodetiming.js",
+      "lib/internal/perf/observe.js",
+      "lib/internal/perf/performance.js",
+      "lib/internal/perf/performance_entry.js",
+      "lib/internal/perf/timerify.js",
+      "lib/internal/perf/usertiming.js",
+      "lib/internal/perf/utils.js",
+      "lib/internal/per_context/domexception.js",
+      "lib/internal/per_context/messageport.js",
+      "lib/internal/per_context/primordials.js",
+      "lib/internal/policy/manifest.js",
+      "lib/internal/policy/sri.js",
+      "lib/internal/process/esm_loader.js",
+      "lib/internal/process/execution.js",
+      "lib/internal/process/per_thread.js",
+      "lib/internal/process/policy.js",
+      "lib/internal/process/promises.js",
+      "lib/internal/process/report.js",
+      "lib/internal/process/signal.js",
+      "lib/internal/process/task_queues.js",
+      "lib/internal/process/warning.js",
+      "lib/internal/process/worker_thread_only.js",
+      "lib/internal/readline/callbacks.js",
+      "lib/internal/readline/emitKeypressEvents.js",
+      "lib/internal/readline/interface.js",
+      "lib/internal/readline/utils.js",
+      "lib/internal/repl/await.js",
+      "lib/internal/repl/history.js",
+      "lib/internal/repl/utils.js",
+      "lib/internal/source_map/prepare_stack_trace.js",
+      "lib/internal/source_map/source_map.js",
+      "lib/internal/source_map/source_map_cache.js",
+      "lib/internal/streams/add-abort-signal.js",
+      "lib/internal/streams/buffer_list.js",
+      "lib/internal/streams/compose.js",
+      "lib/internal/streams/destroy.js",
+      "lib/internal/streams/duplex.js",
+      "lib/internal/streams/duplexify.js",
+      "lib/internal/streams/end-of-stream.js",
+      "lib/internal/streams/from.js",
+      "lib/internal/streams/lazy_transform.js",
+      "lib/internal/streams/legacy.js",
+      "lib/internal/streams/operators.js",
+      "lib/internal/streams/passthrough.js",
+      "lib/internal/streams/pipeline.js",
+      "lib/internal/streams/readable.js",
+      "lib/internal/streams/state.js",
+      "lib/internal/streams/transform.js",
+      "lib/internal/streams/utils.js",
+      "lib/internal/streams/writable.js",
+      "lib/internal/test/binding.js",
+      "lib/internal/test/transfer.js",
+      "lib/internal/tls/parse-cert-string.js",
+      "lib/internal/tls/secure-context.js",
+      "lib/internal/tls/secure-pair.js",
+      "lib/internal/util/comparisons.js",
+      "lib/internal/util/debuglog.js",
+      "lib/internal/util/inspect.js",
+      "lib/internal/util/inspector.js",
+      "lib/internal/util/iterable_weak_map.js",
+      "lib/internal/util/types.js",
+      "lib/internal/vm/module.js",
+      "lib/internal/webstreams/adapters.js",
+      "lib/internal/webstreams/compression.js",
+      "lib/internal/webstreams/encoding.js",
+      "lib/internal/webstreams/queuingstrategies.js",
+      "lib/internal/webstreams/readablestream.js",
+      "lib/internal/webstreams/transfer.js",
+      "lib/internal/webstreams/transformstream.js",
+      "lib/internal/webstreams/util.js",
+      "lib/internal/webstreams/writablestream.js",
+      "lib/internal/worker/io.js",
+      "lib/internal/worker/js_transferable.js",
+      "lib/path/posix.js",
+      "lib/path/win32.js",
+      "lib/stream/consumers.js",
+      "lib/stream/promises.js",
+      "lib/stream/web.js",
+      "lib/timers/promises.js",
+      "lib/util/types.js"
+    ],
+    "node_module_version": 93,
+    "node_no_browser_globals": "false",
+    "node_prefix": "/usr/local",
+    "node_release_urlbase": "https://nodejs.org/download/release/",
+    "node_shared": "false",
+    "node_shared_brotli": "false",
+    "node_shared_cares": "false",
+    "node_shared_http_parser": "false",
+    "node_shared_libuv": "false",
+    "node_shared_nghttp2": "false",
+    "node_shared_nghttp3": "false",
+    "node_shared_ngtcp2": "false",
+    "node_shared_openssl": "false",
+    "node_shared_zlib": "false",
+    "node_tag": "",
+    "node_target_type": "executable",
+    "node_use_bundled_v8": "true",
+    "node_use_dtrace": "false",
+    "node_use_etw": "true",
+    "node_use_node_code_cache": "true",
+    "node_use_node_snapshot": "true",
+    "node_use_openssl": "true",
+    "node_use_v8_platform": "true",
+    "node_with_ltcg": "true",
+    "node_without_node_options": "false",
+    "openssl_fips": "",
+    "openssl_is_fips": "false",
+    "openssl_quic": "true",
+    "ossfuzz": "false",
+    "shlib_suffix": "so.93",
+    "target_arch": "x64",
+    "v8_enable_31bit_smis_on_64bit_arch": 0,
+    "v8_enable_gdbjit": 0,
+    "v8_enable_hugepage": 0,
+    "v8_enable_i18n_support": 1,
+    "v8_enable_inspector": 1,
+    "v8_enable_lite_mode": 0,
+    "v8_enable_object_print": 1,
+    "v8_enable_pointer_compression": 0,
+    "v8_enable_webassembly": 1,
+    "v8_no_strict_aliasing": 1,
+    "v8_optimized_debug": 1,
+    "v8_promise_internal_field_count": 1,
+    "v8_random_seed": 0,
+    "v8_trace_maps": 0,
+    "v8_use_siphash": 1,
+    "want_separate_host_toolset": 0,
+    "nodedir": "C:\\Users\\Caner\\AppData\\Local\\node-gyp\\Cache\\16.15.1",
+    "standalone_static_library": 1,
+    "msbuild_path": "D:\\visualStudio\\MSBuild\\15.0\\Bin\\MSBuild.exe"
+  }
+}

+ 154 - 0
build/kcp.vcxproj

@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{42BA6DA0-F91A-F104-9756-9EEF78CCCB4A}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>kcp</RootNamespace>
+    <IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
+    <PreferredToolArchitecture>x64</PreferredToolArchitecture>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
+  <PropertyGroup Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup Label="Locals">
+    <PlatformToolset>v141</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
+  <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props"/>
+  <ImportGroup Label="ExtensionSettings"/>
+  <ImportGroup Label="PropertySheets">
+    <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros"/>
+  <PropertyGroup>
+    <ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\</ExecutablePath>
+    <IgnoreImportLibrary>true</IgnoreImportLibrary>
+    <IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+    <OutDir>$(SolutionDir)$(Configuration)\</OutDir>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
+    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
+    <TargetName>$(ProjectName)</TargetName>
+    <TargetPath>$(OutDir)\$(ProjectName).node</TargetPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\include\node;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\src;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\config;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\openssl\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\uv\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\zlib;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\v8\include;..\node_modules\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <DebugInformationFormat>OldStyle</DebugInformationFormat>
+      <DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>false</ExceptionHandling>
+      <MinimalRebuild>false</MinimalRebuild>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>false</OmitFramePointers>
+      <Optimization>Disabled</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=kcp;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;V8_DEPRECATION_WARNINGS;V8_IMMINENT_DEPRECATION_WARNINGS;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;V8_ENABLE_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <StringPooling>true</StringPooling>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+    </ClCompile>
+    <Lib>
+      <AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
+    </Lib>
+    <Link>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\\Users\\Caner\\AppData\\Local\\node-gyp\\Cache\\16.15.1\\x64\\node.lib&quot;</AdditionalDependencies>
+      <AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
+      <DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <OptimizeReferences>true</OptimizeReferences>
+      <OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TargetExt>.node</TargetExt>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\include\node;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\src;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\config;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\openssl\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\uv\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\zlib;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\v8\include;..\node_modules\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=kcp;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;V8_DEPRECATION_WARNINGS;V8_IMMINENT_DEPRECATION_WARNINGS;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;V8_ENABLE_CHECKS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\include\node;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\src;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\config;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\openssl\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\uv\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\zlib;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\v8\include;..\node_modules\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
+      <BufferSecurityCheck>true</BufferSecurityCheck>
+      <DebugInformationFormat>OldStyle</DebugInformationFormat>
+      <DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>false</ExceptionHandling>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <OmitFramePointers>true</OmitFramePointers>
+      <Optimization>Full</Optimization>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=kcp;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;V8_DEPRECATION_WARNINGS;V8_IMMINENT_DEPRECATION_WARNINGS;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <StringPooling>true</StringPooling>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <WarningLevel>Level3</WarningLevel>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+    </ClCompile>
+    <Lib>
+      <AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
+    </Lib>
+    <Link>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;DelayImp.lib;&quot;C:\\Users\\Caner\\AppData\\Local\\node-gyp\\Cache\\16.15.1\\x64\\node.lib&quot;</AdditionalDependencies>
+      <AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
+      <DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <OptimizeReferences>true</OptimizeReferences>
+      <OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TargetExt>.node</TargetExt>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\include\node;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\src;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\config;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\openssl\openssl\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\uv\include;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\zlib;C:\Users\Caner\AppData\Local\node-gyp\Cache\16.15.1\deps\v8\include;..\node_modules\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=kcp;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;V8_DEPRECATION_WARNINGS;V8_IMMINENT_DEPRECATION_WARNINGS;_GLIBCXX_USE_CXX11_ABI=1;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <None Include="..\binding.gyp"/>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\kcp\ikcp.c">
+      <ObjectFileName>$(IntDir)\src\kcp\ikcp.obj</ObjectFileName>
+    </ClCompile>
+    <ClCompile Include="..\src\kcpobject.cc">
+      <ObjectFileName>$(IntDir)\src\kcpobject.obj</ObjectFileName>
+    </ClCompile>
+    <ClCompile Include="..\src\node-kcp.cc">
+      <ObjectFileName>$(IntDir)\src\node-kcp.obj</ObjectFileName>
+    </ClCompile>
+    <ClCompile Include="C:\Users\Caner\AppData\Roaming\npm\node_modules\node-gyp\src\win_delay_load_hook.cc"/>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
+  <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets"/>
+  <ImportGroup Label="ExtensionTargets"/>
+</Project>

+ 73 - 0
build/kcp.vcxproj.filters

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="..">
+      <UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..\src">
+      <UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..\src\kcp">
+      <UniqueIdentifier>{3D304605-9FE7-9883-4A87-FF4159A7384F}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..">
+      <UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..\src">
+      <UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..">
+      <UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..\src">
+      <UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:">
+      <UniqueIdentifier>{7B735499-E5DD-1C2B-6C26-70023832A1CF}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users">
+      <UniqueIdentifier>{E9F714C1-DA89-54E2-60CF-39FEB20BF756}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner">
+      <UniqueIdentifier>{B0BAA5CF-1066-40A3-F063-5DF8E3E55EA5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData">
+      <UniqueIdentifier>{F852EB63-437C-846A-220F-8D9ED6DAEC1D}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData\Roaming">
+      <UniqueIdentifier>{D51E5808-912B-5C70-4BB7-475D1DBFA067}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData\Roaming\npm">
+      <UniqueIdentifier>{741E0E76-39B2-B1AB-9FA1-F1A20B16F295}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData\Roaming\npm\node_modules">
+      <UniqueIdentifier>{56DF7A98-063D-FB9D-485C-089023B4C16A}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData\Roaming\npm\node_modules\node-gyp">
+      <UniqueIdentifier>{77348C0E-2034-7791-74D5-63C077DF5A3B}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="C:\Users\Caner\AppData\Roaming\npm\node_modules\node-gyp\src">
+      <UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="..">
+      <UniqueIdentifier>{739DB09A-CC57-A953-A6CF-F64FA08E4FA7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\kcp\ikcp.c">
+      <Filter>..\src\kcp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\kcpobject.cc">
+      <Filter>..\src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\node-kcp.cc">
+      <Filter>..\src</Filter>
+    </ClCompile>
+    <ClCompile Include="C:\Users\Caner\AppData\Roaming\npm\node_modules\node-gyp\src\win_delay_load_hook.cc">
+      <Filter>C:\Users\Caner\AppData\Roaming\npm\node_modules\node-gyp\src</Filter>
+    </ClCompile>
+    <None Include="..\binding.gyp">
+      <Filter>..</Filter>
+    </None>
+  </ItemGroup>
+</Project>

+ 29 - 0
gruntfile.js

@@ -0,0 +1,29 @@
+'use strict';
+
+module.exports = function(grunt) {
+
+    grunt.loadNpmTasks('grunt-mocha-test');
+    grunt.loadNpmTasks('grunt-contrib-clean');
+
+    var src = ["./test/test.js"];
+
+    grunt.initConfig({
+        mochaTest: {
+            test: {
+                options: {
+                    reporter: "spec",
+                    timeout: 5000,
+                    require: ""
+                },
+                src: src
+            }
+        },
+        clean: {
+            "coverage.html": {
+                src: ["coverage.html"]
+            }
+        }
+    });
+
+    grunt.registerTask('default', ['clean', 'mochaTest']);
+}

+ 1 - 0
include_dirs.js

@@ -0,0 +1 @@
+console.log(require('path').relative('.', __dirname));

+ 1 - 0
index.js

@@ -0,0 +1 @@
+module.exports = require('./build/Release/kcp');

+ 37 - 0
package.json

@@ -0,0 +1,37 @@
+{
+  "name": "node-kcp",
+  "version": "1.0.13",
+  "description": "KCP protocol for Node.js",
+  "main": "include_dirs.js",
+  "dependencies": {
+    "nan": "^2.16.0"
+  },
+  "devDependencies": {
+    "chai": "latest",
+    "grunt": "^1.0.4",
+    "grunt-contrib-clean": "latest",
+    "grunt-mocha-test": "latest",
+    "mocha": "^7.0.0"
+  },
+  "scripts": {
+    "test": "grunt",
+    "install": "node-gyp rebuild"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/leenjewel/node-kcp.git"
+  },
+  "keywords": [
+    "kcp",
+    "protocol",
+    "game",
+    "server"
+  ],
+  "author": "leenjewel",
+  "license": "Apache-2.0",
+  "gypfile": true,
+  "bugs": {
+    "url": "https://github.com/leenjewel/node-kcp/issues"
+  },
+  "homepage": "https://github.com/leenjewel/node-kcp#readme"
+}

+ 1 - 0
src/kcp

@@ -0,0 +1 @@
+Subproject commit f553df7afc46fbad599bb6d92484baa02dc83f86

+ 399 - 0
src/kcpobject.cc

@@ -0,0 +1,399 @@
+/**
+ * Copyright 2021 leenjewel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "kcpobject.h"
+#include "node_buffer.h"
+#include <string.h>
+
+#define RECV_BUFFER_SIZE 4096
+
+namespace node_kcp
+{
+    using v8::Context;
+    using v8::Function;
+    using Nan::FunctionCallbackInfo;
+    using v8::FunctionTemplate;
+    using v8::Local;
+    using Nan::MaybeLocal;
+    using v8::Number;
+    using v8::Integer;
+    using v8::Object;
+    using Nan::Persistent;
+    using v8::String;
+    using v8::Value;
+    using v8::Exception;
+    using Nan::Null;
+    using Nan::Callback;
+    using Nan::GetFunction;
+    using Nan::Set;
+    using Nan::To;
+
+    Persistent<Function> KCPObject::constructor;
+
+    int KCPObject::kcp_output(const char *buf, int len, ikcpcb *kcp, void *user)
+    {
+        KCPObject* thiz = (KCPObject*)user;
+        if (thiz->output.IsEmpty()) {
+            return len;
+        }
+        if (thiz->context.IsEmpty()) {
+            const unsigned argc = 2;
+            Local<Value> argv[argc] = {
+                Nan::CopyBuffer(buf, len).ToLocalChecked(),
+                Nan::New<Number>(len)
+            };
+            Callback callback(Nan::New<Function>(thiz->output));
+            Nan::Call(callback, argc, argv);
+        } else {
+            const unsigned argc = 3;
+            Local<Value> argv[argc] = {
+                Nan::CopyBuffer(buf, len).ToLocalChecked(),
+                Nan::New<Number>(len),
+                Nan::New<Object>(thiz->context)
+            };
+            Callback callback(Nan::New<Function>(thiz->output));
+            Nan::Call(callback, argc, argv);
+        }
+        return len;
+    }
+
+    KCPObject::KCPObject(IUINT32 conv)
+    {
+        kcp = ikcp_create(conv, this);
+        kcp->output = KCPObject::kcp_output;
+        recvBuff = (char*)realloc(recvBuff, recvBuffSize);
+    }
+
+    KCPObject::~KCPObject()
+    {
+        if (kcp) {
+            ikcp_release(kcp);
+            kcp = NULL;
+        }
+        if (recvBuff) {
+            free(recvBuff);
+            recvBuff = NULL;
+        }
+        if (!output.IsEmpty()) {
+            output.Reset();
+        }
+        if (!context.IsEmpty()) {
+            context.Reset();
+        }
+    }
+
+    NAN_MODULE_INIT(KCPObject::Init)
+    {
+        Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
+        tpl->SetClassName(Nan::New("KCPObject").ToLocalChecked());
+        tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+        SetPrototypeMethod(tpl, "release", Release);
+        SetPrototypeMethod(tpl, "context", GetContext);
+        SetPrototypeMethod(tpl, "recv", Recv);
+        SetPrototypeMethod(tpl, "send", Send);
+        SetPrototypeMethod(tpl, "input", Input);
+        SetPrototypeMethod(tpl, "output", Output);
+        SetPrototypeMethod(tpl, "update", Update);
+        SetPrototypeMethod(tpl, "check", Check);
+        SetPrototypeMethod(tpl, "flush", Flush);
+        SetPrototypeMethod(tpl, "peeksize", Peeksize);
+        SetPrototypeMethod(tpl, "setmtu", Setmtu);
+        SetPrototypeMethod(tpl, "wndsize", Wndsize);
+        SetPrototypeMethod(tpl, "waitsnd", Waitsnd);
+        SetPrototypeMethod(tpl, "nodelay", Nodelay);
+        SetPrototypeMethod(tpl, "stream", Stream);
+
+        constructor.Reset(GetFunction(tpl).ToLocalChecked());
+        Set(target, Nan::New("KCP").ToLocalChecked(), GetFunction(tpl).ToLocalChecked());
+    }
+
+    NAN_METHOD(KCPObject::New)
+    {
+        if (!info[0]->IsNumber()) {
+            Nan::ThrowTypeError("kcp.KCP 1 arg must be number");
+            return;
+        }
+        if (info.IsConstructCall()) {
+            uint32_t conv = To<uint32_t>(info[0]).FromJust();
+            KCPObject* kcpobj = new KCPObject(conv);
+            if (info[1]->IsObject()) {
+                kcpobj->context.Reset(Local<Object>::Cast(info[1]));
+            }
+            kcpobj->Wrap(info.This());
+            info.GetReturnValue().Set(info.This());
+        } else {
+            Local<Value> argv[2] = {
+                info[0],
+                info[1]
+            };
+            Local<Function> cons = Nan::New(constructor);
+            info.GetReturnValue().Set(Nan::NewInstance(cons, 2, argv).ToLocalChecked());
+        }
+    }
+
+    NAN_METHOD(KCPObject::GetContext)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        if (!thiz->context.IsEmpty()) {
+            info.GetReturnValue().Set(Nan::New<Object>(thiz->context));
+        }
+    }
+
+    NAN_METHOD(KCPObject::Release)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        if (thiz->kcp) {
+            ikcp_release(thiz->kcp);
+            thiz->kcp = NULL;
+        }
+        if (thiz->recvBuff) {
+            free(thiz->recvBuff);
+            thiz->recvBuff = NULL;
+        }
+    }
+
+    NAN_METHOD(KCPObject::Recv)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        int bufsize = 0;
+        unsigned int allsize = 0;
+        int buflen = 0;
+        int len = 0;
+        while(1) {
+            bufsize = ikcp_peeksize(thiz->kcp);
+            if (bufsize <= 0) {
+                break;
+            }
+            allsize += bufsize;
+            if (allsize > thiz->recvBuffSize) {
+                int align = allsize % 4;
+                if (align) {
+                    allsize += 4 - align;
+                }
+                thiz->recvBuffSize = allsize;
+                thiz->recvBuff = (char*)realloc(thiz->recvBuff, thiz->recvBuffSize);
+                if (!thiz->recvBuff) {
+                    Nan::ThrowError("realloc error");
+                    len = 0;
+                    break;
+                }
+            }
+
+            buflen = ikcp_recv(thiz->kcp, thiz->recvBuff + len, bufsize);
+            if (buflen <= 0) {
+                break;
+            }
+            len += buflen;
+            if (thiz->kcp->stream == 0) {
+                break;
+            }
+        }
+        if (len > 0) {
+            info.GetReturnValue().Set(
+                Nan::CopyBuffer((const char*)thiz->recvBuff, len).ToLocalChecked()
+            );
+        }
+    }
+
+    NAN_METHOD(KCPObject::Input)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        char* buf = NULL;
+        int len = 0;
+        Local<Value> arg0 = info[0];
+        if (arg0->IsString()) {
+            Nan::Utf8String data(arg0);
+            len = data.length();
+            if (0 == len) {
+                Nan::ThrowError("INput Nan Utf8String error");
+                return;
+            }
+            int t = ikcp_input(thiz->kcp, *data, len);
+            Local<Number> ret = Nan::New(t);
+            info.GetReturnValue().Set(ret);
+            free(buf);
+        } else if (node::Buffer::HasInstance(arg0)) {
+            Nan::MaybeLocal<v8::Object> maybeObj = Nan::To<v8::Object>(arg0);
+            v8::Local<Object> obj;
+            if (!maybeObj.ToLocal(&obj)) {
+                return;
+            }
+            len = node::Buffer::Length(obj);
+            if (0 == len) {
+                return;
+            }
+            buf = node::Buffer::Data(obj);
+            int t = ikcp_input(thiz->kcp, (const char*)buf, len);
+            Local<Number> ret = Nan::New(t);
+            info.GetReturnValue().Set(ret);
+        }
+    }
+
+    NAN_METHOD(KCPObject::Send)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        char* buf = NULL;
+        int len = 0;
+        Local<Value> arg0 = info[0];
+        if (arg0->IsString()) {
+            Nan::Utf8String data(arg0);
+            len = data.length();
+            if (0 == len) {
+                Nan::ThrowError("Send Nan Utf8String error");
+                return;
+            }
+            int t = ikcp_send(thiz->kcp, *data, len);
+            Local<Number> ret = Nan::New(t);
+            info.GetReturnValue().Set(ret);
+            free(buf);
+        } else if (node::Buffer::HasInstance(arg0)) {
+            Nan::MaybeLocal<v8::Object> maybeObj = Nan::To<v8::Object>(arg0);
+            v8::Local<Object> obj;
+            if (!maybeObj.ToLocal(&obj)) {
+                return;
+            }
+            // len = node::Buffer::Length(arg0->ToObject(isolate));
+            len = node::Buffer::Length(obj);
+            if (0 == len) {
+                return;
+            }
+            // buf = node::Buffer::Data(arg0->ToObject(isolate));
+            buf = node::Buffer::Data(obj);
+            int t = ikcp_send(thiz->kcp, (const char*)buf, len);
+            Local<Number> ret = Nan::New(t);
+            info.GetReturnValue().Set(ret);
+        }
+    }
+
+    NAN_METHOD(KCPObject::Output)
+    {
+        if (!info[0]->IsFunction()) {
+            return;
+        }
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        thiz->output.Reset(Local<Function>::Cast(info[0]));
+    }
+
+    NAN_METHOD(KCPObject::Update)
+    {
+        if (!info[0]->IsNumber()) {
+            Nan::ThrowTypeError("KCP update first argument must be number");
+            return;
+        }
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        int64_t arg0 = To<int64_t>(info[0]).FromJust();
+        IUINT32 current = (IUINT32)(arg0 & 0xfffffffful);
+        ikcp_update(thiz->kcp, current);
+    }
+
+    NAN_METHOD(KCPObject::Check)
+    {
+        if (!info[0]->IsNumber()) {
+            Nan::ThrowTypeError("KCP check first argument must be number");
+            return;
+        }
+
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        int64_t arg0 = To<int64_t>(info[0]).FromJust();
+        IUINT32 current = (IUINT32)(arg0 & 0xfffffffful);
+        IUINT32 ret = ikcp_check(thiz->kcp, current) - current;
+        Local<Integer> num = Nan::New((uint32_t)(ret>0?ret:0));
+        info.GetReturnValue().Set(num);
+    }
+
+    NAN_METHOD(KCPObject::Flush)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        ikcp_flush(thiz->kcp);
+    }
+
+    NAN_METHOD(KCPObject::Peeksize)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        Local<v8::Int32> ret = Nan::New(ikcp_peeksize(thiz->kcp));
+        info.GetReturnValue().Set(ret);
+    }
+
+    NAN_METHOD(KCPObject::Setmtu)
+    {
+        int mtu = 1400;
+        if (info[0]->IsNumber()) {
+            mtu = To<int>(info[0]).FromJust();
+        }
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        Local<v8::Int32> ret = Nan::New(ikcp_setmtu(thiz->kcp, mtu));
+        info.GetReturnValue().Set(ret);
+    }
+
+    NAN_METHOD(KCPObject::Wndsize)
+    {
+        int sndwnd = 32;
+        int rcvwnd = 32;
+        if (info[0]->IsNumber()) {
+            sndwnd = To<int>(info[0]).FromJust();
+        }
+        if (info[1]->IsNumber()) {
+            rcvwnd = To<int>(info[1]).FromJust();
+        }
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        Local<v8::Int32> ret = Nan::New(ikcp_wndsize(thiz->kcp, sndwnd, rcvwnd));
+        info.GetReturnValue().Set(ret);
+    }
+
+    NAN_METHOD(KCPObject::Waitsnd)
+    {
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        Local<v8::Int32> ret = Nan::New(ikcp_waitsnd(thiz->kcp));
+        info.GetReturnValue().Set(ret);
+    }
+
+    NAN_METHOD(KCPObject::Nodelay)
+    {
+        int nodelay = 0;
+        int interval = 100;
+        int resend = 0;
+        int nc = 0;
+        if (info[0]->IsNumber()) {
+            nodelay = To<int>(info[0]).FromJust();
+        }
+        if (info[1]->IsNumber()) {
+            interval = To<int>(info[1]).FromJust();
+        }
+        if (info[2]->IsNumber()) {
+            resend = To<int>(info[2]).FromJust();
+        }
+        if (info[3]->IsNumber()) {
+            nc = To<int>(info[3]).FromJust();
+        }
+        KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+        Local<v8::Int32> ret = Nan::New(ikcp_nodelay(thiz->kcp, nodelay, interval, resend, nc));
+        info.GetReturnValue().Set(ret);
+    }
+
+    NAN_METHOD(KCPObject::Stream)
+    {
+        if (info[0]->IsNumber()) {
+            int stream = To<int>(info[0]).FromJust();
+            KCPObject* thiz = ObjectWrap::Unwrap<KCPObject>(info.Holder());
+            thiz->kcp->stream = stream;
+            Local<v8::Int32> ret = Nan::New(thiz->kcp->stream);
+            info.GetReturnValue().Set(ret);
+        }
+    }
+
+}
+

+ 62 - 0
src/kcpobject.h

@@ -0,0 +1,62 @@
+/**
+ * Copyright 2021 leenjewel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef KCPOBJECT_H
+#define KCPOBJECT_H
+
+#include <nan.h>
+#include <nan_object_wrap.h>
+#include "kcp/ikcp.h"
+
+namespace node_kcp {
+
+    class KCPObject : public Nan::ObjectWrap
+    {
+        public:
+            static NAN_MODULE_INIT(Init);
+
+        private:
+            explicit KCPObject(IUINT32 conv);
+            ~KCPObject();
+
+            static NAN_METHOD(New);
+            static NAN_METHOD(Release);
+            static NAN_METHOD(GetContext);
+            static NAN_METHOD(Recv);
+            static NAN_METHOD(Send);
+            static NAN_METHOD(Output);
+            static NAN_METHOD(Input);
+            static NAN_METHOD(Update);
+            static NAN_METHOD(Check);
+            static NAN_METHOD(Flush);
+            static NAN_METHOD(Peeksize);
+            static NAN_METHOD(Setmtu);
+            static NAN_METHOD(Wndsize);
+            static NAN_METHOD(Waitsnd);
+            static NAN_METHOD(Nodelay);
+            static NAN_METHOD(Stream);
+            static Nan::Persistent<v8::Function> constructor;
+            static int kcp_output(const char *buf, int len, ikcpcb *kcp, void *user);
+            ikcpcb* kcp;
+            Nan::Persistent<v8::Function> output;
+            Nan::Persistent<v8::Object> context;
+            char *recvBuff = NULL;
+            unsigned int recvBuffSize = 1024;
+    };
+
+}
+
+#endif

+ 32 - 0
src/node-kcp.cc

@@ -0,0 +1,32 @@
+/**
+ * Copyright 2021 leenjewel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "kcpobject.h"
+
+namespace node_kcp {
+
+    using v8::Local;
+    using v8::Object;
+
+    void InitModule(Local<Object> exports)
+    {
+        KCPObject::Init(exports);
+    }
+
+    NODE_MODULE(kcp, InitModule)
+
+}
+

+ 55 - 0
test/test.js

@@ -0,0 +1,55 @@
+var kcp = require('./../build/Release/kcp');
+var expect = require('chai').expect;
+
+var kcpobj1 = new kcp.KCP(123, {name : 'kcpobj1'});
+var kcpobj2 = new kcp.KCP(123, {name : 'kcpobj2'});
+
+var interval = 10;
+var msg = 'helloworld';
+
+describe('Test node-kcp', function(){
+
+    describe('# nodelay', function(){
+        it('set default mode', function(){
+            expect(kcpobj1.nodelay(0, interval, 0, 0)).to.be.equal(0);
+            expect(kcpobj2.nodelay(0, interval, 0, 0)).to.be.equal(0);
+        });
+    });
+
+    describe('# update & check', function(){
+        it('test update and check', function(){
+            var now = Date.now();
+            kcpobj1.update(now);
+            expect(kcpobj1.check(now)).to.be.equal(interval);
+            kcpobj2.update(now);
+            expect(kcpobj2.check(now)).to.be.equal(interval);
+        });
+    });
+
+    describe('# input & output', function(){
+        it('test input and output', function(done){
+            var kcpobj1TID = setTimeout(function(){
+                kcpobj1.update(Date.now());
+            }, interval);
+            kcpobj1.output(function(data, size, context){
+                expect(context.name).to.be.equal('kcpobj1');
+                expect(kcpobj2.input(data)).to.be.equal(0);
+                clearTimeout(kcpobj1TID);
+                done();
+            });
+            kcpobj1.send(msg);
+        });
+    });
+
+    describe('# recveive message', function(){
+        it('test receive msg', function(done){
+            var kcpobj2TID = setTimeout(function(){
+                kcpobj2.update(Date.now());
+                expect(kcpobj2.recv().toString()).to.be.equal(msg);
+                done();
+            }, interval);
+        });
+    });
+
+});
+

+ 38 - 0
test/udpclient.js

@@ -0,0 +1,38 @@
+var kcp = require('./../build/Release/kcp');
+var kcpobj = new kcp.KCP(123, {address: '127.0.0.1', port: 41234});
+var dgram = require('dgram');
+var client = dgram.createSocket('udp4');
+var msg = JSON.stringify({
+    id: 'test',
+    route: 'test',
+    body: 'test'
+});
+var idx = 1;
+var interval = 200;
+
+kcpobj.stream(1);
+kcpobj.nodelay(0, interval, 0, 0);
+
+kcpobj.output((data, size, context) => {
+    client.send(data, 0, size, context.port, context.address);
+});
+
+client.on('error', (err) => {
+    console.log(`client error:\n${err.stack}`);
+    client.close();
+});
+
+client.on('message', (data, rinfo) => {
+    kcpobj.input(data);
+    var recv = kcpobj.recv();
+    if (recv) {
+    	console.log(`Client recv ${recv} from ${kcpobj.context().address}:${kcpobj.context().port}`);
+        kcpobj.send(msg+(idx++));
+    }
+});
+
+setInterval(() => {
+    kcpobj.update(Date.now());
+}, interval);
+
+kcpobj.send(msg);

+ 50 - 0
test/udpserver.js

@@ -0,0 +1,50 @@
+var kcp = require('./../build/Release/kcp');
+var dgram = require('dgram');
+var server = dgram.createSocket('udp4');
+var clients = {};
+var interval = 200;
+
+var output = function(data, size, context) {
+    server.send(data, 0, size, context.port, context.address);
+};
+
+server.on('error', (err) => {
+    console.log(`server error:\n${err.stack}`);
+    server.close();
+});
+
+server.on('message', (data, rinfo) => {
+    var k = rinfo.address+'_'+rinfo.port;
+    if (undefined === clients[k]) {
+        var context = {
+            address : rinfo.address,
+            port : rinfo.port
+        };
+        var kcpobj = new kcp.KCP(123, context);
+        kcpobj.stream(1);
+        kcpobj.nodelay(0, interval, 0, 0);
+        kcpobj.output(output);
+        clients[k] = kcpobj;
+    }
+    var kcpobj = clients[k];
+    kcpobj.input(data);
+    var recv = kcpobj.recv();
+    if (recv) {
+        recv = recv.toString();
+    	console.log(`Server recv ${recv} from ${kcpobj.context().address}:${kcpobj.context().port}`);
+    	kcpobj.send('RE-'+recv);
+    }
+});
+
+server.on('listening', () => {
+    var address = server.address();
+    console.log(`server listening ${address.address} : ${address.port}`);
+    setInterval(() => {
+        for (var k in clients) {
+            var kcpobj = clients[k];
+        	kcpobj.update(Date.now());
+       	}
+    }, interval);
+});
+
+server.bind(41234);