├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── codeql-analysis.yml │ ├── linters.yml │ └── linux.yml ├── .gitignore ├── .golangci.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── amqp ├── amqpjobs │ ├── config.go │ ├── consumer.go │ ├── item.go │ ├── listener.go │ ├── rabbit_init.go │ └── redial.go ├── docs │ └── amqp_jobs.md └── plugin.go ├── beanstalk ├── beanstalkjobs │ ├── config.go │ ├── connection.go │ ├── consumer.go │ ├── item.go │ └── listen.go ├── docs │ └── beanstalk_jobs.md └── plugin.go ├── boltdb ├── boltjobs │ ├── config.go │ ├── consumer.go │ ├── item.go │ └── listener.go ├── boltkv │ ├── config.go │ └── driver.go ├── docs │ ├── boltdb_jobs.md │ ├── boltjobs.drawio │ └── job_lifecycle.md └── plugin.go ├── bors.toml ├── broadcast ├── config.go ├── doc │ └── broadcast_arch.drawio ├── plugin.go └── rpc.go ├── codecov.yml ├── config ├── configs │ ├── v2_6 │ │ ├── drivers.go │ │ └── v2.6.go │ └── v2_7 │ │ ├── drivers.go │ │ └── v2.7.go ├── docs │ └── config.md ├── plugin.go └── versions.go ├── fileserver ├── config.go ├── docs │ └── fileserver.md └── plugin.go ├── go.mod ├── go.sum ├── grpc ├── codec │ ├── codec.go │ └── codec_test.go ├── config.go ├── docs │ └── grpc.md ├── parser │ ├── message.proto │ ├── parse.go │ ├── parse_test.go │ ├── pong.proto │ ├── test.proto │ ├── test_import.proto │ └── test_nested │ │ ├── message.proto │ │ ├── pong.proto │ │ └── test_import.proto ├── plugin.go ├── protoc_plugins │ └── protoc-gen-php-grpc │ │ ├── main.go │ │ └── php │ │ ├── generate.go │ │ ├── keywords.go │ │ ├── ns.go │ │ └── template.go ├── proxy │ └── proxy.go └── server.go ├── http ├── acme.go ├── attributes │ └── attributes.go ├── config │ ├── acme.go │ ├── fcgi.go │ ├── http.go │ ├── http2.go │ ├── ip.go │ ├── tls.go │ ├── tls_config_test.go │ └── uploads_config.go ├── docs │ ├── cache.md │ ├── gzip.md │ ├── headers.md │ ├── http.md │ ├── new_relic.md │ ├── sendfile.md │ └── static.md ├── handler │ ├── errors.go │ ├── errors_windows.go │ ├── handler.go │ ├── parse.go │ ├── request.go │ ├── response.go │ └── uploads.go ├── http.go ├── metrics.go ├── middleware │ ├── cache │ │ ├── cache.go │ │ ├── config.go │ │ ├── const.go │ │ ├── directives │ │ │ ├── directives.go │ │ │ └── directives_test.go │ │ ├── doc.go │ │ ├── get.go │ │ ├── plugin.go │ │ ├── pool.go │ │ └── writer.go │ ├── gzip │ │ └── plugin.go │ ├── headers │ │ ├── config.go │ │ └── plugin.go │ ├── new_relic │ │ ├── config.go │ │ ├── error.go │ │ ├── error_test.go │ │ ├── plugin.go │ │ ├── splitter.go │ │ ├── splitter_test.go │ │ └── writer.go │ ├── prometheus │ │ ├── plugin.go │ │ └── writer.go │ ├── send │ │ └── plugin.go │ ├── static │ │ ├── config.go │ │ ├── etag.go │ │ └── plugin.go │ └── websockets │ │ ├── commands │ │ └── enums.go │ │ ├── config.go │ │ ├── connection │ │ └── connection.go │ │ ├── doc │ │ ├── broadcast.drawio │ │ └── doc.go │ │ ├── executor │ │ └── executor.go │ │ ├── origin.go │ │ ├── origin_test.go │ │ ├── plugin.go │ │ ├── pool │ │ └── workers_pool.go │ │ ├── validator │ │ └── access_validator.go │ │ └── wildcard.go ├── plugin.go ├── serve.go └── ssl.go ├── informer ├── plugin.go └── rpc.go ├── jobs ├── config.go ├── docs │ ├── jobs.md │ ├── jobs_arch.drawio │ └── response_protocol.md ├── listener.go ├── metrics.go ├── plugin.go ├── protocol │ ├── error.go │ ├── handler.go │ ├── qresp.go │ └── structs.go └── rpc.go ├── kv ├── config.go ├── doc │ └── kv.drawio ├── plugin.go └── rpc.go ├── logger ├── config.go ├── docs │ └── logger.md ├── encoder.go ├── enums.go ├── plugin.go └── std_log_adapter.go ├── memcached ├── memcachedkv │ ├── config.go │ └── driver.go └── plugin.go ├── memory ├── memoryhttpcache │ └── driver.go ├── memoryjobs │ ├── consumer.go │ └── item.go ├── memorykv │ ├── config.go │ └── kv.go ├── memorypubsub │ └── pubsub.go └── plugin.go ├── metrics ├── config.go ├── config_test.go ├── doc.go ├── plugin.go └── rpc.go ├── nats ├── docs │ └── nats.md ├── natsjobs │ ├── config.go │ ├── consumer.go │ ├── item.go │ └── listener.go └── plugin.go ├── redis ├── config.go ├── kv │ ├── config.go │ └── kv.go ├── plugin.go └── pubsub │ ├── channel.go │ ├── config.go │ └── pubsub.go ├── reload ├── config.go ├── plugin.go └── watcher.go ├── resetter ├── plugin.go └── rpc.go ├── rpc ├── config.go ├── doc │ └── plugin_arch.drawio └── plugin.go ├── server ├── config.go ├── docs │ └── server.md ├── oninit.go └── plugin.go ├── service ├── config.go ├── docs │ └── service.md ├── plugin.go ├── process.go └── state.go ├── sqs ├── docs │ └── sqs_jobs.md ├── plugin.go └── sqsjobs │ ├── config.go │ ├── consumer.go │ ├── item.go │ └── listener.go ├── status ├── config.go ├── plugin.go └── rpc.go ├── tcp ├── config.go ├── docs │ ├── tcp-flow.drawio │ └── tcp.md ├── handler │ ├── events.go │ ├── handler.go │ ├── helpers.go │ └── pool.go ├── plugin.go └── rpc.go └── tests ├── env ├── Dockerfile ├── Dockerfile-beanstalkd.yaml ├── Dockerfile-elastic-mq.yaml ├── custom.conf └── docker-compose.yaml ├── mock ├── logger.go └── observer.go ├── php_test_files ├── allocate-failed.php ├── broken.php ├── client.php ├── composer.json ├── delay.php ├── echo.php ├── error.php ├── exec_ttl.php ├── failboot.php ├── gzip-large-file.txt ├── head.php ├── http │ ├── client.php │ ├── cookie.php │ ├── data.php │ ├── echo.php │ ├── echoDelay.php │ ├── echoerr.php │ ├── env.php │ ├── error.php │ ├── error2.php │ ├── header.php │ ├── headers.php │ ├── ip.php │ ├── memleak.php │ ├── payload.php │ ├── pid.php │ ├── push.php │ ├── request-uri.php │ ├── server.php │ ├── slow-client.php │ ├── stuck.php │ ├── upload.php │ └── user-agent.php ├── idle.php ├── issue659.php ├── jobs_bad_resp.php ├── jobs_create_memory.php ├── jobs_err.php ├── jobs_ok.php ├── jobs_respond.php ├── jobs_respond_sqs.php ├── loop.php ├── memleak.php ├── metrics-issue-571.php ├── pid.php ├── psr-worker-all.php ├── psr-worker-bench.php ├── psr-worker-new_relic.php ├── psr-worker-post.php ├── psr-worker-slow.php ├── psr-worker-tcp-cont.php ├── psr-worker-tcp.php ├── psr-worker.php ├── raw-error.php ├── sleep-ttl.php ├── sleep.php ├── slow-client.php ├── slow-destroy.php ├── slow-pid.php ├── src │ ├── EchoService.php │ ├── GPBMetadata │ │ ├── Health.php │ │ └── Service.php │ ├── Health │ │ ├── HealthCheckRequest.php │ │ ├── HealthCheckResponse.php │ │ ├── HealthCheckResponse │ │ │ └── ServingStatus.php │ │ ├── HealthCheckResponse_ServingStatus.php │ │ └── HealthInterface.php │ ├── HealthService.php │ └── Service │ │ ├── EchoInterface.php │ │ └── Message.php ├── stop.php ├── supervised.php ├── temporal-worker.php ├── worker-cors.php ├── worker-deny.php ├── worker-grpc.php ├── worker-ok.php ├── worker-origin.php ├── worker-stop.php └── worker_new_relic.php ├── plugins ├── all │ └── bombers │ │ └── jobs │ │ └── main.go ├── broadcast │ ├── broadcast_plugin_test.go │ ├── configs │ │ ├── .rr-broadcast-config-error.yaml │ │ ├── .rr-broadcast-global.yaml │ │ ├── .rr-broadcast-init.yaml │ │ ├── .rr-broadcast-no-config.yaml │ │ └── .rr-broadcast-same-section.yaml │ └── plugins │ │ ├── plugin1.go │ │ ├── plugin2.go │ │ ├── plugin3.go │ │ ├── plugin4.go │ │ ├── plugin5.go │ │ └── plugin6.go ├── config │ ├── config_test.go │ ├── configs │ │ ├── .rr-env.yaml │ │ ├── .rr-init-version-2.7.yaml │ │ ├── .rr-init-version.yaml │ │ └── .rr.yaml │ ├── plugin1.go │ ├── plugin2.go │ └── plugin3.go ├── grpc │ ├── configs │ │ ├── .rr-grpc-init-duplicate-2.yaml │ │ ├── .rr-grpc-init-duplicate.yaml │ │ ├── .rr-grpc-init-multiple.yaml │ │ ├── .rr-grpc-init.yaml │ │ ├── .rr-grpc-rq-multiple.yaml │ │ ├── .rr-grpc-rq-tls-rootca.yaml │ │ ├── .rr-grpc-rq-tls.yaml │ │ ├── .rr-grpc-rq.yaml │ │ └── test-certs │ │ │ ├── ca.cert │ │ │ ├── ca.key │ │ │ ├── ca.srl │ │ │ ├── certificate.conf │ │ │ ├── test.csr │ │ │ ├── test.key │ │ │ └── test.pem │ ├── grpc_plugin_gzip_test.go │ ├── grpc_plugin_test.go │ ├── plugin_test.go │ ├── proto │ │ ├── external.proto │ │ ├── health │ │ │ ├── Makefile │ │ │ ├── health.pb.go │ │ │ ├── health.proto │ │ │ └── health_grpc.pb.go │ │ ├── service │ │ │ ├── service.pb.go │ │ │ ├── service.proto │ │ │ └── service_grpc.pb.go │ │ ├── test │ │ │ ├── test.pb.go │ │ │ └── test.proto │ │ └── test_dup │ │ │ ├── test_dup.pb.go │ │ │ └── test_dup.proto │ └── testdata │ │ ├── import │ │ ├── Import │ │ │ └── ServiceInterface.php │ │ ├── service.proto │ │ └── sub │ │ │ └── message.proto │ │ ├── import_custom │ │ ├── Test │ │ │ └── CustomImport │ │ │ │ └── ServiceInterface.php │ │ ├── service.proto │ │ └── sub │ │ │ └── message.proto │ │ ├── php_namespace │ │ ├── Test │ │ │ └── CustomNamespace │ │ │ │ └── ServiceInterface.php │ │ └── service.proto │ │ ├── simple │ │ ├── TestSimple │ │ │ └── SimpleServiceInterface.php │ │ └── simple.proto │ │ └── use_empty │ │ ├── Test │ │ └── ServiceInterface.php │ │ └── service.proto ├── gzip │ ├── configs │ │ ├── .rr-http-middlewareNotExist.yaml │ │ └── .rr-http-withGzip.yaml │ └── plugin_test.go ├── headers │ ├── configs │ │ ├── .rr-cors-headers.yaml │ │ ├── .rr-headers-init.yaml │ │ ├── .rr-req-headers.yaml │ │ └── .rr-res-headers.yaml │ └── headers_plugin_test.go ├── http │ ├── attributes_test.go │ ├── configs │ │ ├── .rr-big-req-size.yaml │ │ ├── .rr-broken-pipes.yaml │ │ ├── .rr-env.yaml │ │ ├── .rr-fcgi-reqUri.yaml │ │ ├── .rr-fcgi-unix.yaml │ │ ├── .rr-fcgi.yaml │ │ ├── .rr-h2c.yaml │ │ ├── .rr-http-access-logs.yaml │ │ ├── .rr-http-cache-requests.yaml │ │ ├── .rr-http-cache.yaml │ │ ├── .rr-http-init.yaml │ │ ├── .rr-http-ipv6-2.yaml │ │ ├── .rr-http-ipv6.yaml │ │ ├── .rr-http-new-relic.yaml │ │ ├── .rr-http-sendfile.yaml │ │ ├── .rr-http-static-disabled.yaml │ │ ├── .rr-http-static-etags.yaml │ │ ├── .rr-http-static-files-disable.yaml │ │ ├── .rr-http-static-files.yaml │ │ ├── .rr-http-static-new.yaml │ │ ├── .rr-http-static-security.yaml │ │ ├── .rr-http-static.yaml │ │ ├── .rr-http-supervised-pool.yaml │ │ ├── .rr-http.yaml │ │ ├── .rr-init.yaml │ │ ├── .rr-issue659.yaml │ │ ├── .rr-no-http.yaml │ │ ├── .rr-post-test.yaml │ │ ├── .rr-reset-forced.yaml │ │ ├── .rr-resetter.yaml │ │ ├── .rr-ssl-no-http.yaml │ │ ├── .rr-ssl-push.yaml │ │ ├── .rr-ssl-redirect.yaml │ │ └── .rr-ssl.yaml │ ├── fixtures │ │ ├── server.crt │ │ ├── server.key │ │ └── test-certs │ │ │ ├── ca.cert │ │ │ ├── ca.key │ │ │ ├── ca.srl │ │ │ ├── certificate.conf │ │ │ ├── test.csr │ │ │ ├── test.key │ │ │ └── test.pem │ ├── handler_test.go │ ├── http_plugin2_test.go │ ├── http_plugin_test.go │ ├── parse_test.go │ ├── plugin1.go │ ├── plugin_middleware.go │ └── uploads_test.go ├── informer │ ├── configs │ │ ├── .rr-informer-early-call.yaml │ │ └── .rr-informer.yaml │ ├── informer_test.go │ ├── test_plugin.go │ └── test_plugin_2.go ├── jobs │ ├── amqp │ │ ├── .rr-amqp-declare.yaml │ │ ├── .rr-amqp-init-br.yaml │ │ ├── .rr-amqp-init-v27-durable.yaml │ │ ├── .rr-amqp-init-v27.yaml │ │ ├── .rr-amqp-init.yaml │ │ ├── .rr-amqp-jobs-err.yaml │ │ ├── .rr-amqp-resp-jobs-ok.yaml │ │ └── .rr-no-global.yaml │ ├── beanstalk │ │ ├── .rr-beanstalk-declare.yaml │ │ ├── .rr-beanstalk-init-br.yaml │ │ ├── .rr-beanstalk-init-v27.yaml │ │ ├── .rr-beanstalk-init.yaml │ │ ├── .rr-beanstalk-jobs-err.yaml │ │ ├── .rr-beanstalk-respond.yaml │ │ └── .rr-no-global.yaml │ ├── boltdb │ │ ├── .rr-boltdb-declare.yaml │ │ ├── .rr-boltdb-init-v27-br.yaml │ │ ├── .rr-boltdb-init-v27.yaml │ │ ├── .rr-boltdb-init.yaml │ │ ├── .rr-boltdb-jobs-err.yaml │ │ └── .rr-no-global.yaml │ ├── configs │ │ ├── .rr-jobs-init.yaml │ │ └── .rr-jobs-metrics.yaml │ ├── durability │ │ ├── .rr-amqp-durability-redial.yaml │ │ ├── .rr-beanstalk-durability-redial.yaml │ │ ├── .rr-nats-durability-redial.yaml │ │ └── .rr-sqs-durability-redial.yaml │ ├── helpers.go │ ├── jobs_amqp_test.go │ ├── jobs_beanstalk_test.go │ ├── jobs_boltdb_test.go │ ├── jobs_general_test.go │ ├── jobs_memory_test.go │ ├── jobs_nats_test.go │ ├── jobs_sqs_test.go │ ├── jobs_with_toxics_test.go │ ├── memory │ │ ├── .rr-memory-create.yaml │ │ ├── .rr-memory-declare.yaml │ │ ├── .rr-memory-init-v27-br.yaml │ │ ├── .rr-memory-init-v27.yaml │ │ ├── .rr-memory-init.yaml │ │ ├── .rr-memory-jobs-err.yaml │ │ └── .rr-memory-pause-resume.yaml │ ├── nats │ │ ├── .rr-nats-declare.yaml │ │ ├── .rr-nats-init-v27-br.yaml │ │ ├── .rr-nats-init-v27.yaml │ │ ├── .rr-nats-init.yaml │ │ ├── .rr-nats-jobs-err.yaml │ │ ├── .rr-nats-respond.yaml │ │ ├── .rr-nats-stat.yaml │ │ └── .rr-no-global.yaml │ └── sqs │ │ ├── .rr-no-global.yaml │ │ ├── .rr-sqs-declare.yaml │ │ ├── .rr-sqs-init-v27-br.yaml │ │ ├── .rr-sqs-init-v27.yaml │ │ ├── .rr-sqs-init.yaml │ │ ├── .rr-sqs-jobs-err.yaml │ │ └── .rr-sqs-respond.yaml ├── kv │ ├── configs │ │ ├── .rr-boltdb.yaml │ │ ├── .rr-in-memory.yaml │ │ ├── .rr-kv-bolt-no-interval.yaml │ │ ├── .rr-kv-bolt-perms.yaml │ │ ├── .rr-kv-init.yaml │ │ ├── .rr-memcached.yaml │ │ ├── .rr-redis-global.yaml │ │ ├── .rr-redis-no-config.yaml │ │ └── .rr-redis.yaml │ └── storage_plugin_test.go ├── logger │ ├── configs │ │ ├── .rr-file-logger.yaml │ │ ├── .rr-no-logger.yaml │ │ ├── .rr-no-logger2.yaml │ │ ├── .rr-raw-mode.yaml │ │ └── .rr.yaml │ ├── logger_test.go │ └── plugin.go ├── metrics │ ├── configs │ │ ├── .rr-http-metrics-no-free-workers.yaml │ │ ├── .rr-http-metrics.yaml │ │ ├── .rr-issue-571.yaml │ │ └── .rr-test.yaml │ ├── metrics_test.go │ └── plugin1.go ├── reload │ ├── config_test.go │ ├── configs │ │ ├── .rr-reload-2.yaml │ │ ├── .rr-reload-3.yaml │ │ ├── .rr-reload-4.yaml │ │ └── .rr-reload.yaml │ └── reload_plugin_test.go ├── resetter │ ├── .rr-resetter.yaml │ ├── resetter_test.go │ └── test_plugin.go ├── rpc │ ├── config_test.go │ ├── configs │ │ ├── .rr-rpc-disabled.yaml │ │ └── .rr.yaml │ ├── plugin1.go │ ├── plugin2.go │ └── rpc_test.go ├── server │ ├── configs │ │ ├── .rr-no-app-section.yaml │ │ ├── .rr-sockets-on-init-fast-close.yaml │ │ ├── .rr-sockets-on-init.yaml │ │ ├── .rr-sockets.yaml │ │ ├── .rr-tcp-on-init.yaml │ │ ├── .rr-tcp.yaml │ │ ├── .rr-wrong-command-on-init.yaml │ │ ├── .rr-wrong-command.yaml │ │ ├── .rr-wrong-relay.yaml │ │ └── .rr.yaml │ ├── plugin_pipes.go │ ├── plugin_sockets.go │ ├── plugin_tcp.go │ ├── server_plugin_test.go │ ├── socket.php │ ├── tcp-on-init.php │ └── tcp.php ├── service │ ├── configs │ │ ├── .rr-service-env.yaml │ │ ├── .rr-service-error.yaml │ │ ├── .rr-service-init-stdout.yaml │ │ ├── .rr-service-init.yaml │ │ ├── .rr-service-init_win.yaml │ │ └── .rr-service-restarts.yaml │ ├── service_plugin_test.go │ └── test_files │ │ ├── loop.php │ │ ├── loop_env.php │ │ ├── loop_stdout.php │ │ └── test_binary ├── status │ ├── configs │ │ ├── .rr-ready-init.yaml │ │ └── .rr-status-init.yaml │ └── plugin_test.go ├── tcp │ ├── configs │ │ ├── .rr-tcp-close.yaml │ │ ├── .rr-tcp-empty.yaml │ │ ├── .rr-tcp-full.yaml │ │ └── .rr-tcp-init.yaml │ └── tcp_plugin_test.go └── websockets │ ├── configs │ ├── .rr-websockets-allow.yaml │ ├── .rr-websockets-allow2.yaml │ ├── .rr-websockets-broker-no-section.yaml │ ├── .rr-websockets-deny.yaml │ ├── .rr-websockets-deny2.yaml │ ├── .rr-websockets-init.yaml │ ├── .rr-websockets-redis.yaml │ └── .rr-websockets-stop.yaml │ └── websocket_plugin_test.go └── sample.txt /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: ❓ Start a discussion or ask a question. 5 | url: https://github.com/spiral/roadrunner-plugins/discussions 6 | about: Please ask and answer questions here. 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feauture request 2 | description: 💡 Suggest an idea for this project 3 | title: "[💡 FEATURE REQUEST]: " 4 | labels: ["C-feature-request"] 5 | assignees: 6 | - rustatian 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to share your idea! 12 | 13 | - type: dropdown 14 | id: plugin 15 | attributes: 16 | label: Plugin 17 | description: What plugin is affected? 18 | options: 19 | - GRPC 20 | - HTTP 21 | - JOBS 22 | - TCP 23 | - File server 24 | - Config 25 | - KV 26 | - Service 27 | - Server 28 | - Status 29 | - Metrics 30 | - Temporal 31 | - Broadcast 32 | - Websockets 33 | 34 | - type: textarea 35 | id: idea 36 | attributes: 37 | label: I have an idea! 38 | description: Clear and concise description of your idea. 39 | placeholder: Tell us what you see! 40 | value: "I have an idea, listen to me!!" 41 | validations: 42 | required: true 43 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: gomod # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: daily 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: daily 17 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Reason for This PR 2 | 3 | `[Author TODO: add issue # or explain reasoning.]` 4 | 5 | ## Description of Changes 6 | 7 | `[Author TODO: add description of changes.]` 8 | 9 | ## License Acceptance 10 | 11 | By submitting this pull request, I confirm that my contribution is made under 12 | the terms of the MIT license. 13 | 14 | ## PR Checklist 15 | 16 | `[Author TODO: Meet these criteria.]` 17 | `[Reviewer TODO: Verify that these criteria are met. Request changes if not]` 18 | 19 | - [ ] All commits in this PR are signed (`git commit -s`). 20 | - [ ] The reason for this PR is clearly provided (issue no. or explanation). 21 | - [ ] The description of changes is clear and encompassing. 22 | - [ ] Any required documentation changes (code and docs) are included in this PR. 23 | - [ ] Any user-facing changes are mentioned in `CHANGELOG.md`. 24 | - [ ] All added/changed functionality is tested. 25 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | golangci-lint: 7 | name: Golang-CI (lint) 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Check out code 11 | uses: actions/checkout@v2 12 | 13 | - name: Run linter 14 | uses: golangci/golangci-lint-action@v2 # Action page: 15 | with: 16 | version: v1.43 # without patch version 17 | only-new-issues: false # show only new issues if it's a pull request 18 | args: --timeout=10m --build-tags=safe 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .idea 17 | coverage-ci 18 | **/vendor 19 | tests/php_test_files/composer.lock 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Spiral Scout 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /amqp/amqpjobs/listener.go: -------------------------------------------------------------------------------- 1 | package amqpjobs 2 | 3 | import ( 4 | amqp "github.com/rabbitmq/amqp091-go" 5 | "go.uber.org/zap" 6 | ) 7 | 8 | func (c *consumer) listener(deliv <-chan amqp.Delivery) { 9 | go func() { 10 | for { //nolint:gosimple 11 | select { 12 | case msg, ok := <-deliv: 13 | if !ok { 14 | c.log.Debug("delivery channel was closed, leaving the rabbit listener") 15 | return 16 | } 17 | 18 | d, err := c.fromDelivery(msg) 19 | if err != nil { 20 | c.log.Error("delivery convert", zap.Error(err)) 21 | /* 22 | Acknowledge failed job to prevent endless loo; 23 | */ 24 | err = msg.Ack(false) 25 | if err != nil { 26 | c.log.Error("nack failed", zap.Error(err)) 27 | } 28 | 29 | if d != nil { 30 | d.Headers = nil 31 | d.Options = nil 32 | } 33 | continue 34 | } 35 | 36 | // insert job into the main priority queue 37 | c.pq.Insert(d) 38 | } 39 | } 40 | }() 41 | } 42 | -------------------------------------------------------------------------------- /beanstalk/beanstalkjobs/listen.go: -------------------------------------------------------------------------------- 1 | package beanstalkjobs 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/beanstalkd/go-beanstalk" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func (c *consumer) listen() { 11 | for { 12 | select { 13 | case <-c.stopCh: 14 | c.log.Debug("beanstalk listener stopped") 15 | return 16 | default: 17 | id, body, err := c.pool.Reserve(c.reserveTimeout) 18 | if err != nil { 19 | if errB, ok := err.(beanstalk.ConnError); ok { 20 | switch errB.Err { //nolint:gocritic 21 | case beanstalk.ErrTimeout: 22 | c.log.Info("beanstalk reserve timeout", zap.Error(errB)) 23 | continue 24 | } 25 | } 26 | // in case of other error - continue 27 | c.log.Warn("beanstalk reserve", zap.Error(err)) 28 | continue 29 | } 30 | 31 | // todo(rustatian): to sync pool 32 | item := &Item{} 33 | err = c.unpack(id, body, item) 34 | if err != nil { 35 | c.log.Error("beanstalk unpack item", zap.Error(err)) 36 | _ = c.pool.Delete(context.Background(), id) 37 | continue 38 | } 39 | 40 | // insert job into the priority queue 41 | c.pq.Insert(item) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /boltdb/boltjobs/config.go: -------------------------------------------------------------------------------- 1 | package boltjobs 2 | 3 | const ( 4 | file string = "file" 5 | prefetch string = "prefetch" 6 | ) 7 | 8 | type config struct { 9 | // global 10 | Permissions int `mapstructure:"permissions"` 11 | 12 | // local 13 | File string `mapstructure:"file"` 14 | Priority int64 `mapstructure:"priority"` 15 | Prefetch int `mapstructure:"prefetch"` 16 | } 17 | 18 | func (c *config) InitDefaults() { 19 | if c.File == "" { 20 | c.File = "rr.db" 21 | } 22 | 23 | if c.Priority == 0 { 24 | c.Priority = 10 25 | } 26 | 27 | if c.Prefetch == 0 { 28 | c.Prefetch = 1000 29 | } 30 | 31 | if c.Permissions == 0 { 32 | c.Permissions = 0777 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /boltdb/boltkv/config.go: -------------------------------------------------------------------------------- 1 | package boltkv 2 | 3 | type Config struct { 4 | // File is boltDB file. No need to create it by your own, 5 | // boltdb driver is able to create the file, or read existing 6 | File string 7 | // Bucket to store data in boltDB 8 | bucket string 9 | // db file permissions 10 | Permissions int 11 | // timeout 12 | Interval int `mapstructure:"interval"` 13 | } 14 | 15 | // InitDefaults initializes default values for the boltdb 16 | func (s *Config) InitDefaults() { 17 | s.bucket = "default" 18 | 19 | if s.File == "" { 20 | s.File = "rr.db" // default file name 21 | } 22 | 23 | if s.Permissions == 0 { 24 | s.Permissions = 0777 // free for all 25 | } 26 | 27 | if s.Interval == 0 { 28 | s.Interval = 60 // default is 60 seconds timeout 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /boltdb/docs/job_lifecycle.md: -------------------------------------------------------------------------------- 1 | ### Job lifecycle 2 | 3 | There are several boltdb buckets: 4 | 5 | 1. `PushBucket` - used for pushed jobs via RPC. 6 | 2. `InQueueBucket` - when the job consumed from the `PushBucket`, in the same transaction, it copied into the priority queue and 7 | get into the `InQueueBucket` waiting to acknowledgement. 8 | 3. `DelayBucket` - used for delayed jobs. RFC3339 used as a timestamp to track delay expiration. 9 | 10 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | 'Linux / Build (Go 1.17.3, PHP 7.4, OS ubuntu-latest)', 3 | 'Linux / Build (Go 1.17.3, PHP 8.0, OS ubuntu-latest)', 4 | 'Linux / Build (Go 1.17.3, PHP 8.1, OS ubuntu-latest)', 5 | 'Linters / Golang-CI (lint) ', 6 | ] 7 | required_approvals = 0 8 | delete_merged_branches = true 9 | timeout-sec = 1800 10 | -------------------------------------------------------------------------------- /broadcast/config.go: -------------------------------------------------------------------------------- 1 | package broadcast 2 | 3 | /* 4 | 5 | # Global redis config (priority - 2) 6 | default: 7 | # redis configuration here 8 | 9 | websockets: # <----- one of possible subscribers 10 | path: /ws 11 | broker: default # <------ broadcast broker to use --------------- | 12 | | match 13 | broadcast: # <-------- broadcast entry point plugin | 14 | default: # <----------------------------------------------------- | 15 | driver: redis 16 | # local redis config (priority - 1) 17 | test: 18 | driver: memory 19 | 20 | 21 | priority local -> global 22 | */ 23 | 24 | // Config ... 25 | type Config struct { 26 | Data map[string]interface{} `mapstructure:"broadcast"` 27 | } 28 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: auto 6 | threshold: 50% 7 | informational: true 8 | patch: 9 | default: 10 | target: auto 11 | threshold: 50% 12 | informational: true 13 | 14 | # do not include tests folders 15 | ignore: 16 | - ".github" 17 | - "config/configs" 18 | - "grpc/parser/parse_test.go" 19 | - "grpc/codec/codec_test.go" 20 | - "http/config" 21 | - "http/middleware/new_relic/error_test.go" 22 | - "http/middleware/new_relic/splitter_test.go" 23 | - "http/middleware/websockets/origin_test.go" 24 | - "jobs/pipeline/pipeline_test.go" 25 | - "jobs/job/job_test.go" 26 | - "metrics/config_test.go" 27 | - "tests" 28 | - "utils" 29 | -------------------------------------------------------------------------------- /config/docs/config.md: -------------------------------------------------------------------------------- 1 | ## PHP Client 2 | 3 | [Roadrunner Worker](https://github.com/spiral/roadrunner-worker) 4 | 5 | ## Configuration 6 | 7 | This plugin parse other's plugins configuration and uses flags to find the YAML config. 8 | 9 | ## Flags 10 | 11 | 1. `-c [PATH]`: points RR to the configuration location. 12 | 13 | ## Minimal dependencies: 14 | 15 | This plugin is independent. 16 | 17 | ## Worker sample: 18 | 19 | ```php 20 | waitPayload()) { 28 | // Received Payload 29 | var_dump($data); 30 | 31 | // Respond Answer 32 | $worker->respond(new \Spiral\RoadRunner\Payload('DONE')); 33 | } 34 | ``` 35 | 36 | ## Tips: 37 | 38 | 1. By default, `.rr.yaml` used as the configuration, located in the same directory with RR binary. 39 | 40 | ## Common issues: 41 | -------------------------------------------------------------------------------- /grpc/parser/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | message Message { 5 | string msg = 1; 6 | int64 value = 2; 7 | } -------------------------------------------------------------------------------- /grpc/parser/pong.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | import "message.proto"; 5 | 6 | // Pong service. 7 | service PongService { 8 | rpc Pong (stream Message) returns (stream Message) { 9 | } 10 | } -------------------------------------------------------------------------------- /grpc/parser/test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | // Ping Service. 5 | service PingService { 6 | // Ping Method. 7 | rpc Ping (Message) returns (Message) { 8 | } 9 | } 10 | 11 | // Pong service. 12 | service PongService { 13 | rpc Pong (stream Message) returns (stream Message) { 14 | } 15 | } 16 | 17 | message Message { 18 | string msg = 1; 19 | int64 value = 2; 20 | } -------------------------------------------------------------------------------- /grpc/parser/test_import.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | import "message.proto"; 5 | import "pong.proto"; 6 | 7 | // Ping Service. 8 | service PingService { 9 | // Ping Method. 10 | rpc Ping (Message) returns (Message) { 11 | } 12 | } -------------------------------------------------------------------------------- /grpc/parser/test_nested/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | message Message { 5 | string msg = 1; 6 | int64 value = 2; 7 | } -------------------------------------------------------------------------------- /grpc/parser/test_nested/pong.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | import "message.proto"; 5 | 6 | // Pong service. 7 | service PongService { 8 | rpc Pong (stream Message) returns (stream Message) { 9 | } 10 | } -------------------------------------------------------------------------------- /grpc/parser/test_nested/test_import.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package app.namespace; 3 | 4 | import "message.proto"; 5 | import "pong.proto"; 6 | 7 | // Ping Service. 8 | service PingService { 9 | // Ping Method. 10 | rpc Ping (Message) returns (Message) { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /http/config/fcgi.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // FCGI for FastCGI server. 4 | type FCGI struct { 5 | // Address and port to handle as http server. 6 | Address string 7 | } 8 | -------------------------------------------------------------------------------- /http/config/ip.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "net" 4 | 5 | // Cidrs is a slice of IPNet addresses 6 | type Cidrs []*net.IPNet 7 | 8 | // IsTrusted checks if the ip address exists in the provided in the config addresses 9 | func (c *Cidrs) IsTrusted(ip string) bool { 10 | if len(*c) == 0 { 11 | return false 12 | } 13 | 14 | i := net.ParseIP(ip) 15 | if i == nil { 16 | return false 17 | } 18 | 19 | for _, cird := range *c { 20 | if cird.Contains(i) { 21 | return true 22 | } 23 | } 24 | 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /http/docs/cache.md: -------------------------------------------------------------------------------- 1 | ## Cache (RFC7234) middleware [WIP] 2 | 3 | Cache middleware implements http-caching RFC 7234 (not fully yet). 4 | It handles the following headers: 5 | 6 | - `Cache-Control` 7 | - `max-age` 8 | 9 | **Responses**: 10 | 11 | - `Age` 12 | 13 | **HTTP codes**: 14 | 15 | - `OK (200)` 16 | 17 | **Available backends**: 18 | 19 | - `memory` 20 | 21 | **Available methods**: 22 | 23 | - `GET` 24 | 25 | ## Configuration 26 | 27 | ```yaml 28 | http: 29 | address: 127.0.0.1:44933 30 | middleware: ["cache"] 31 | # ... 32 | cache: 33 | driver: memory 34 | cache_methods: ["GET", "HEAD", "POST"] # only GET by default 35 | config: {} 36 | ``` 37 | 38 | For the worker sample and other docs, please, refer to the [http plugin](http.md) -------------------------------------------------------------------------------- /http/docs/gzip.md: -------------------------------------------------------------------------------- 1 | - ### GZIP HTTP middleware 2 | 3 | ```yaml 4 | http: 5 | address: 127.0.0.1:55555 6 | max_request_size: 1024 7 | access_logs: false 8 | middleware: ["gzip"] 9 | 10 | pool: 11 | num_workers: 2 12 | max_jobs: 0 13 | allocate_timeout: 60s 14 | destroy_timeout: 60s 15 | ``` 16 | 17 | Used to compress incoming or outgoing data with the default gzip compression level. -------------------------------------------------------------------------------- /http/docs/sendfile.md: -------------------------------------------------------------------------------- 1 | - ### X-Sendfile 2 | 3 | ```yaml 4 | http: 5 | address: 127.0.0.1:55555 6 | max_request_size: 1024 7 | access_logs: false 8 | middleware: ["sendfile"] 9 | 10 | pool: 11 | num_workers: 2 12 | max_jobs: 0 13 | allocate_timeout: 60s 14 | destroy_timeout: 60s 15 | ``` 16 | 17 | HTTP middleware to handle `X-Sendfile` [header](https://github.com/spiral/roadrunner-plugins/issues/9) 18 | Middleware reads the file in 10MB chunks. So, for example for the 5Gb file, only 10MB of RSS will be used. If the file size is smaller than 10MB, the middleware fits the buffer to the file size. 19 | -------------------------------------------------------------------------------- /http/handler/errors.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package handler 5 | 6 | import ( 7 | "errors" 8 | ) 9 | 10 | // Broken pipe 11 | var errEPIPE = errors.New("EPIPE(32) -> connection reset by peer") 12 | -------------------------------------------------------------------------------- /http/handler/errors_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package handler 5 | 6 | import ( 7 | "errors" 8 | ) 9 | 10 | //Software caused connection abort. 11 | //An established connection was aborted by the software in your host computer, 12 | //possibly due to a data transmission time-out or protocol error. 13 | var errEPIPE = errors.New("WSAECONNABORTED (10053) -> an established connection was aborted by peer") 14 | -------------------------------------------------------------------------------- /http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/spiral/errors" 7 | "github.com/spiral/roadrunner/v2/utils" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func (p *Plugin) serveHTTP(errCh chan error) { 12 | const op = errors.Op("serveHTTP") 13 | 14 | if len(p.mdwr) > 0 { 15 | applyMiddlewares(p.http, p.mdwr, p.cfg.Middleware, p.log) 16 | } 17 | 18 | l, err := utils.CreateListener(p.cfg.Address) 19 | if err != nil { 20 | errCh <- errors.E(op, err) 21 | return 22 | } 23 | 24 | p.log.Debug("http server was started", zap.String("address", p.cfg.Address)) 25 | err = p.http.Serve(l) 26 | if err != nil && err != http.ErrServerClosed { 27 | errCh <- errors.E(op, err) 28 | return 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /http/middleware/cache/config.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type Config struct { 8 | // Driver name 9 | Driver string `mapstructure:"driver"` 10 | 11 | // Only get by default 12 | CacheMethods []string `mapstructure:"cache_methods"` 13 | 14 | // Driver specific configuration 15 | Config interface{} `mapstructure:"config"` 16 | } 17 | 18 | func (c *Config) InitDefaults() { 19 | if c.Driver == "" { 20 | c.Driver = "memory" 21 | } 22 | 23 | // cache only GET requests 24 | if len(c.CacheMethods) == 0 { 25 | c.CacheMethods = append(c.CacheMethods, http.MethodGet) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /http/middleware/cache/const.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | /* 4 | Cache-Control keys and values https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#cache_directives 5 | */ 6 | 7 | const ( 8 | auth string = "Authorization" 9 | age string = "Age" 10 | cacheControl string = "Cache-Control" 11 | ) 12 | -------------------------------------------------------------------------------- /http/middleware/cache/doc.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | /* 4 | In the initial release, the cache middleware doesn't support the Range and Content-Range headers. 5 | https://datatracker.ietf.org/doc/html/rfc7234#section-3.1 6 | a cache MUST NOT store 7 | incomplete or partial-content responses if it does not support the 8 | Range and Content-Range header fields or if it does not understand 9 | the range units used in those fields. 10 | 11 | 12 | https://datatracker.ietf.org/doc/html/rfc7234#section-4 13 | cache should not use stored responses 14 | */ 15 | -------------------------------------------------------------------------------- /http/middleware/cache/pool.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "hash" 5 | 6 | cacheV1beta "github.com/roadrunner-server/api/v2/proto/cache/v1beta" 7 | "github.com/spiral/roadrunner-plugins/v2/http/middleware/cache/directives" 8 | ) 9 | 10 | func (p *Plugin) getHash() hash.Hash64 { 11 | return p.hashPool.Get().(hash.Hash64) 12 | } 13 | 14 | func (p *Plugin) putHash(h hash.Hash64) { 15 | h.Reset() 16 | p.hashPool.Put(h) 17 | } 18 | 19 | func (p *Plugin) getWriter() *writer { 20 | wr := p.writersPool.Get().(*writer) 21 | return wr 22 | } 23 | 24 | func (p *Plugin) putWriter(w *writer) { 25 | w.Code = -1 26 | w.Data = nil 27 | 28 | for k := range w.HdrToSend { 29 | delete(w.HdrToSend, k) 30 | } 31 | 32 | p.writersPool.Put(w) 33 | } 34 | 35 | func (p *Plugin) getRsp() *cacheV1beta.Response { 36 | return p.rspPool.Get().(*cacheV1beta.Response) 37 | } 38 | 39 | func (p *Plugin) putRsp(r *cacheV1beta.Response) { 40 | r.Reset() 41 | p.rspPool.Put(r) 42 | } 43 | 44 | func (p *Plugin) getRq() *directives.Req { 45 | return p.rqPool.Get().(*directives.Req) 46 | } 47 | 48 | func (p *Plugin) putRq(r *directives.Req) { 49 | r.Reset() 50 | p.rqPool.Put(r) 51 | } 52 | -------------------------------------------------------------------------------- /http/middleware/cache/writer.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type writer struct { 8 | Code int `json:"code"` 9 | Data []byte `json:"data"` 10 | HdrToSend map[string][]string `json:"headers"` 11 | } 12 | 13 | func (w *writer) WriteHeader(code int) { 14 | w.Code = code 15 | } 16 | 17 | func (w *writer) Write(b []byte) (int, error) { 18 | w.Data = make([]byte, len(b)) 19 | copy(w.Data, b) 20 | return len(w.Data), nil 21 | } 22 | 23 | func (w *writer) Header() http.Header { 24 | return w.HdrToSend 25 | } 26 | -------------------------------------------------------------------------------- /http/middleware/gzip/plugin.go: -------------------------------------------------------------------------------- 1 | package gzip 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/klauspost/compress/gzhttp" 7 | ) 8 | 9 | const PluginName = "gzip" 10 | 11 | type Plugin struct{} 12 | 13 | func (g *Plugin) Init() error { 14 | return nil 15 | } 16 | 17 | func (g *Plugin) Middleware(next http.Handler) http.Handler { 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 19 | gzhttp.GzipHandler(next).ServeHTTP(w, r) 20 | }) 21 | } 22 | 23 | func (g *Plugin) Name() string { 24 | return PluginName 25 | } 26 | -------------------------------------------------------------------------------- /http/middleware/new_relic/config.go: -------------------------------------------------------------------------------- 1 | package newrelic 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/spiral/errors" 7 | ) 8 | 9 | const ( 10 | newRelicLK string = "NEW_RELIC_LICENSE_KEY" 11 | newRelicAppName string = "NEW_RELIC_APP_NAME" 12 | ) 13 | 14 | type Config struct { 15 | AppName string `mapstructure:"app_name"` 16 | LicenseKey string `mapstructure:"license_key"` 17 | } 18 | 19 | func (c *Config) InitDefaults() error { 20 | if c.LicenseKey == "" { 21 | lc := os.Getenv(newRelicLK) 22 | 23 | if lc == "" { 24 | return errors.Str("license key should not be empty") 25 | } 26 | 27 | c.LicenseKey = os.Getenv(newRelicLK) 28 | } 29 | 30 | if c.AppName == "" { 31 | an := os.Getenv(newRelicAppName) 32 | 33 | if an == "" { 34 | return errors.Str("application name should not be empty") 35 | } 36 | 37 | c.AppName = os.Getenv(newRelicAppName) 38 | } 39 | 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /http/middleware/new_relic/error.go: -------------------------------------------------------------------------------- 1 | package newrelic 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/newrelic/go-agent/v3/newrelic" 7 | "github.com/spiral/roadrunner/v2/utils" 8 | ) 9 | 10 | const ( 11 | message string = "message" 12 | class string = "class" 13 | attributes string = "attributes" 14 | ) 15 | 16 | /* 17 | Error headers format: 18 | 19 | message:foo 20 | class:bar 21 | attributes:baz 22 | 23 | */ 24 | func handleErr(headers []string) error { 25 | nrErr := newrelic.Error{} 26 | 27 | for i := 0; i < len(headers); i++ { 28 | key, value := split(utils.AsBytes(headers[i])) 29 | switch { 30 | case strings.EqualFold(utils.AsString(key), message): 31 | nrErr.Message = utils.AsString(value) 32 | case strings.EqualFold(utils.AsString(key), class): 33 | nrErr.Class = utils.AsString(value) 34 | case strings.EqualFold(utils.AsString(key), attributes): 35 | nrErr.Attributes = map[string]interface{}{ 36 | "attributes": utils.AsString(value), 37 | } 38 | } 39 | } 40 | 41 | return nrErr 42 | } 43 | -------------------------------------------------------------------------------- /http/middleware/new_relic/splitter.go: -------------------------------------------------------------------------------- 1 | package newrelic 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | func split(target []byte) ([]byte, []byte) { 8 | // 58 according to the ASCII table is -> : 9 | pos := bytes.IndexByte(target, 58) 10 | 11 | // not found 12 | if pos == -1 { 13 | return nil, nil 14 | } 15 | 16 | // ":foo" or ":" 17 | if pos == 0 { 18 | return nil, nil 19 | } 20 | 21 | /* 22 | we should split headers into 2 parts. Parts are separated by the colon (:) 23 | "foo:bar" 24 | we should not panic on cases like: 25 | ":foo" 26 | "foo: bar" 27 | : 28 | */ 29 | 30 | // handle case like this "bar:" 31 | if len(target) < pos+1 { 32 | return nil, nil 33 | } 34 | 35 | return target[:pos], target[pos+1:] 36 | } 37 | -------------------------------------------------------------------------------- /http/middleware/new_relic/splitter_test.go: -------------------------------------------------------------------------------- 1 | package newrelic 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestSplitter(t *testing.T) { 10 | target1 := []byte("hello:world") 11 | key, value := split(target1) 12 | require.Equal(t, []byte("hello"), key) 13 | require.Equal(t, []byte("world"), value) 14 | 15 | target2 := []byte(":") 16 | key, value = split(target2) 17 | require.Equal(t, []byte(nil), key) 18 | require.Equal(t, []byte(nil), value) 19 | 20 | target3 := []byte(" : ") 21 | key, value = split(target3) 22 | require.Equal(t, []byte(" "), key) 23 | require.Equal(t, []byte(" "), value) 24 | 25 | target4 := []byte(" :") 26 | key, value = split(target4) 27 | require.Equal(t, []byte(" "), key) 28 | require.Equal(t, []byte{}, value) 29 | 30 | target5 := []byte(": ") 31 | key, value = split(target5) 32 | require.Equal(t, []byte(nil), key) 33 | require.Equal(t, []byte(nil), value) 34 | } 35 | -------------------------------------------------------------------------------- /http/middleware/new_relic/writer.go: -------------------------------------------------------------------------------- 1 | package newrelic 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type writer struct { 8 | code int 9 | data []byte 10 | hdrToSend map[string][]string 11 | } 12 | 13 | func (w *writer) WriteHeader(code int) { 14 | w.code = code 15 | } 16 | 17 | func (w *writer) Write(b []byte) (int, error) { 18 | w.data = make([]byte, len(b)) 19 | copy(w.data, b) 20 | return len(w.data), nil 21 | } 22 | 23 | func (w *writer) Header() http.Header { 24 | return w.hdrToSend 25 | } 26 | -------------------------------------------------------------------------------- /http/middleware/prometheus/writer.go: -------------------------------------------------------------------------------- 1 | package prometheus 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type writer struct { 8 | w http.ResponseWriter 9 | code int 10 | } 11 | 12 | func (w *writer) WriteHeader(code int) { 13 | w.code = code 14 | w.w.WriteHeader(code) 15 | } 16 | 17 | func (w *writer) Write(b []byte) (int, error) { 18 | return w.w.Write(b) 19 | } 20 | 21 | func (w *writer) Header() http.Header { 22 | return w.w.Header() 23 | } 24 | -------------------------------------------------------------------------------- /http/middleware/websockets/commands/enums.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | type Command string 4 | 5 | const ( 6 | Leave string = "leave" 7 | Join string = "join" 8 | Headers string = "headers" 9 | ) 10 | -------------------------------------------------------------------------------- /http/middleware/websockets/doc/doc.go: -------------------------------------------------------------------------------- 1 | package doc 2 | 3 | /* 4 | RPC message structure: 5 | 6 | type Msg struct { 7 | // Topic message been pushed into. 8 | Topics_ []string `json:"topic"` 9 | 10 | // Command (join, leave, headers) 11 | Command_ string `json:"command"` 12 | 13 | // Broker (redis, memory) 14 | Broker_ string `json:"broker"` 15 | 16 | // Payload to be broadcasted 17 | Payload_ []byte `json:"payload"` 18 | } 19 | 20 | 1. Topics - string array (slice) with topics to join or leave 21 | 2. Command - string, command to apply on the provided topics 22 | 3. Broker - string, pub-sub broker to use, for the one-node systems might be used `memory` broker or `redis`. For the multi-node - 23 | `redis` broker should be used. 24 | 4. Payload - raw byte array to send to the subscribers (binary messages). 25 | 26 | 27 | */ 28 | -------------------------------------------------------------------------------- /http/middleware/websockets/origin.go: -------------------------------------------------------------------------------- 1 | package websockets 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func isOriginAllowed(origin string, cfg *Config) bool { 8 | if cfg.allowedAll { 9 | return true 10 | } 11 | 12 | origin = strings.ToLower(origin) 13 | // simple case 14 | origin = strings.ToLower(origin) 15 | for _, o := range cfg.allowedOrigins { 16 | if o == origin { 17 | return true 18 | } 19 | } 20 | // check wildcards 21 | for _, w := range cfg.allowedWOrigins { 22 | if w.match(origin) { 23 | return true 24 | } 25 | } 26 | 27 | return false 28 | } 29 | -------------------------------------------------------------------------------- /http/middleware/websockets/wildcard.go: -------------------------------------------------------------------------------- 1 | package websockets 2 | 3 | import "strings" 4 | 5 | type wildcard struct { 6 | prefix string 7 | suffix string 8 | } 9 | 10 | func (w wildcard) match(s string) bool { 11 | return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix) 12 | } 13 | -------------------------------------------------------------------------------- /jobs/protocol/error.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | json "github.com/json-iterator/go" 5 | "github.com/roadrunner-server/api/v2/plugins/jobs" 6 | "github.com/spiral/errors" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func (rh *RespHandler) handleErrResp(data []byte, jb jobs.Acknowledger) error { 11 | er := rh.getErrResp() 12 | defer rh.putErrResp(er) 13 | 14 | err := json.Unmarshal(data, er) 15 | if err != nil { 16 | return err 17 | } 18 | 19 | rh.log.Error("jobs protocol error", zap.Error(errors.E(er.Msg)), zap.Int64("delay", er.Delay), zap.Bool("requeue", er.Requeue)) 20 | 21 | // requeue the job 22 | if er.Requeue { 23 | err = jb.Requeue(er.Headers, er.Delay) 24 | if err != nil { 25 | return err 26 | } 27 | return nil 28 | } 29 | 30 | // user don't want to requeue the job - silently ACK and return nil 31 | errAck := jb.Ack() 32 | if errAck != nil { 33 | rh.log.Error("job acknowledge was failed", zap.Error(errors.E(er.Msg)), zap.Error(errAck)) 34 | // do not return any error 35 | } 36 | 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /jobs/protocol/qresp.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | json "github.com/json-iterator/go" 5 | "github.com/roadrunner-server/api/v2/plugins/jobs" 6 | "github.com/spiral/roadrunner/v2/utils" 7 | ) 8 | 9 | // data - data to redirect to the queue 10 | func (rh *RespHandler) handleQueueResp(data []byte, jb jobs.Acknowledger) error { 11 | qs := rh.getQResp() 12 | defer rh.putQResp(qs) 13 | 14 | err := json.Unmarshal(data, qs) 15 | if err != nil { 16 | return err 17 | } 18 | 19 | err = jb.Respond(utils.AsBytes(qs.Payload), qs.Queue) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /jobs/protocol/structs.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | type errorResp struct { 4 | Msg string `json:"message"` 5 | Requeue bool `json:"requeue"` 6 | Delay int64 `json:"delay_seconds"` 7 | Headers map[string][]string `json:"headers"` 8 | } 9 | 10 | type queueResp struct { 11 | Queue string `json:"queue"` 12 | Payload string `json:"payload"` 13 | } 14 | -------------------------------------------------------------------------------- /kv/config.go: -------------------------------------------------------------------------------- 1 | package kv 2 | 3 | // Config represents general storage configuration with keys as the user defined kv-names and values as the constructors 4 | type Config struct { 5 | Data map[string]interface{} `mapstructure:"kv"` 6 | } 7 | -------------------------------------------------------------------------------- /logger/encoder.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/fatih/color" 7 | "go.uber.org/zap/zapcore" 8 | ) 9 | 10 | // ColoredLevelEncoder colorizes log levels. 11 | func ColoredLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { 12 | switch level { 13 | case zapcore.DebugLevel: 14 | enc.AppendString(color.HiWhiteString(level.CapitalString())) 15 | case zapcore.InfoLevel: 16 | enc.AppendString(color.HiCyanString(level.CapitalString())) 17 | case zapcore.WarnLevel: 18 | enc.AppendString(color.HiYellowString(level.CapitalString())) 19 | case zapcore.ErrorLevel, zapcore.DPanicLevel: 20 | enc.AppendString(color.HiRedString(level.CapitalString())) 21 | case zapcore.PanicLevel, zapcore.FatalLevel: 22 | enc.AppendString(color.HiMagentaString(level.CapitalString())) 23 | } 24 | } 25 | 26 | // ColoredNameEncoder colorizes service names. 27 | func ColoredNameEncoder(s string, enc zapcore.PrimitiveArrayEncoder) { 28 | if len(s) < 12 { 29 | s += strings.Repeat(" ", 12-len(s)) 30 | } 31 | 32 | enc.AppendString(color.HiGreenString(s)) 33 | } 34 | -------------------------------------------------------------------------------- /logger/enums.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | // Mode represents available logger modes 4 | type Mode string 5 | 6 | const ( 7 | none Mode = "none" 8 | off Mode = "off" 9 | production Mode = "production" 10 | development Mode = "development" 11 | raw Mode = "raw" 12 | ) 13 | -------------------------------------------------------------------------------- /logger/std_log_adapter.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "github.com/spiral/roadrunner/v2/utils" 5 | "go.uber.org/zap" 6 | ) 7 | 8 | // StdLogAdapter can be passed to the http.Server or any place which required standard logger to redirect output 9 | // to the logger plugin 10 | type StdLogAdapter struct { 11 | log *zap.Logger 12 | } 13 | 14 | // Write io.Writer interface implementation 15 | func (s *StdLogAdapter) Write(p []byte) (n int, err error) { 16 | s.log.Error("internal server error", zap.String("message", utils.AsString(p))) 17 | return len(p), nil 18 | } 19 | 20 | // NewStdAdapter constructs StdLogAdapter 21 | func NewStdAdapter(log *zap.Logger) *StdLogAdapter { 22 | logAdapter := &StdLogAdapter{ 23 | log: log, 24 | } 25 | 26 | return logAdapter 27 | } 28 | -------------------------------------------------------------------------------- /memcached/memcachedkv/config.go: -------------------------------------------------------------------------------- 1 | package memcachedkv 2 | 3 | type Config struct { 4 | // Addr is url for memcached, 11211 port is used by default 5 | Addr []string 6 | } 7 | 8 | func (s *Config) InitDefaults() { 9 | if s.Addr == nil { 10 | s.Addr = []string{"127.0.0.1:11211"} // default url for memcached 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /memory/memoryhttpcache/driver.go: -------------------------------------------------------------------------------- 1 | package memoryhttpcache 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/spiral/errors" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | type Cache struct { 11 | log *zap.Logger 12 | data sync.Map // map[string][]byte 13 | } 14 | 15 | func NewCacheDriver(log *zap.Logger) (*Cache, error) { 16 | l := new(zap.Logger) 17 | *l = *log 18 | return &Cache{ 19 | log: l, 20 | }, nil 21 | } 22 | 23 | func (c *Cache) Get(id uint64) ([]byte, error) { 24 | c.log.Debug("cache_get", zap.Uint64("id", id)) 25 | data, ok := c.data.Load(id) 26 | if !ok { 27 | return nil, errors.E(errors.EmptyItem) 28 | } 29 | 30 | return data.([]byte), nil 31 | } 32 | 33 | func (c *Cache) Set(id uint64, value []byte) error { 34 | c.log.Debug("cache_set", zap.Uint64("id", id), zap.ByteString("data", value)) 35 | c.data.Store(id, value) 36 | return nil 37 | } 38 | 39 | func (c *Cache) Delete(id uint64) { 40 | c.log.Debug("cache_delete", zap.Uint64("id", id)) 41 | c.data.Delete(id) 42 | } 43 | -------------------------------------------------------------------------------- /memory/memorykv/config.go: -------------------------------------------------------------------------------- 1 | package memorykv 2 | 3 | // Config is default config for the in-memory driver 4 | type Config struct { 5 | // Interval for the check 6 | Interval int 7 | } 8 | 9 | // InitDefaults by default driver is turned off 10 | func (c *Config) InitDefaults() { 11 | if c.Interval == 0 { 12 | c.Interval = 60 // seconds 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /metrics/doc.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | -------------------------------------------------------------------------------- /resetter/rpc.go: -------------------------------------------------------------------------------- 1 | package resetter 2 | 3 | import "github.com/spiral/errors" 4 | 5 | type rpc struct { 6 | srv *Plugin 7 | } 8 | 9 | // List all resettable plugins. 10 | func (rpc *rpc) List(_ bool, list *[]string) error { 11 | *list = make([]string, 0) 12 | 13 | for name := range rpc.srv.registry { 14 | *list = append(*list, name) 15 | } 16 | return nil 17 | } 18 | 19 | // Reset named plugin. 20 | func (rpc *rpc) Reset(service string, done *bool) error { 21 | const op = errors.Op("resetter_rpc_reset") 22 | err := rpc.srv.Reset(service) 23 | if err != nil { 24 | *done = false 25 | return errors.E(op, err) 26 | } 27 | *done = true 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /service/state.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/shirou/gopsutil/process" 5 | "github.com/spiral/errors" 6 | rrProcess "github.com/spiral/roadrunner/v2/state/process" 7 | ) 8 | 9 | func generalProcessState(pid int, command string) (rrProcess.State, error) { 10 | const op = errors.Op("process_state") 11 | p, _ := process.NewProcess(int32(pid)) 12 | i, err := p.MemoryInfo() 13 | if err != nil { 14 | return rrProcess.State{}, errors.E(op, err) 15 | } 16 | percent, err := p.CPUPercent() 17 | if err != nil { 18 | return rrProcess.State{}, err 19 | } 20 | 21 | return rrProcess.State{ 22 | CPUPercent: percent, 23 | Pid: pid, 24 | MemoryUsage: i.RSS, 25 | Command: command, 26 | }, nil 27 | } 28 | -------------------------------------------------------------------------------- /sqs/plugin.go: -------------------------------------------------------------------------------- 1 | package sqs 2 | 3 | import ( 4 | "github.com/roadrunner-server/api/v2/plugins/config" 5 | "github.com/roadrunner-server/api/v2/plugins/jobs" 6 | "github.com/roadrunner-server/api/v2/plugins/jobs/pipeline" 7 | "github.com/spiral/roadrunner-plugins/v2/sqs/sqsjobs" 8 | priorityqueue "github.com/spiral/roadrunner/v2/priority_queue" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | const ( 13 | pluginName string = "sqs" 14 | ) 15 | 16 | type Plugin struct { 17 | log *zap.Logger 18 | cfg config.Configurer 19 | } 20 | 21 | func (p *Plugin) Init(log *zap.Logger, cfg config.Configurer) error { 22 | p.log = new(zap.Logger) 23 | *p.log = *log 24 | p.cfg = cfg 25 | return nil 26 | } 27 | 28 | func (p *Plugin) Name() string { 29 | return pluginName 30 | } 31 | 32 | func (p *Plugin) ConsumerFromConfig(configKey string, pq priorityqueue.Queue) (jobs.Consumer, error) { 33 | return sqsjobs.NewSQSConsumer(configKey, p.log, p.cfg, pq) 34 | } 35 | 36 | func (p *Plugin) ConsumerFromPipeline(pipe *pipeline.Pipeline, pq priorityqueue.Queue) (jobs.Consumer, error) { 37 | return sqsjobs.FromPipeline(pipe, p.log, p.cfg, pq) 38 | } 39 | -------------------------------------------------------------------------------- /status/config.go: -------------------------------------------------------------------------------- 1 | package status 2 | 3 | import "net/http" 4 | 5 | // Config is the configuration reference for the Status plugin 6 | type Config struct { 7 | // Address of the http server 8 | Address string 9 | // Status code returned in case of fail, 503 by default 10 | UnavailableStatusCode int `mapstructure:"unavailable_status_code"` 11 | } 12 | 13 | // InitDefaults configuration options 14 | func (c *Config) InitDefaults() { 15 | if c.UnavailableStatusCode == 0 { 16 | c.UnavailableStatusCode = http.StatusServiceUnavailable 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tcp/handler/events.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | // immutable 4 | var ( 5 | CLOSE = []byte("CLOSE") //nolint:gochecknoglobals 6 | CONTINUE = []byte("CONTINUE") //nolint:gochecknoglobals 7 | WRITECLOSE = []byte("WRITECLOSE") //nolint:gochecknoglobals 8 | WRITE = []byte("WRITE") //nolint:gochecknoglobals 9 | ) 10 | 11 | type ServerInfo struct { 12 | RemoteAddr string `json:"remote_addr"` 13 | Server string `json:"server"` 14 | UUID string `json:"uuid"` 15 | Event string `json:"event"` 16 | } 17 | 18 | const ( 19 | EventConnected string = "CONNECTED" 20 | EventIncomingData string = "DATA" 21 | EventClose string = "CLOSE" 22 | ) 23 | -------------------------------------------------------------------------------- /tcp/handler/helpers.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | json "github.com/json-iterator/go" 5 | "go.uber.org/zap" 6 | ) 7 | 8 | func (h *handler) generate(event string) ([]byte, error) { 9 | si := h.getServInfo(event) 10 | pld, err := json.Marshal(si) 11 | if err != nil { 12 | h.putServInfo(si) 13 | return nil, err 14 | } 15 | 16 | h.putServInfo(si) 17 | return pld, nil 18 | } 19 | 20 | func (h *handler) sendClose() { 21 | c, err := h.generate(EventClose) 22 | if err != nil { 23 | h.log.Error("payload marshaling error", zap.Error(err)) 24 | return 25 | } 26 | pld := h.getPayload() 27 | pld.Context = c 28 | _, _ = h.wPool(pld) 29 | h.putPayload(pld) 30 | } 31 | -------------------------------------------------------------------------------- /tcp/rpc.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | type rpc struct { 4 | p *Plugin 5 | } 6 | 7 | func (r *rpc) Close(uuid string, ret *bool) error { 8 | *ret = true 9 | return r.p.Close(uuid) 10 | } 11 | -------------------------------------------------------------------------------- /tests/env/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/spiral/roadrunner:2.5.1@sha256:e9f87866845479ede406d441a5f949adf0d05ef67a29615851021561326224c3 AS roadrunner 2 | FROM php:8.0-cli 3 | RUN apt update -y 4 | RUN apt install build-essential -y 5 | 6 | 7 | COPY --from=roadrunner /usr/bin/rr /usr/local/bin/rr 8 | -------------------------------------------------------------------------------- /tests/env/Dockerfile-beanstalkd.yaml: -------------------------------------------------------------------------------- 1 | FROM ubuntu:rolling 2 | 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | 5 | RUN apt-get update && apt-get install -y curl build-essential pkg-config 6 | 7 | RUN curl -sL https://github.com/kr/beanstalkd/archive/v1.12.tar.gz | tar xvz -C /tmp 8 | 9 | WORKDIR /tmp/beanstalkd-1.12 10 | RUN make 11 | RUN cp beanstalkd /usr/bin 12 | 13 | EXPOSE 11300 14 | ENTRYPOINT ["/usr/bin/beanstalkd"] 15 | -------------------------------------------------------------------------------- /tests/env/Dockerfile-elastic-mq.yaml: -------------------------------------------------------------------------------- 1 | FROM openjdk:16 2 | 3 | ADD https://s3-eu-west-1.amazonaws.com/softwaremill-public/elasticmq-server-1.3.3.jar / 4 | COPY custom.conf / 5 | ENTRYPOINT ["java", "-Dconfig.file=custom.conf", "-jar", "/elasticmq-server-1.3.3.jar"] 6 | 7 | EXPOSE 9324 8 | 9 | CMD ["-help"] 10 | -------------------------------------------------------------------------------- /tests/env/custom.conf: -------------------------------------------------------------------------------- 1 | include classpath("application.conf") 2 | 3 | node-address { 4 | protocol = http 5 | host = "*" 6 | port = 9324 7 | context-path = "" 8 | } 9 | -------------------------------------------------------------------------------- /tests/env/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | memcached: 5 | image: memcached:latest 6 | ports: 7 | - "127.0.0.1:11211:11211" 8 | 9 | redis: 10 | image: redis:6 11 | ports: 12 | - "127.0.0.1:6379:6379" 13 | 14 | nats: 15 | image: nats:latest 16 | command: 17 | - "-js" 18 | ports: 19 | - "127.0.0.1:4222:4222" 20 | 21 | redis2: 22 | image: redis:6 23 | ports: 24 | - "127.0.0.1:6378:6379" 25 | 26 | toxicproxy: 27 | image: shopify/toxiproxy:latest 28 | network_mode: "host" 29 | 30 | beanstalk: 31 | build: 32 | context: . 33 | dockerfile: Dockerfile-beanstalkd.yaml 34 | ports: 35 | - "127.0.0.1:11300:11300" 36 | 37 | sqs: 38 | build: 39 | context: . 40 | dockerfile: Dockerfile-elastic-mq.yaml 41 | ports: 42 | - "127.0.0.1:9324:9324" 43 | 44 | rabbitmq: 45 | image: rabbitmq:3-management 46 | ports: 47 | - "127.0.0.1:15672:15672" 48 | - "127.0.0.1:5672:5672" 49 | 50 | prometheus: 51 | image: prom/prometheus 52 | ports: 53 | - "9090:9090" 54 | -------------------------------------------------------------------------------- /tests/mock/logger.go: -------------------------------------------------------------------------------- 1 | package mock_logger //nolint:stylecheck 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "go.uber.org/zap/zapcore" 6 | ) 7 | 8 | type ZapLoggerMock struct { 9 | l *zap.Logger 10 | } 11 | 12 | func ZapTestLogger(enab zapcore.LevelEnabler) (*ZapLoggerMock, *ObservedLogs) { 13 | core, logs := New(enab) 14 | obsLog := zap.New(core, zap.Development()) 15 | 16 | return &ZapLoggerMock{ 17 | l: obsLog, 18 | }, logs 19 | } 20 | 21 | func (z *ZapLoggerMock) Init() error { 22 | return nil 23 | } 24 | 25 | func (z *ZapLoggerMock) Serve() chan error { 26 | return make(chan error, 1) 27 | } 28 | 29 | func (z *ZapLoggerMock) Stop() error { 30 | return z.l.Sync() 31 | } 32 | 33 | func (z *ZapLoggerMock) Provides() []interface{} { 34 | return []interface{}{ 35 | z.ProvideZapLogger, 36 | } 37 | } 38 | 39 | func (z *ZapLoggerMock) ProvideZapLogger() *zap.Logger { 40 | return z.l 41 | } 42 | -------------------------------------------------------------------------------- /tests/php_test_files/allocate-failed.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 17 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 18 | } 19 | -------------------------------------------------------------------------------- /tests/php_test_files/broken.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | echo undefined_function(); 13 | $rr->respond(new RoadRunner\Payload((string)$in->body, null)); 14 | } 15 | -------------------------------------------------------------------------------- /tests/php_test_files/client.php: -------------------------------------------------------------------------------- 1 | =1.0", 9 | "spiral/tokenizer": ">=2.7", 10 | "spiral/roadrunner-metrics": "^2.0", 11 | "spiral/roadrunner-grpc": "^2.0", 12 | "spiral/roadrunner-tcp": "*", 13 | "spiral/roadrunner-jobs": "^2.0", 14 | "arku31/roadrunner-newrelic": "^0.1.4" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "": "src" 19 | } 20 | }, 21 | "repositories": [ 22 | { 23 | "type": "vcs", 24 | "url": "https://github.com/spiral/roadrunner-tcp" 25 | } 26 | ], 27 | "name": "test/test", 28 | "description": "test" 29 | } 30 | -------------------------------------------------------------------------------- /tests/php_test_files/delay.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | try { 13 | usleep($in->body * 1000); 14 | $rr->respond(new RoadRunner\Payload('')); 15 | } catch (\Throwable $e) { 16 | $rr->error((string)$e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/php_test_files/echo.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | try { 13 | $rr->respond(new RoadRunner\Payload((string)$in->body)); 14 | } catch (\Throwable $e) { 15 | $rr->error((string)$e); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php_test_files/error.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | $rr->error((string)$in->body); 13 | } 14 | -------------------------------------------------------------------------------- /tests/php_test_files/exec_ttl.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | sleep(3); 14 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/failboot.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | try { 13 | $rr->respond(new RoadRunner\Payload("", (string)$in->header)); 14 | } catch (\Throwable $e) { 15 | $rr->error((string)$e); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php_test_files/http/data.php: -------------------------------------------------------------------------------- 1 | getParsedBody(); 9 | 10 | ksort($data); 11 | ksort($data['arr']); 12 | ksort($data['arr']['x']['y']); 13 | 14 | $resp->getBody()->write(json_encode($data)); 15 | 16 | return $resp; 17 | } 18 | -------------------------------------------------------------------------------- /tests/php_test_files/http/echo.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getQueryParams()['hello'])); 9 | return $resp->withStatus(201); 10 | } 11 | -------------------------------------------------------------------------------- /tests/php_test_files/http/echoDelay.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getQueryParams()['hello'])); 10 | return $resp->withStatus(201); 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/echoerr.php: -------------------------------------------------------------------------------- 1 | getQueryParams()['hello'])); 9 | 10 | $resp->getBody()->write(strtoupper($req->getQueryParams()['hello'])); 11 | return $resp->withStatus(201); 12 | } 13 | -------------------------------------------------------------------------------- /tests/php_test_files/http/env.php: -------------------------------------------------------------------------------- 1 | getBody()->write($_SERVER['ENV_KEY']); 9 | return $resp; 10 | } 11 | -------------------------------------------------------------------------------- /tests/php_test_files/http/error.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getHeaderLine('input'))); 9 | 10 | return $resp->withAddedHeader("Header", $req->getQueryParams()['hello']); 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/headers.php: -------------------------------------------------------------------------------- 1 | getBody()->write(json_encode($req->getHeaders())); 9 | 10 | return $resp; 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/ip.php: -------------------------------------------------------------------------------- 1 | getBody()->write($req->getServerParams()['REMOTE_ADDR']); 9 | 10 | return $resp; 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/memleak.php: -------------------------------------------------------------------------------- 1 | getHeaderLine("Content-Type") != 'application/json') { 9 | $resp->getBody()->write("invalid content-type"); 10 | return $resp; 11 | } 12 | 13 | // we expect json body 14 | $p = json_decode($req->getBody(), true); 15 | $resp->getBody()->write(json_encode(array_flip($p))); 16 | 17 | return $resp; 18 | } 19 | -------------------------------------------------------------------------------- /tests/php_test_files/http/pid.php: -------------------------------------------------------------------------------- 1 | getBody()->write((string)getmypid()); 9 | 10 | return $resp; 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/push.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getQueryParams()['hello'])); 9 | return $resp->withAddedHeader("Http2-Push", __FILE__)->withStatus(201); 10 | } 11 | -------------------------------------------------------------------------------- /tests/php_test_files/http/request-uri.php: -------------------------------------------------------------------------------- 1 | getBody()->write($_SERVER['REQUEST_URI']); 9 | return $resp; 10 | } 11 | -------------------------------------------------------------------------------- /tests/php_test_files/http/server.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getHeaderLine('input'))); 9 | 10 | return $resp->withAddedHeader("Header", $req->getQueryParams()['hello']); 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/stuck.php: -------------------------------------------------------------------------------- 1 | getBody()->write(strtoupper($req->getQueryParams()['hello'])); 10 | return $resp->withStatus(201); 11 | } 12 | -------------------------------------------------------------------------------- /tests/php_test_files/http/user-agent.php: -------------------------------------------------------------------------------- 1 | getBody()->write($_SERVER['HTTP_USER_AGENT']); 9 | return $resp; 10 | } 11 | -------------------------------------------------------------------------------- /tests/php_test_files/idle.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | sleep(3); 14 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/issue659.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | $psr7->getWorker()->error("test_error"); 21 | } 22 | -------------------------------------------------------------------------------- /tests/php_test_files/jobs_bad_resp.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 16 | try { 17 | $rr->respond(new RoadRunner\Payload('foo')); 18 | } catch (\Throwable $e) { 19 | $rr->error((string)$e); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/php_test_files/jobs_create_memory.php: -------------------------------------------------------------------------------- 1 | create(new MemoryCreateInfo( 19 | name: 'example', 20 | priority: 42, 21 | prefetch: 10, 22 | )); 23 | 24 | $queue->resume(); 25 | 26 | $consumer = new Consumer(); 27 | while ($task = $consumer->waitTask()) { 28 | $task->complete(); 29 | } -------------------------------------------------------------------------------- /tests/php_test_files/jobs_ok.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 16 | try { 17 | $ctx = json_decode($in->header, true); 18 | $headers = $ctx['headers']; 19 | 20 | $rr->respond(new RoadRunner\Payload(json_encode([ 21 | 'type' => 0, 22 | 'data' => [] 23 | ]))); 24 | } catch (\Throwable $e) { 25 | $rr->error((string)$e); 26 | } 27 | } -------------------------------------------------------------------------------- /tests/php_test_files/jobs_respond.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 16 | try { 17 | $ctx = json_decode($in->header, true); 18 | $headers = $ctx['headers']; 19 | 20 | $rr->respond(new RoadRunner\Payload(json_encode([ 21 | 'type' => 2, 22 | 'data' => [ 23 | 'queue' => 'test-1-queue', 24 | 'payload' => 'foo' 25 | ] 26 | ]))); 27 | } catch (\Throwable $e) { 28 | $rr->error((string)$e); 29 | } 30 | } -------------------------------------------------------------------------------- /tests/php_test_files/jobs_respond_sqs.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 16 | try { 17 | $ctx = json_decode($in->header, true); 18 | $headers = $ctx['headers']; 19 | 20 | $rr->respond(new RoadRunner\Payload(json_encode([ 21 | 'type' => 2, 22 | 'data' => [ 23 | 'queue' => 'http://127.0.0.1:9324/000000000000/test-1-queue', 24 | 'payload' => 'foo' 25 | ] 26 | ]))); 27 | } catch (\Throwable $e) { 28 | $rr->error((string)$e); 29 | } 30 | } -------------------------------------------------------------------------------- /tests/php_test_files/loop.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tests/php_test_files/memleak.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | $mem .= str_repeat("a", 1024*1024*10); 14 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/metrics-issue-571.php: -------------------------------------------------------------------------------- 1 | getRPCAddress()) 19 | ); 20 | 21 | $metrics->declare( 22 | 'test', 23 | RoadRunner\Metrics\Collector::counter()->withHelp('Test counter') 24 | ); 25 | 26 | while ($req = $worker->waitRequest()) { 27 | try { 28 | $rsp = new \Nyholm\Psr7\Response(); 29 | $rsp->getBody()->write("hello world"); 30 | 31 | $metrics->add('test', 1); 32 | 33 | $worker->respond($rsp); 34 | } catch (\Throwable $e) { 35 | $worker->getWorker()->error((string)$e); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/php_test_files/pid.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | try { 13 | $rr->respond(new RoadRunner\Payload((string)getmypid())); 14 | } catch (\Throwable $e) { 15 | $rr->error((string)$e); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker-bench.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | $resp->getBody()->write("hello world"); 23 | 24 | $psr7->respond($resp); 25 | } catch (\Throwable $e) { 26 | $psr7->getWorker()->error((string)$e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker-new_relic.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 22 | try { 23 | $resp = new \Nyholm\Psr7\Response(); 24 | $rrNewRelic = [ 25 | 'shopId:1', //custom data 26 | 'auth:password', //custom data 27 | 'transaction_name:test_transaction' //name - special key to override the name. By default it will use requestUri. 28 | ]; 29 | 30 | $resp = $resp->withHeader('rr_newrelic', $rrNewRelic); 31 | 32 | $psr7->respond($resp); 33 | } catch (\Throwable $e) { 34 | $psr7->getWorker()->error((string)$e); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker-post.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 22 | try { 23 | $resp = new \Nyholm\Psr7\Response(); 24 | $resp->getBody()->write((string) $req->getBody()); 25 | 26 | $psr7->respond($resp); 27 | } catch (\Throwable $e) { 28 | $psr7->getWorker()->error((string)$e); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker-slow.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | sleep(mt_rand(1,20)); 23 | $resp->getBody()->write("hello world"); 24 | 25 | $psr7->respond($resp); 26 | } catch (\Throwable $e) { 27 | $psr7->getWorker()->error((string)$e); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker-tcp.php: -------------------------------------------------------------------------------- 1 | waitRequest(); 16 | 17 | $tcpWorker->respond(json_encode([ 18 | 'remote_addr' => $request->remoteAddr, 19 | 'server' => $request->server, 20 | 'uuid' => $request->connectionUuid, 21 | 'body' => $request->body, 22 | 'event' => $request->event 23 | ])); 24 | } catch (\Throwable $e) { 25 | $tcpWorker->respond("Something went wrong"); 26 | 27 | $worker->error((string)$e); 28 | 29 | continue; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/php_test_files/psr-worker.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | $resp->getBody()->write(str_repeat("d", 1024*1024*5)); 23 | 24 | $psr7->respond($resp); 25 | } catch (\Throwable $e) { 26 | $psr7->getWorker()->error((string)$e); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/php_test_files/raw-error.php: -------------------------------------------------------------------------------- 1 | waitRequest()) {} 22 | -------------------------------------------------------------------------------- /tests/php_test_files/sleep-ttl.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | sleep(10); 14 | $rr->respond(new \Spiral\RoadRunner\Payload("hello world")); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/sleep.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | sleep(300); 14 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/slow-client.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 12 | try { 13 | sleep(1); 14 | $rr->respond(new RoadRunner\Payload((string)getmypid())); 15 | } catch (\Throwable $e) { 16 | $rr->error((string)$e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/php_test_files/src/EchoService.php: -------------------------------------------------------------------------------- 1 | setMsg(strtoupper($in->getMsg())); 16 | } 17 | } -------------------------------------------------------------------------------- /tests/php_test_files/src/GPBMetadata/Health.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roadrunner-server/roadrunner-plugins/fe9027cfd72bb95f0ac5d2f65aee340530453f10/tests/php_test_files/src/GPBMetadata/Health.php -------------------------------------------------------------------------------- /tests/php_test_files/src/GPBMetadata/Service.php: -------------------------------------------------------------------------------- 1 | internalAddGeneratedFile( 18 | ' 19 | | 20 | service.protoservice" 21 | Message 22 | msg ( 24 23 | Echo, 24 | Ping.service.Message.service.Message"B Z 25 | ./;servicebproto3' 26 | , true); 27 | 28 | static::$is_initialized = true; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /tests/php_test_files/src/Health/HealthCheckResponse_ServingStatus.php: -------------------------------------------------------------------------------- 1 | setStatus(HealthCheckResponse\ServingStatus::SERVING); 17 | return $out; 18 | } 19 | 20 | public function Watch(ContextInterface $ctx, HealthCheckRequest $in): HealthCheckResponse 21 | { 22 | $out = new HealthCheckResponse(); 23 | $out->setStatus(HealthCheckResponse\ServingStatus::SERVING); 24 | return $out; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/php_test_files/src/Service/EchoInterface.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 13 | try { 14 | if ($used) { 15 | // kill on second attempt 16 | $rr->stop(); 17 | continue; 18 | } 19 | 20 | $used = true; 21 | $rr->respond(new RoadRunner\Payload((string)getmypid())); 22 | } catch (\Throwable $e) { 23 | $rr->error((string)$e); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/php_test_files/supervised.php: -------------------------------------------------------------------------------- 1 | waitPayload()){ 13 | $rr->respond(new \Spiral\RoadRunner\Payload("")); 14 | } 15 | -------------------------------------------------------------------------------- /tests/php_test_files/temporal-worker.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | $getClasses = static function (string $dir): iterable { 12 | $files = glob($dir . '/*.php'); 13 | 14 | foreach ($files as $file) { 15 | yield substr(basename($file), 0, -4); 16 | } 17 | }; 18 | 19 | $factory = \Temporal\WorkerFactory::create(); 20 | 21 | $worker = $factory->newWorker('default'); 22 | 23 | // register all workflows 24 | foreach ($getClasses(__DIR__ . '/src/Workflow') as $name) { 25 | $worker->registerWorkflowTypes('Temporal\\Tests\\Workflow\\' . $name); 26 | } 27 | 28 | // register all activity 29 | foreach ($getClasses(__DIR__ . '/src/Activity') as $name) { 30 | $class = 'Temporal\\Tests\\Activity\\' . $name; 31 | $worker->registerActivityImplementations(new $class); 32 | } 33 | 34 | $factory->run(); 35 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-cors.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 12 | $http->respond(200, 'Response', [ 13 | 'Access-Control-Allow-Origin' => ['*'] 14 | ]); 15 | } 16 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-deny.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | if ($req->getAttribute('ws:joinServer')) { 23 | $psr7->respond($resp->withStatus(200)); 24 | } else { 25 | $psr7->respond($resp->withStatus(401)); 26 | } 27 | } catch (\Throwable $e) { 28 | $psr7->getWorker()->error((string)$e); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-grpc.php: -------------------------------------------------------------------------------- 1 | false, // optional (default: false) 16 | ]); 17 | 18 | $server->registerService(EchoInterface::class, new EchoService()); 19 | $server->registerService(HealthInterface::class, new HealthService()); 20 | 21 | $server->serve(Worker::create()); 22 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-ok.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | $resp->getBody()->write($_SERVER['RR_BROADCAST_PATH'] ?? ''); 23 | $psr7->respond($resp); 24 | } catch (\Throwable $e) { 25 | $psr7->getWorker()->error((string)$e); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-origin.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 11 | $http->respond(200, 'Response', [ 12 | 'Access-Control-Allow-Origin' => ['*'] 13 | ]); 14 | } 15 | -------------------------------------------------------------------------------- /tests/php_test_files/worker-stop.php: -------------------------------------------------------------------------------- 1 | waitRequest()) { 20 | try { 21 | $resp = new \Nyholm\Psr7\Response(); 22 | $psr7->respond($resp->withAddedHeader('stop', 'we-dont-like-you')->withStatus(401)); 23 | } catch (\Throwable $e) { 24 | $psr7->getWorker()->error((string)$e); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/plugins/broadcast/configs/.rr-broadcast-config-error.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | relay: "pipes" 7 | relay_timeout: "20s" 8 | 9 | http: 10 | address: 127.0.0.1:21345 11 | max_request_size: 1024 12 | middleware: [ "websockets" ] 13 | trusted_subnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] 14 | pool: 15 | num_workers: 2 16 | max_jobs: 0 17 | allocate_timeout: 60s 18 | destroy_timeout: 60s 19 | 20 | # no global or local config 21 | broadcast: 22 | default: 23 | driver: redis 24 | 25 | logs: 26 | mode: development 27 | level: debug 28 | 29 | endure: 30 | grace_period: 120s 31 | print_graph: false 32 | log_level: error 33 | -------------------------------------------------------------------------------- /tests/plugins/broadcast/configs/.rr-broadcast-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:22444 13 | max_request_size: 1024 14 | middleware: [ "websockets" ] 15 | trusted_subnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] 16 | pool: 17 | num_workers: 2 18 | max_jobs: 0 19 | allocate_timeout: 60s 20 | destroy_timeout: 60s 21 | 22 | broadcast: 23 | default: 24 | driver: redis 25 | config: 26 | addrs: 27 | - "127.0.0.1:6379" 28 | 29 | logs: 30 | mode: development 31 | level: error 32 | 33 | endure: 34 | grace_period: 120s 35 | print_graph: false 36 | log_level: error 37 | -------------------------------------------------------------------------------- /tests/plugins/broadcast/configs/.rr-broadcast-no-config.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:25213 13 | max_request_size: 1024 14 | middleware: [ "websockets" ] 15 | trusted_subnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] 16 | pool: 17 | num_workers: 2 18 | max_jobs: 0 19 | allocate_timeout: 60s 20 | destroy_timeout: 60s 21 | 22 | logs: 23 | mode: development 24 | level: debug 25 | 26 | endure: 27 | grace_period: 120s 28 | print_graph: false 29 | log_level: error 30 | -------------------------------------------------------------------------------- /tests/plugins/broadcast/configs/.rr-broadcast-same-section.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6002 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | relay: "pipes" 7 | relay_timeout: "20s" 8 | 9 | http: 10 | address: 127.0.0.1:28976 11 | max_request_size: 1024 12 | middleware: ["websockets"] 13 | pool: 14 | num_workers: 2 15 | max_jobs: 0 16 | allocate_timeout: 60s 17 | destroy_timeout: 60s 18 | 19 | broadcast: 20 | test: 21 | driver: redis 22 | config: 23 | addrs: 24 | - "127.0.0.1:6379" 25 | test2: 26 | driver: redis 27 | config: 28 | addrs: 29 | - "127.0.0.1:6378" 30 | test3: 31 | driver: memory 32 | config: {} 33 | test4: 34 | driver: memory 35 | config: {} 36 | logs: 37 | mode: development 38 | level: info 39 | -------------------------------------------------------------------------------- /tests/plugins/config/configs/.rr-env.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: ${SUPER_RPC_ENV} 3 | 4 | logs: 5 | mode: development 6 | level: error 7 | 8 | reload: 9 | interval: 1s 10 | patterns: [ ".php" ] 11 | services: 12 | http: 13 | recursive: true 14 | ignore: [ "vendor" ] 15 | patterns: [ ".php", ".go",".md", ] 16 | dirs: [ "." ] 17 | jobs: 18 | recursive: false 19 | ignore: [ "service/metrics" ] 20 | dirs: [ "./jobs" ] 21 | rpc: 22 | recursive: true 23 | patterns: [ ".json" ] 24 | dirs: [ "" ] 25 | -------------------------------------------------------------------------------- /tests/plugins/config/configs/.rr.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6060 3 | 4 | logs: 5 | mode: development 6 | level: error 7 | 8 | reload: 9 | interval: 1s 10 | patterns: [".php"] 11 | services: 12 | http: 13 | recursive: true 14 | ignore: ["vendor"] 15 | patterns: [".php", ".go",".md",] 16 | dirs: ["."] 17 | jobs: 18 | recursive: false 19 | ignore: ["service/metrics"] 20 | dirs: ["./jobs"] 21 | rpc: 22 | recursive: true 23 | patterns: [".json"] 24 | dirs: [""] 25 | -------------------------------------------------------------------------------- /tests/plugins/config/plugin3.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/roadrunner-server/api/v2/plugins/config" 7 | "github.com/spiral/errors" 8 | ) 9 | 10 | type Foo3 struct { 11 | configProvider config.Configurer 12 | } 13 | 14 | // Depends on S2 and DB (S3 in the current case) 15 | func (f *Foo3) Init(p config.Configurer) error { 16 | f.configProvider = p 17 | return nil 18 | } 19 | 20 | func (f *Foo3) Serve() chan error { 21 | const op = errors.Op("foo_plugin_serve") 22 | errCh := make(chan error, 1) 23 | 24 | if f.configProvider.GracefulTimeout() != time.Second*10 { 25 | errCh <- errors.E(op, errors.Str("GracefulTimeout should be eq to 10 seconds")) 26 | return errCh 27 | } 28 | 29 | return errCh 30 | } 31 | 32 | func (f *Foo3) Stop() error { 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /tests/plugins/grpc/configs/.rr-grpc-init-duplicate-2.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: "tcp://127.0.0.1:6001" 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | relay: "pipes" 7 | relay_timeout: "20s" 8 | 9 | # GRPC service configuration 10 | grpc: 11 | # socket to listen 12 | listen: "tcp://127.0.0.1:9001" 13 | 14 | # proto root file 15 | proto: 16 | - "proto/test/test.proto" 17 | - "proto/test_dup/test_dup.proto" 18 | 19 | max_send_msg_size: 50 20 | max_recv_msg_size: 50 21 | max_connection_idle: 0s 22 | max_connection_age: 0s 23 | max_connection_age_grace: 0s 24 | max_concurrent_streams: 10 25 | ping_time: 1s 26 | timeout: 200s 27 | 28 | # Usual workers pool configuration 29 | pool: 30 | num_workers: 2 31 | max_jobs: 0 32 | allocate_timeout: 60s 33 | destroy_timeout: 60 34 | -------------------------------------------------------------------------------- /tests/plugins/grpc/configs/.rr-grpc-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: "tcp://127.0.0.1:6001" 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | relay: "pipes" 7 | relay_timeout: "20s" 8 | 9 | # GRPC service configuration 10 | grpc: 11 | listen: "tcp://127.0.0.1:9001" 12 | proto: "proto/test/test.proto" 13 | max_send_msg_size: 50 14 | max_recv_msg_size: 50 15 | max_connection_idle: 0s 16 | max_connection_age: 0s 17 | max_connection_age_grace: 0s 18 | max_concurrent_streams: 10 19 | ping_time: 1s 20 | timeout: 200s 21 | pool: 22 | num_workers: 2 23 | max_jobs: 0 24 | allocate_timeout: 60s 25 | destroy_timeout: 60 26 | -------------------------------------------------------------------------------- /tests/plugins/grpc/configs/test-certs/ca.srl: -------------------------------------------------------------------------------- 1 | 1ED5BE64C37F8D2C82C435EB9A2C83A644DB5BCB 2 | -------------------------------------------------------------------------------- /tests/plugins/grpc/configs/test-certs/certificate.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 4096 3 | prompt = no 4 | default_md = sha256 5 | req_extensions = req_ext 6 | distinguished_name = dn 7 | [dn] 8 | C = US 9 | ST = NJ 10 | O = Test, Inc. 11 | CN = localhost 12 | [req_ext] 13 | subjectAltName = @alt_names 14 | [alt_names] 15 | DNS.1 = localhost 16 | IP.1 = ::1 17 | IP.2 = 127.0.0.1 18 | -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/external.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tests; 3 | 4 | service External { 5 | rpc Echo (Ping) returns (Pong) { 6 | } 7 | 8 | rpc Empty (EmptyMessage) returns (EmptyMessage) { 9 | 10 | } 11 | } 12 | 13 | message Ping { 14 | int64 value = 1; 15 | } 16 | 17 | message Pong { 18 | int64 value = 1; 19 | } -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/health/Makefile: -------------------------------------------------------------------------------- 1 | PHP_OUT_DIR = ../../../../php_test_files/src 2 | GO_OUT_DIR = ./ 3 | 4 | all: build 5 | build: health_go health_php 6 | 7 | health_php: 8 | protoc --php_out=$(PHP_OUT_DIR) --php-grpc_out=$(PHP_OUT_DIR) \ 9 | health.proto 10 | health_go: 11 | protoc --go_out=$(GO_OUT_DIR) --go_opt=paths=source_relative \ 12 | --go-grpc_out=$(GO_OUT_DIR) --go-grpc_opt=paths=source_relative \ 13 | health.proto 14 | clean: 15 | rm -rf ./$(PHP_OUT_DIR)/* 16 | rm ./$(GO_OUT_DIR)/*.go 17 | -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/health/health.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grpc.health.v1; 4 | option go_package = "./;health"; 5 | option php_namespace = "Health"; 6 | option php_metadata_namespace = "GPBMetadata"; 7 | 8 | message HealthCheckRequest { 9 | string service = 1; 10 | } 11 | 12 | // https://github.com/grpc/grpc/blob/master/doc/health-checking.md 13 | message HealthCheckResponse { 14 | enum ServingStatus { 15 | UNKNOWN = 0; 16 | SERVING = 1; 17 | NOT_SERVING = 2; 18 | SERVICE_UNKNOWN = 3; // Used only by the Watch method. 19 | } 20 | ServingStatus status = 1; 21 | } 22 | 23 | service Health { 24 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); 25 | 26 | rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); 27 | } 28 | -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/service/service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package service; 4 | option go_package = "./;service"; 5 | 6 | service Echo { 7 | rpc Ping(Message) returns (Message) {} 8 | } 9 | 10 | message Message { string msg = 1; } -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/test/test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package service; 4 | option go_package = "./;test"; 5 | 6 | service Test { 7 | rpc Echo (Message) returns (Message) { 8 | } 9 | 10 | rpc Throw (Message) returns (Message) { 11 | } 12 | 13 | rpc Die (Message) returns (Message) { 14 | } 15 | 16 | rpc Info (Message) returns (Message) { 17 | } 18 | 19 | rpc Ping (EmptyMessage) returns (EmptyMessage) { 20 | } 21 | } 22 | 23 | message Message { 24 | string msg = 1; 25 | } 26 | 27 | message EmptyMessage { 28 | } 29 | 30 | message DetailsMessageForException { 31 | uint64 code = 1; 32 | string message = 2; 33 | } -------------------------------------------------------------------------------- /tests/plugins/grpc/proto/test_dup/test_dup.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package service; 4 | option go_package = "./;test_dup"; 5 | 6 | service Test2 { 7 | rpc Echo (Message) returns (Message) { 8 | } 9 | 10 | rpc Throw (Message) returns (Message) { 11 | } 12 | 13 | rpc Die (Message) returns (Message) { 14 | } 15 | 16 | rpc Info (Message) returns (Message) { 17 | } 18 | 19 | rpc Ping (EmptyMessage) returns (EmptyMessage) { 20 | } 21 | } 22 | 23 | message Message { 24 | string msg = 1; 25 | } 26 | 27 | message EmptyMessage { 28 | } 29 | 30 | message DetailsMessageForException { 31 | uint64 code = 1; 32 | string message = 2; 33 | } -------------------------------------------------------------------------------- /tests/plugins/grpc/testdata/import/Import/ServiceInterface.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 20 | try { 21 | $rr->respond(new RoadRunner\Payload((string)$in->body)); 22 | } catch (\Throwable $e) { 23 | $rr->error((string)$e); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/plugins/server/tcp-on-init.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 15 | try { 16 | $rr->respond(new RoadRunner\Payload((string)$in->body)); 17 | } catch (\Throwable $e) { 18 | $rr->error((string)$e); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/plugins/server/tcp.php: -------------------------------------------------------------------------------- 1 | waitPayload()) { 15 | try { 16 | $rr->respond(new RoadRunner\Payload((string)$in->body)); 17 | } catch (\Throwable $e) { 18 | $rr->error((string)$e); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-env.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_1: 3 | command: "php test_files/loop_env.php" 4 | process_num: 1 5 | exec_timeout: 5s # s,m,h (seconds, minutes, hours) 6 | remain_after_exit: true 7 | env: 8 | foo: "BAR" 9 | restart_sec: 1 10 | endure: 11 | grace_period: 120s 12 | print_graph: false 13 | log_level: error 14 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-error.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_1: 3 | command: "php test_files/loopo.php" 4 | process_num: 1 5 | exec_timeout: 5s # s,m,h (seconds, minutes, hours) 6 | remain_after_exit: true 7 | restart_sec: 1 8 | 9 | logs: 10 | level: info 11 | mode: raw 12 | 13 | endure: 14 | grace_period: 120s 15 | print_graph: false 16 | log_level: error 17 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-init-stdout.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_1: 3 | command: "php test_files/loop_stdout.php" 4 | process_num: 1 5 | exec_timeout: 5s # s,m,h (seconds, minutes, hours) 6 | remain_after_exit: true 7 | restart_sec: 1 8 | env: 9 | - "FOO": "BAR" 10 | - "FOO2": "BAZ" 11 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-init.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_1: 3 | command: "php test_files/loop.php" 4 | process_num: 1 5 | exec_timeout: 5s # s,m,h (seconds, minutes, hours) 6 | remain_after_exit: true 7 | restart_sec: 1 8 | some_service_2: 9 | command: "test_files/test_binary" 10 | process_num: 1 11 | remain_after_exit: true 12 | restart_delay: 1s 13 | exec_timeout: 5s 14 | 15 | endure: 16 | grace_period: 120s 17 | print_graph: false 18 | log_level: error 19 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-init_win.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_1: 3 | command: "php test_files/loop.php" 4 | process_num: 1 5 | exec_timeout: 5s # s,m,h (seconds, minutes, hours) 6 | remain_after_exit: true 7 | restart_sec: 1 8 | 9 | endure: 10 | grace_period: 120s 11 | print_graph: false 12 | log_level: error 13 | -------------------------------------------------------------------------------- /tests/plugins/service/configs/.rr-service-restarts.yaml: -------------------------------------------------------------------------------- 1 | service: 2 | some_service_2: 3 | command: "test_files/test_binary" 4 | process_num: 1 5 | remain_after_exit: true 6 | restart_delay: 1s 7 | exec_timeout: 2s 8 | 9 | logs: 10 | level: debug 11 | mode: raw 12 | 13 | endure: 14 | grace_period: 120s 15 | print_graph: false 16 | log_level: error 17 | -------------------------------------------------------------------------------- /tests/plugins/service/test_files/loop.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tests/plugins/service/test_files/loop_env.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /tests/plugins/service/test_files/loop_stdout.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tests/plugins/service/test_files/test_binary: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roadrunner-server/roadrunner-plugins/fe9027cfd72bb95f0ac5d2f65aee340530453f10/tests/plugins/service/test_files/test_binary -------------------------------------------------------------------------------- /tests/plugins/status/configs/.rr-ready-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6007 3 | 4 | server: 5 | command: "php ../../php_test_files/sleep.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | status: 12 | address: "127.0.0.1:34334" 13 | 14 | logs: 15 | mode: development 16 | level: error 17 | http: 18 | address: 127.0.0.1:11933 19 | max_request_size: 1024 20 | middleware: [ "" ] 21 | uploads: 22 | forbid: [ ".php", ".exe", ".bat" ] 23 | trusted_subnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] 24 | pool: 25 | num_workers: 1 26 | max_jobs: 0 27 | allocate_timeout: 60s 28 | destroy_timeout: 60s 29 | -------------------------------------------------------------------------------- /tests/plugins/status/configs/.rr-status-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6005 3 | 4 | server: 5 | command: "php ../../php_test_files/http/client.php echo pipes" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | status: 12 | address: "127.0.0.1:34333" 13 | 14 | logs: 15 | mode: development 16 | level: error 17 | http: 18 | address: 127.0.0.1:11933 19 | max_request_size: 1024 20 | middleware: [ "" ] 21 | uploads: 22 | forbid: [ ".php", ".exe", ".bat" ] 23 | trusted_subnets: [ "10.0.0.0/8", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "::1/128", "fc00::/7", "fe80::/10" ] 24 | pool: 25 | num_workers: 2 26 | max_jobs: 0 27 | allocate_timeout: 60s 28 | destroy_timeout: 60s -------------------------------------------------------------------------------- /tests/plugins/tcp/configs/.rr-tcp-close.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-tcp.php" 6 | 7 | tcp: 8 | servers: 9 | server1: 10 | addr: tcp://127.0.0.1:7788 11 | delimiter: "\r\n" 12 | 13 | pool: 14 | num_workers: 2 15 | max_jobs: 0 16 | allocate_timeout: 60s 17 | destroy_timeout: 60s -------------------------------------------------------------------------------- /tests/plugins/tcp/configs/.rr-tcp-empty.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6002 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-tcp.php" 6 | 7 | tcp: 8 | servers: 9 | tcp_access_point_1: 10 | addr: tcp://127.0.0.1:7779 11 | delimiter: "\r\n" 12 | 13 | pool: 14 | num_workers: 2 15 | max_jobs: 0 16 | allocate_timeout: 60s 17 | destroy_timeout: 60s -------------------------------------------------------------------------------- /tests/plugins/tcp/configs/.rr-tcp-full.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-tcp-cont.php" 6 | 7 | tcp: 8 | servers: 9 | server1: 10 | addr: 127.0.0.1:7778 11 | delimiter: "\r\n" 12 | server2: 13 | addr: 127.0.0.1:8811 14 | read_buf_size: 10 15 | server3: 16 | addr: 127.0.0.1:8812 17 | delimiter: "\r\n" 18 | read_buf_size: 1 19 | 20 | pool: 21 | num_workers: 5 22 | max_jobs: 0 23 | allocate_timeout: 60s 24 | destroy_timeout: 60s -------------------------------------------------------------------------------- /tests/plugins/tcp/configs/.rr-tcp-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6002 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-tcp.php" 6 | 7 | tcp: 8 | servers: 9 | server1: 10 | addr: tcp://127.0.0.1:7777 11 | delimiter: "\r\n" 12 | server2: 13 | addr: tcp://127.0.0.1:8889 14 | read_buf_size: 10 15 | server3: 16 | addr: tcp://127.0.0.1:8810 17 | delimiter: "\r\n" 18 | read_buf_size: 1 19 | 20 | pool: 21 | num_workers: 2 22 | max_jobs: 0 23 | allocate_timeout: 60s 24 | destroy_timeout: 60s -------------------------------------------------------------------------------- /tests/plugins/websockets/configs/.rr-websockets-broker-no-section.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:13235 13 | max_request_size: 1024 14 | middleware: ["websockets"] 15 | trusted_subnets: 16 | [ 17 | "10.0.0.0/8", 18 | "127.0.0.0/8", 19 | "172.16.0.0/12", 20 | "192.168.0.0/16", 21 | "::1/128", 22 | "fc00::/7", 23 | "fe80::/10", 24 | ] 25 | pool: 26 | num_workers: 2 27 | max_jobs: 0 28 | allocate_timeout: 60s 29 | destroy_timeout: 60s 30 | 31 | broadcast: 32 | test1: 33 | driver: no 34 | config: 35 | 36 | websockets: 37 | broker: test 38 | allowed_origin: "*" 39 | path: "/ws" 40 | 41 | logs: 42 | mode: development 43 | level: error 44 | 45 | endure: 46 | grace_period: 120s 47 | print_graph: false 48 | log_level: error 49 | -------------------------------------------------------------------------------- /tests/plugins/websockets/configs/.rr-websockets-deny.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/worker-deny.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:15587 13 | max_request_size: 1024 14 | middleware: ["websockets"] 15 | trusted_subnets: 16 | [ 17 | "10.0.0.0/8", 18 | "127.0.0.0/8", 19 | "172.16.0.0/12", 20 | "192.168.0.0/16", 21 | "::1/128", 22 | "fc00::/7", 23 | "fe80::/10", 24 | ] 25 | pool: 26 | num_workers: 2 27 | max_jobs: 0 28 | allocate_timeout: 60s 29 | destroy_timeout: 60s 30 | 31 | broadcast: 32 | test: 33 | driver: memory 34 | config: {} 35 | 36 | websockets: 37 | broker: test 38 | allowed_origin: "*" 39 | path: "/ws" 40 | 41 | logs: 42 | mode: development 43 | level: error 44 | 45 | endure: 46 | grace_period: 120s 47 | print_graph: false 48 | log_level: error 49 | -------------------------------------------------------------------------------- /tests/plugins/websockets/configs/.rr-websockets-init.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | relay: "pipes" 7 | relay_timeout: "20s" 8 | 9 | http: 10 | address: 127.0.0.1:11111 11 | max_request_size: 1024 12 | middleware: ["websockets"] 13 | trusted_subnets: 14 | [ 15 | "10.0.0.0/8", 16 | "127.0.0.0/8", 17 | "172.16.0.0/12", 18 | "192.168.0.0/16", 19 | "::1/128", 20 | "fc00::/7", 21 | "fe80::/10", 22 | ] 23 | pool: 24 | num_workers: 2 25 | max_jobs: 0 26 | allocate_timeout: 60s 27 | destroy_timeout: 60s 28 | 29 | broadcast: 30 | default: 31 | driver: memory 32 | config: {} 33 | 34 | websockets: 35 | broker: default 36 | allowed_origin: "*" 37 | path: "/ws" 38 | 39 | logs: 40 | mode: development 41 | level: error 42 | 43 | endure: 44 | grace_period: 120s 45 | print_graph: false 46 | log_level: error 47 | -------------------------------------------------------------------------------- /tests/plugins/websockets/configs/.rr-websockets-redis.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/psr-worker-bench.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:13235 13 | max_request_size: 1024 14 | middleware: ["websockets"] 15 | trusted_subnets: 16 | [ 17 | "10.0.0.0/8", 18 | "127.0.0.0/8", 19 | "172.16.0.0/12", 20 | "192.168.0.0/16", 21 | "::1/128", 22 | "fc00::/7", 23 | "fe80::/10", 24 | ] 25 | pool: 26 | num_workers: 2 27 | max_jobs: 0 28 | allocate_timeout: 60s 29 | destroy_timeout: 60s 30 | 31 | test: 32 | addrs: 33 | - "127.0.0.1:6379" 34 | 35 | broadcast: 36 | test: 37 | driver: redis 38 | 39 | websockets: 40 | broker: test 41 | allowed_origin: "*" 42 | path: "/ws" 43 | 44 | logs: 45 | mode: development 46 | level: error 47 | 48 | endure: 49 | grace_period: 120s 50 | print_graph: false 51 | log_level: error 52 | -------------------------------------------------------------------------------- /tests/plugins/websockets/configs/.rr-websockets-stop.yaml: -------------------------------------------------------------------------------- 1 | rpc: 2 | listen: tcp://127.0.0.1:6001 3 | 4 | server: 5 | command: "php ../../php_test_files/worker-stop.php" 6 | user: "" 7 | group: "" 8 | relay: "pipes" 9 | relay_timeout: "20s" 10 | 11 | http: 12 | address: 127.0.0.1:11114 13 | max_request_size: 1024 14 | middleware: ["websockets"] 15 | trusted_subnets: 16 | [ 17 | "10.0.0.0/8", 18 | "127.0.0.0/8", 19 | "172.16.0.0/12", 20 | "192.168.0.0/16", 21 | "::1/128", 22 | "fc00::/7", 23 | "fe80::/10", 24 | ] 25 | pool: 26 | num_workers: 2 27 | max_jobs: 0 28 | allocate_timeout: 60s 29 | destroy_timeout: 60s 30 | 31 | broadcast: 32 | test: 33 | driver: memory 34 | config: {} 35 | 36 | websockets: 37 | broker: test 38 | allowed_origin: "*" 39 | path: "/ws" 40 | 41 | logs: 42 | mode: development 43 | level: error 44 | 45 | endure: 46 | grace_period: 120s 47 | print_graph: false 48 | log_level: error 49 | -------------------------------------------------------------------------------- /tests/sample.txt: -------------------------------------------------------------------------------- 1 | sample 2 | --------------------------------------------------------------------------------