├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTION.md ├── LICENSE ├── MIGRATION.md ├── Makefile ├── README.md ├── argstream.js ├── as ├── http.js ├── json.js ├── meta.thrift └── thrift.js ├── benchmarks ├── Makefile ├── README.md ├── bench_server.js ├── compare.js ├── d8_peer_heap.js ├── http │ ├── Makefile │ └── index.js ├── index.js ├── micro │ ├── reading-all-important-fields.js │ ├── reading-arg1-str.js │ ├── reading-caller-name-str.js │ ├── reading-service-name-str.js │ └── reading-tracing-value.js ├── multi_bench.js ├── peer_heap.js ├── random_sample.js ├── read-bench-config.js ├── relay_server.js └── trace_server.js ├── bin ├── adhoc-multi.js ├── adhoc-multi.thrift └── adhoc.js ├── channel.js ├── connection.js ├── docs.jsig ├── docs ├── GUIDE.md ├── README.md ├── as-json.md ├── as-thrift.md ├── channel.md ├── errors.md ├── handlers.md ├── host-port.md ├── hyperbahn.md ├── index.md ├── peer-to-peer.md ├── requests.md ├── statsd.md ├── streaming.md └── sub-channels.md ├── drain.js ├── endpoint-handler.js ├── errors.js ├── examples ├── as-thrift.js ├── as_example1.js ├── echo.thrift ├── example1.js ├── example2.js ├── http_egress.js ├── http_ingress.js ├── josh_test_client.js ├── josh_test_server.js ├── keyvalue │ ├── client.js │ ├── keyvalue.thrift │ └── server.js ├── legacy_example.js ├── repl_client.js ├── repl_server.js ├── send_test.js ├── term_client.js └── term_server.js ├── host-port.js ├── hyperbahn-client.js ├── hyperbahn.thrift ├── hyperbahn └── index.js ├── in_request.js ├── in_response.js ├── lazy_relay.js ├── lib ├── event_emitter.js ├── lcg.js ├── multicast_ctl.js ├── object_pool.js ├── part-list.js ├── pipeline_streams.js ├── rate_counter.js ├── retry_ratio_tracker.js └── statsd.js ├── mkdocs.yml ├── monitor.js ├── null-logger.js ├── operations.js ├── out_request.js ├── out_response.js ├── package-lock.json ├── package.json ├── peer-file-watcher.js ├── peer.js ├── peer_heap.js ├── peer_score_strategies.js ├── peers_base.js ├── publish.sh ├── range.js ├── relay_handler.js ├── reqres_states.js ├── request-handler.js ├── request.js ├── retry-flags.js ├── root_peers.js ├── scripts ├── changelog_halp.sh ├── check_files.sh ├── check_unique_test_names.sh ├── no_only.sh ├── verify_included.sh └── xlang_test.js ├── service-name-handler.js ├── services.js ├── stat-tags.js ├── streaming_in_request.js ├── streaming_in_response.js ├── streaming_out_request.js ├── streaming_out_response.js ├── sub_peers.js ├── tag.sh ├── tcollector ├── reporter.js └── tcollector.thrift ├── test ├── anechoic-chamber.thrift ├── argstream.js ├── as-http.js ├── as-json.js ├── as-thrift.js ├── bad-anechoic-chamber.thrift ├── balance_peer_requests.js ├── busy.js ├── chan_drain.js ├── config │ ├── with_lazy_relay.json │ ├── with_peer_heap.json │ ├── without_lazy_relay.json │ └── without_peer_heap.json ├── connection-stats.js ├── connection-with-statsd.js ├── double-response.js ├── ephemeral-client.js ├── errors.js ├── event_emitter.js ├── examples.js ├── health.js ├── hyperbahn-client │ ├── constructor.js │ ├── sub-channel.js │ └── thrift-codec.js ├── identify.js ├── index.js ├── large-send.js ├── lazy_conn_handler.js ├── lazy_handler.js ├── lib │ ├── alloc-cluster.js │ ├── barplot.js │ ├── barrier.js │ ├── base2.js │ ├── batch-client.js │ ├── cluster_search.js │ ├── collapsed-assert.js │ ├── count_stream.js │ ├── iter_stream.js │ ├── link_test.sh │ ├── load_config.js │ ├── peer_score_obs.js │ ├── raw_service.js │ ├── resource_pool.js │ ├── rng_stream.js │ ├── run_server.js │ ├── simple_validators.js │ ├── stream_check.js │ ├── stream_search.js │ ├── test_isolate_search.js │ └── test_search.js ├── link_hyperbahn.sh ├── link_tcurl.sh ├── max-call-overhead.js ├── max_pending.js ├── no_frag_arg1.js ├── non-zero-ttl.js ├── object_pool.js ├── peer-file-watcher.js ├── peer-to-peer-load-balance.js ├── peer.js ├── peer_drain.js ├── peer_strategies.js ├── peers.js ├── ping.js ├── pool-of-servers.js ├── rate_counter.js ├── register.js ├── regression-conn-double-buildResponse.js ├── regression-inOps-leak.js ├── regression-listening-on-used-port.js ├── relay-clamps-the-ttl.js ├── relay-kills-socket-after-timeouts.js ├── relay-stats.js ├── relay-to-dead.js ├── relay-under-timeouts.js ├── relay.js ├── relay_lazy.js ├── request-error-context.js ├── request-stats.js ├── request-with-statsd.js ├── response-stats.js ├── response-with-statsd.js ├── retry.js ├── safe-quit.js ├── send.js ├── streaming-resp-err.js ├── streaming.js ├── streaming_bisect.js ├── streaming_bisect_relabel.sh ├── tchannel.js ├── tcollector-reporter.js ├── time_heap.js ├── timeouts.js ├── trace │ ├── basic_server.js │ ├── lib │ │ ├── basic_server_fixture.js │ │ └── server_2_requests_fixture.js │ ├── outpeer_span_handle.js │ └── server_2_requests.js └── v2 │ ├── args.js │ ├── call.js │ ├── cancel.js │ ├── checksum.js │ ├── claim.js │ ├── cont.js │ ├── error_response.js │ ├── frame.js │ ├── header.js │ ├── init.js │ ├── lazy_frame.js │ ├── lib │ └── test_body.js │ ├── ping.js │ └── tracing.js ├── time_heap.js ├── trace ├── agent.js └── span.js ├── v1 ├── frame.js ├── handler.js ├── header.js ├── index.js └── parser.js └── v2 ├── args.js ├── call.js ├── call_flags.js ├── cancel.js ├── checksum.js ├── claim.js ├── cont.js ├── error_response.js ├── frame.js ├── handler.js ├── header.js ├── index.js ├── init.js ├── lazy_frame.js ├── out_request.js ├── out_response.js ├── ping.js └── tracing.js /.eslintignore: -------------------------------------------------------------------------------- 1 | examples/*.js 2 | scripts/*.js 3 | test/ 4 | v1/*.js 5 | benchmarks/d8_peer_heap.js 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["perf-standard"], 3 | "globals": { 4 | "global": false 5 | }, 6 | "rules": { 7 | "max-params": [2, 5], 8 | "max-len": [0], 9 | "max-statements": [2, 25] 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | TODO.md 3 | coverage/ 4 | .nyc_output/ 5 | benchmarks/*.json 6 | node/ 7 | benchmarks/*.svg 8 | benchmarks/*.raw 9 | benchmarks/*.html 10 | benchmarks/*.folded 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | jobs: 4 | include: 5 | - node_js: "10" 6 | env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG= NPM_TEST_SCRIPT=travis 7 | - node_js: "12" 8 | env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG= NPM_TEST_SCRIPT=travis 9 | - node_js: "12" 10 | env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG=test/config/with_lazy_relay.json NPM_TEST_SCRIPT=travis 11 | # - node_js: "12" 12 | # env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG= NPM_TEST_SCRIPT=hyperbahn-link-test 13 | # - node_js: "12" 14 | # env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG=test/config/with_lazy_relay.json NPM_TEST_SCRIPT=hyperbahn-link-test 15 | # - node_js: "12" 16 | # env: CXX=g++-4.8 TCHANNEL_TEST_CONFIG= NPM_TEST_SCRIPT=tcurl-link-test 17 | 18 | script: npm run $NPM_TEST_SCRIPT 19 | 20 | addons: 21 | apt: 22 | sources: 23 | - ubuntu-toolchain-r-test 24 | packages: 25 | - gcc-4.8 26 | - g++-4.8 27 | -------------------------------------------------------------------------------- /CONTRIBUTION.md: -------------------------------------------------------------------------------- 1 | # Want to contribute? 2 | 3 | Great! That's why this is an open source project. We use this project in our infrastructure at Uber, and we hope that it's useful to others as well. 4 | 5 | Before you get started, here are some suggestions: 6 | 7 | - Check open issues for what you want. 8 | - If there is an open issue, comment on it. Otherwise open an issue describing your bug or feature with use cases. 9 | - Before undertaking a major change, please discuss this on the issue. We'd hate to see you spend a lot of time working on something that conflicts with other goals or requirements that might not be obvious. 10 | - Write code to fix the problem, then open a pull request with tests and documentation. 11 | - The pull requests gets reviewed and then merged assuming there are no problems. 12 | - A new release version gets cut. 13 | 14 | ## Licencing 15 | 16 | - Every file must have a licence block at the top. This is enforced using `uber-licence` 17 | - If you contribute to a file in this project and are not an Uber employee, then you should 18 | add your name to the copyright section of the licence file. 19 | - Work that you contribute must be your own. 20 | 21 | ## Releases 22 | 23 | Declaring formal releases requires peer review. 24 | 25 | - A reviewer of a pull request should recommend a new version number (patch, minor or major). 26 | - Once your change is merged feel free to bump the version as recommended by the reviewer. 27 | - A new version number should not be cut without peer review unless done by the project maintainer. 28 | 29 | ### Cutting a new version 30 | 31 | - Get your branch merged on master 32 | - Run `npm version major` or `npm version minor` or `npm version patch` 33 | - `git push origin master --tags` 34 | - If you are a project owner, then `npm publish` 35 | 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration 2 | 3 | # Upgrading from 2.x to 3.x 4 | 5 | This is a pretty easy upgrade. We removed `test/lib/hyperbahn-cluster.js` 6 | 7 | It's now recommended that you `npm install hyperbahn --save-dev` and import 8 | `require('hyperbahn/test/lib/test-cluster.js')` instead. 9 | 10 | The interface is the same. 11 | 12 | # Upgrading from 1.x to 2.x 13 | 14 | ## .register() -> .handler.register() 15 | 16 | Before: 17 | 18 | ```js 19 | chan.register('my-endpoint', function (arg2, arg3, hi, cb) { 20 | // either 21 | cb(new Error('oops')); 22 | 23 | // or 24 | cb(null, 'res1', 'res2'); 25 | }) 26 | ``` 27 | 28 | After: 29 | 30 | ```js 31 | var TChannel = require('tchannel'); 32 | 33 | var server = TChannel(); 34 | var appChan = server.makeSubChannel({ 35 | serviceName: 'my-app' 36 | }); 37 | 38 | appChan.register('my-endpoint', function (req, res, arg2, arg3) { 39 | // req.remoteAddr 40 | 41 | // either 42 | res.headers.as = 'raw'; 43 | res.sendNotOk(null, 'oops'); 44 | 45 | // or 46 | res.headers.as = 'raw'; 47 | res.sendOk('res1', 'res2'); 48 | }); 49 | ``` 50 | 51 | If your server is JSON or Thrift consider using `as/json` or 52 | `as/thrift` to handle encoding & decoding. 53 | 54 | ## .send() -> .request().send() 55 | 56 | Before: 57 | 58 | ```js 59 | chan 60 | .send(options, a1, a2, a3, function (err, res1, res2) { 61 | // CallResponse error is in `err` 62 | // CallResponse ok is in `res1`, `res2` 63 | }); 64 | ``` 65 | 66 | After: 67 | 68 | ```js 69 | var TChannel = require('tchannel'); 70 | 71 | var client = TChannel(); 72 | var appChane = client.makeSubChannel({ 73 | serviceName: 'my-app', 74 | peers: ['{host}:{port}'], 75 | requestDefaults: { 76 | headers: { 77 | 'as': 'raw', 78 | 'cn': 'my-client-name' 79 | } 80 | } 81 | }); 82 | 83 | chan 84 | .request({ 85 | parent: inRequest 86 | /* ... */ 87 | }) 88 | .send(a1, a2, a3, function (err, res, arg2, arg3) { 89 | // res has an `.ok` field that tells whether it is 90 | // an error or not. 91 | 92 | // This means that an application error returns 93 | // `err` === null and a `resp` where `.ok` is false. 94 | 95 | // If `err` is non null then it will be an err related 96 | // to client TCP IO errors or TChannel error frames. 97 | }); 98 | ``` 99 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test_server 2 | 3 | TEST_HOST=127.0.0.1 4 | TEST_PORT=0 5 | TEST_LOG_FILE=test-server.log 6 | 7 | test_server: 8 | node test/lib/run_server.js --logFile ${TEST_LOG_FILE} --host ${TEST_HOST} --port ${TEST_PORT} 9 | 10 | -------------------------------------------------------------------------------- /as/meta.thrift: -------------------------------------------------------------------------------- 1 | struct HealthStatus { 2 | 1: required bool ok 3 | 2: optional string message 4 | } 5 | 6 | typedef string filename 7 | 8 | struct ThriftIDLs { 9 | // map: filename -> contents 10 | 1: required map idls 11 | // the entry IDL that imports others 12 | 2: required filename entryPoint 13 | } 14 | 15 | service Meta { 16 | HealthStatus health() 17 | ThriftIDLs thriftIDL() 18 | } -------------------------------------------------------------------------------- /benchmarks/Makefile: -------------------------------------------------------------------------------- 1 | torch-client-bench: 2 | node index.js --relay --torch client --torchFile ./flame.raw --torchTime 10 \ 3 | -- --relay --skipPing -s 4096,16384 -p 1000 -m 3 4 | 5 | torch-client-only-bench: 6 | node index.js --torch client --torchFile ./flame.raw --torchTime 10 \ 7 | -- --skipPing -s 4096,16384 -p 1000 -m 3 8 | 9 | torch-server-bench: 10 | node index.js --relay --torch server --torchFile ./flame.raw --torchTime 10 \ 11 | -- --relay --skipPing -s 4096,16384 -p 1000 12 | 13 | torch-relay-bench: 14 | node index.js --relay --torch relay --torchFile ./flame.raw --torchTime 10 \ 15 | -- --relay --skipPing -s 4096,16384 -p 1000,1500 16 | 17 | flame-torch-relay-bench: 18 | node index.js --relay --torch relay --torchFile ./flame.html --torchTime 10 --torchType flame \ 19 | -- --relay --skipPing -s 4096,16384 -p 1000 20 | 21 | # torch-trace-bench: 22 | # node index.js --trace --relay --torch server --torchFile ./flame.raw \ 23 | # -- --skipPing -s 4096 24 | 25 | create-flame: 26 | stackcollapse-stap.pl ./flame.raw | tr -d "\0" > ./flame.folded 27 | flamegraph.pl ./flame.folded > ./flame.svg 28 | google-chrome ./flame.svg 29 | 30 | kill-dead-benchmarks: 31 | pkill -f nodejs-benchmarks; 32 | 33 | top-benchmark: 34 | top -d1 -cp `pgrep -f nodejs-benchmarks | tr "\\n" "," | sed 's/,$$//'`; 35 | 36 | take: 37 | node index.js --noEndpointOverhead -o $$(git rev-parse --short HEAD).json -- \ 38 | -m 5 -s 4,4096,16384 -p 1000 39 | ln -sf $$(git rev-parse --short HEAD).json $$(basename $$(git symbolic-ref HEAD)).json 40 | 41 | take_relay: 42 | node index.js --relay --noEndpointOverhead -o relay-$$(git rev-parse --short HEAD).json \ 43 | -- --relay --skipPing -m 3 -s 4096,16384 -p 1000 44 | ln -sf relay-$$(git rev-parse --short HEAD).json relay-$$(basename $$(git symbolic-ref HEAD)).json 45 | 46 | take_trace: 47 | # Cannot take --trace flag to multi_bench due to timeout+OOM. 48 | # Cannot take 20k concurrency as it totally falls over 49 | node index.js --relay --trace --noEndpointOverhead -o trace-$$(git rev-parse --short HEAD).json \ 50 | -- --relay -m 5 -c 10 -s 4096,16384 -p 1000 -r 10000 51 | ln -sf trace-$$(git rev-parse --short HEAD).json trace-$$(basename $$(git symbolic-ref HEAD)).json 52 | 53 | .PHONY: kill-dead-benchmarks top-benchmark take take_relay take_trace 54 | -------------------------------------------------------------------------------- /benchmarks/README.md: -------------------------------------------------------------------------------- 1 | # How to read comparison output 2 | 3 | The comparison script runs the benchmark suite against two different git 4 | branches and reports stats on the difference in message rate. 5 | 6 | The reported stat is the difference of the "hi" B value and the "hi" A value. 7 | So since we're talking about message rates where higher is better, a negative 8 | value is a slow down and a positive value is a speedup. The "hi" value of the 9 | A/B sample is the standard "flier" point on a boxplot (that is, the highest 10 | value less-than-or-equal-to `Q3 + 3/2*(Q3 - Q1)` where Q1 and Q3 are the 11 | 25%-ile and 75%-ile). 12 | 13 | Note the 5x multiplicity of test runs is just barely enough to provide a 14 | sufficiently sized sample. 15 | 16 | ```bash 17 | $ ./benchmarks/compare_to.sh -m 5 master 18 | + multiplicity=2 19 | + getopts m: OPT 20 | + case $OPT in 21 | + multiplicity=5 22 | + getopts m: OPT 23 | + shift 2 24 | + base_branch=master 25 | + shift 26 | +++ readlink -f ./benchmarks/compare_to.sh 27 | ++ dirname .../benchmarks/compare_to.sh 28 | + bench_dir=.../benchmarks 29 | +++ git symbolic-ref HEAD 30 | ++ basename refs/heads/dev 31 | + cur_branch=dev 32 | + for branch in '$base_branch' '$cur_branch' 33 | + git checkout master 34 | Switched to branch 'master' 35 | Your branch and 'origin/master' have diverged, 36 | and have 4 and 2 different commits each, respectively. 37 | + node .../benchmarks/index.js -m 5 -o benchmarks/master.json 38 | PING, 1/5 min/max/avg/p95: 0/ 6/ 0.07/ 1.00 1406ms total, 14224.75 ops/sec 39 | ... 40 | + for branch in '$base_branch' '$cur_branch' 41 | + git checkout dev 42 | Switched to branch 'dev' 43 | Your branch and 'origin/dev' have diverged, 44 | and have 20 and 13 different commits each, respectively. 45 | + node .../benchmarks/index.js -m 5 -o benchmarks/dev.json 46 | PING, 1/5 min/max/avg/p95: 0/ 6/ 0.07/ 1.00 1414ms total, 14144.27 ops/sec 47 | ... 48 | + node .../benchmarks/compare.js .../benchmarks/such_bench.json .../benchmarks/wat_ident.json 49 | GET large str, 1/5 rate: hi-diff: 38.27 ( 0.3%) 50 | GET large str, 200/5 rate: hi-diff: -823.92 ( -2.4%) 51 | GET large str, 20000/5 rate: hi-diff: -331.19 ( -0.9%) 52 | GET large str, 50/5 rate: hi-diff: -368.36 ( -1.1%) 53 | GET small str, 1/5 rate: hi-diff: -78.97 ( -0.5%) 54 | GET small str, 200/5 rate: hi-diff: 1263.28 ( 2.4%) 55 | GET small str, 20000/5 rate: hi-diff: 1036.05 ( 2.1%) 56 | GET small str, 50/5 rate: hi-diff: 793.06 ( 1.6%) 57 | PING, 1/5 rate: hi-diff: -292.08 ( -1.9%) 58 | PING, 200/5 rate: hi-diff: -617.30 ( -1.1%) 59 | PING, 20000/5 rate: hi-diff: 1095.51 ( 2.0%) 60 | PING, 50/5 rate: hi-diff: 141.84 ( 0.3%) 61 | SET large buf, 1/5 rate: hi-diff: 122.13 ( 1.0%) 62 | SET large buf, 200/5 rate: hi-diff: 1134.64 ( 3.5%) 63 | SET large buf, 20000/5 rate: hi-diff: -263.80 ( -1.0%) 64 | SET large buf, 50/5 rate: hi-diff: 799.79 ( 2.5%) 65 | SET large str, 1/5 rate: hi-diff: 155.50 ( 1.3%) 66 | SET large str, 200/5 rate: hi-diff: 499.20 ( 1.5%) 67 | SET large str, 20000/5 rate: hi-diff: 1175.22 ( 4.4%) 68 | SET large str, 50/5 rate: hi-diff: 484.56 ( 1.5%) 69 | SET small buf, 1/5 rate: hi-diff: 171.00 ( 1.2%) 70 | SET small buf, 200/5 rate: hi-diff: -777.00 ( -1.5%) 71 | SET small buf, 20000/5 rate: hi-diff: -1195.77 ( -2.4%) 72 | SET small buf, 50/5 rate: hi-diff: 951.90 ( 2.0%) 73 | SET small str, 1/5 rate: hi-diff: -324.90 ( -2.2%) 74 | SET small str, 200/5 rate: hi-diff: -517.98 ( -1.0%) 75 | SET small str, 20000/5 rate: hi-diff: -620.36 ( -1.2%) 76 | SET small str, 50/5 rate: hi-diff: 0.00 ( 0.0%) 77 | ``` 78 | -------------------------------------------------------------------------------- /benchmarks/http/Makefile: -------------------------------------------------------------------------------- 1 | run-raw-http: 2 | node index.js --keepAlive 3 | 4 | torch-ingress-nonstreamed: 5 | node index.js --relay --keepAlive --torch relay --torchIndex 0 --torchFile ./flame.raw --torchTime 10 6 | 7 | torch-egress-nonstreamed: 8 | node index.js --relay --keepAlive --torch relay --torchIndex 1 --torchFile ./flame.raw --torchTime 10 9 | 10 | torch-ingress-streamed: 11 | node index.js --relay --ingressStreamed --keepAlive --torch relay --torchIndex 0 --torchFile ./flame.raw --torchTime 10 12 | 13 | torch-egress-streamed: 14 | node index.js --relay --egressStreamed --keepAlive --torch relay --torchIndex 1 --torchFile ./flame.raw --torchTime 10 15 | 16 | create-flame: 17 | stackcollapse-stap.pl ./flame.raw | tr -d "\0" > ./flame.folded 18 | flamegraph.pl ./flame.folded > ./flame.svg 19 | google-chrome ./flame.svg 20 | -------------------------------------------------------------------------------- /benchmarks/random_sample.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | // Random sampling functions borrowed from python standard library 24 | 25 | var RandomSample = module.exports; 26 | RandomSample.variate = {}; 27 | 28 | RandomSample.variate.norm = function normalvariate(mu, sigma, random) { 29 | var nvMagicConst = 4 * Math.exp(-0.5) / Math.sqrt(2.0); 30 | return function sampleNormalRandom() { 31 | for (;;) { 32 | var u1 = random(); 33 | var u2 = 1.0 - random(); 34 | var z = nvMagicConst * (u1 - 0.5) / u2; 35 | var zz = z * z / 4.0; 36 | if (zz <= -Math.log(u2)) { 37 | return mu + z * sigma; 38 | } 39 | } 40 | }; 41 | }; 42 | 43 | RandomSample.variate.expo = function expovariate(mu, random) { 44 | return function sampleExponentialRandom() { 45 | return -Math.log(1 - random()) * mu; 46 | }; 47 | }; 48 | 49 | RandomSample.fromString = function fromString(str, random) { 50 | if (!random) { 51 | random = Math.random; 52 | } 53 | 54 | // norm:mu,sigma 55 | // expo:mu 56 | var match = /^(\w+):(.+)$/.exec(str); 57 | if (!match) { 58 | throw new Error('invalid random sample spec, expected "kind:arg[,arg[,...]]"'); 59 | } 60 | var kind = match[1]; 61 | str = match[2]; 62 | 63 | var variate = RandomSample.variate[kind]; 64 | if (!variate) { 65 | throw new Error('invalid random sample kind ' + kind); 66 | } 67 | 68 | var args = str.split(','); 69 | if (args.length !== variate.length - 1) { 70 | throw new Error('wrong number of args for random sample kind ' + kind); 71 | } 72 | 73 | for (var i = 0; i < args.length; i++) { 74 | var n = parseFloat(args[i]); 75 | if (isNaN(n)) { 76 | throw new Error('invalid argument, not a number: ' + args[i]); 77 | } 78 | args[i] = n; 79 | } 80 | 81 | args.push(random); 82 | return variate.apply(null, args); 83 | }; 84 | -------------------------------------------------------------------------------- /benchmarks/trace_server.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var process = require('process'); 24 | process.title = 'nodejs-benchmarks-trace_server'; 25 | 26 | var Statsd = require('uber-statsd-client'); 27 | var Buffer = require('buffer').Buffer; 28 | var TChannel = require('../channel'); 29 | 30 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 31 | // istanbul ignore next 32 | var bufferFrom = Buffer.from || Buffer; 33 | 34 | var TRACE_SERVER_PORT = 7039; 35 | var STATSD_PORT = 7036; 36 | 37 | var server = TChannel({ 38 | statTags: { 39 | app: 'tcollector' 40 | }, 41 | emitConnectionMetrics: false, 42 | trace: false, 43 | statsd: new Statsd({ 44 | host: '127.0.0.1', 45 | port: STATSD_PORT 46 | }) 47 | }); 48 | 49 | var tcollectorChan = server.makeSubChannel({ 50 | serviceName: 'tcollector' 51 | }); 52 | 53 | server.listen(TRACE_SERVER_PORT, '127.0.0.1'); 54 | 55 | tcollectorChan.register('TCollector::submit', function onSubmit(req, res) { 56 | var arg2 = bufferFrom([0x00, 0x00]); 57 | // 0c00 0002 0001 0100 00 58 | var arg3 = bufferFrom([ 59 | 0x0c, 0x00, 0x00, 0x02, 60 | 0x00, 0x01, 0x01, 0x00, 61 | 0x00 62 | ]); 63 | 64 | res.headers.as = 'raw'; 65 | res.sendOk(arg2, arg3); 66 | }); 67 | -------------------------------------------------------------------------------- /bin/adhoc-multi.thrift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | service AdhocMulti { 22 | string echo(0: required string value) 23 | } 24 | -------------------------------------------------------------------------------- /docs.jsig: -------------------------------------------------------------------------------- 1 | type Logger : { 2 | debug: (String, Object) => void, 3 | info: (String, Object) => void, 4 | warn: (String, Object) => void, 5 | error: (String, Object) => void, 6 | fatal: (String, Object) => void 7 | } 8 | type Timers : { 9 | setTimeout: (Function, timeout: Number) => id: Number, 10 | clearTimeout: (id: Number) => void, 11 | now: () => timestamp: Number 12 | } 13 | 14 | type IP : String 15 | type HostInfo : String 16 | type TChannelValue : 17 | Buffer | String | null | undefined 18 | 19 | type TChannelInResponse : { 20 | id: Number, 21 | ok: Boolean, 22 | 23 | arg1: Buffer, 24 | arg2: Buffer, 25 | arg3: Buffer 26 | } 27 | 28 | type TChannelOutRequest : { 29 | id: Number, 30 | serviceName: String, 31 | 32 | send: ( 33 | arg1: Buffer | String, 34 | arg2: TChannelValue, 35 | arg3: TChannelValue, 36 | cb: Callback 37 | ) => void 38 | } 39 | 40 | type TChannelInRequest : { 41 | id: Number, 42 | serviceName: String, 43 | 44 | arg1: Buffer, 45 | arg2: Buffer, 46 | arg3: Buffer 47 | } 48 | 49 | type TChannelOutResponse : { 50 | id: Number, 51 | code: Number, 52 | ok: Boolean, 53 | 54 | arg1: Buffer, 55 | arg2: Buffer, 56 | arg3: Buffer, 57 | 58 | sendOk: (res1: Buffer, res2: Buffer) => void, 59 | sendNotOk: (res1: Buffer, res2: Buffer) => void 60 | } 61 | 62 | type TChannelHandler : { 63 | handleRequest : ( 64 | req: TChannelInRequest, 65 | res: TChannelOutResponse 66 | ) => void 67 | } 68 | 69 | type TChannel : { 70 | handler: TChannelHandler 71 | 72 | request: ( 73 | options: { 74 | host: HostInfo, 75 | timeout?: Number 76 | } 77 | ) => TChannelOutRequest, 78 | 79 | listen: ( 80 | port:Number, 81 | hostname:String, 82 | Callback? 83 | ) => void, 84 | address: () => ?{port, family, address} 85 | close: (Callback) => void, 86 | hostPort: HostInfo 87 | } 88 | 89 | tchannel : (options: { 90 | handler?: TChannelHandler, 91 | 92 | logger?: Logger, 93 | timers?: Timers, 94 | 95 | reqTimeoutDefault?: Number, 96 | serverTimeoutDefault?: Number, 97 | timeoutCheckInterval?: Number, 98 | timeoutFuzz?: Number 99 | }) => TChannel 100 | 101 | tchannel/endpoint-handler : (serviceName: String) => 102 | TChannelHandler & { 103 | register: ( 104 | name: String, 105 | handler: ( 106 | req: TChannelInRequest, 107 | res: TChannelOutResponse 108 | ) => void 109 | ) 110 | } 111 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # TChannel documentation 2 | 3 | The tchannel documentation is spread out in multiple parts 4 | 5 | ## Read the Node GUIDE 6 | 7 | Check out our [GUIDE](./GUIDE.md) 8 | 9 | ## Core topics 10 | 11 | The following documents are core to tchannel 12 | 13 | - [channel](./channel.md) 14 | - [sub-channels](./sub-channels.md) 15 | - [requests](./requests.md) 16 | - [handlers](./handlers.md) 17 | - [hyperbahn](./hyperbahn.md) 18 | - [as-thrift](./as-thrift.md) 19 | - [as-json](./as-json.md) 20 | 21 | 22 | ## Extra topics 23 | 24 | The following documents give more details for other use cases 25 | that are available. 26 | 27 | - [as-json](./as-json.md) 28 | - [errors](./errors.md) 29 | - [peer-to-peer](./peer-to-peer.md) 30 | - [statsd](./statsd.md) 31 | - [streaming](./streaming.md) 32 | -------------------------------------------------------------------------------- /docs/errors.md: -------------------------------------------------------------------------------- 1 | # Errors from tchannel 2 | 3 | TChannel can return many different types of errors when 4 | making outgoing requests 5 | 6 | ## Stability: stable 7 | 8 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 9 | 10 | ## TChannel client Errors. Errors from `.request().send()` 11 | 12 | When making an `OutRequest` there are multiple edge cases 13 | that can go happen. There are multiple operational errors that 14 | can occur. 15 | 16 | There are many different types of errors; for an exhaustive list 17 | please check the [source code of `errors.js`](../errors.js) 18 | 19 | - `tchannel.protocol.write-failed` Your application is sending 20 | invalid tchannel frames 21 | - `ProtocolError` There are many different types protocol errors 22 | that can occur that fail your requests. Most of these are bugs 23 | - `tchannel.protocol.read-failed` The tchannel library can fail 24 | to read an incoming frame. When it does this it logs a 25 | frame parser error 26 | - `isErrorFrame: true` When you make an outgoing call it's always 27 | possible to receive one of the error frames. All of these 28 | errors have an `isErrorFrame` boolean on them. You can read 29 | the [protocol docs](../../docs/protocol.md) for more info 30 | on what the error frames are. 31 | - `NetworkError` There are multiple types of TCP errors that can 32 | occur and these are all net work errors; when a connection 33 | dies any pending in or out requests will fail. 34 | - `TimeoutError` TChannel has per-request timeouts. This means 35 | any in request or out request can timeout when it's ttl is 36 | up. 37 | -------------------------------------------------------------------------------- /docs/handlers.md: -------------------------------------------------------------------------------- 1 | # TChannel transport handlers 2 | 3 | You can handle TChannel requests by specifying a handler to sub-channel `register()` 4 | 5 | - [sub-channels](./sub-channels.md) 6 | 7 | The TChannel argument schemes wrap handlers, taking responsibility for encoding 8 | and decoding arg2 and arg3. 9 | 10 | - [as-thrift](./as-thrift.md) 11 | - [as-json](./as-json.md) 12 | 13 | ### `handler(req, res, arg2, arg3)` 14 | 15 | Your handler will get called with an `IncomingRequest` and an 16 | `OutgoingResponse`. 17 | 18 | You will also receive `arg2` and `arg3` as buffers. 19 | 20 | ### `res.sendOk(arg2, arg3)` 21 | 22 | To send an ok response you can call `sendOk()` on the outgoing 23 | response with two buffers for `arg2` and `arg3` 24 | 25 | ### `res.sendNotOk(arg2, arg3)` 26 | 27 | To send an application error response you can call `sendNotOk()` 28 | on the outgoing response with two buffers for `arg2` and `arg3` 29 | 30 | ### `res.sendError(codeString, codeMessage)` 31 | 32 | To send an error frame instead of a call response you can call 33 | `res.sendError()`. 34 | 35 | Valid `codeString` values are: `Timeout`, `Cancelled`, `Busy`, 36 | `Declined`, `UnexpectedError`, `BadRequest`, `NetworkError`, 37 | `UnHealthy`, `ProtocolError` 38 | 39 | For the samentics of the code string please read the 40 | [protocol document](https://github.com/uber/tchannel-node/pull/350) 41 | 42 | You can also pass an arbitrary string `codeMessage` that will 43 | be in the error frame. 44 | -------------------------------------------------------------------------------- /docs/host-port.md: -------------------------------------------------------------------------------- 1 | # Valid hostPorts 2 | 3 | ## What is a valid host 4 | 5 | A valid host must be a string containing an IPv4 address. 6 | The IPv4 address is formatted as `{n}.{n}.{n}.{n}` where `n` is a valid integer. 7 | 8 | If the host is non-ephemeral then it must NOT be `0.0.0.0` 9 | 10 | ## What is a valid port 11 | 12 | A valid port must be a integer representing the port. 13 | The integer must be between 0 and 65536. 14 | 15 | If the port is non-ephemeral then it must NOT be `0` 16 | 17 | ## What is a valid host:port 18 | 19 | A valid host:port must be a string containing both the host and port 20 | The string must be formatted as `{host}:{port}` and must follow 21 | the host and port rules. 22 | 23 | If the host:port is non-ephemeral then it must NOT contain the IP 24 | `0.0.0.0` and must NOT contain the port `0` 25 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /docs/peer-to-peer.md: -------------------------------------------------------------------------------- 1 | # Making peer to peer requests 2 | 3 | TChannel is designed for interacting with a hyperbahn router. 4 | 5 | The majority of the requests you make will be send directly 6 | to the hyperbahn instances and will be routed based on the 7 | `serviceName` 8 | 9 | However tchannel can also be used to make peer to peer request 10 | to individual tchannel instances 11 | 12 | ## Stability: unstable 13 | 14 | [![unstable](http://badges.github.io/stability-badges/dist/unstable.svg)](http://github.com/badges/stability-badges) 15 | 16 | ## `subChannel.waitForIdentified(options, cb)` 17 | 18 | To be able to make peer to peer requests you have to wait for 19 | the init request/response to complete on the connection. 20 | 21 | When doing logical retryable requests againsts a `serviceName` 22 | tchannel will wait for init response to finish; However when making 23 | a peer to peer request this is your responsibility 24 | 25 | You can pass in `options.host` to wait for a connection to that 26 | host to open; your `cb` will be called when it's opened. 27 | 28 | `options.host` must be a valid non-ephmeral host port as per the 29 | [host port rules](./host-port.md) 30 | 31 | We may give your `cb` an `err` if the connection failed 32 | 33 | ## `subChannel.request({ host: ... })` 34 | 35 | You must `waitForIdentified` before making an outgoing peer to 36 | peer request. 37 | 38 | When making an outgoing request on a `subChannel` you can set 39 | `options.host` to be `'{host}:{port}'` string. This will make 40 | a direct request to that concrete host. 41 | 42 | `options.host` must be a valid non-ephmeral host port as per the 43 | [host port rules](./host-port.md) 44 | 45 | This request is a non-retryable request. 46 | 47 | All other documentation for `request()` can be found in the 48 | [sub-channel document](./sub-channels.md) 49 | -------------------------------------------------------------------------------- /docs/statsd.md: -------------------------------------------------------------------------------- 1 | ## Statsd 2 | 3 | TChannel can emit the following stats: 4 | 5 | ## Stability: stable 6 | 7 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 8 | 9 | ### Counters 10 | 11 | - `outbound.calls.sent.{service}.{target-service}.{target-endpoint}` 12 | - `outbound.calls.success.{service}.{target-service}.{target-endpoint}` 13 | - `outbound.calls.system-errors.{service}.{target-service}.{target-endpoint}.{type}` 14 | - `outbound.calls.per-attempt.system-errors.{service}.{target-service}.{target-endpoint}.{type}.{retry-count}` 15 | - `outbound.calls.operational-errors.{service}.{target-service}.{target-endpoint}.{type}` 16 | - `outbound.calls.per-attempt.operational-errors.{service}.{target-service}.{target-endpoint}.{type}.{retry-count}` 17 | - `outbound.calls.app-errors.{service}.{target-service}.{target-endpoint}.{type}` 18 | - `outbound.calls.per-attempt.app-errors.{service}.{target-service}.{target-endpoint}.{type}.{retry-count}` 19 | - `outbound.calls.retries.{service}.{target-service}.{target-endpoint}.{retry-count}` 20 | - `outbound.request.size.{service}.{target-service}.{target-endpoint}` 21 | - `outbound.response.size.{service}.{target-service}.{target-endpoint}` 22 | - `inbound.calls.recvd.{calling-service}.{service}.{endpoint}` 23 | - `inbound.calls.success.{calling-service}.{service}.{endpoint}` 24 | - `inbound.calls.system-errors.{calling-service}.{service}.{endpoint}.{type}` 25 | - `inbound.calls.app-errors.{calling-service}.{service}.{endpoint}.{type}` 26 | - `inbound.request.size.{calling-service}.{service}.{endpoint}` 27 | - `inbound.response.size.{calling-service}.{service}.{endpoint}` 28 | - `connections.initiated.{peer-host}` 29 | - `connections.connect-errors.{peer-host}` 30 | - `connections.accepted.{peer-host}` 31 | - `connections.accept-errors.{host}` 32 | - `connections.errors.{peer-host}.{type}` 33 | - `connections.closed.{peer-host}.{reason}` 34 | - `rate-limiting.service-busy.{target-service}` 35 | - `rate-limiting.total-busy.{target-service}` 36 | 37 | ### Timers 38 | 39 | - `outbound.calls.latency.{service}.{target-service}.{target-endpoint}` 40 | - `outbound.calls.per-attempt-latency.{service}.{target-service}.{target-endpoint}.{retry-count}` 41 | - `inbound.calls.latency.{calling-service}.{service}.{endpoint}` 42 | 43 | ### Gauges 44 | 45 | - `connections.active.{peer-host}` 46 | - `rate-limiting.service-rps.{target-service}` 47 | - `rate-limiting.service-rps-limit.{target-service}` 48 | - `rate-limiting.total-rps` 49 | - `rate-limiting.total-rps-limit` 50 | -------------------------------------------------------------------------------- /docs/streaming.md: -------------------------------------------------------------------------------- 1 | # Streaming 2 | 3 | TChannel supports streaming as a first class use-case 4 | 5 | ## Stability: unstable 6 | 7 | [![unstable](http://badges.github.io/stability-badges/dist/unstable.svg)](http://github.com/badges/stability-badges) 8 | 9 | In TChannel you can fully stream `arg2` and `arg3` as a stream of 10 | binary Buffers. 11 | 12 | ## `subChannel.register(name, { streamed: true }, handler)` 13 | 14 | To implement a streaming server you must call `register()` with 15 | a options argument to opt into streaming. 16 | 17 | The `handler` interface is different when doing streaming. 18 | 19 | `handler(req, buildResponse)` - you get a streaming incoming 20 | request and you get a `buildResponse({ streamed: bool })` function 21 | which takes options and can be used to build a streaming or 22 | non-streaming outgoing response. 23 | 24 | - `req.arg1` A string or buffer 25 | - `req.arg2` A readable stream of buffers for arg1 26 | - `req.arg3` A readable stream of buffers for arg1 27 | 28 | If you call `buildResponse` with `{ streamed: false }` it will 29 | return the normal outgoing response as documented in the 30 | [sub-channel](./sub-channel.md) documentation. 31 | 32 | If you call `buildResponse` with `{ streamed: true }` it will 33 | return a streaming out response with three fields. An `arg1`, 34 | `arg2` and `arg3` field, all of which are writable streams of 35 | buffers. 36 | 37 | ## `req = subChannel.request({ streamed: true })` 38 | 39 | To making a streaming out request you can set the `streamed` 40 | boolean to `true`. 41 | 42 | The rest of the options are documented in the 43 | [sub-channel](./sub-channel.md) docs. 44 | 45 | - `req.arg1` A string or buffer 46 | - `req.arg2` A writable stream of buffers for arg2 47 | - `req.arg3` A writable stream of buffers for arg3 48 | 49 | To handle the response you **should not** pass a callback 50 | to `.send()` 51 | 52 | Instead you should add a listener to `"response"` event on 53 | the request; The incoming response will have three fields; `arg1`, 54 | `arg2` and `arg3`. They are all readable streams of buffers. 55 | 56 | ```js 57 | var req = subChan.request({ 58 | streamed: true, 59 | serviceName: 'foo' 60 | }); 61 | 62 | req.sendArg1('endpoint'); 63 | req.arg2.end(''); 64 | myStream.pipe(req.arg3); 65 | 66 | req.on('error', function onError(err) { 67 | /* handle errors */ 68 | }); 69 | req.on('response', function onResponse(res) { 70 | // handle res.arg2 and res.arg3 71 | }); 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/sub-channels.md: -------------------------------------------------------------------------------- 1 | # Sub channels 2 | 3 | TChannel supports the notion of sub channels. Whenever you want 4 | to implement a serviceName you create a subchannel for it. 5 | 6 | Whenever you want to talk to a downstream service; you create 7 | a subchannel for it. 8 | 9 | Read on for details on using a sub channel to send and handle requests. 10 | 11 | - [requests](./requests.md) 12 | - [handlers](./handlers.md) 13 | 14 | ## Stability: stable 15 | 16 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 17 | 18 | ## `channel.makeSubChannel(options)` 19 | 20 | **Note:** Favor using `hyperbahnClient.getClientChannel()` for 21 | any creating sub channels if your making requests to hyperbahn 22 | 23 | See the [hyperbahn](./hyperbahn.md) documentation on how to 24 | create sub channels with hyperbahn 25 | 26 | To create a sub channel you call `makeSubChannel` on the root 27 | channel. 28 | 29 | ```js 30 | var channel = TChannel() 31 | 32 | var myChannel = channel.makeSubChannel({ 33 | serviceName: 'my-service' 34 | }); 35 | ``` 36 | 37 | ### `options.serviceName` 38 | 39 | The `serviceName` for this channel. If this is a `serviceName` 40 | that you are implementing then you will probably call `register()` 41 | on the sub channel. 42 | 43 | If this is a `serviceName` that you want to talk to then you'll 44 | probably call `request()` on the sub channel. 45 | 46 | ### `options.peers` 47 | 48 | If this sub channel is used to talk to other services then you 49 | want to pre-populate a `peers` list. 50 | 51 | In the hyperbahn use case you will use 52 | `hyperbahnClient.getClientChannel()` and it will prepopulate the 53 | correct hyperbahn peers. 54 | 55 | In the peer to peer use case you will want to specify an array 56 | of `host:port` strings for all the other instances you want to 57 | talk to. 58 | 59 | The `host:port` strings must be non-ephemeral hostPort as per the 60 | [host-port rules](./host-port.md) 61 | 62 | If you do not specify a `peers` array you must pass a `host` 63 | option for every outgoing request. 64 | 65 | ### `options.peerFile` 66 | 67 | A filePath to read & watch that contains a JSON encoded array 68 | of host ports. A host port is a string that is `{ip}:{port}`. 69 | 70 | This is useful if you want to use tchannel in a p2p fashion 71 | and make requests based on a hostfile on disk. 72 | 73 | ## `var req = subChannel.request(options)` 74 | 75 | `request()` is used to initiate an outgoing request to another channel. 76 | 77 | - [requests](./requests.md) 78 | 79 | ## `subChannel.register(name, handler)` 80 | 81 | Consider using [`as-json`](./as-json.md) or 82 | [`as-thrift`](./as-thrift.md) to register endpoints 83 | that use json or thrift encoding. Calling `register()` directly 84 | is for when you want to deal with binary buffers. 85 | 86 | You can call `register` to register an named endpoint with 87 | handler 88 | 89 | - [requests](./handlers.md) 90 | -------------------------------------------------------------------------------- /endpoint-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var EventEmitter = require('./lib/event_emitter'); 24 | var inherits = require('util').inherits; 25 | var util = require('util'); 26 | var errors = require('./errors'); 27 | var coerceRequestHandler = require('./request-handler'); 28 | 29 | function TChannelEndpointHandler(serviceName) { 30 | if (!(this instanceof TChannelEndpointHandler)) { 31 | return new TChannelEndpointHandler(serviceName); 32 | } 33 | var self = this; 34 | EventEmitter.call(self); 35 | self.handleEndpointEvent = self.defineEvent('handleEndpoint'); 36 | 37 | self.serviceName = serviceName; 38 | self.endpoints = Object.create(null); 39 | } 40 | inherits(TChannelEndpointHandler, EventEmitter); 41 | 42 | TChannelEndpointHandler.prototype.type = 'tchannel.endpoint-handler'; 43 | 44 | TChannelEndpointHandler.prototype.register = function register(name, options, handler) { 45 | var self = this; 46 | if (typeof options === 'function') { 47 | handler = options; 48 | options = {}; 49 | } 50 | if (typeof handler !== 'function') { 51 | throw errors.InvalidHandlerError(); 52 | } 53 | if (options.streamed) { 54 | handler.canStream = true; 55 | } 56 | self.endpoints[name] = coerceRequestHandler(handler, self, options); 57 | return handler; 58 | }; 59 | 60 | TChannelEndpointHandler.prototype.handleRequest = function handleRequest(req, buildResponse) { 61 | var self = this; 62 | 63 | var handler = self.endpoints[req.endpoint]; 64 | self.handleEndpointEvent.emit(self, { 65 | name: req.endpoint, 66 | handler: handler 67 | }); 68 | if (!handler) { 69 | buildResponse({streamed: false}).sendError('BadRequest', util.format( 70 | 'no such endpoint service=%j endpoint=%j', 71 | req.serviceName, req.endpoint)); 72 | } else { 73 | handler.handleRequest(req, buildResponse); 74 | } 75 | }; 76 | 77 | TChannelEndpointHandler.prototype.withArg23 = function withArg23(req, buildResponse, handler) { 78 | req.withArg23(function gotArg23(err, arg2, arg3) { 79 | var res = buildResponse({streamed: false}); 80 | if (err) { 81 | // TODO: log error 82 | res.sendError('UnexpectedError', util.format( 83 | 'error accumulating arg2/arg3: %s: %s', 84 | err.constructor.name, err.message)); 85 | } else { 86 | handler.handleRequest(req, res, arg2, arg3); 87 | } 88 | }); 89 | }; 90 | 91 | module.exports = TChannelEndpointHandler; 92 | -------------------------------------------------------------------------------- /examples/as-thrift.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var TChannelAsThrift = require('../as/thrift'); 24 | var TChannel = require('../channel'); 25 | // In sync with ../docs/as-thrift.md hereafter 26 | var fs = require('fs'); 27 | var path = require('path'); 28 | 29 | var server = TChannel({serviceName: 'server'}); 30 | 31 | var client = TChannel(); 32 | var echoChannel = client.makeSubChannel({ 33 | serviceName: 'echo', 34 | peers: ['127.0.0.1:4040'] 35 | }); 36 | var thriftPath = path.join(__dirname, 'echo.thrift'); 37 | var tchannelThrift = TChannelAsThrift({ 38 | channel: echoChannel, 39 | entryPoint: thriftPath 40 | }); 41 | 42 | var context = {}; 43 | tchannelThrift.register(server, 'Echo::echo', context, echo); 44 | function echo(context, req, head, body, callback) { 45 | callback(null, { 46 | ok: true, 47 | head: head, 48 | body: body 49 | }); 50 | } 51 | 52 | server.listen(4040, '127.0.0.1', onListening); 53 | function onListening() { 54 | tchannelThrift.request({ 55 | serviceName: 'echo', 56 | headers: { 57 | cn: 'echo' 58 | }, 59 | hasNoParent: true 60 | }).send('Echo::echo', { 61 | someHeader: 'headerValue' 62 | }, { 63 | value: 'some-string' 64 | }, onResponse); 65 | 66 | function onResponse(err, res) { 67 | if (err) { 68 | console.log('got error', err); 69 | } else { 70 | console.log('got response', res); 71 | } 72 | 73 | server.close(); 74 | client.close(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /examples/as_example1.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var assert = require('assert'); 24 | 25 | var TChannelJSON = require('../as/json'); 26 | var TChannel = require('../'); 27 | 28 | var server = TChannel({ 29 | serviceName: 'server' 30 | }); 31 | var client = TChannel(); 32 | var tchannelJSON = TChannelJSON(); 33 | 34 | var context = {}; 35 | 36 | tchannelJSON.register(server, 'echo', context, echo); 37 | function echo(context, req, head, body, callback) { 38 | callback(null, { 39 | ok: true, 40 | head: head, 41 | body: body 42 | }); 43 | } 44 | 45 | server.listen(4040, '127.0.0.1', onListening); 46 | 47 | function onListening() { 48 | var clientChan = client.makeSubChannel({ 49 | serviceName: 'server', 50 | peers: [server.hostPort] 51 | }); 52 | tchannelJSON.send(clientChan.request({ 53 | headers: { 54 | cn: 'client' 55 | }, 56 | serviceName: 'server', 57 | hasNoParent: true 58 | }), 'echo', { 59 | head: 'object' 60 | }, { 61 | body: 'object' 62 | }, onResponse); 63 | 64 | function onResponse(err, resp) { 65 | if (err) { 66 | console.log('got error', err); 67 | } else { 68 | assert.equal(resp.ok, true); 69 | console.log('got resp', resp); 70 | } 71 | 72 | server.close(); 73 | client.close(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/echo.thrift: -------------------------------------------------------------------------------- 1 | struct EchoResult { 2 | 1: required string value 3 | } 4 | 5 | service Echo { 6 | EchoResult echo( 7 | 1: string value 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /examples/http_egress.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var parseArgs = require('minimist'); 24 | var http = require('http'); 25 | var TChannel = require('../channel'); 26 | var TChannelAsHTTP = require('../as/http'); 27 | 28 | var argv = parseArgs(process.argv.slice(2), { 29 | default: { 30 | bind: '127.0.0.1', 31 | httpPort: 0, 32 | tchannelPort: 0 33 | }, 34 | alias: { 35 | 'tchannel-port': 'tchannelPort', 36 | 'http-port': 'httpPort' 37 | } 38 | }); 39 | 40 | function usage() { 41 | console.error('usage http_relay [options] '); 42 | console.error('\nOptions:'); 43 | console.error(' --bind
(default: 127.0.0.1)'); 44 | console.error(' --http-port (default: 0)'); 45 | console.error(' --tchannel-port (default: 0)'); 46 | console.error(' --peers [,[,...]]'); 47 | console.error(' --streamed (default false)'); 48 | process.exit(1); 49 | } 50 | 51 | if (argv._.length !== 1) usage(); 52 | 53 | var serviceName = argv._[0]; 54 | 55 | var asHTTP = TChannelAsHTTP(); 56 | 57 | var tchan = TChannel(); 58 | tchan.listen(argv.tchannelPort, argv.bind, onChannelListening); 59 | 60 | var httpServer = http.createServer(onHTTPRequest); 61 | httpServer.listen(argv.httpPort, argv.bind, onHTTPListening); 62 | 63 | var svcChan = tchan.makeSubChannel({ 64 | serviceName: serviceName, 65 | requestDefaults: { 66 | serviceName: serviceName, 67 | headers: { 68 | cn: 'examples/http_ingress' 69 | } 70 | } 71 | }); 72 | 73 | if (argv.peers) { 74 | argv.peers.split(/\s*,\s*/).forEach(function each(hostPort) { 75 | var peer = svcChan.peers.add(hostPort); 76 | console.log('added peer', peer.hostPort); 77 | }); 78 | } 79 | 80 | function onChannelListening() { 81 | var addr = tchan.address(); 82 | console.log('tchannel listening on %s:%s', addr.address, addr.port); 83 | } 84 | 85 | function onHTTPListening() { 86 | var addr = httpServer.address(); 87 | console.log('http listening on %s:%s', addr.address, addr.port); 88 | } 89 | 90 | function onHTTPRequest(hreq, hres) { 91 | asHTTP.forwardToTChannel(svcChan, hreq, hres, { 92 | streamed: argv.streamed 93 | }, function onComplete(error) { 94 | if (error) { 95 | console.error('forward to tchannel failed', error); 96 | } 97 | }); 98 | } 99 | -------------------------------------------------------------------------------- /examples/josh_test_client.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var argv = require('minimist')(process.argv.slice(2)); 24 | var async = require('async'); 25 | 26 | var RNGStream = require('../test/lib/rng_stream'); 27 | 28 | var tchan = require('../channel'); 29 | var chan = tchan(); 30 | var req = chan.request({ 31 | host: '127.0.0.1:4040', 32 | timeout: 10000, 33 | streamed: true 34 | }); 35 | req.on('response', onResponse); 36 | chan.waitForIdentified({ 37 | host: '127.0.0.1:4040' 38 | }, onIdentified); 39 | 40 | function onIdentified() { 41 | req.arg1.end(argv._[0]); 42 | req.arg2.end(argv._[1]); 43 | setImmediate(function sinkBody() { 44 | if (argv.rand) { 45 | RNGStream({limit: argv.rand}).pipe(req.arg3); 46 | } else { 47 | process.stdin.pipe(req.arg3); 48 | } 49 | 50 | setImmediate(function end() { 51 | req.arg3.end(); 52 | }); 53 | }); 54 | } 55 | 56 | function onResponse(res) { 57 | res.arg2.on('data', function onArg2Data(chunk) { 58 | process.stdout.write(chunk); 59 | }); 60 | 61 | res.arg3.on('data', function onArg3Data(chunk) { 62 | process.stdout.write(chunk); 63 | }); 64 | res.arg3.on('end', function onArg3End() { 65 | chan.quit(); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /examples/keyvalue/keyvalue.thrift: -------------------------------------------------------------------------------- 1 | struct GetResult { 2 | 1: required string value 3 | } 4 | 5 | service KeyValue { 6 | GetResult get_v1( 7 | 1: required string key 8 | ) 9 | void put_v1( 10 | 1: required string key, 11 | 2: required string value 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /examples/legacy_example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var console = require('console'); 24 | var CountedReadySignal = require('ready-signal/counted'); 25 | 26 | var TChannel = require('../channel.js'); 27 | 28 | var ready = CountedReadySignal(2); 29 | var server = new TChannel({ 30 | serviceName: 'server' 31 | }); 32 | server.listen(4040, '127.0.0.1', ready.signal); 33 | var client = new TChannel(); 34 | client.listen(4041, '127.0.0.1', ready.signal); 35 | 36 | // normal response 37 | server.register('func 1', function func1(req, res, arg2, arg3) { 38 | console.log('func 1 responding immediately 1:' + 39 | arg2.toString() + ' 2:' + arg3.toString()); 40 | res.sendOk('result', 'indeed it did'); 41 | }); 42 | 43 | // err response 44 | server.register('func 2', function func2(req, res, arg2, arg3) { 45 | res.sendNotOk(null, 'it failed'); 46 | }); 47 | 48 | ready(function onReady() { 49 | client.send({ 50 | host: '127.0.0.1:4040' 51 | }, 'func 1', 'arg 1', 'arg 2', function onResp1(err, res, res1, res2) { 52 | if (err) { 53 | console.log('unexpected err: ' + err.message); 54 | } else { 55 | console.log('normal res: ' + res1.toString() + ' ' + res2.toString()); 56 | } 57 | }); 58 | 59 | client.send({ 60 | host: '127.0.0.1:4040' 61 | }, 'func 2', 'arg 1', 'arg 2', function onResp2(err, res, res1, res2) { 62 | console.log('ok: ' + res.ok + ' err res: ' + res2.toString()); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /examples/repl_client.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | function main() { 24 | var tchan = require('../channel'); 25 | var replrClient = require('replr/bin/replr'); 26 | var TermClient = require('./term_client'); 27 | 28 | var chan = tchan(); 29 | var client = TermClient(chan, { 30 | request: { 31 | host: '127.0.0.1:4040', 32 | timeout: 1000, 33 | } 34 | }); 35 | client.on('error', onError); 36 | client.on('started', start); 37 | client.on('finished', finish); 38 | client.start(); 39 | 40 | function onError(err) { 41 | console.error(err); 42 | finish(); 43 | } 44 | 45 | function start() { 46 | client.linkSize(process.stdout); 47 | replrClient.attachStdinStdoutToReplStream(client.stream); 48 | } 49 | 50 | function finish() { 51 | process.stdin.setRawMode(false); 52 | chan.quit(); 53 | } 54 | } 55 | 56 | if (require.main === module) { 57 | main(); 58 | } 59 | -------------------------------------------------------------------------------- /host-port.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var validIPv4 = /^\d+\.\d+\.\d+\.\d+$/; 24 | 25 | module.exports.validateHostPort = validateHostPort; 26 | module.exports.validateHost = validateHost; 27 | module.exports.validatePort = validatePort; 28 | 29 | function validateHost(host, allowEmphemeral) { 30 | if (typeof host !== 'string') { 31 | return 'Expected host to be a string'; 32 | } 33 | 34 | if (!validIPv4.test(host)) { 35 | return 'Expected host to contain IPv4'; 36 | } 37 | 38 | if (!allowEmphemeral && host === '0.0.0.0') { 39 | return 'Expected host to not be 0.0.0.0'; 40 | } 41 | 42 | return null; 43 | } 44 | 45 | function validatePort(portNum, allowEmphemeral) { 46 | if (typeof portNum !== 'number') { 47 | return 'Expected port to be a number'; 48 | } 49 | 50 | if (!(portNum >= 0 && portNum < 65536)) { 51 | return 'Expected port to be between >=0 & <65536'; 52 | } 53 | 54 | if (!allowEmphemeral && portNum === 0) { 55 | return 'Expected port to not be 0'; 56 | } 57 | 58 | return null; 59 | } 60 | 61 | function validateHostPort(hostPort, allowEmphemeral) { 62 | var reason; 63 | if (typeof hostPort !== 'string') { 64 | return 'Expected hostPort to be a string, got ' + JSON.stringify(hostPort) + ' instead'; 65 | } 66 | 67 | var parts = hostPort.split(':'); 68 | if (parts.length !== 2) { 69 | return 'Expected hostPort to be {ipv4}:{port}, got ' + JSON.stringify(hostPort) + 'instead'; 70 | } 71 | 72 | var host = parts[0]; 73 | reason = validateHost(host, allowEmphemeral); 74 | if (reason) { 75 | return reason + ' in ' + JSON.stringify(hostPort); 76 | } 77 | 78 | var portStr = parts[1]; 79 | if (!stringIsValidNumber(portStr)) { 80 | return 'Expected port to be a valid number in ' + JSON.stringify(hostPort); 81 | } 82 | 83 | var portNum = parseInt(portStr, 10); 84 | reason = validatePort(portNum, allowEmphemeral); 85 | if (reason) { 86 | return reason + ' in ' + JSON.stringify(hostPort); 87 | } 88 | 89 | return null; 90 | } 91 | 92 | function stringIsValidNumber(numAsStr) { 93 | var num = parseInt(numAsStr, 10); 94 | return num.toString() === numAsStr; 95 | } 96 | -------------------------------------------------------------------------------- /hyperbahn.thrift: -------------------------------------------------------------------------------- 1 | exception NoPeersAvailable { 2 | 1: required string message 3 | 2: required string serviceName 4 | } 5 | 6 | exception InvalidServiceName { 7 | 1: required string message 8 | 2: required string serviceName 9 | } 10 | 11 | struct DiscoveryQuery { 12 | 1: required string serviceName 13 | } 14 | 15 | union IpAddress { 16 | 1: i32 ipv4 17 | } 18 | 19 | struct ServicePeer { 20 | 1: required IpAddress ip 21 | 2: required i32 port 22 | } 23 | 24 | struct DiscoveryResult { 25 | 1: required list peers 26 | } 27 | 28 | service Hyperbahn { 29 | DiscoveryResult discover( 30 | 1: required DiscoveryQuery query 31 | ) throws ( 32 | 1: NoPeersAvailable noPeersAvailable 33 | 2: InvalidServiceName invalidServiceName 34 | ) 35 | } -------------------------------------------------------------------------------- /hyperbahn/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var HyperbahnClient = require('../hyperbahn-client.js'); 24 | 25 | module.exports = HyperbahnClient; 26 | -------------------------------------------------------------------------------- /lib/lcg.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Buffer = require('buffer').Buffer; 24 | 25 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 26 | // istanbul ignore next 27 | var bufferAlloc = Buffer.alloc || Buffer; 28 | 29 | // NOTE: this RNG is not suitable for real usage, it exists only for a 30 | // predictable test/benchmark fixture. 31 | 32 | function LCG(seed) { 33 | var self = this; 34 | if (typeof seed === 'number') { 35 | self.last = seed; 36 | } else { 37 | self.last = Math.floor(Math.pow(2, 32) * Math.random()); 38 | } 39 | self.mod = Math.pow(2, 32); 40 | self.mul = 214013; 41 | self.add = 253101; 42 | } 43 | 44 | LCG.prototype.rand = function rand() { 45 | var self = this; 46 | self.last = (self.mul * self.last + self.add) % self.mod; 47 | return self.last; 48 | }; 49 | 50 | LCG.prototype.rand64 = function rand64() { 51 | var self = this; 52 | var ret = bufferAlloc(8); 53 | ret.writeUInt32BE(self.rand(), 0); 54 | ret.writeUInt32BE(self.rand(), 4); 55 | return ret; 56 | }; 57 | 58 | module.exports = LCG; 59 | -------------------------------------------------------------------------------- /lib/pipeline_streams.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var hex; 24 | var util = require('util'); 25 | var process = require('process'); 26 | var Buffer = require('buffer').Buffer; 27 | 28 | /*eslint complexity: [2, 15], max-statements: [2, 40] */ 29 | module.exports = pipelineStreams; 30 | 31 | function pipelineStreams(sources, dests, options, callback) { 32 | if (typeof options === 'function') { 33 | callback = options; 34 | options = {}; 35 | } else if (!options) { 36 | options = {}; 37 | } 38 | next(0); 39 | function next(i) { 40 | if (i >= dests.length) { 41 | if (callback) { 42 | callback(null); 43 | } 44 | return; 45 | } 46 | var src = sources[i]; 47 | var dst = dests[i]; 48 | if (src === null || src === undefined) { 49 | dst.end(); 50 | if (options.debug) { 51 | process.stdout.write(util.format('%s END ARG%s: EMPTY\n', options.debug, i + 1)); 52 | } 53 | next(i + 1); 54 | } else if (typeof src === 'string' || Buffer.isBuffer(src)) { 55 | if (options.debug) { 56 | if (!hex) { 57 | hex = require('hexer'); 58 | } 59 | 60 | process.stdout.write( 61 | util.format('%s END ARG%s:\n', options.debug, i + 1) + 62 | hex(src) + '\n'); 63 | } 64 | dst.end(src); 65 | next(i + 1); 66 | } else { 67 | if (options.debug) { 68 | if (!hex) { 69 | hex = require('hexer'); 70 | } 71 | 72 | var n = i + 1; 73 | process.stdout.write(util.format('%s PIPE ARG%s:\n', options.debug, n)); 74 | src = src.pipe(hex.Spy(process.stdout)); 75 | src.on('end', function onEnd() { 76 | process.stdout.write(util.format('%s PIPE ARG%s END\n', options.debug, n)); 77 | }); 78 | } 79 | src.pipe(dst); 80 | dst.once('finish', onStreamFinished); 81 | } 82 | function onStreamFinished() { 83 | next(i + 1); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/rate_counter.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = RateCounter; 24 | 25 | var assert = require('assert'); 26 | 27 | var DEFAULT_RATE_INTERVAL = 1000; 28 | var DEFAULT_NUM_OF_BUCKETS = 20; 29 | 30 | function RateCounter(options) { 31 | assert(options.timers, 'options.timers required'); 32 | 33 | var self = this; 34 | 35 | this.index = 0; 36 | this.rate = 0; // requests per interval 37 | this.numOfBuckets = options.numOfBuckets || DEFAULT_NUM_OF_BUCKETS; 38 | this.buckets = []; 39 | this.buckets[0] = 0; 40 | 41 | this.timers = options.timers; 42 | this.rateInterval = options.rateInterval || DEFAULT_RATE_INTERVAL; 43 | this.refreshInterval = this.rateInterval / this.numOfBuckets; 44 | 45 | _refreshAndScheduleNext(); 46 | 47 | function _refreshAndScheduleNext() { 48 | self._refresh(); 49 | self.refreshTimer = self.timers.setTimeout(_refreshAndScheduleNext, self.refreshInterval); 50 | } 51 | } 52 | 53 | RateCounter.prototype.isWarmedUp = function isWarmedUp() { 54 | return this.buckets.length === this.numOfBuckets; 55 | }; 56 | 57 | RateCounter.prototype.increment = function increment() { 58 | this.buckets[this.index] += 1; 59 | this.rate += 1; 60 | }; 61 | 62 | RateCounter.prototype.destroy = function destory() { 63 | this.timers.clearTimeout(this.refreshTimer); 64 | this.refreshTimer = null; 65 | }; 66 | 67 | RateCounter.prototype._refresh = function _refresh() { 68 | // update the sliding window 69 | var next = (this.index + 1) % this.numOfBuckets; 70 | if (this.buckets[next]) { 71 | // offset the bucket being moved out 72 | this.rate -= this.buckets[next]; 73 | } 74 | 75 | assert(this.rate >= 0, 'rate should always be larger equal to 0'); 76 | this.index = next; 77 | this.buckets[this.index] = 0; 78 | }; 79 | -------------------------------------------------------------------------------- /lib/retry_ratio_tracker.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = RetryRatioTracker; 24 | 25 | var RateCounter = require('./rate_counter'); 26 | 27 | var DEFAULT_RATE_COUNTER_INTERVAL = 30 * 1000; 28 | var DEFAULT_RATE_COUNTER_NUM_OF_BUCKETS = 30 * 20; 29 | 30 | function RetryRatioTracker(options) { 31 | var rateCounterOpts = { 32 | rateInterval: options.rateCounterInterval || DEFAULT_RATE_COUNTER_INTERVAL, 33 | numBuckets: options.rateCounterNumOfBuckets || DEFAULT_RATE_COUNTER_NUM_OF_BUCKETS, 34 | timers: options.timers 35 | }; 36 | 37 | this.retryRateCounter = new RateCounter(rateCounterOpts); 38 | this.requestRateCounter = new RateCounter(rateCounterOpts); // counts non-retry requests only 39 | } 40 | 41 | RetryRatioTracker.prototype.isWarmedUp = function isWarmedUp() { 42 | return this.requestRateCounter.isWarmedUp() && this.retryRateCounter.isWarmedUp(); 43 | }; 44 | 45 | RetryRatioTracker.prototype.currentRetryRatio = function currentRetryRatio() { 46 | if (this.requestRateCounter.rate === 0) { 47 | return 0; 48 | } 49 | return 1.0 * this.retryRateCounter.rate / this.requestRateCounter.rate; 50 | }; 51 | 52 | RetryRatioTracker.prototype.incrementRequest = function incrementRequest(isRetry) { 53 | if (isRetry) { 54 | this.retryRateCounter.increment(); 55 | } else { 56 | this.requestRateCounter.increment(); 57 | } 58 | }; 59 | 60 | RetryRatioTracker.prototype.destroy = function destroy() { 61 | this.retryRateCounter.destroy(); 62 | this.requestRateCounter.destroy(); 63 | }; 64 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: TChannel Node 2 | repo_url: https://github.com/uber/tchannel-node 3 | 4 | pages: 5 | - Home: index.md 6 | - Guide: GUIDE.md 7 | - TChannel: channel.md 8 | - Sub Channels: sub-channels.md 9 | - Hyperbahn: hyperbahn.md 10 | - As Thrift: as-thrift.md 11 | - As JSON: as-json.md 12 | - Errors: errors.md 13 | - Peer to Peer: peer-to-peer.md 14 | - Statsd: statsd.md 15 | - Streaming: streaming.md 16 | 17 | theme: readthedocs 18 | 19 | markdown_extensions: 20 | - toc: 21 | permalink:  22 | - admonition: 23 | -------------------------------------------------------------------------------- /null-logger.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | function noop() {} 24 | 25 | module.exports = { 26 | debug: noop, 27 | error: noop, 28 | fatal: noop, 29 | info: noop, 30 | warn: noop 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tchannel", 3 | "description": "network multiplexing and framing protocol for RPC or parser drag racing", 4 | "author": "mranney@uber.com", 5 | "version": "4.0.0", 6 | "scripts": { 7 | "lint": "eslint $(git ls-files | grep '.js$')", 8 | "travis": "npm run check-licence && npm run lint -s && npm run travis-cover -s && npm run check-benchmark -s", 9 | "test": "npm run check-licence && npm run lint -s && npm run cover -s && npm run check-benchmark -s", 10 | "benchmark": "echo '!!! DEPRECATED: Better to just run `node benchmarks` directly' >&2; node benchmarks", 11 | "hyperbahn-link-test": "./test/link_hyperbahn.sh", 12 | "tcurl-link-test": "./test/link_tcurl.sh", 13 | "check-benchmark": "node benchmarks -- -r 10000 -p 750", 14 | "take-benchmark": "make -C benchmarks take", 15 | "take-relay-benchmark": "make -C benchmarks take_relay", 16 | "take-trace-benchmark": "amke -C benchmarks take_trace", 17 | "cover": "npm run check-files && npm run test-cover && nyc check-coverage", 18 | "travis-cover": "npm run check-files && npm run travis-test-cover && nyc check-coverage", 19 | "check-files": "bash scripts/verify_included.sh", 20 | "test-cover": "nyc node test/index.js | faucet && nyc report --reporter=lcov --reporter text", 21 | "travis-test-cover": "nyc node test/index.js && nyc report --reporter text", 22 | "check-cover": "nyc check-coverage", 23 | "view-cover": "opn coverage/lcov-report/index.html", 24 | "check-licence": "uber-licence --dry", 25 | "add-licence": "uber-licence" 26 | }, 27 | "main": "channel", 28 | "repository": { 29 | "type": "git", 30 | "url": "git@github.com:uber/tchannel-node" 31 | }, 32 | "dependencies": { 33 | "bufrw": "^1.2.1", 34 | "crc": "^3.8.0", 35 | "error": "^7.0.1", 36 | "farmhash": "^3.0.0", 37 | "json-stringify-safe": "^5.0.1", 38 | "metrics": "^0.1.21", 39 | "minimist": "^1.2.0", 40 | "process": "^0.11.10", 41 | "raw-body": "^2.4.1", 42 | "ready-signal": "^1.3.0", 43 | "run-parallel": "^1.1.9", 44 | "run-series": "^1.1.8", 45 | "safe-json-parse": "^4.0.0", 46 | "sse4_crc32": "^6.0.1", 47 | "thriftrw": "^3.12.0", 48 | "xorshift": "^1.1.1", 49 | "xtend": "^4.0.2" 50 | }, 51 | "devDependencies": { 52 | "async": "^3.1.0", 53 | "chalk": "^1.1.3", 54 | "collect-parallel": "^1.0.1", 55 | "debug-logtron": "^5.2.0", 56 | "duplexer": "^0.1.1", 57 | "eslint": "0.24.0", 58 | "eslint-config-perf-standard": "1.0.0", 59 | "faucet": "0.0.1", 60 | "format-stack": "^4.1.1", 61 | "hexer": "^1.5.0", 62 | "itape": "^1.9.1", 63 | "lb_pool": "^1.6.3", 64 | "ldjson-stream": "^1.2.1", 65 | "loadtest": "1.2.14", 66 | "my-local-ip": "1.0.0", 67 | "nyc": "^15.0.0", 68 | "once": "^1.4.0", 69 | "opn": "^1.0.2", 70 | "replr": "^1.0.6", 71 | "split2": "^3.1.1", 72 | "tape": "^4.13.0", 73 | "through2": "^3.0.1", 74 | "time-mock": "^0.1.4", 75 | "uber-licence": "^3.1.1", 76 | "uber-statsd-client": "^1.7.3" 77 | }, 78 | "pre-commit": [], 79 | "pre-commit.silent": true, 80 | "nyc": { 81 | "branches": 60, 82 | "lines": 60, 83 | "statements": 60, 84 | "functions": 60 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2015 Uber Technologies, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | set -e 24 | set -x 25 | 26 | if [ -z "$1" ]; then 27 | echo "must pass in version as first arg" >&2 28 | exit 1 29 | fi 30 | 31 | if ! which tac >/dev/null 2>&1; then 32 | function tac() 33 | { 34 | tail -r 35 | } 36 | fi 37 | 38 | GIT_TAG=$(npm version "$1") 39 | 40 | if [[ $(head -n1 CHANGELOG.md) = '# vNEXT'* ]]; then 41 | sed -i -e "/^# vNEXT/s/vNEXT.*/$GIT_TAG/" CHANGELOG.md 42 | git commit --amend --no-edit CHANGELOG.md 43 | git tag -a -f -F <( 44 | git cat-file tag "$GIT_TAG" | tac | sed -e '/^$/q' | tac | tail -n+2 45 | ) "$GIT_TAG" HEAD 46 | fi 47 | 48 | if head_ref=$(git symbolic-ref HEAD 2>/dev/null); then 49 | branch_name=${head_ref##*/} 50 | git push origin "$branch_name" --tags 51 | else 52 | git push origin --tags 53 | fi 54 | 55 | git archive --prefix=package/ --format tgz HEAD >package.tgz 56 | ${NPM:-npm} publish --registry=https://registry.npmjs.org/ package.tgz --tag "${NPM_TAG:-alpha}" 57 | rm package.tgz 58 | npm cache clean tchannel 59 | -------------------------------------------------------------------------------- /range.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = Range; 24 | 25 | function Range(lo, hi) { 26 | this.lo = lo; 27 | this.hi = hi; 28 | } 29 | 30 | // Scale this range by another range 31 | Range.prototype.multiply = function multiply(range) { 32 | var diff = this.hi - this.lo; 33 | this.hi = this.lo + (range.hi * diff); 34 | this.lo += (range.lo * diff); 35 | }; 36 | 37 | Range.prototype.inspect = 38 | Range.prototype.toString = function toString() { 39 | return 'Range(' + this.lo + ', ' + this.hi + ')'; 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /reqres_states.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports.Initial = 0; 24 | module.exports.Streaming = 1; 25 | module.exports.Done = 2; 26 | module.exports.Error = 3; 27 | 28 | module.exports.classify = function classify(state) { 29 | switch (state) { 30 | case module.exports.Initial: 31 | return 'Initial'; 32 | case module.exports.Streaming: 33 | return 'Streaming'; 34 | case module.exports.Done: 35 | return 'Done'; 36 | case module.exports.Error: 37 | return 'Error'; 38 | default: 39 | return null; 40 | } 41 | }; 42 | 43 | module.exports.describe = function describe(state) { 44 | return module.exports.classify(state) || 'Unknown(' + state + ')'; 45 | }; 46 | -------------------------------------------------------------------------------- /retry-flags.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = RetryFlags; 24 | 25 | function RetryFlags(never, onConnectionError, onTimeout) { 26 | this.never = never; 27 | this.onConnectionError = onConnectionError; 28 | this.onTimeout = onTimeout; 29 | } 30 | -------------------------------------------------------------------------------- /scripts/changelog_halp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | LAST=$(grep '^# v' CHANGELOG.md | head -n1 | cut -d' ' -f2) 6 | 7 | { 8 | echo '# vNEXT // FIXME' 9 | echo 10 | 11 | git log --first-parent "${LAST}.." | grep -A4 '^Date:' | sed \ 12 | -e '/^ *$/d' \ 13 | -e '/Merge pull request/d' \ 14 | -e '/^Date:/d' \ 15 | -e '/^--/d' \ 16 | -e '/^commit /d' \ 17 | -e '/^ [0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*/ s/^ /# v/' \ 18 | -e '/^ [0-9]\.[0-9][0-9]*\.[0-9][0-9]*/ s/^ /# v/' \ 19 | -e '/^# v/i\' \ 20 | -e '/^# v/a\' \ 21 | -e 's/^ /- /' 22 | 23 | echo 24 | echo '# -- NEW ABOVE, OLD BELOW --' 25 | echo 26 | 27 | cat CHANGELOG.md 28 | } > CHANGELOG.md.new 29 | 30 | mv -vf CHANGELOG.md.new CHANGELOG.md 31 | -------------------------------------------------------------------------------- /scripts/check_files.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | # set -x 4 | 5 | bash "$(dirname $0)/verify_included.sh" 6 | bash "$(dirname $0)/no_only.sh" 7 | bash "$(dirname $0)/check_unique_test_names.sh" 8 | -------------------------------------------------------------------------------- /scripts/check_unique_test_names.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | text=$(git grep "\ /dev/null 2>&1; then 7 | COLORFLAG="--color=never" 8 | else 9 | COLORFLAG="" 10 | fi 11 | 12 | FILES=$( 13 | ls $COLORFLAG test/**/*.js test/*.js | \ 14 | sed "s/test\//.\//g" | \ 15 | grep -v 'lib' | \ 16 | grep -v './index.js' 17 | ) 18 | 19 | # echo $FILES 20 | 21 | for FILE in $FILES; do 22 | # echo $FILE 23 | 24 | set +e 25 | WORD=$(git grep "require.*$FILE" | grep 'test/index') 26 | EXIT_CODE="$?" 27 | set -e 28 | 29 | if [ "$EXIT_CODE" != "0" ]; then 30 | echo "Could not find $FILE"; 31 | exit 1 32 | fi 33 | done 34 | 35 | echo "All tests included!" 36 | -------------------------------------------------------------------------------- /streaming_out_request.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var inherits = require('util').inherits; 24 | 25 | var OutArgStream = require('./argstream').OutArgStream; 26 | var pipelineStreams = require('./lib/pipeline_streams'); 27 | var TChannelOutRequest = require('./out_request'); 28 | var States = require('./reqres_states'); 29 | 30 | function StreamingOutRequest(id, options) { 31 | TChannelOutRequest.call(this, id, options); 32 | this.streamed = true; 33 | this._argstream = new OutArgStream(); 34 | this.arg2 = this._argstream.arg2; 35 | this.arg3 = this._argstream.arg3; 36 | 37 | var self = this; 38 | this._argstream.errorEvent.on(passError); 39 | this._argstream.frameEvent.on(onFrame); 40 | this._argstream.finishEvent.on(onFinish); 41 | 42 | function passError(err) { 43 | self.errorEvent.emit(self, err); 44 | } 45 | 46 | function onFrame(tup) { 47 | var parts = tup[0]; 48 | var isLast = tup[1]; 49 | if (self.state === States.Initial) { 50 | parts.unshift(self.arg1); 51 | } 52 | self.sendParts(parts, isLast); 53 | } 54 | 55 | function onFinish() { 56 | self.finishEvent.emit(self); 57 | } 58 | } 59 | 60 | inherits(StreamingOutRequest, TChannelOutRequest); 61 | 62 | StreamingOutRequest.prototype.type = 'tchannel.outgoing-request.streaming'; 63 | 64 | StreamingOutRequest.prototype.sendArg1 = function sendArg1(arg1) { 65 | var self = this; 66 | 67 | TChannelOutRequest.prototype.sendArg1.call(self, arg1); 68 | self._argstream.deferFlushParts(); 69 | }; 70 | 71 | StreamingOutRequest.prototype.send = function send(arg1, arg2, arg3, callback) { 72 | var self = this; 73 | 74 | if (callback) { 75 | self.hookupCallback(callback); 76 | } 77 | 78 | self.sendArg1(arg1); 79 | self.arg2.end(arg2); 80 | self.arg3.end(arg3); 81 | 82 | return self; 83 | }; 84 | 85 | StreamingOutRequest.prototype.sendStreams = function sendStreams(arg1, arg2, arg3, callback) { 86 | var self = this; 87 | 88 | if (callback) { 89 | self.hookupStreamCallback(callback); 90 | } 91 | 92 | self.sendArg1(arg1); 93 | pipelineStreams([arg2, arg3], [self.arg2, self.arg3]); 94 | 95 | return self; 96 | }; 97 | 98 | module.exports = StreamingOutRequest; 99 | -------------------------------------------------------------------------------- /tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) 2015 Uber Technologies, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | set -e 24 | set -x 25 | 26 | package=$(node -e 'console.log(require("./package.json").name);') 27 | version=$(npm dist-tag ls "$package" | grep '^alpha:' | cut -d ' ' -f2) 28 | tag=${1:-latest} 29 | 30 | npm dist-tag add "$package"@"$version" "$tag" 31 | -------------------------------------------------------------------------------- /tcollector/tcollector.thrift: -------------------------------------------------------------------------------- 1 | // One span refers to one RPC call. The `host` field, which is of type 2 | // `Endpoint`, will be the server being hit by the call. 3 | 4 | struct Endpoint { 5 | 1: required i32 ipv4 6 | 2: required i32 port 7 | 3: required string serviceName 8 | } 9 | 10 | // Regular annotations just associate a timestamp with a string value 11 | struct Annotation { 12 | // Timestamp is in milliseconds since epoch. This is converted to 13 | // microseconds since epoch in the query service since that's what the 14 | // web frontend expects. 15 | 1: required double timestamp 16 | 2: required string value // what happened at the timestamp? 17 | 3: optional i32 duration // how long did the operation take in ms 18 | } 19 | 20 | enum AnnotationType { BOOL, BYTES, I16, I32, I64, DOUBLE, STRING } 21 | 22 | // Binary annotations associate a string key with a value of a particular 23 | // type 24 | struct BinaryAnnotation { 25 | 1: required string key 26 | 2: optional string stringValue 27 | 3: optional double doubleValue 28 | 4: optional bool boolValue 29 | 5: optional binary bytesValue 30 | 6: optional i64 intValue 31 | 7: required AnnotationType annotationType 32 | } 33 | 34 | struct Span { 35 | 1: required binary traceId // unique trace id, use for all spans in trace 36 | 2: required Endpoint host // host being remotely procedure called 37 | 3: required string name // span name, rpc method for example 38 | 4: required binary id // unique span id, only used for this span 39 | 5: required binary parentId // parent span id, 0 if no parent 40 | 6: required list annotations 41 | 7: required list binaryAnnotations 42 | 8: optional bool debug = 0 43 | } 44 | 45 | struct Response { 46 | 1: required bool ok 47 | } 48 | 49 | service TCollector { 50 | Response submit(1: Span span) 51 | } 52 | -------------------------------------------------------------------------------- /test/anechoic-chamber.thrift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | exception NoEchoError { 22 | 1: required i32 value 23 | 2: required string message 24 | } 25 | 26 | exception NoEchoTypedError { 27 | 1: required i32 value 28 | 2: required string message 29 | 3: required string type 30 | } 31 | 32 | service Chamber { 33 | i32 echo(1: required i32 value) throws ( 34 | 1: NoEchoError noEcho 35 | 2: NoEchoTypedError noEchoTyped 36 | ) 37 | i32 echo_big(1: required list value) 38 | } 39 | -------------------------------------------------------------------------------- /test/bad-anechoic-chamber.thrift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | exception NoEchoError { 22 | 1: required i32 value 23 | 2: required string message 24 | } 25 | 26 | exception NoEchoTypedError { 27 | 1: required i32 value 28 | 2: required string message 29 | 3: required string type 30 | } 31 | 32 | service Chamber { 33 | i32 echo(1: required string value) throws ( 34 | 1: NoEchoError noEcho 35 | 2: NoEchoTypedError noEchoTyped 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /test/busy.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Buffer = require('buffer').Buffer; 24 | var allocCluster = require('./lib/alloc-cluster.js'); 25 | var TChannel = require('../channel.js'); 26 | 27 | allocCluster.test('request().send() to a busy server', 2, function t(cluster, assert) { 28 | var two = cluster.channels[1]; 29 | 30 | var count = 0; 31 | 32 | function isBusy() { 33 | count += 1; 34 | 35 | if (count < 2) { 36 | return null; 37 | } 38 | 39 | else { 40 | return 'server is too busy'; 41 | } 42 | } 43 | 44 | var one = TChannel({ 45 | isBusy: isBusy 46 | }); 47 | 48 | one.listen(0, '127.0.0.1', listening); 49 | 50 | var twoSubChan; 51 | var called = 0; 52 | 53 | function listening () { 54 | twoSubChan = two.makeSubChannel({ 55 | serviceName: 'server', 56 | peers: [one.hostPort] 57 | }); 58 | 59 | one.makeSubChannel({ 60 | serviceName: 'server' 61 | }).register('foo', function foo(req, res, arg2, arg3) { 62 | called++; 63 | 64 | assert.ok(Buffer.isBuffer(arg2), 'handler got an arg2 buffer'); 65 | assert.ok(Buffer.isBuffer(arg3), 'handler got an arg3 buffer'); 66 | res.headers.as = 'raw'; 67 | res.sendOk(arg2, arg3); 68 | }); 69 | 70 | twoSubChan.request({ 71 | serviceName: 'server', 72 | hasNoParent: true, 73 | headers: { 74 | as: 'raw', 75 | cn: 'two' 76 | } 77 | }).send('foo', 'arg1', 'arg2', onResp); 78 | } 79 | 80 | function onResp(err, res, arg2, arg3) { 81 | twoSubChan.request({ 82 | serviceName: 'server', 83 | hasNoParent: true, 84 | headers: { 85 | as: 'raw', 86 | cn: 'two' 87 | } 88 | }).send('foo', 'arg1', 'arg2', onResp2); 89 | } 90 | 91 | function onResp2(err, res, arg2, arg3) { 92 | assert.ok(err.isErrorFrame, 'got an error frame'); 93 | assert.equals(err.type, 'tchannel.busy'); 94 | assert.ok(err.isErrorFrame, 'err isErrorFrame'); 95 | assert.equals(err.codeName, 'Busy', 'error code name busy'); 96 | assert.equals(err.fullType, 'tchannel.busy'); 97 | 98 | one.close(); 99 | assert.equal(called, 1); 100 | 101 | assert.end(); 102 | } 103 | }); 104 | -------------------------------------------------------------------------------- /test/config/with_lazy_relay.json: -------------------------------------------------------------------------------- 1 | { 2 | "useLazyHandling": true, 3 | "useLazyRelaying": true 4 | } 5 | -------------------------------------------------------------------------------- /test/config/with_peer_heap.json: -------------------------------------------------------------------------------- 1 | { 2 | "choosePeerWithHeap": true 3 | } 4 | -------------------------------------------------------------------------------- /test/config/without_lazy_relay.json: -------------------------------------------------------------------------------- 1 | { 2 | "useLazyHandling": false, 3 | "useLazyRelaying": false 4 | } 5 | -------------------------------------------------------------------------------- /test/config/without_peer_heap.json: -------------------------------------------------------------------------------- 1 | { 2 | "choosePeerWithHeap": false 3 | } 4 | -------------------------------------------------------------------------------- /test/ephemeral-client.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var TChannel = require('../channel.js'); 24 | 25 | module.exports = runTests; 26 | 27 | if (require.main === module) { 28 | runTests(require('./lib/hyperbahn-cluster.js')); 29 | } 30 | 31 | function runTests(HyperbahnCluster) { 32 | HyperbahnCluster.test('ephemeral client works', { 33 | size: 5 34 | }, function t(cluster, assert) { 35 | var bob = cluster.remotes.bob; 36 | 37 | for (var i = 0; i < cluster.apps.length; i++) { 38 | var app = cluster.apps[i]; 39 | app.clients.serviceProxy.block('*', bob.serviceName); 40 | } 41 | 42 | var client = TChannel({ 43 | trace: false 44 | }); 45 | var subClient = client.makeSubChannel({ 46 | serviceName: 'test', 47 | requestDefaults: { 48 | hasNoParent: true, 49 | headers: { 50 | as: 'raw', 51 | cn: 'client' 52 | } 53 | }, 54 | peers: [cluster.hostPortList[0]] 55 | }); 56 | 57 | subClient.waitForIdentified({ 58 | host: cluster.hostPortList[0] 59 | }, onIdentified); 60 | 61 | function onIdentified(err) { 62 | assert.ifError(err); 63 | 64 | subClient.request({ 65 | serviceName: bob.serviceName 66 | }).send('echo', 'a', 'b', onResponse); 67 | } 68 | 69 | function onResponse(err, res, arg2, arg3) { 70 | assert.ok(err); 71 | assert.equal(err.type, 'tchannel.request.timeout'); 72 | 73 | assert.equal(res, null); 74 | 75 | client.close(); 76 | 77 | setTimeout(function later() { 78 | assert.end(); 79 | }, 10); 80 | } 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /test/event_emitter.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var EventEmitter = require('../lib/event_emitter'); 25 | var inherits = require('util').inherits; 26 | 27 | function Foo() { 28 | EventEmitter.call(this); 29 | this.errorEvent = this.defineEvent('error'); 30 | this.fooEvent = this.defineEvent('foo'); 31 | this.barEvent = this.defineEvent('bar'); 32 | } 33 | 34 | inherits(Foo, EventEmitter); 35 | 36 | test('classic on works', function t(assert) { 37 | var fooCalled = null; 38 | var errCalled = null; 39 | var f = new Foo(); 40 | 41 | f.on('error', function(err) { 42 | assert.deepEqual(this, f, 'expected context'); 43 | errCalled = err; 44 | }); 45 | 46 | f.on('foo', function(arg) { 47 | assert.deepEqual(this, f, 'expected context'); 48 | fooCalled = arg; 49 | }); 50 | 51 | f.emit('foo', 'abc'); 52 | assert.deepEqual(errCalled, null, 'expected no err'); 53 | assert.deepEqual(fooCalled, 'abc', 'expected arg'); 54 | 55 | fooCalled = errCalled = null; 56 | var err = new Error('ERR'); 57 | f.emit('error', err); 58 | assert.deepEqual(errCalled, err, 'expected err'); 59 | assert.deepEqual(fooCalled, null, 'expected no arg'); 60 | 61 | assert.end(); 62 | }); 63 | 64 | test('default error behavior', function t(assert) { 65 | var f = new Foo(); 66 | assert.throws(function() { 67 | f.emit('error', new Error('ERR')); 68 | }, /ERR/); 69 | assert.end(); 70 | }); 71 | 72 | test('multiple on works', function t(assert) { 73 | var f = new Foo(); 74 | var fooCalled = null; 75 | 76 | fooCalled = []; 77 | f.on('foo', one); 78 | f.on('foo', two); 79 | f.emit('foo', 'abc'); 80 | assert.deepEqual(fooCalled, [ 81 | [1, 'abc'], 82 | [2, 'abc'] 83 | ], 'expected arg'); 84 | 85 | fooCalled = []; 86 | f.removeListener('foo', one); 87 | f.emit('foo', 'abc'); 88 | assert.deepEqual(fooCalled, [ 89 | [2, 'abc'] 90 | ], 'expected arg'); 91 | 92 | assert.end(); 93 | 94 | function one(arg) { 95 | fooCalled.push([1, arg]); 96 | } 97 | 98 | function two(arg) { 99 | fooCalled.push([2, arg]); 100 | } 101 | }); 102 | -------------------------------------------------------------------------------- /test/hyperbahn-client/sub-channel.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | 25 | var TChannel = require('../../'); 26 | var HyperbahnClient = require('../../hyperbahn/index.js'); 27 | 28 | test('getting client subChannel without serviceName', function t(assert) { 29 | var client = HyperbahnClient({ 30 | tchannel: TChannel(), 31 | serviceName: 'foo', 32 | callerName: 'foo-test', 33 | hostPortList: [] 34 | }); 35 | 36 | assert.throws(function throwIt() { 37 | client.getClientChannel(); 38 | }, /must pass serviceName/); 39 | 40 | assert.throws(function throwIt() { 41 | client.getClientChannel({}); 42 | }, /must pass serviceName/); 43 | 44 | client.tchannel.close(); 45 | assert.end(); 46 | }); 47 | 48 | test('getting a client subChannel', function t(assert) { 49 | var client = HyperbahnClient({ 50 | tchannel: TChannel(), 51 | serviceName: 'foo', 52 | callerName: 'foo-test', 53 | hostPortList: [] 54 | }); 55 | 56 | var subChannel = client.getClientChannel({ 57 | serviceName: 'bar' 58 | }); 59 | 60 | assert.equal(subChannel.topChannel, client.tchannel); 61 | 62 | client.tchannel.close(); 63 | assert.end(); 64 | }); 65 | 66 | test('double getting a client subChannel', function t(assert) { 67 | var client = HyperbahnClient({ 68 | tchannel: TChannel(), 69 | serviceName: 'foo', 70 | callerName: 'foo-test', 71 | hostPortList: [] 72 | }); 73 | 74 | var subChannel1 = client.getClientChannel({ 75 | serviceName: 'bar' 76 | }); 77 | var subChannel2 = client.getClientChannel({ 78 | serviceName: 'bar' 79 | }); 80 | 81 | assert.equal(subChannel1, subChannel2); 82 | 83 | client.tchannel.close(); 84 | assert.end(); 85 | }); 86 | -------------------------------------------------------------------------------- /test/hyperbahn-client/thrift-codec.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var path = require('path'); 25 | 26 | var TChannel = require('../../'); 27 | var HyperbahnClient = require('../../hyperbahn/index.js'); 28 | 29 | test('calling getThrift', function t(assert) { 30 | var hypeClient = makeHyperbahnClient(); 31 | var hypeServer = makeHyperbahnClient(); 32 | 33 | var thriftClient = hypeClient.getThriftSync({ 34 | serviceName: 'foo', 35 | thriftFile: path.join(__dirname, '..', 'anechoic-chamber.thrift') 36 | }); 37 | var thriftServer = hypeServer.getThriftSync({ 38 | serviceName: 'foo', 39 | thriftFile: path.join(__dirname, '..', 'anechoic-chamber.thrift') 40 | }); 41 | 42 | assert.equal( 43 | thriftClient.spec.getSources().entryPoint, 44 | thriftServer.spec.getSources().entryPoint, 45 | 'client and server have the same entrypoint' 46 | ); 47 | 48 | thriftServer.register('Chamber::echo', {}, echo); 49 | 50 | var counter = 2; 51 | hypeClient.tchannel.listen(0, '127.0.0.1', onListen); 52 | hypeServer.tchannel.listen(0, '127.0.0.1', onListen); 53 | 54 | function onListen() { 55 | if (--counter === 0) { 56 | sendRequests(); 57 | } 58 | } 59 | 60 | function sendRequests() { 61 | thriftClient.channel.peers.add(hypeServer.tchannel.hostPort); 62 | 63 | thriftClient.request({ 64 | hasNoParent: true 65 | }).send('Chamber::echo', null, { 66 | value: 10 67 | }, function onResponse(err, resp) { 68 | assert.ifError(err, 'request() has no error'); 69 | 70 | assert.ok(resp, 'request() has response'); 71 | assert.equal(resp.ok, true, 'response is ok'); 72 | assert.equal(resp.body, 10, 'response body is 10'); 73 | 74 | hypeClient.tchannel.close(); 75 | hypeServer.tchannel.close(); 76 | assert.end(); 77 | }); 78 | } 79 | 80 | function echo(context, req, arg2, arg3, cb) { 81 | cb(null, { 82 | ok: true, 83 | body: arg3.value 84 | }); 85 | } 86 | }); 87 | 88 | function makeHyperbahnClient() { 89 | var channel = TChannel(); 90 | 91 | return HyperbahnClient({ 92 | tchannel: channel, 93 | serviceName: 'foo', 94 | callerName: 'foo-test', 95 | hostPortList: [] 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /test/identify.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var allocCluster = require('./lib/alloc-cluster.js'); 24 | var barrier = require('./lib/barrier'); 25 | 26 | allocCluster.test('identify', 2, function t(cluster, assert) { 27 | var one = cluster.channels[0]; 28 | var two = cluster.channels[1]; 29 | var hostOne = cluster.hosts[0]; 30 | var hostTwo = cluster.hosts[1]; 31 | 32 | assert.equal(one.peers.get(hostTwo), null, 'one has no peer two'); 33 | assert.equal(two.peers.get(hostOne), null, 'two has no peer one'); 34 | 35 | var idBar = barrier.keyed(2, function(idents, done) { 36 | assert.equal(idents.one.hostPort, hostTwo, 'one identified two'); 37 | assert.equal(idents.two.hostPort, hostOne, 'two identified one'); 38 | 39 | cluster.assertEmptyState(assert); 40 | 41 | done(); 42 | }, assert.end); 43 | 44 | two.on('connection', function onConn(conn) { 45 | conn.on('identified', idBar('two')); 46 | }); 47 | 48 | var one2two = one.peers.add(hostTwo); 49 | one2two.connect().on('identified', idBar('one')); 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /test/large-send.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var allocCluster = require('./lib/alloc-cluster.js'); 24 | 25 | allocCluster.test('large arg3 on utf8 non-English characters', 2, function t(cluster, assert) { 26 | var one = cluster.channels[0]; 27 | var two = cluster.channels[1]; 28 | 29 | var bigStr = ''; 30 | for (var i = 0; i < 150000; i++) { 31 | bigStr += '正'; 32 | } 33 | 34 | two = two.makeSubChannel({ 35 | serviceName: 'server', 36 | peers: [one.hostPort] 37 | }); 38 | 39 | one.makeSubChannel({ 40 | serviceName: 'server' 41 | }).register('foo', function foo(req, res, arg2, arg3) { 42 | assert.ok(bigStr === arg3.toString(), 'send should work'); 43 | res.headers.as = 'raw'; 44 | res.sendOk(arg2, arg3.toString()); 45 | }); 46 | 47 | two.request({ 48 | serviceName: 'server', 49 | timeout: 1500, 50 | hasNoParent: true, 51 | headers: { 52 | cn: 'test', 53 | as: 'raw' 54 | } 55 | }).send('foo', '', bigStr, function onResp(err, res, arg2, arg3) { 56 | if (err) { 57 | assert.end(err); 58 | } else { 59 | assert.ok(bigStr === arg3.toString(), 'response should work'); 60 | assert.end(); 61 | } 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/lib/barplot.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = barplot; 24 | 25 | function barplot(emit, pairs) { 26 | var key, i; 27 | 28 | var maxKeyLen = 0; 29 | for (i = 0; i < pairs.length; i++) { 30 | key = pairs[i][0]; 31 | var keyLen = pairs[i][0].length; 32 | if (keyLen > maxKeyLen) { 33 | maxKeyLen = keyLen; 34 | } 35 | } 36 | 37 | maxKeyLen++; 38 | for (i = 0; i < pairs.length; i++) { 39 | key = pairs[i][0]; 40 | var count = pairs[i][1]; 41 | var countStr = 'count=' + count.toString(); 42 | emit(pad(maxKeyLen, ' ', key) + 43 | pad(10, ' ', countStr) + 44 | mulchr(count, '*')); 45 | } 46 | } 47 | 48 | function pad(n, c, s) { 49 | while (s.length < n) { 50 | s += c; 51 | } 52 | return s; 53 | } 54 | 55 | function mulchr(n, c) { 56 | var s = ''; 57 | while (s.length < n) { 58 | s += c; 59 | } 60 | return s; 61 | } 62 | -------------------------------------------------------------------------------- /test/lib/barrier.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* 24 | * Provides an async "barrier" for use in tests. 25 | * 26 | * A barrier is a function that expects to be called N-times. Calling it more 27 | * than N times is an error. 28 | * 29 | * Once called N times, it executes a check function. 30 | * 31 | * The check function gets an array of the calling arguments in temporal order. 32 | * 33 | * To help with reconciling arbitrarily ordered events, a keyed convenience 34 | * layer is defined. 35 | */ 36 | 37 | module.exports = barrier; 38 | module.exports.keyed = keyedBarrier; 39 | 40 | function barrier(expected, check, callback) { 41 | var got = 0; 42 | var buffer = new Array(expected); 43 | return function() { 44 | if (got >= expected) return callback(new Error('barrier called two many times')); 45 | buffer[got] = Array.prototype.slice.call(arguments); 46 | if (++got < expected) return; 47 | check(buffer, callback); 48 | }; 49 | } 50 | 51 | function keyedBarrier(expected, check, callback) { 52 | var bar = barrier(expected, function(results, done) { 53 | var idents = {}; 54 | results.forEach(function(result) { 55 | idents[result[0]] = result[1]; 56 | }); 57 | check(idents, done); 58 | }, callback); 59 | return function(name) { 60 | return bar.bind(null, name); 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /test/lib/base2.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | // constants for easy declaration, e.g.: 24 | // size = 1 * Mi 25 | var Ki = Math.pow(2, 10); 26 | var Mi = Math.pow(2, 20); 27 | var Gi = Math.pow(2, 30); 28 | var Ti = Math.pow(2, 40); 29 | module.exports.Ki = Ki; 30 | module.exports.Mi = Mi; 31 | module.exports.Gi = Gi; 32 | module.exports.Ti = Ti; 33 | 34 | /* 35 | * decomposes byte numbers into human-friendly linear combinations, e.g.: 36 | * - pretty(1025) => '1Ki + 1' 37 | * - pretty(32745) => '31Ki + 1001' 38 | * - pretty(9372651) => '8Mi + 960Ki + 1003' 39 | * - pretty(2163342357) => '2Gi + 15Mi + 127Ki + 21' 40 | */ 41 | 42 | var units = { 43 | Ti: Ti, 44 | Gi: Gi, 45 | Mi: Mi, 46 | Ki: Ki 47 | }; 48 | 49 | var tiers = Object.keys(units).map(function each(name) { 50 | return [name, units[name]]; 51 | }); 52 | 53 | var pattern = /(\d+)(Ki|Mi|Gi|Ti)?/; 54 | 55 | function parse(s) { 56 | if (typeof s === 'number') return s; 57 | var n = 0; 58 | var parts = s.split(/\s*\+\s*/); 59 | for (var i = 0; i < parts.length; i++) { 60 | var match = pattern.exec(parts[i]); 61 | if (!match) return NaN; 62 | var d = parseInt(match[1], 10); 63 | if (match[2]) { 64 | if (units[match[2]] === undefined) return NaN; 65 | d *= units[match[2]]; 66 | } 67 | n += d; 68 | } 69 | return n; 70 | } 71 | 72 | module.exports.parse = parse; 73 | 74 | function pretty(n, suffix) { 75 | suffix = suffix || ''; 76 | var s = ''; 77 | var i = 0; 78 | while (n > 0 && i < tiers.length) { 79 | if (s.length > 0) s += ' + '; 80 | var name = tiers[i][0]; 81 | var unit = tiers[i][1]; 82 | if (n >= unit) { 83 | var d = Math.floor(n / unit); 84 | n = n % unit; 85 | s += d.toString(10) + name + suffix; 86 | } 87 | i++; 88 | } 89 | if (n > 0) { 90 | if (s.length > 0) s += ' + '; 91 | s += n.toString(10) + suffix; 92 | } else if (!s.length) { 93 | s += '0' + suffix; 94 | } 95 | return s; 96 | } 97 | 98 | module.exports.pretty = pretty; 99 | -------------------------------------------------------------------------------- /test/lib/count_stream.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var bufrw = require('bufrw'); 24 | var inherits = require('util').inherits; 25 | var IterStream = require('./iter_stream'); 26 | 27 | function CountStream(options) { 28 | if (!(this instanceof CountStream)) { 29 | return new CountStream(options); 30 | } 31 | var self = this; 32 | // TODO: allow to change rw 33 | IterStream.call(self, bufrw.UInt32BE, options); 34 | self._max = Math.pow(2, 8 * self._rw.width); 35 | self._n = 0; 36 | } 37 | inherits(CountStream, IterStream); 38 | 39 | CountStream.prototype._next = function _read() { 40 | var self = this; 41 | var n = self._n; 42 | self._n = (self._n + 1) % self._max; 43 | return n; 44 | }; 45 | 46 | module.exports = CountStream; 47 | -------------------------------------------------------------------------------- /test/lib/iter_stream.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var inherits = require('util').inherits; 24 | var Readable = require('stream').Readable; 25 | 26 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 27 | // istanbul ignore next 28 | var bufferAlloc = Buffer.alloc || Buffer; 29 | 30 | function IterStream(rw, options) { 31 | if (!(this instanceof IterStream)) { 32 | return new IterStream(options); 33 | } 34 | if (!rw.width) throw new Error('not an atomic RW'); 35 | var self = this; 36 | Readable.call(self); 37 | self._rw = rw; 38 | self._limit = ( 39 | typeof options.limit !== 'number' || 40 | options.limit < 0 41 | ) ? Math.pow(2, 16) : options.limit; 42 | self._cur = 0; 43 | } 44 | inherits(IterStream, Readable); 45 | 46 | IterStream.prototype._read = function _read(size) { 47 | var self = this; 48 | var remain = Math.max(0, self._limit - self._cur); 49 | size = Math.min(remain, size); 50 | if (!size) { 51 | self.push(null); 52 | return; 53 | } 54 | var count = Math.ceil(size / self._rw.width); 55 | var buf = bufferAlloc(self._rw.width * count); 56 | var offset = 0; 57 | for (var i = 0; i < count; i++) { 58 | var n = self._next(); 59 | var res = self._rw.writeInto(n, buf, offset); 60 | if (res.err) { 61 | if (offset > 0) { 62 | self.push(buf.slice(0, offset)); 63 | self._cur += offset; 64 | } 65 | self.emit('error', res.err); 66 | self.push(null); 67 | return; 68 | } 69 | offset = res.offset; 70 | } 71 | buf = buf.slice(0, size); 72 | self.push(buf); 73 | self._cur += buf.length; 74 | }; 75 | 76 | module.exports = IterStream; 77 | -------------------------------------------------------------------------------- /test/lib/link_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2015 Uber Technologies, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | given_or_clone() 24 | { 25 | if [ -z "$1" ]; then 26 | name=$(basename "$2") 27 | TCHANNEL_TEST_DIR=$(mktemp -d -t tchannel-link-"$name".XXXXXX) 28 | git clone "$2" "$TCHANNEL_TEST_DIR" 29 | else 30 | TCHANNEL_TEST_DIR=$1 31 | fi 32 | } 33 | 34 | function copy_test_config() 35 | { 36 | if [ -n "$TCHANNEL_TEST_CONFIG" ]; then 37 | for part in $(eval "echo $TCHANNEL_TEST_CONFIG"); do 38 | dest_part="$TCHANNEL_TEST_DIR/from_tchannel_$(echo "$part" | tr '/' '_')" 39 | cp -fv "$part" "$dest_part" 40 | done 41 | TCHANNEL_TEST_CONFIG=from_tchannel_$(echo "$TCHANNEL_TEST_CONFIG" | tr '/' '_') 42 | export TCHANNEL_TEST_CONFIG 43 | fi 44 | } 45 | -------------------------------------------------------------------------------- /test/lib/load_config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var extendInto = require('xtend/mutable'); 24 | var fs = require('fs'); 25 | 26 | var extractParts = require('../../lib/part-list.js').extractParts; 27 | 28 | module.exports = combineConfig; 29 | 30 | function combineConfig(configPath) { 31 | var parts = extractParts(configPath); 32 | var paths = parts.all(); 33 | var config = {}; 34 | for (var i = 0; i < paths.length; i++) { 35 | var contents = fs.readFileSync(paths[i], 'utf8'); 36 | var partConfig = JSON.parse(contents); 37 | extendInto(config, partConfig); 38 | } 39 | return config; 40 | } 41 | -------------------------------------------------------------------------------- /test/lib/peer_score_obs.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var format = require('util').format; 24 | 25 | module.exports = hookupPeerScoreObs; 26 | 27 | function hookupPeerScoreObs(log, client, servers) { 28 | client.peerScoredEvent.on(onPeerScored); 29 | client.peerChosenEvent.on(onPeerChosen); 30 | 31 | function onPeerScored(info) { 32 | var peerDesc = describeServerPeer(servers, info.peer); 33 | var mess = format('%s scored peer %s', info.reason, peerDesc); 34 | if (info.scores) { 35 | var changes = info.scores.map(function each(score, i) { 36 | var change = score.hi / info.oldScores[i].hi - 1; 37 | var sign = change > 0 ? '+' : ''; 38 | var str = sign + (100 * change).toFixed(1); 39 | return pad(5, ' ', str) + '%'; 40 | }); 41 | mess += ' by ' + changes.join(', '); 42 | } else { 43 | mess += ' score=' + info.score; 44 | } 45 | log(mess); 46 | } 47 | 48 | function onPeerChosen(info) { 49 | var peerDesc = describeServerPeer(servers, info.peer); 50 | var mess = format('%s chose server %s', info.mode, peerDesc); 51 | log(mess); 52 | } 53 | } 54 | 55 | function describeServerPeer(servers, peer) { 56 | for (var i = 0; i < servers.length; i++) { 57 | if (peer.hostPort === servers[i].hostPort) { 58 | return '' + (i + 1); 59 | } 60 | } 61 | return 'unknown(' + peer.hostPort + ')'; 62 | } 63 | 64 | function pad(n, c, s) { 65 | while (s.length < n) { 66 | s = c + s; 67 | } 68 | return s; 69 | } 70 | -------------------------------------------------------------------------------- /test/lib/raw_service.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | function setupRawTestService(chan) { 24 | if (!chan.serviceName) { 25 | chan = chan.makeSubChannel({ 26 | serviceName: 'test_as_raw' 27 | }); 28 | } 29 | chan.register('echo', echo); 30 | chan.register('streaming_echo', { 31 | streamed: true 32 | }, streamingEcho); 33 | } 34 | 35 | function echo(req, buildRes, arg2, arg3) { 36 | var res = buildRes(); 37 | res.headers.as = 'raw'; 38 | if (req.headers.as !== 'raw') { 39 | res.sendError('BadRequest', 'expected as=raw transport header'); 40 | } else { 41 | res.sendOk(req.arg2, req.arg3); 42 | } 43 | } 44 | 45 | function streamingEcho(req, buildRes) { 46 | if (!req.streamed) { 47 | echo(req, buildRes, req.arg2, req.arg3); 48 | } else if (req.headers.as !== 'raw') { 49 | buildRes().sendError('BadRequest', 'expected as=raw transport header'); 50 | } else { 51 | var res = buildRes({streamed: true}); 52 | res.headers.as = 'raw'; 53 | res.setOk(true); 54 | res.sendStreams(req.arg2, req.arg3); 55 | } 56 | } 57 | 58 | module.exports = setupRawTestService; 59 | -------------------------------------------------------------------------------- /test/lib/resource_pool.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | function ResourcePool(setup, destroy) { 24 | var self = this; 25 | self.free = []; 26 | self.setup = setup; 27 | self.destroyRes = destroy || callDestroy; 28 | } 29 | 30 | ResourcePool.prototype.get = function getCluster(callback) { 31 | var self = this; 32 | if (self.free.length) { 33 | callback(null, self.free.shift()); 34 | } else { 35 | self.setup(callback); 36 | } 37 | }; 38 | 39 | ResourcePool.prototype.release = function release(res) { 40 | var self = this; 41 | self.free.push(res); 42 | }; 43 | 44 | ResourcePool.prototype.destroy = function destroy(callback) { 45 | var self = this; 46 | var free = self.free; 47 | var errs = []; 48 | self.free = []; 49 | var toDestroy = free.length; 50 | free.forEach(function each(res) { 51 | self.destroyRes(res, destroyed); 52 | }); 53 | 54 | function destroyed(err) { 55 | if (err) errs.push(err); 56 | if (--toDestroy <= 0) { 57 | if (toDestroy < 0) { 58 | errs.push(new Error('too many destroyed callbacks')); 59 | } 60 | finish(); 61 | } 62 | } 63 | 64 | function finish() { 65 | // TODO: aggregated error wrapper? 66 | var err = errs.length && errs[errs.length - 1] || null; 67 | callback(err); 68 | } 69 | }; 70 | 71 | function callDestroy(res, callback) { 72 | res.destroy(callback); 73 | } 74 | 75 | module.exports = ResourcePool; 76 | -------------------------------------------------------------------------------- /test/lib/rng_stream.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var bufrw = require('bufrw'); 24 | var inherits = require('util').inherits; 25 | var IterStream = require('./iter_stream'); 26 | var LCG = require('../../lib/lcg'); 27 | 28 | function LCGStream(options) { 29 | if (!(this instanceof LCGStream)) { 30 | return new LCGStream(options); 31 | } 32 | var self = this; 33 | IterStream.call(self, bufrw.UInt32BE, options); 34 | self.rng = new LCG(options.seed); 35 | } 36 | inherits(LCGStream, IterStream); 37 | 38 | LCGStream.prototype._next = function _next() { 39 | var self = this; 40 | return self.rng.rand(); 41 | }; 42 | 43 | module.exports = LCGStream; 44 | -------------------------------------------------------------------------------- /test/lib/run_server.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Logger = require('debug-logtron'); 24 | var parseArgs = require('minimist'); 25 | var util = require('util'); 26 | 27 | var TChannel = require('../channel'); 28 | var setupRawTestService = require('./lib/raw_service'); 29 | 30 | var argv = parseArgs(process.argv.slice(2), { 31 | alias: { 32 | h: 'host', 33 | p: 'port' 34 | }, 35 | default: { 36 | host: '127.0.0.1', 37 | port: 0, 38 | } 39 | }); 40 | 41 | var chan = TChannel({ 42 | logger: Logger('testserver') 43 | }); 44 | setupRawTestService(chan); 45 | 46 | // TODO: logger? 47 | chan.listen(argv.port, argv.host); 48 | chan.on('listening', function onListening() { 49 | var addr = chan.address(); 50 | process.stdout.write(util.format( 51 | 'listening on %s:%s\n', addr.address, addr.port 52 | )); 53 | }); 54 | -------------------------------------------------------------------------------- /test/lib/simple_validators.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports.timestamp = function (assert, value) { 22 | assert.ok(typeof value === 'number'); 23 | assert.ok(value.toString().length === 13); 24 | }; 25 | 26 | // Sets the first time it's seen then validates the rest of the time 27 | module.exports.checkId = function (idStore, idKey) { 28 | return function (assert, id, key) { 29 | if (!idStore[idKey]) { 30 | idStore[idKey] = id; 31 | return; 32 | } 33 | 34 | assert.deepEquals(id, idStore[idKey], "idKey: " + idKey + " key: " + key); 35 | }; 36 | }; 37 | 38 | module.exports.validateSpans = 39 | function validateSpans(assert, actual, expected) { 40 | // Spans may be received in a different order than in the fixture, so we 41 | // need to find a way to identify them in order to check their contents. 42 | // Unfortunately since the ids are randomly generated we can't use those. 43 | // So we base an id off the contents and then validate. 44 | 45 | var actualById = {}; 46 | var expectedById = {}; 47 | 48 | function mapSpanToUniqueId(item) { 49 | return item.name + item.endpoint.ipv4 + item.endpoint.port + 50 | item.annotations.reduce(function (str, item) { 51 | return str + item.value; 52 | }, ""); 53 | } 54 | 55 | actual.forEach(function (item) { 56 | actualById[mapSpanToUniqueId(item)] = item; 57 | }); 58 | 59 | expected.forEach(function (item) { 60 | expectedById[mapSpanToUniqueId(item)] = item; 61 | }); 62 | 63 | validate(assert, actualById, expectedById); 64 | }; 65 | 66 | module.exports.validate = validate; 67 | module.exports.validate1 = validate1; 68 | 69 | function validate(assert, actual, expected, prefix) { 70 | if (prefix) { 71 | prefix += '.'; 72 | } else { 73 | prefix = ''; 74 | } 75 | Object.keys(expected).forEach(function each(key) { 76 | validate1(assert, 77 | prefix + key, 78 | actual && actual[key], 79 | expected && expected[key]); 80 | }); 81 | } 82 | 83 | function validate1(assert, desc, actual, expected) { 84 | if (Buffer.isBuffer(actual)) { 85 | actual = actual.toString('hex'); 86 | } 87 | 88 | if (typeof expected === 'function') { 89 | return expected(assert, actual, desc); 90 | } 91 | 92 | if (typeof expected === 'object') { 93 | return validate(assert, actual, expected, desc); 94 | } 95 | 96 | assert.equals(actual, expected, desc); 97 | } 98 | -------------------------------------------------------------------------------- /test/lib/stream_check.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var util = require('util'); 24 | 25 | var base2 = require('./base2'); 26 | 27 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 28 | // istanbul ignore next 29 | var bufferAlloc = Buffer.alloc || Buffer; 30 | var emptyBuffer = bufferAlloc(0); 31 | 32 | module.exports = StreamCheck; 33 | 34 | function StreamCheck(name, assert, expected) { 35 | var self = this; 36 | self.name = name; 37 | self.assert = assert; 38 | self.expected = expected; 39 | } 40 | 41 | StreamCheck.prototype.verifyChunk = function verifyChunk(offset, gotChunk) { 42 | var self = this; 43 | var expectedChunk = self.expected.read(gotChunk.length) || emptyBuffer; 44 | self.assert.deepEqual(gotChunk, expectedChunk, util.format( 45 | self.name + ': expected chunk %s bytes @%s', 46 | base2.pretty(gotChunk.length, 'B'), 47 | '0x' + offset.toString(16)) 48 | ); 49 | return offset + gotChunk.length; 50 | }; 51 | 52 | StreamCheck.prototype.verifyDrained = function verifyDrained() { 53 | var self = this; 54 | var remain = self.expected.read(); 55 | self.assert.equal(remain, null, self.name + ': got all expected data (bytes)'); 56 | self.assert.equal(remain && remain.length || 0, 0, self.name + ': got all expected data (length)'); 57 | }; 58 | 59 | StreamCheck.prototype.verifyStream = function verifyStream(got) { 60 | var self = this; 61 | return function verifyStreamThunk(callback) { 62 | var offset = 0; 63 | got.on('data', onData); 64 | got.on('error', streamDone); 65 | got.on('end', streamDone); 66 | function onData(gotChunk) { 67 | offset = self.verifyChunk(offset, gotChunk); 68 | } 69 | function streamDone(err) { 70 | self.assert.ifError(err, self.name + ': no error'); 71 | if (!err) self.verifyDrained(); 72 | callback(); 73 | } 74 | }; 75 | }; 76 | -------------------------------------------------------------------------------- /test/lib/stream_search.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | -------------------------------------------------------------------------------- /test/link_hyperbahn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2015 Uber Technologies, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | set -e 24 | 25 | source test/lib/link_test.sh 26 | 27 | given_or_clone "$1" https://github.com/uber/hyperbahn 28 | 29 | copy_test_config 30 | 31 | npm link 32 | 33 | cd "$TCHANNEL_TEST_DIR" 34 | 35 | npm install 36 | npm link tchannel 37 | npm run test-ci 38 | -------------------------------------------------------------------------------- /test/link_tcurl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2015 Uber Technologies, Inc. 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | set -e 24 | 25 | source test/lib/link_test.sh 26 | 27 | given_or_clone "$1" https://github.com/uber/tcurl 28 | 29 | copy_test_config 30 | 31 | npm link 32 | 33 | cd "$TCHANNEL_TEST_DIR" 34 | 35 | npm install 36 | npm link tchannel 37 | npm run lint 38 | npm run cover 39 | -------------------------------------------------------------------------------- /test/ping.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var allocCluster = require('./lib/alloc-cluster.js'); 24 | 25 | allocCluster.test('ping with a remote connection', 2, function t(cluster, assert) { 26 | var client = cluster.channels[0]; 27 | var server = cluster.channels[1]; 28 | var peer = client.peers.add(server.hostPort); 29 | var conn = peer.connect(); 30 | conn.pingResponseEvent.on(function onResponse(res) { 31 | assert.equals(res.id, conn.handler.lastSentFrameId, 32 | 'validate ping response id'); 33 | server.close(); 34 | assert.end(); 35 | }); 36 | 37 | conn.ping(); 38 | }); 39 | 40 | allocCluster.test('ping with a self connection', 1, function t(cluster, assert) { 41 | var server = cluster.channels[0]; 42 | var peer = server.peers.add(server.hostPort); 43 | var conn = peer.connect(); 44 | conn.pingResponseEvent.on(function onResponse(res) { 45 | assert.equals(res.id, conn.handler.lastSentFrameId, 46 | 'validate ping response id'); 47 | server.close(); 48 | assert.end(); 49 | }); 50 | 51 | conn.ping(); 52 | }); 53 | -------------------------------------------------------------------------------- /test/regression-inOps-leak.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var setTimeout = require('timers').setTimeout; 24 | 25 | var allocCluster = require('./lib/alloc-cluster.js'); 26 | 27 | allocCluster.test('does not leak inOps', { 28 | numPeers: 2, 29 | channelOptions: { 30 | timeoutCheckInterval: 100, 31 | serverTimeoutDefault: 100, 32 | requestDefaults: { 33 | headers: { 34 | as: 'raw', 35 | cn: 'wat' 36 | } 37 | } 38 | } 39 | }, function t(cluster, assert) { 40 | var one = cluster.channels[0]; 41 | var two = cluster.channels[1]; 42 | 43 | var subTwo = two.makeSubChannel({ 44 | serviceName: 'server', 45 | peers: [one.hostPort] 46 | }); 47 | 48 | one.makeSubChannel({ 49 | serviceName: 'server' 50 | }).register('/timeout', timeout); 51 | 52 | two.timeoutCheckInterval = 99999; 53 | subTwo 54 | .request({ 55 | serviceName: 'server', 56 | hasNoParent: true, 57 | timeout: 100 58 | }) 59 | .send('/timeout', 'h', 'b', onTimeout); 60 | 61 | function onTimeout(err) { 62 | var type = err && err.type; 63 | assert.ok( 64 | type === 'tchannel.request.timeout' || 65 | type === 'tchannel.timeout', 66 | 'expected timeout error' 67 | ); 68 | 69 | // Force the server to reap in operations 70 | setTimeout(function checkState() { 71 | cluster.assertEmptyState(assert); 72 | assert.end(); 73 | }, 150); 74 | } 75 | 76 | function timeout() { 77 | // do not call cb(); 78 | } 79 | }); 80 | -------------------------------------------------------------------------------- /test/regression-listening-on-used-port.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | 25 | var TChannel = require('../channel.js'); 26 | 27 | test('listening on a used port', function t(assert) { 28 | var otherServer = TChannel(); 29 | var server = TChannel(); 30 | 31 | otherServer.on('listening', onPortAllocated); 32 | otherServer.listen(0, '127.0.0.1'); 33 | 34 | function onPortAllocated() { 35 | server.on('error', onError); 36 | 37 | server.listen(otherServer.address().port, '127.0.0.1'); 38 | } 39 | 40 | function onError(err) { 41 | assert.notEqual(-1, err.message 42 | .indexOf('tchannel: listen EADDRINUSE')); 43 | assert.equal(err.type, 'tchannel.server.listen-failed'); 44 | assert.equal(err.requestedPort, 45 | otherServer.address().port); 46 | assert.equal(err.host, '127.0.0.1'); 47 | assert.equal(err.code, 'EADDRINUSE'); 48 | assert.equal(err.errno, 'EADDRINUSE'); 49 | assert.equal(err.syscall, 'listen'); 50 | assert.notEqual(-1, err.origMessage 51 | .indexOf('listen EADDRINUSE')); 52 | 53 | server.close(); 54 | otherServer.close(); 55 | assert.end(); 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /test/relay-clamps-the-ttl.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var allocCluster = require('./lib/alloc-cluster'); 24 | var RelayHandler = require('../relay_handler'); 25 | 26 | allocCluster.test('relay will clamp ttl to 2 minutes', { 27 | numPeers: 3 28 | }, function t(cluster, assert) { 29 | cluster.logger.whitelist('warn', 'Clamping timeout to maximum ttl allowed'); 30 | 31 | var client = cluster.channels[0]; 32 | var relay = cluster.channels[1]; 33 | var server = cluster.channels[2]; 34 | 35 | var subClient = client.makeSubChannel({ 36 | serviceName: 'server', 37 | peers: [relay.hostPort], 38 | requestDefaults: { 39 | hasNoParent: true, 40 | headers: { 41 | as: 'raw', 42 | cn: 'client' 43 | } 44 | } 45 | }); 46 | var subServer = server.makeSubChannel({ 47 | serviceName: 'server' 48 | }); 49 | var subRelay = relay.makeSubChannel({ 50 | serviceName: 'server', 51 | peers: [server.hostPort] 52 | }); 53 | subRelay.handler = new RelayHandler(subRelay); 54 | 55 | subServer.register('echo', echo); 56 | 57 | subClient.request({ 58 | serviceName: 'server', 59 | timeout: 5 * 60 * 1000 60 | }).send('echo', 'a', 'b', onResponse); 61 | 62 | function echo(req, res, arg2, arg3) { 63 | assert.equal(req.timeout, 2 * 60 * 1000); 64 | 65 | res.headers.as = 'raw'; 66 | res.sendOk(arg2, arg3); 67 | } 68 | 69 | function onResponse(err, resp) { 70 | assert.ifError(err); 71 | 72 | assert.equal(resp.ok, true); 73 | 74 | var items = cluster.logger.items(); 75 | assert.equal(items.length, 1); 76 | 77 | var logLine = items[0]; 78 | assert.equal(logLine.levelName, 'warn'); 79 | assert.equal(logLine.msg, 'Clamping timeout to maximum ttl allowed'); 80 | 81 | assert.equal(logLine.meta.maximumTTL, 2 * 60 * 1000); 82 | assert.ok(logLine.meta.timeout > 2 * 60 * 1000); 83 | 84 | assert.end(); 85 | } 86 | }); 87 | -------------------------------------------------------------------------------- /test/safe-quit.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | 25 | var TChannel = require('../channel.js'); 26 | 27 | test('can call quit() safely async', function t(assert) { 28 | var channel = TChannel(); 29 | channel.listen(0, '127.0.0.1'); 30 | 31 | channel.on('listening', function onListen() { 32 | assert.doesNotThrow(function noThrow() { 33 | channel.quit(); 34 | }); 35 | 36 | assert.end(); 37 | }); 38 | }); 39 | 40 | test('can call quit() safely sync', function t(assert) { 41 | var channel = TChannel(); 42 | channel.listen(0, '127.0.0.1'); 43 | 44 | assert.doesNotThrow(function noThrow() { 45 | channel.quit(); 46 | }); 47 | assert.end(); 48 | }); 49 | 50 | test('can call quit() safely async w/ callback', function t(assert) { 51 | var channel = TChannel(); 52 | channel.listen(0, '127.0.0.1'); 53 | 54 | channel.on('listening', function onListen() { 55 | assert.doesNotThrow(function noThrow() { 56 | channel.quit(assert.end); 57 | }); 58 | }); 59 | }); 60 | 61 | test('can call quit() safely sync w/ callback', function t(assert) { 62 | var channel = TChannel(); 63 | channel.listen(0, '127.0.0.1'); 64 | assert.doesNotThrow(function noThrow() { 65 | channel.quit(assert.end); 66 | }); 67 | }); 68 | 69 | -------------------------------------------------------------------------------- /test/streaming_bisect_relabel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # A utility script to make repro output from the streaming_bisect test more 5 | # readily diff-able. 6 | # 7 | # Example: 8 | # 9 | # $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \ 10 | # --repro --head '31KiB + 965B' --body '64KiB' --timeout 1000 2>&1 | tee good 11 | # 12 | # $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \ 13 | # --repro --head '31KiB + 966B' --body 64KiB --timeout 1000 2>&1 | tee bad 14 | # 15 | # $ diff -u \ 16 | # <(./test/streaming_bisect_relabel.sh good) \ 17 | # <(./test/streaming_bisect_relabel.sh bad) 18 | 19 | if [ $# -eq 0 ]; then 20 | res=$(mktemp) 21 | cat >$res 22 | else 23 | res=$1 24 | fi 25 | 26 | # find the '# cluster host N: HOST:PORT' comments and use them to transform all 27 | # matching "HOST:PORT"s into "hostN:SERVER"s 28 | # 29 | # also find the (single!) test pid and replace it with "TESTPID" 30 | sed_args=$( 31 | <$res grep '# cluster host' | grep -o '[0-9]:.*' | 32 | while read numColon host_port; do 33 | name=host${numColon%*:}:SERVER 34 | echo "-e s/$host_port/$name/" 35 | done 36 | 37 | test_pid=$( 38 | <$res egrep -om1 'TCHANNEL [0-9]+:' | egrep -o '[0-9]+' 39 | ) 40 | echo "-e s/\\<$test_pid\\>/TESTPID/" 41 | ) 42 | out=$(mktemp) 43 | <$res sed $sed_args >$out 44 | res=$out 45 | 46 | # find all lines like: 47 | # "debug: incoming server connection ~ { hostPort: 'hostN:SERVER', remoteAddr: '127.0.0.1:12345' }" 48 | # then transform all matching "HOST:PORT"s from the found remoteAddrs into "hostN:CLIENT"s 49 | sed_args=$( 50 | <$res grep 'debug: incoming server connection' | 51 | cut -d~ -f2- | 52 | tr -d "{',}" | { 53 | declare -A counts 54 | while read hp host_port ra remote_addr; do 55 | if [ "$hp" == 'hostPort:' ] && [ "$ra" == 'remoteAddr:' ]; then 56 | host_port=${host_port%*SERVER} 57 | count=${counts[$host_port]} 58 | count=$(( ${count:=0} + 1 )) 59 | counts[$host_port]=$count 60 | echo "-e s/$remote_addr/${host_port}CLIENT$count/" 61 | fi 62 | done 63 | } 64 | ) 65 | <$res sed $sed_args 66 | -------------------------------------------------------------------------------- /test/v2/cancel.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Cancel = require('../../v2/cancel.js'); 25 | var testRW = require('bufrw/test_rw'); 26 | var Tracing = require('../../v2/tracing.js'); 27 | 28 | var testTracing = new Tracing( 29 | [66051, 67438087], 30 | [134810123, 202182159], 31 | [269554195, 336926231], 32 | 24 33 | ); 34 | 35 | test('Cancel.RW: read/write payload', testRW.cases(Cancel.RW, [ 36 | 37 | // simple example payload 38 | [ 39 | new Cancel(42, testTracing, 'too bad.'), [ 40 | 0x00, 0x00, 0x00, 0x2a, // ttl:4 41 | 0x00, 0x01, 0x02, 0x03, // tracing:24 42 | 0x04, 0x05, 0x06, 0x07, // ... 43 | 0x08, 0x09, 0x0a, 0x0b, // ... 44 | 0x0c, 0x0d, 0x0e, 0x0f, // ... 45 | 0x10, 0x11, 0x12, 0x13, // ... 46 | 0x14, 0x15, 0x16, 0x17, // ... 47 | 0x18, // traceflags:1 48 | 0x00, 0x08, 0x74, 0x6f, // why~2 49 | 0x6f, 0x20, 0x62, 0x61, // ... 50 | 0x64, 0x2e // ... 51 | ] 52 | ] 53 | 54 | ])); 55 | -------------------------------------------------------------------------------- /test/v2/checksum.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Checksum = require('../../v2/checksum.js'); 25 | var testRW = require('bufrw/test_rw'); 26 | 27 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 28 | // istanbul ignore next 29 | var bufferFrom = Buffer.from || Buffer; 30 | 31 | var args = ['arg1', 'arg2', 'arg3']; 32 | var parts = args.map(function mapArg(arg) {return bufferFrom(arg);}); 33 | var uparts = args.map(function mapArg(arg) {return bufferFrom(arg.toUpperCase());}); 34 | 35 | var CRC32Hash = 0x8c38c3af; 36 | var Farm32Hash = 0xeed86ea9; 37 | 38 | var NoneBytes = [ 39 | Checksum.Types.None // csumtype:1 40 | ]; 41 | 42 | var CRC32Bytes = [ 43 | Checksum.Types.CRC32, // csumtype:1 44 | 0x8c, 0x38, 0xc3, 0xaf // csum:4 45 | ]; 46 | 47 | var Farm32Bytes = [ 48 | Checksum.Types.Farm32, // csumtype:1 49 | 0xee, 0xd8, 0x6e, 0xa9 // csum:4 50 | ]; 51 | 52 | test('Checksum: read/write', testRW.cases(Checksum.RW, [ 53 | [new Checksum(Checksum.Types.None), NoneBytes], 54 | [new Checksum(Checksum.Types.CRC32, CRC32Hash), CRC32Bytes], 55 | [new Checksum(Checksum.Types.Farm32, Farm32Hash), Farm32Bytes] 56 | ])); 57 | 58 | test('verify none checksum', function t(assert) { 59 | var csum = new Checksum(Checksum.Types.None); 60 | var good = csum.verify(parts); 61 | assert.equal(good, null, 'none expected to verify parts'); 62 | var bad = csum.verify(uparts); 63 | assert.equal(bad, null, 'none expected to accept anything'); 64 | assert.end(); 65 | }); 66 | 67 | test('verify crc32 checksum', function t(assert) { 68 | var csum = new Checksum(Checksum.Types.CRC32, CRC32Hash); 69 | var good = csum.verify(parts); 70 | assert.equal(good, null, 'crc32 expected to verify parts'); 71 | var bad = csum.verify(uparts); 72 | assert.equal(bad && bad.type, 'tchannel.checksum', 'crc32 expected to fail'); 73 | assert.end(); 74 | }); 75 | 76 | test('read and verify farm32 checksum', function t(assert) { 77 | var csum = new Checksum(Checksum.Types.Farm32, Farm32Hash); 78 | var good = csum.verify(parts); 79 | assert.equal(good, null, 'farm32 expected to verify parts'); 80 | var bad = csum.verify(uparts); 81 | assert.equal(bad && bad.type, 'tchannel.checksum', 'farm32 expected to fail'); 82 | assert.end(); 83 | }); 84 | -------------------------------------------------------------------------------- /test/v2/claim.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Claim = require('../../v2/claim.js'); 25 | var testRW = require('bufrw/test_rw'); 26 | var Tracing = require('../../v2/tracing.js'); 27 | 28 | var testTracing = new Tracing( 29 | [66051, 67438087], 30 | [134810123, 202182159], 31 | [269554195, 336926231], 32 | 24 33 | ); 34 | 35 | test('Claim.RW: read/write payload', testRW.cases(Claim.RW, [ 36 | 37 | // simple example payload 38 | [ 39 | new Claim(42, testTracing), [ 40 | 0x00, 0x00, 0x00, 0x2a, // ttl:4 41 | 0x00, 0x01, 0x02, 0x03, // tracing:24 42 | 0x04, 0x05, 0x06, 0x07, // ... 43 | 0x08, 0x09, 0x0a, 0x0b, // ... 44 | 0x0c, 0x0d, 0x0e, 0x0f, // ... 45 | 0x10, 0x11, 0x12, 0x13, // ... 46 | 0x14, 0x15, 0x16, 0x17, // ... 47 | 0x18 // traceflags:1 48 | ] 49 | ] 50 | 51 | ])); 52 | -------------------------------------------------------------------------------- /test/v2/cont.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var testRW = require('bufrw/test_rw'); 25 | var Cont = require('../../v2/cont.js'); 26 | var Checksum = require('../../v2/checksum.js'); 27 | 28 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 29 | // istanbul ignore next 30 | var bufferFrom = Buffer.from || Buffer; 31 | 32 | var testReqCont = new Cont.RequestCont( 33 | 0, Checksum.Types.Farm32, 34 | [bufferFrom('on'), bufferFrom('to'), bufferFrom('te')] 35 | ); 36 | 37 | var testReqContBytes = [ 38 | 0x00, // flags:1 39 | Checksum.Types.Farm32, // csumtype:1 40 | 0x8e, 0x09, 0xa1, 0xbd, // (csum:4){0,1} 41 | 0x00, 0x02, 0x6f, 0x6e, // arg1~2 42 | 0x00, 0x02, 0x74, 0x6f, // arg2~2 43 | 0x00, 0x02, 0x74, 0x65 // arg3~2 44 | ]; 45 | 46 | test('Cont.RequestCont.RW: read/write payload', testRW.cases(Cont.RequestCont.RW, [ 47 | { 48 | lengthTest: { 49 | length: testReqContBytes.length, 50 | value: testReqCont 51 | }, 52 | writeTest: { 53 | bytes: testReqContBytes, 54 | value: testReqCont 55 | }, 56 | readTest: { 57 | bytes: testReqContBytes, 58 | value: testReqCont 59 | } 60 | } 61 | ])); 62 | 63 | var testResCont = new Cont.ResponseCont( 64 | 0, Checksum.Types.Farm32, 65 | [bufferFrom('ON'), bufferFrom('TO'), bufferFrom('TE')] 66 | ); 67 | 68 | var testResContBytes = [ 69 | 0x00, // flags:1 70 | Checksum.Types.Farm32, // csumtype:1 71 | 0x8d, 0x82, 0xe8, 0xba, // (csum:4){0,1} 72 | 0x00, 0x02, 0x4f, 0x4e, // arg1~2 73 | 0x00, 0x02, 0x54, 0x4f, // arg2~2 74 | 0x00, 0x02, 0x54, 0x45 // arg3~2 75 | ]; 76 | 77 | test('Cont.ResponseCont.RW: read/write payload', testRW.cases(Cont.ResponseCont.RW, [ 78 | { 79 | lengthTest: { 80 | length: testResContBytes.length, 81 | value: testResCont 82 | }, 83 | writeTest: { 84 | bytes: testResContBytes, 85 | value: testResCont 86 | }, 87 | readTest: { 88 | bytes: testResContBytes, 89 | value: testResCont 90 | } 91 | } 92 | ])); 93 | -------------------------------------------------------------------------------- /test/v2/error_response.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var ErrorResponse = require('../../v2/error_response.js'); 25 | var testRW = require('bufrw/test_rw'); 26 | var Tracing = require('../../v2/tracing.js'); 27 | 28 | var testTracing = new Tracing( 29 | [66051, 67438087], 30 | [134810123, 202182159], 31 | [269554195, 336926231], 32 | 24 33 | ); 34 | 35 | test('ErrorResponse.RW: read/write payload', testRW.cases(ErrorResponse.RW, [ 36 | 37 | // simple example payload 38 | [ 39 | new ErrorResponse( 40 | ErrorResponse.Codes.ProtocolError, 41 | testTracing, 42 | 'too bad.' 43 | ), [ 44 | ErrorResponse.Codes.ProtocolError, // code:1 45 | 0x00, 0x01, 0x02, 0x03, // tracing:24 46 | 0x04, 0x05, 0x06, 0x07, // ... 47 | 0x08, 0x09, 0x0a, 0x0b, // ... 48 | 0x0c, 0x0d, 0x0e, 0x0f, // ... 49 | 0x10, 0x11, 0x12, 0x13, // ... 50 | 0x14, 0x15, 0x16, 0x17, // ... 51 | 0x18, // traceflags:1 52 | 0x00, 0x08, 0x74, 0x6f, // message~2 53 | 0x6f, 0x20, 0x62, 0x61, // ... 54 | 0x64, 0x2e // ... 55 | ] 56 | ] 57 | 58 | ])); 59 | -------------------------------------------------------------------------------- /test/v2/frame.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var testRW = require('bufrw/test_rw'); 24 | var Frame = require('../../v2/frame.js'); 25 | var TestBody = require('./lib/test_body.js'); 26 | 27 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 28 | // istanbul ignore next 29 | var bufferFrom = Buffer.from || Buffer; 30 | 31 | TestBody.testWith('Frame.RW: read/write payload', testRW.cases(Frame.RW, [ 32 | 33 | [ 34 | new Frame(0x01020304, TestBody(bufferFrom('doge'))), [ 35 | 0x00, 0x15, // size:2: 36 | TestBody.TypeCode, // type:1 37 | 0x00, // reserved:1 38 | 0x01, 0x02, 0x03, 0x04, // id:4 39 | 0x00, 0x00, 0x00, 0x00, // reserved:4 40 | 0x00, 0x00, 0x00, 0x00, // reserved:4 41 | 0x04, 0x64, 0x6f, 0x67, // payload~1 42 | 0x65 // ... 43 | ] 44 | ], 45 | 46 | [ 47 | new Frame(0x01020304, TestBody(bufferFrom('cat'))),[ 48 | 0x00, 0x14, // size:2: 49 | TestBody.TypeCode, // type:1 50 | 0x00, // reserved:1 51 | 0x01, 0x02, 0x03, 0x04, // id:4 52 | 0x00, 0x00, 0x00, 0x00, // reserved:4 53 | 0x00, 0x00, 0x00, 0x00, // reserved:4 54 | 0x03, 0x63, 0x61, 0x74 // payload~1 55 | ] 56 | ] 57 | 58 | ])); 59 | -------------------------------------------------------------------------------- /test/v2/lib/test_body.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Frame = require('../../../v2/frame.js'); 24 | 25 | var bufrw = require('bufrw'); 26 | 27 | module.exports = TestBody; 28 | 29 | function TestBody(payload) { 30 | if (!(this instanceof TestBody)) { 31 | return new TestBody(payload); 32 | } 33 | var self = this; 34 | self.type = TestBody.TypeCode; 35 | self.payload = payload; 36 | } 37 | 38 | TestBody.TypeCode = 0x00; 39 | 40 | TestBody.RW = bufrw.Struct(TestBody, { 41 | payload: bufrw.buf1 42 | }); 43 | 44 | TestBody.testWith = function testWidTestBody(desc, t) { 45 | var test = require('tape'); 46 | test(desc, function s(assert) { 47 | Frame.Types[TestBody.TypeCode] = TestBody; 48 | assert.once('end', function removeTestBody() { 49 | delete Frame.Types[TestBody.TypeCode]; 50 | }); 51 | return t(assert); 52 | }); 53 | }; 54 | -------------------------------------------------------------------------------- /test/v2/ping.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Ping = require('../../v2/ping.js'); 25 | var testRW = require('bufrw/test_rw'); 26 | 27 | test('Ping.Request.RW: read/write payload', 28 | testRW.cases(Ping.Request.RW, [ 29 | 30 | [ 31 | new Ping.Request(), 32 | [] 33 | ] 34 | 35 | ])); 36 | 37 | test('Ping.Reponse.RW: read/write payload', 38 | testRW.cases(Ping.Response.RW, [ 39 | 40 | [ 41 | new Ping.Response(), 42 | [] 43 | ] 44 | 45 | ])); 46 | -------------------------------------------------------------------------------- /test/v2/tracing.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Tracing = require('../../v2/tracing'); 25 | var testRW = require('bufrw/test_rw'); 26 | 27 | // Node.js deprecated Buffer in favor of Buffer.alloc and Buffer.from. 28 | // istanbul ignore next 29 | var bufferFrom = Buffer.from || Buffer; 30 | 31 | var spanidBuf = bufferFrom([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]); 32 | var parentidBuf = bufferFrom([0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10]); 33 | var traceidBuf = bufferFrom([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18]); 34 | 35 | var spanid = [spanidBuf.readUInt32BE(0), spanidBuf.readUInt32BE(4)]; 36 | var parentid = [parentidBuf.readUInt32BE(0), parentidBuf.readUInt32BE(4)]; 37 | var traceid = [traceidBuf.readUInt32BE(0), traceidBuf.readUInt32BE(4)]; 38 | 39 | test('Tracing: read/write', testRW.cases(Tracing.RW, [ 40 | 41 | [ 42 | new Tracing(), [ 43 | 0x00, 0x00, 0x00, 0x00, // spanid:8 44 | 0x00, 0x00, 0x00, 0x00, // ... 45 | 0x00, 0x00, 0x00, 0x00, // parentid:8 46 | 0x00, 0x00, 0x00, 0x00, // ... 47 | 0x00, 0x00, 0x00, 0x00, // traceid:8 48 | 0x00, 0x00, 0x00, 0x00, // ... 49 | 0x00 // flags:1 50 | ] 51 | ], 52 | 53 | [ 54 | new Tracing( 55 | spanid, 56 | parentid, 57 | traceid, 58 | 42 59 | ), [ 60 | 0x01, 0x02, 0x03, 0x04, // spanid:8 61 | 0x05, 0x06, 0x07, 0x08, // ... 62 | 0x09, 0x0a, 0x0b, 0x0c, // parentid:8 63 | 0x0d, 0x0e, 0x0f, 0x10, // ... 64 | 0x11, 0x12, 0x13, 0x14, // traceid:8 65 | 0x15, 0x16, 0x17, 0x18, // ... 66 | 0x2a // flags:1 67 | ] 68 | ] 69 | 70 | ])); 71 | -------------------------------------------------------------------------------- /v1/header.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = TChannelHeader; 24 | 25 | function TChannelHeader() { 26 | this.type = null; 27 | this.id = null; 28 | this.seq = null; 29 | this.arg1len = null; 30 | this.arg2len = null; 31 | this.arg3len = null; 32 | this.csum = null; 33 | } 34 | -------------------------------------------------------------------------------- /v1/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports.VERSION = 1; 24 | 25 | module.exports.Frame = require('./frame'); 26 | module.exports.Header = require('./header'); 27 | module.exports.Parser = require('./parser'); 28 | module.exports.Handler = require('./handler'); 29 | 30 | 31 | var types = module.exports.Types = {}; 32 | types.reqCompleteMessage = types.req_complete_message = 0x01; 33 | types.reqMessageFragment = types.req_message_fragment = 0x02; 34 | types.reqLastFragment = types.req_last_fragment = 0x03; 35 | types.resCompleteMessage = types.res_complete_message = 0x80; 36 | types.resMessageFragment = types.res_message_fragment = 0x81; 37 | types.resLastFragment = types.res_last_fragment = 0x82; 38 | types.resError = types.res_error = 0xC0; 39 | 40 | -------------------------------------------------------------------------------- /v2/call_flags.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | Fragment: 0x01 25 | }; 26 | -------------------------------------------------------------------------------- /v2/cancel.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var bufrw = require('bufrw'); 24 | var Tracing = require('./tracing'); 25 | 26 | // ttl:4 tracing:25 why~2 27 | function Cancel(ttl, tracing, why) { 28 | this.type = Cancel.TypeCode; 29 | this.ttl = ttl || 0; 30 | this.tracing = tracing || Tracing.emptyTracing; 31 | this.why = why || ''; 32 | } 33 | 34 | Cancel.TypeCode = 0xc0; 35 | 36 | Cancel.RW = bufrw.Struct(Cancel, [ 37 | {name: 'ttl', rw: bufrw.UInt32BE}, // ttl:4 38 | {name: 'tracing', rw: Tracing.RW}, // tracing:25 39 | {name: 'why', rw: bufrw.str2} // why~2 40 | ]); 41 | 42 | module.exports = Cancel; 43 | -------------------------------------------------------------------------------- /v2/claim.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var bufrw = require('bufrw'); 24 | var Tracing = require('./tracing'); 25 | 26 | // ttl:4 tracing:25 27 | function Claim(ttl, tracing) { 28 | this.type = Claim.TypeCode; 29 | this.ttl = ttl || 0; 30 | this.tracing = tracing || Tracing.emptyTracing; 31 | } 32 | 33 | Claim.TypeCode = 0xc1; 34 | 35 | Claim.RW = bufrw.Struct(Claim, [ 36 | {name: 'ttl', rw: bufrw.UInt32BE}, // ttl:4 37 | {name: 'tracing', rw: Tracing.RW} // tracing:25 38 | ]); 39 | 40 | module.exports = Claim; 41 | -------------------------------------------------------------------------------- /v2/init.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable curly */ 24 | 25 | var bufrw = require('bufrw'); 26 | var header = require('./header'); 27 | var errors = require('../errors'); 28 | 29 | module.exports.Request = InitRequest; 30 | module.exports.Response = InitResponse; 31 | 32 | var RequiredHeaderFields = ['host_port', 'process_name']; 33 | 34 | function InitRequest(version, headers) { 35 | this.type = InitRequest.TypeCode; 36 | this.version = version || 0; 37 | this.headers = headers || {}; 38 | } 39 | 40 | InitRequest.TypeCode = 0x01; 41 | 42 | InitRequest.RW = bufrw.Struct(InitRequest, [ 43 | {call: {poolWriteInto: writeFieldGuard}}, 44 | {name: 'version', rw: bufrw.UInt16BE}, // version:2 45 | {name: 'headers', rw: header.header2}, // nh:2 (hk~2 hv~2){nh} 46 | {call: {poolReadFrom: readFieldGuard}} 47 | ]); 48 | 49 | // TODO: MissingInitHeaderError check / guard 50 | 51 | function InitResponse(version, headers) { 52 | this.type = InitResponse.TypeCode; 53 | this.version = version || 0; 54 | this.headers = headers || {}; 55 | } 56 | 57 | InitResponse.TypeCode = 0x02; 58 | 59 | InitResponse.RW = bufrw.Struct(InitResponse, [ 60 | {call: {poolWriteInto: writeFieldGuard}}, 61 | {name: 'version', rw: bufrw.UInt16BE}, // version:2 62 | {name: 'headers', rw: header.header2}, // nh:2 (hk~2 hv~2){nh} 63 | {call: {poolReadFrom: readFieldGuard}} 64 | ]); 65 | 66 | function writeFieldGuard(destResult, initBody, buffer, offset) { 67 | var err = requiredFieldGuard(initBody.headers); 68 | if (err) return destResult.reset(err, offset); 69 | else return destResult.reset(null, offset); 70 | } 71 | 72 | function readFieldGuard(destResult, initBody, buffer, offset) { 73 | var err = requiredFieldGuard(initBody.headers); 74 | if (err) return destResult.reset(err, offset); 75 | else return destResult.reset(null, offset); 76 | } 77 | 78 | function requiredFieldGuard(headers) { 79 | for (var i = 0; i < RequiredHeaderFields.length; i++) { 80 | var field = RequiredHeaderFields[i]; 81 | if (headers[field] === undefined) { 82 | return errors.MissingInitHeaderError({field: field}); 83 | } 84 | } 85 | return null; 86 | } 87 | -------------------------------------------------------------------------------- /v2/out_request.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var inherits = require('util').inherits; 24 | 25 | var OutRequest = require('../out_request'); 26 | var StreamingOutRequest = require('../streaming_out_request'); 27 | 28 | var CallFlags = require('./call_flags'); 29 | var v2 = require('./index'); 30 | var errors = require('../errors'); 31 | 32 | function V2OutRequest(handler, id, options) { 33 | OutRequest.call(this, id, options); 34 | this.handler = handler; 35 | } 36 | 37 | inherits(V2OutRequest, OutRequest); 38 | 39 | function V2StreamingOutRequest(handler, id, options) { 40 | StreamingOutRequest.call(this, id, options); 41 | this.handler = handler; 42 | } 43 | 44 | inherits(V2StreamingOutRequest, StreamingOutRequest); 45 | 46 | V2OutRequest.prototype._sendCallRequest = 47 | V2StreamingOutRequest.prototype._sendCallRequest = 48 | function _sendCallRequest(args, isLast) { 49 | var err = null; 50 | 51 | var flags = 0; 52 | if (!isLast) { 53 | flags |= CallFlags.Fragment; 54 | } 55 | 56 | if (args && args[0] && args[0].length > v2.MaxArg1Size) { 57 | err = errors.Arg1OverLengthLimit({ 58 | length: args[0].length, 59 | limit: v2.MaxArg1Size 60 | }); 61 | } else { 62 | err = this.handler.sendCallRequestFrame(this, flags, args); 63 | } 64 | 65 | if (err) { 66 | this.operations.popOutReq(this.id); 67 | this.emitError(err); 68 | } 69 | }; 70 | 71 | V2OutRequest.prototype._sendCallRequestCont = 72 | V2StreamingOutRequest.prototype._sendCallRequestCont = 73 | function _sendCallRequestCont(args, isLast) { 74 | var flags = 0; 75 | if (!isLast) { 76 | flags |= CallFlags.Fragment; 77 | } 78 | 79 | this.handler.sendCallRequestContFrame(this, flags, args); 80 | }; 81 | 82 | module.exports.OutRequest = V2OutRequest; 83 | module.exports.StreamingOutRequest = V2StreamingOutRequest; 84 | -------------------------------------------------------------------------------- /v2/out_response.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable curly */ 24 | 25 | var inherits = require('util').inherits; 26 | 27 | var OutResponse = require('../out_response'); 28 | var StreamingOutResponse = require('../streaming_out_response'); 29 | 30 | var CallFlags = require('./call_flags'); 31 | var v2 = require('./index'); 32 | var errors = require('../errors'); 33 | 34 | function V2OutResponse(handler, id, options) { 35 | OutResponse.call(this, id, options); 36 | this.handler = handler; 37 | } 38 | 39 | inherits(V2OutResponse, OutResponse); 40 | 41 | function V2StreamingOutResponse(handler, id, options) { 42 | StreamingOutResponse.call(this, id, options); 43 | this.handler = handler; 44 | } 45 | 46 | inherits(V2StreamingOutResponse, StreamingOutResponse); 47 | 48 | V2OutResponse.prototype._sendCallResponse = 49 | V2StreamingOutResponse.prototype._sendCallResponse = 50 | function _sendCallResponse(args, isLast) { 51 | var flags = 0; 52 | if (args && args[0] && args[0].length > v2.MaxArg1Size) { 53 | this.errorEvent.emit(this, errors.Arg1OverLengthLimit({ 54 | length: args[0].length, 55 | limit: v2.MaxArg1Size 56 | })); 57 | return; 58 | } 59 | if (!isLast) flags |= CallFlags.Fragment; 60 | this.handler.sendCallResponseFrame(this, flags, args); 61 | }; 62 | 63 | V2OutResponse.prototype._sendCallResponseCont = 64 | V2StreamingOutResponse.prototype._sendCallResponseCont = 65 | function _sendCallResponseCont(args, isLast) { 66 | var flags = 0; 67 | if (!isLast) flags |= CallFlags.Fragment; 68 | this.handler.sendCallResponseContFrame(this, flags, args); 69 | }; 70 | 71 | V2OutResponse.prototype._sendError = 72 | V2StreamingOutResponse.prototype._sendError = 73 | function _sendError(codeString, message) { 74 | this.handler.sendErrorFrame(this.id, this.tracing, codeString, message); 75 | }; 76 | 77 | module.exports.OutResponse = V2OutResponse; 78 | module.exports.StreamingOutResponse = V2StreamingOutResponse; 79 | -------------------------------------------------------------------------------- /v2/ping.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var bufrw = require('bufrw'); 24 | 25 | module.exports.Request = PingRequest; 26 | module.exports.Response = PingResponse; 27 | 28 | function PingRequest() { 29 | this.type = PingRequest.TypeCode; 30 | } 31 | 32 | PingRequest.TypeCode = 0xd0; 33 | PingRequest.RW = bufrw.Struct(PingRequest, []); 34 | 35 | function PingResponse() { 36 | this.type = PingResponse.TypeCode; 37 | } 38 | 39 | PingResponse.TypeCode = 0xd1; 40 | PingResponse.RW = bufrw.Struct(PingResponse, []); 41 | --------------------------------------------------------------------------------