diff --git a/.gitignore b/.gitignore index 7945cc0..f963207 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ rebar3.crashdump *~ doc/ rebar3 +certs/key.pem +certs/cert.pem diff --git a/README.md b/README.md index 99d2034..05cee4c 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,18 @@ rpc_server/ │ └── include/rpc_server.hrl ├── config/ │ ├── dev_sys.config +│ ├── dev_sys_quic.config │ ├── dev_vm.config +│ ├── dev_vm_quic.config │ ├── dev_http.vm.args -│ └── dev_shell.vm.args +│ ├── dev_http_quic.vm.args +│ ├── dev_shell.vm.args +│ └── dev_shell_quic.vm.args +├── certs/ +│ ├── generate.sh +│ ├── cert.pem +│ └── key.pem +├── start.sh └── rebar.config ``` @@ -60,7 +69,41 @@ rebar3 compile ## Como rodar -### Desenvolvimento (interativo) +O script `start.sh` permite iniciar cada nó com o protocolo de distribuição desejado: **TCP** (padrão Erlang) ou **QUIC** (RFC 9000, via [erlang_quic](https://github.com/benoitc/erlang_quic)). + +### Pré-requisitos para QUIC + +Gere os certificados TLS (necessários apenas uma vez): + +```bash +cd certs && bash generate.sh +``` + +### Usando o start.sh + +```bash +# TCP (padrão) +./start.sh --node http # nó HTTP na porta 8080 +./start.sh --node shell # nó Shell +./start.sh --node default # ambos os apps no mesmo nó + +# QUIC +./start.sh --node http --protocol quic # nó HTTP com distribuição QUIC (porta dist 4434) +./start.sh --node shell --protocol quic # nó Shell com distribuição QUIC (porta dist 4435) +./start.sh --node default --protocol quic # ambos os apps com QUIC (porta dist 4433) +``` + +Cada tipo de nó usa uma porta QUIC diferente para evitar conflito no mesmo host: + +| Nó | Porta QUIC | +|----|------------| +| default | 4433 | +| http | 4434 | +| shell | 4435 | + +> **Importante:** Todos os nós do cluster devem usar o mesmo protocolo. Nós QUIC e TCP não se conectam entre si. + +### Desenvolvimento (interativo, sem script) ```bash rebar3 shell --config config/dev_sys.config @@ -99,7 +142,7 @@ rebar3 as shell_node release -n rpc_server_shell ## Configuração -Arquivo principal: `config/dev_sys.config`. +Arquivo principal: `config/dev_sys.config` (TCP) ou `config/dev_sys_quic.config` (QUIC). Parâmetros relevantes do `rpc_server_http` (padrões): @@ -111,7 +154,27 @@ Parâmetros relevantes do `rpc_server_http` (padrões): ]} ``` -Nomes de nós e cookie (releases e dev): +### Configuração QUIC + +O `dev_sys_quic.config` inclui a seção de distribuição QUIC: + +```erlang +{quic, [ + {dist, [ + {cert_file, "/path/to/cert.pem"}, + {key_file, "/path/to/key.pem"}, + {verify, verify_none}, + {discovery_module, quic_discovery_static}, + {nodes, [ + {'rpc_server@127.0.0.1', {"127.0.0.1", 4433}}, + {'rpc_server_http@127.0.0.1', {"127.0.0.1", 4434}}, + {'rpc_server_shell@127.0.0.1', {"127.0.0.1", 4435}} + ]} + ]} +]} +``` + +### Nomes de nós e cookie - Nó único: `config/dev_vm.config` (ex.: `-name rpc_server@127.0.0.1`, cookie `service_discovery_cookie`). - HTTP: `config/dev_http.vm.args` (ex.: `-name rpc_server_http@127.0.0.1`). diff --git a/certs/generate.sh b/certs/generate.sh new file mode 100755 index 0000000..78cacba --- /dev/null +++ b/certs/generate.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR" + +if [ -f cert.pem ] && [ -f key.pem ]; then + echo "Certificates already exist. Remove cert.pem and key.pem to regenerate." + exit 0 +fi + +echo "Generating self-signed certificate for QUIC distribution..." +openssl req -x509 -newkey rsa:2048 \ + -keyout key.pem -out cert.pem \ + -days 365 -nodes -subj '/CN=localhost' + +echo "Done. Files created:" +echo " $SCRIPT_DIR/cert.pem" +echo " $SCRIPT_DIR/key.pem" diff --git a/config/dev_http_quic.vm.args b/config/dev_http_quic.vm.args new file mode 100644 index 0000000..1e99e7d --- /dev/null +++ b/config/dev_http_quic.vm.args @@ -0,0 +1,15 @@ +-name rpc_server_http@127.0.0.1 +-setcookie service_discovery_cookie +-env ERL_MAX_PORTS 4096 +-env ERL_CRASH_DUMP ./log/erl_crash_http.dump + +-kernel logger_level info + +## QUIC distribution +-proto_dist quic +-epmd_module quic_epmd +-start_epmd false +-quic_dist_port 4434 + ++zdbbl 32768 ++K true diff --git a/config/dev_shell_quic.vm.args b/config/dev_shell_quic.vm.args new file mode 100644 index 0000000..5236756 --- /dev/null +++ b/config/dev_shell_quic.vm.args @@ -0,0 +1,15 @@ +-name rpc_server_shell@127.0.0.1 +-setcookie service_discovery_cookie +-env ERL_MAX_PORTS 4096 +-env ERL_CRASH_DUMP ./log/erl_crash_shell.dump + +-kernel logger_level info + +## QUIC distribution +-proto_dist quic +-epmd_module quic_epmd +-start_epmd false +-quic_dist_port 4435 + ++zdbbl 32768 ++K true diff --git a/config/dev_sys_quic.config b/config/dev_sys_quic.config new file mode 100644 index 0000000..6af1063 --- /dev/null +++ b/config/dev_sys_quic.config @@ -0,0 +1,66 @@ +[ + {quic, [ + {dist, [ + {cert_file, "rpc_server/certs/cert.pem"}, + {key_file, "rpc_server/certs/key.pem"}, + {verify, verify_none}, + {discovery_module, quic_discovery_static}, + {nodes, [ + {'rpc_server@127.0.0.1', {"127.0.0.1", 4433}}, + {'rpc_server_http@127.0.0.1', {"127.0.0.1", 4434}}, + {'rpc_server_shell@127.0.0.1', {"127.0.0.1", 4435}} + ]} + ]} + ]}, + + {kernel, [ + {sync_nodes_optional, ['rpc_server_http@127.0.0.1','rpc_server_shell@127.0.0.1']}, + {sync_nodes_timeout, 30000}, + {logger_level, info}, + {logger, [ + {handler, default, logger_std_h, + #{level => info, + formatter => {logger_formatter, #{single_line => true}}}}, + {handler, error_logger, logger_std_h, + #{level => info, + formatter => {logger_formatter, #{single_line => true}}}} + ]} + ]}, + + {lager, [ + {handlers, [ + {lager_console_backend, [{level, info}]}, + {lager_file_backend, [ + {file, "log/rpc_server.log"}, + {level, info}, + {size, 10485760}, + {date, "$D0"}, + {count, 5} + ]} + ]} + ]}, + + {rpc_server_http, [ + {tcp_port, 8080}, + {num_acceptors, 100}, + {max_connections, 10000}, + {tcp_listen_options, [ + binary, + {packet, raw}, + {reuseaddr, true}, + {active, true}, + {backlog, 128} + ]}, + {tcp_connection_options, [ + binary, + {packet, raw}, + {active, false}, + {keepalive, true}, + {send_timeout, 5000}, + {send_timeout_close, true}, + {exit_on_close, true} + ]} + ]}, + + {rpc_server_shell, []} +]. diff --git a/config/dev_vm_quic.config b/config/dev_vm_quic.config new file mode 100644 index 0000000..6906749 --- /dev/null +++ b/config/dev_vm_quic.config @@ -0,0 +1,20 @@ +-name rpc_server@127.0.0.1 + +-setcookie service_discovery_cookie + ++S 1 + ++C multi_time_warp + ++sbwt none + ++A30 + +## QUIC distribution +-proto_dist quic +-epmd_module quic_epmd +-start_epmd false +-quic_dist_port 4433 + ++zdbbl 32768 ++K true diff --git a/rebar.config b/rebar.config index d931497..c866257 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,7 @@ {erl_opts, [debug_info]}. {deps, [ - {lager, "3.9.2"} % Dependência do Lager(https://github.com/erlang-lager/lager) para logging estruturado + {lager, "3.9.2"}, % Dependência do Lager(https://github.com/erlang-lager/lager) para logging estruturado + {quic, "0.11.0"} ]}. {apps_dirs, ["apps"]}. @@ -11,6 +12,8 @@ stdlib, sasl, crypto, + ssl, + quic, lager, runtime_tools, observer, wx, rpc_server_http, @@ -71,7 +74,7 @@ {http_node, [ {relx, [ {release, {rpc_server_http, "0.1.0"}, - [kernel, stdlib, sasl, crypto, lager, runtime_tools, observer, wx, rpc_server_http]}, + [kernel, stdlib, sasl, crypto, ssl, quic, lager, runtime_tools, observer, wx, rpc_server_http]}, {sys_config, "./config/dev_sys.config"}, {vm_args, "./config/dev_http.vm.args"}, {dev_mode, true}, @@ -82,7 +85,7 @@ {shell_node, [ {relx, [ {release, {rpc_server_shell, "0.1.0"}, - [kernel, stdlib, sasl, crypto, lager, runtime_tools, observer, wx, rpc_server_shell]}, + [kernel, stdlib, sasl, crypto, ssl, quic, lager, runtime_tools, observer, wx, rpc_server_shell]}, {sys_config, "./config/dev_sys.config"}, {vm_args, "./config/dev_shell.vm.args"}, {dev_mode, true}, diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..a36104f --- /dev/null +++ b/start.sh @@ -0,0 +1,121 @@ +#!/bin/bash +set -e + +PROTOCOL="tcp" +NODE_TYPE="default" + +usage() { + echo "Usage: $0 --node [--protocol ]" + echo "" + echo "Options:" + echo " --node Node type: http, shell, or default (default: default)" + echo " --protocol Distribution protocol: tcp or quic (default: tcp)" + echo "" + echo "Examples:" + echo " $0 --node http --protocol quic" + echo " $0 --node shell --protocol tcp" + echo " $0 --node http" + exit 1 +} + +while [[ $# -gt 0 ]]; do + case $1 in + --protocol) + PROTOCOL="$2" + shift 2 + ;; + --node) + NODE_TYPE="$2" + shift 2 + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +if [[ "$PROTOCOL" != "tcp" && "$PROTOCOL" != "quic" ]]; then + echo "Error: --protocol must be 'tcp' or 'quic'" + exit 1 +fi + +if [[ "$PROTOCOL" == "quic" && ! -f certs/cert.pem ]]; then + echo "Error: QUIC certificates not found. Run: cd certs && bash generate.sh" + exit 1 +fi + +case "$NODE_TYPE" in + http) + NODE_NAME="rpc_server_http@127.0.0.1" + PROFILE="http_node" + APPS="rpc_server_http" + if [[ "$PROTOCOL" == "quic" ]]; then + SYS_CONFIG="config/dev_sys_quic.config" + QUIC_PORT=4434 + else + SYS_CONFIG="config/dev_sys.config" + fi + ;; + shell) + NODE_NAME="rpc_server_shell@127.0.0.1" + PROFILE="shell_node" + APPS="rpc_server_shell" + if [[ "$PROTOCOL" == "quic" ]]; then + SYS_CONFIG="config/dev_sys_quic.config" + QUIC_PORT=4435 + else + SYS_CONFIG="config/dev_sys.config" + fi + ;; + default) + NODE_NAME="rpc_server@127.0.0.1" + PROFILE="" + APPS="rpc_server_http,rpc_server_shell" + if [[ "$PROTOCOL" == "quic" ]]; then + SYS_CONFIG="config/dev_sys_quic.config" + QUIC_PORT=4433 + else + SYS_CONFIG="config/dev_sys.config" + fi + ;; + *) + echo "Error: --node must be 'http', 'shell', or 'default'" + exit 1 + ;; +esac + +EXTRA_FLAGS="" +if [[ "$PROTOCOL" == "quic" ]]; then + CERT_PATH="$(pwd)/certs/cert.pem" + KEY_PATH="$(pwd)/certs/key.pem" + EXTRA_FLAGS="-proto_dist quic -epmd_module quic_epmd -start_epmd false -quic_dist_port $QUIC_PORT -quic_dist_cert $CERT_PATH -quic_dist_key $KEY_PATH" +fi + +echo "=== rpc_server ===" +echo " Node: $NODE_TYPE ($NODE_NAME)" +echo " Protocol: $PROTOCOL" +echo " Config: $SYS_CONFIG" +if [[ "$PROTOCOL" == "quic" ]]; then + echo " QUIC port: $QUIC_PORT" +fi +echo "" + +export ERL_FLAGS="$EXTRA_FLAGS" + +if [[ -n "$PROFILE" ]]; then + exec rebar3 as "$PROFILE" shell \ + --name "$NODE_NAME" \ + --setcookie service_discovery_cookie \ + --config "$SYS_CONFIG" \ + --apps "$APPS" +else + exec rebar3 shell \ + --name "$NODE_NAME" \ + --setcookie service_discovery_cookie \ + --config "$SYS_CONFIG" \ + --apps "$APPS" +fi