diff --git a/.dockerdev/.bashrc b/.dockerdev/.bashrc deleted file mode 100644 index 4f233c53..00000000 --- a/.dockerdev/.bashrc +++ /dev/null @@ -1 +0,0 @@ -alias be="bundle exec" diff --git a/.dockerdev/.psqlrc b/.dockerdev/.psqlrc deleted file mode 100644 index 57ea736f..00000000 --- a/.dockerdev/.psqlrc +++ /dev/null @@ -1,26 +0,0 @@ --- Don't display the "helpful" message on startup. -\set QUIET 1 - --- Allow specifying the path to history file via `PSQL_HISTFILE` env variable --- (and fallback to the default $HOME/.psql_history otherwise) -\set HISTFILE `[[ -z $PSQL_HISTFILE ]] && echo $HOME/.psql_history || echo $PSQL_HISTFILE` - --- Show how long each query takes to execute -\timing - --- Use best available output format -\x auto - --- Verbose error reports -\set VERBOSITY verbose - --- If a command is run more than once in a row, --- only store it once in the history -\set HISTCONTROL ignoredups -\set COMP_KEYWORD_CASE upper - --- By default, NULL displays as an empty space. Is it actually an empty --- string, or is it null? This makes that distinction visible -\pset null '[NULL]' - -\unset QUIET diff --git a/.dockerdev/Aptfile b/.dockerdev/Aptfile deleted file mode 100644 index f027e0d4..00000000 --- a/.dockerdev/Aptfile +++ /dev/null @@ -1 +0,0 @@ -vim diff --git a/.dockerdev/Dockerfile b/.dockerdev/Dockerfile deleted file mode 100644 index 2c9f6e53..00000000 --- a/.dockerdev/Dockerfile +++ /dev/null @@ -1,75 +0,0 @@ -ARG RUBY_VERSION -ARG DISTRO_NAME=bullseye - -FROM ruby:$RUBY_VERSION-slim-$DISTRO_NAME - -ARG DISTRO_NAME - -# Common dependencies -# Using --mount to speed up build with caching, see https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---mount -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - --mount=type=tmpfs,target=/var/log \ - rm -f /etc/apt/apt.conf.d/docker-clean; \ - echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache; \ - apt-get update -qq && \ - DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - build-essential \ - gnupg2 \ - curl \ - less \ - git - -ARG PG_MAJOR -RUN curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgres-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgres-archive-keyring.gpg] https://apt.postgresql.org/pub/repos/apt/" \ - $DISTRO_NAME-pgdg main $PG_MAJOR | tee /etc/apt/sources.list.d/postgres.list > /dev/null -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - --mount=type=tmpfs,target=/var/log \ - apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - libpq-dev \ - postgresql-client-$PG_MAJOR - -ARG NODE_MAJOR -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - --mount=type=tmpfs,target=/var/log \ - curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash - && \ - DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - nodejs - -ARG YARN_VERSION=latest -RUN npm install -g yarn@$YARN_VERSION - -# Application dependencies -# We use an external Aptfile for this, stay tuned -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - --mount=type=tmpfs,target=/var/log \ - --mount=type=bind,source=Aptfile,target=/tmp/Aptfile \ - DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - $(grep -Ev '^\s*#' /tmp/Aptfile | xargs) - -# Configure bundler -ENV LANG=C.UTF-8 \ - BUNDLE_JOBS=4 \ - BUNDLE_RETRY=3 - -# Store Bundler settings in the project's root -ENV BUNDLE_APP_CONFIG=.bundle - -# Upgrade RubyGems and install latest Bundler -RUN gem update --system && \ - gem install bundler - -# Create a directory for the app code -RUN mkdir -p /app -WORKDIR /app - -# Document that we're going to expose port 3000 -EXPOSE 3000 -# Use Bash as the default command -CMD ["/usr/bin/bash"] diff --git a/.dockerdev/compose.yml b/.dockerdev/compose.yml deleted file mode 100644 index 560b46c2..00000000 --- a/.dockerdev/compose.yml +++ /dev/null @@ -1,200 +0,0 @@ -x-app: &app - build: - context: . - args: - RUBY_VERSION: '3.3.0' - PG_MAJOR: '16' - NODE_MAJOR: '18' - environment: &env - NODE_ENV: development - RAILS_ENV: ${RAILS_ENV:-development} - image: anycable-rails-demo-dev:2.3.0 - tmpfs: - - /tmp - - /app/tmp/pids - -x-backend: &backend - <<: *app - stdin_open: true - tty: true - volumes: - - ..:/app:cached - - rails_cache:/app/tmp/cache - - bundle:/usr/local/bundle - - node_modules:/app/node_modules - - assets:/app/public/assets - - assets_builds:/app/app/assets/builds - - history:/usr/local/hist - - .psqlrc:/root/.psqlrc:ro - - .bashrc:/root/.bashrc:ro - environment: &backend_environment - <<: *env - REDIS_URL: redis://redis:6379/ - DATABASE_URL: postgres://postgres:postgres@postgres:5432 - BOOTSNAP_CACHE_DIR: /usr/local/bundle/_bootsnap - WEBPACKER_DEV_SERVER_HOST: webpacker - WEB_CONCURRENCY: 1 - HISTFILE: /usr/local/hist/.bash_history - PSQL_HISTFILE: /usr/local/hist/.psql_history - IRB_HISTFILE: /usr/local/hist/.irb_history - ACTION_CABLE_ADAPTER: ${ACTION_CABLE_ADAPTER:-anycable} - ANYCABLE_RPC_HOST: 0.0.0.0:50051 - ANYCABLE_BROADCAST_ADAPTER: http - ANYCABLE_HTTP_BROADCAST_URL: http://ws:8090/_broadcast - CHROME_URL: ${CHROME_URL:-http://chrome:3333} - EDITOR: vi - LOG: ${LOG:-0} - depends_on: &backend_depends_on - postgres: - condition: service_healthy - redis: - condition: service_healthy - -services: - rails: - <<: *backend - command: bundle exec rails - - web: - <<: *backend - command: bundle exec rails server -b 0.0.0.0 - ports: - - '3000:3000' - depends_on: - <<: *backend_depends_on - css: - condition: service_started - js: - condition: service_started - ws: - condition: service_started - anycable: - condition: service_started - - # Separate definition for system tests to add Chrome as a dependency - rspec_system: - <<: *backend - ports: - - '3001:3001' - - '50051' - environment: - <<: *backend_environment - APP_HOST: ${APP_HOST:-anycable.test} - ANYCABLE_RPC_HOST: 0.0.0.0:50051 - ANYCABLE_HTTP_BROADCAST_URL: http://ws.anycable.test:8090/_broadcast - ANYCABLE_WEBSOCKET_URL: ${ANYCABLE_WEBSOCKET_URL:-ws://ws.anycable.test:8081/cable} - depends_on: - <<: *backend_depends_on - chrome: - condition: service_started - ws_test: - condition: service_started - networks: - default: - aliases: - - anycable.test - - ws: &ws - image: anycable/anycable-go:1.5 - ports: - - '8080:8080' - environment: &ws_environment - ANYCABLE_HOST: "0.0.0.0" - ANYCABLE_PORT: 8080 - ANYCABLE_REDIS_URL: redis://redis:6379/0 - ANYCABLE_RPC_HOST: anycable:50051 - ANYCABLE_BROADCAST_ADAPTER: http - ANYCABLE_PUBSUB: redis - ANYCABLE_BROKER: memory - ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-1} - depends_on: - redis: - condition: service_healthy - - ws_test: - <<: *ws - ports: - - '8081:8081' - environment: - <<: *ws_environment - ANYCABLE_PORT: "8081" - # Disable broker to avoid race conditions when - # we load history since from previous examples - ANYCABLE_BROKER: "" - ANYCABLE_RPC_HOST: anycable.test:50051 - networks: - default: - aliases: - - ws.anycable.test - - anycable: - <<: *backend - command: bundle exec anycable - environment: - <<: *backend_environment - ANYCABLE_REDIS_URL: redis://redis:6379/0 - ANYCABLE_RPC_HOST: 0.0.0.0:50051 - ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-1} - ports: - - '50051' - depends_on: - <<: *backend_depends_on - ws: - condition: service_started - - css: - <<: *backend - command: yarn build:css --watch - - js: - <<: *backend - command: yarn build --watch - - postgres: - image: postgres:16.0 - volumes: - - .psqlrc:/root/.psqlrc:ro - - postgres:/var/lib/postgresql/data - - history:/user/local/hist - environment: - POSTGRES_PASSWORD: postgres - PSQL_HISTFILE: /user/local/hist/.psql_history - ports: - - 5432 - healthcheck: - test: pg_isready -U postgres -h 127.0.0.1 - interval: 5s - - redis: - image: redis:6.2-alpine - volumes: - - redis:/data - ports: - - 6379 - healthcheck: - test: redis-cli ping - interval: 1s - timeout: 3s - retries: 30 - - chrome: - # Currently, Apple M1 is only supported in unnumbered "latest" versions. - # See https://github.com/browserless/chrome/issues/1393 - image: browserless/chrome:latest - ports: - - '3333:3333' - environment: - PORT: 3333 - # Set connection timeout for debugging - # https://docs.browserless.io/docs/docker.html#connection-timeout - CONNECTION_TIMEOUT: 600000 - -volumes: - postgres: - redis: - bundle: - node_modules: - rails_cache: - history: - assets: - assets_builds: diff --git a/.github/workflows/system_test.yml b/.github/workflows/system_test.yml index a48bfd08..f64e3667 100644 --- a/.github/workflows/system_test.yml +++ b/.github/workflows/system_test.yml @@ -14,41 +14,16 @@ jobs: BUNDLE_RETRY: 3 BUNDLE_FROZEN: true CI: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432 - CHROME_URL: http://localhost:3000 - ANYCABLE_RPC_HOST: 0.0.0.0:50051 RAILS_ENV: test - services: - postgres: - image: postgres:16.0 - env: - POSTGRES_PASSWORD: postgres - ports: ["5432:5432"] - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - redis: - image: redis:6.2-alpine - ports: ["6379:6379"] - options: --health-cmd="redis-cli ping" --health-interval 1s --health-timeout 3s --health-retries 30 - chrome: - image: browserless/chrome:latest - ports: ["3000:3000"] - options: -e CONNECTION_TIMEOUT=600000 -e PORT=3000 - anycable: - image: anycable/anycable-go:1.5.0 - ports: ["8080:8080"] - options: --add-host=host.docker.internal:host-gateway - env: - ANYCABLE_HOST: "0.0.0.0" - ANYCABLE_REDIS_URL: redis://host.docker.internal:6379/0 - ANYCABLE_RPC_HOST: host.docker.internal:50051 steps: - - uses: actions/checkout@v3 - - name: Install PostgreSQL client + - uses: actions/checkout@v2 + - name: Install libsqlite3 run: | - sudo apt-get -yqq install libpq-dev + sudo apt-get update + sudo apt-get install libsqlite3-dev - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3.0 + ruby-version: 3.2.2 bundler-cache: true - name: Get yarn cache directory path id: yarn-cache-dir-path @@ -66,8 +41,8 @@ jobs: - name: Run RSpec run: | bundle exec rails db:test:prepare - export ANYCABLE_WEBSOCKET_URL="ws://$(hostname):8080/cable" bundle exec rspec --tag type:system --force-color + wsdirector: runs-on: ubuntu-latest env: @@ -75,44 +50,34 @@ jobs: BUNDLE_RETRY: 3 BUNDLE_FROZEN: true CI: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432 - ANYCABLE_RPC_HOST: 0.0.0.0:50051 - RAILS_ENV: test + RAILS_ENV: development services: - postgres: - image: postgres:16.0 - env: - POSTGRES_PASSWORD: postgres - ports: ["5432:5432"] - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - redis: - image: redis:6.2-alpine - ports: ["6379:6379"] - options: --health-cmd="redis-cli ping" --health-interval 1s --health-timeout 3s --health-retries 30 anycable: image: anycable/anycable-go:1.5.0 - ports: ["8080:8080"] + ports: + - 8080:8080 + - 8090:8090 options: --add-host=host.docker.internal:host-gateway env: ANYCABLE_HOST: "0.0.0.0" - ANYCABLE_REDIS_URL: redis://host.docker.internal:6379/0 - ANYCABLE_RPC_HOST: host.docker.internal:50051 + ANYCABLE_RPC_HOST: http://host.docker.internal:3000/_anycable + ANYCABLE_BROADCAST_ADAPTER: http ANYCABLE_DEBUG: "true" steps: - uses: actions/checkout@v3 - - name: Install PostgreSQL client + - name: Install libsqlite3 run: | - sudo apt-get -yqq install libpq-dev + sudo apt-get update + sudo apt-get install libsqlite3-dev - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3.0 + ruby-version: 3.2.2 bundler-cache: true - name: Run WebSocket Director scenarios run: | - bundle exec rails db:test:prepare + bundle exec rails db:prepare bundle exec rails db:seed - mkdir -p tmp/pids - bundle exec anycabled start + bundle exec rails server -b 0.0.0.0 -d sleep 10 gem install wsdirector-cli wsdirector etc/wsdirector/chat.yml localhost:8080/cable -c -vv diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index e7989362..7ddcb19d 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -14,28 +14,18 @@ jobs: BUNDLE_RETRY: 3 BUNDLE_FROZEN: true CI: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432 RAILS_ENV: test - services: - postgres: - image: postgres:16.0 - ports: ["5432:5432"] - env: - POSTGRES_PASSWORD: postgres - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - redis: - image: redis:6.2-alpine - ports: ["6379:6379"] - options: --health-cmd="redis-cli ping" --health-interval 1s --health-timeout 3s --health-retries 30 steps: - - uses: actions/checkout@v3 - - name: Install PostgreSQL client + - uses: actions/checkout@v2 + - name: Install libsqlite3 run: | - sudo apt-get -yqq install libpq-dev + sudo apt-get update + sudo apt-get install libsqlite3-dev - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.3.0 + ruby-version: 3.2.2 bundler-cache: true + bundler-version: 2.4.5 - name: Run RSpec run: | bundle exec rails db:test:prepare diff --git a/.gitignore b/.gitignore index 5c514e8d..310459a3 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ yarn-debug.log* /app/assets/builds/* !/app/assets/builds/.keep + +bin/dist diff --git a/Gemfile b/Gemfile index 965f85d5..908279eb 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,10 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~> 3.3.0' +ruby '~> 3.2.0' gem 'rails', '~> 7.1.0' -gem 'pg', '~> 1.0' +gem 'sqlite3', '~> 1.4' gem 'puma', '~> 6.0' gem 'redis', '~> 5.0' gem 'grpc', '~> 1.37' @@ -22,16 +22,20 @@ gem 'jsbundling-rails' gem 'propshaft' group :development, :test do - gem 'debug', '1.7.0' + gem 'debug', '~> 1.9' gem 'rspec-rails', '~> 6.0' end group :development do + gem 'overmind' end group :test do gem 'capybara' gem 'cuprite' + # Rack-based AnyCable server implementation + gem 'anycable-rack-server', '~> 0.5' + gem 'test-prof' end diff --git a/Gemfile.lock b/Gemfile.lock index 78e79f71..731f06cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,10 +83,15 @@ GEM anycable-core (1.5.0) anyway_config (~> 2.2) google-protobuf (~> 3.25) - anycable-rails (1.5.0) + anycable-rack-server (0.5.1) + anycable (> 1.0.99, < 2.0) + anyway_config (>= 2.1.0) + connection_pool (~> 2.2) + websocket (~> 1.2) + anycable-rails (1.5.1) anycable (~> 1.5.0) - anycable-rails-core (= 1.5.0) - anycable-rails-core (1.5.0) + anycable-rails-core (= 1.5.1) + anycable-rails-core (1.5.1) actioncable (>= 6.0) anycable-core (~> 1.5.0) globalid @@ -117,9 +122,9 @@ GEM ferrum (~> 0.14.0) daemons (1.4.1) date (3.3.4) - debug (1.7.0) - irb (>= 1.5.0) - reline (>= 0.3.1) + debug (1.9.2) + irb (~> 1.10) + reline (>= 0.3.8) diff-lcs (1.5.1) drb (2.2.1) erubi (1.12.0) @@ -201,11 +206,15 @@ GEM racc (~> 1.4) nokogiri (1.16.3-x86_64-linux) racc (~> 1.4) + overmind (2.5.1) + overmind (2.5.1-arm-linux) + overmind (2.5.1-arm64-darwin) + overmind (2.5.1-x86-linux) + overmind (2.5.1-x86_64-darwin) paco (0.2.3) parser (3.3.0.5) ast (~> 2.4.1) racc - pg (1.5.6) propshaft (0.8.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) @@ -213,7 +222,7 @@ GEM railties (>= 7.0.0) psych (5.1.2) stringio - public_suffix (5.0.4) + public_suffix (5.0.5) puma (6.4.2) nio4r (~> 2.0) racc (1.7.3) @@ -291,6 +300,12 @@ GEM ruby-next-core (1.0.2) ruby-next-parser (3.2.2.0) parser (>= 3.0.3.1) + sqlite3 (1.7.3-aarch64-linux) + sqlite3 (1.7.3-arm-linux) + sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86-linux) + sqlite3 (1.7.3-x86_64-darwin) + sqlite3 (1.7.3-x86_64-linux) stringio (3.1.0) test-prof (1.3.2) thor (1.3.1) @@ -305,6 +320,7 @@ GEM diff-lcs (~> 1.3) parser (>= 3.3.0) webrick (1.8.1) + websocket (1.2.10) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -316,33 +332,37 @@ PLATFORMS aarch64-linux arm-linux arm64-darwin + arm64-darwin-21 + arm64-darwin-21 x86-linux x86_64-darwin x86_64-linux DEPENDENCIES + anycable-rack-server (~> 0.5) anycable-rails (~> 1.5) bootsnap (>= 1.4.2) capybara cssbundling-rails cuprite daemons (~> 1.3) - debug (= 1.7.0) + debug (~> 1.9) grpc (~> 1.37) jsbundling-rails nanoid - pg (~> 1.0) + overmind propshaft puma (~> 6.0) rails (~> 7.1.0) redis (~> 5.0) rspec-rails (~> 6.0) ruby-next (~> 1.0) + sqlite3 (~> 1.4) test-prof turbo-rails RUBY VERSION - ruby 3.3.0p0 + ruby 3.2.0p0 BUNDLED WITH - 2.5.7 + 2.4.5 diff --git a/Procfile.dev b/Procfile.dev new file mode 100644 index 00000000..42284b39 --- /dev/null +++ b/Procfile.dev @@ -0,0 +1,4 @@ +server: bundle exec rails s -p 3000 +css: yarn build:css --watch +js: yarn build --watch +ws: bin/anycable-go --port=8080 --broadcast_adapter=http --presets=broker --rpc_host=http://localhost:3000/_anycable diff --git a/README.md b/README.md index c6bd391c..132143bf 100644 --- a/README.md +++ b/README.md @@ -12,56 +12,38 @@ This repository contains the code for AnyCable Rails demo application and its di ## Installation -This app has a Docker-first configuration based one the [Ruby on Whales post](https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development). +This branch has a minimal number of dependencies to make it easier to run the project locally: SQLite instead of Postgres, no Redis, no Docker. -You need: - -- Docker installed. - -For MacOS just use [official app](https://docs.docker.com/engine/installation/mac/). - -- [Dip](https://github.com/bibendi/dip) installed. - -Run the following command to build images and provision the application: +You need Ruby and NodeJS installed on your local machine (and maybe some common system deps for such gems as nokogiri and sqlite3). ```sh -dip provision +bundle install +yarn install +bin/setup ``` ## Running -You can start Rails server along with AnyCable by running: +Since you need to run multiple processes (Rails, AnyCable-Go), we recommend using a process manager, e.g., [Hivemind](https://github.com/DarthSim/hivemind): ```sh -dip up web +hivemind Procfile.dev ``` Then go to [http://localhost:3000/](http://localhost:3000/) and see the application in action. -## Debugging - -If you want to run Rails server and/or with debugging capabilities, run the following commands: - -```sh -# for Rails server -dip rails s -``` - ## Testing -We separate unit and system specs and provide convenient Dip commands to run them: +We use RSpec for testing: ```sh -# only unit tests -dip rspec - -# only system tests -dip rspec system +bundle exec rspec ``` +**NOTE:** System tests require Chrome browser to be installed on your machine (no other software required). + ## Resources -- [Ruby on Whales](https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development)—learn about the Docker development setup used for this application. - [RuboCoping with legacy](https://evilmartians.com/chronicles/rubocoping-with-legacy-bring-your-ruby-code-up-to-standard)—this is how we configure RuboCop. - [Evil Front](https://evilmartians.com/chronicles/evil-front-part-3)—some frontend ideas are borrowed from this post. - [Ruby Next](https://evilmartians.com/chronicles/ruby-next-make-all-rubies-quack-alike)—we're using the edge Ruby syntax! diff --git a/bin/anycable-go b/bin/anycable-go new file mode 100755 index 00000000..6e167a41 --- /dev/null +++ b/bin/anycable-go @@ -0,0 +1,19 @@ +#!/bin/bash + +cd $(dirname $0)/.. + +version="1.5.0" + +if [ ! -f ./bin/dist/anycable-go ]; then + echo "AnyCable-go is not installed, downloading..." + ./bin/rails g anycable:download --version=$version --bin-path=./bin/dist +fi + +curVersion=$(./bin/dist/anycable-go -v) + +if [[ "$curVersion" != "$version"* ]]; then + echo "AnyCable-go version is not $version, downloading a new one..." + ./bin/rails g anycable:download --version=$version --bin-path=./bin/dist +fi + +./bin/dist/anycable-go $@ diff --git a/bin/dev b/bin/dev new file mode 100755 index 00000000..1aae6408 --- /dev/null +++ b/bin/dev @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +bin/overmind start -f Procfile.dev diff --git a/bin/overmind b/bin/overmind new file mode 100755 index 00000000..cb365584 --- /dev/null +++ b/bin/overmind @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'overmind' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("overmind", "overmind") diff --git a/config.ru b/config.ru index bff88d60..2e030846 100644 --- a/config.ru +++ b/config.ru @@ -5,3 +5,4 @@ require_relative "config/environment" run Rails.application +Rails.application.load_server diff --git a/config/anycable.yml b/config/anycable.yml index 7348341b..101512d2 100644 --- a/config/anycable.yml +++ b/config/anycable.yml @@ -20,8 +20,8 @@ default: &default rpc_host: "127.0.0.1:50051" # Whether to enable gRPC level logging or not log_grpc: false - # Use Redis to broadcast messages to AnyCable server - broadcast_adapter: redis + # Use HTTP adapter for a quick start (since redis gem is not present in the project) + broadcast_adapter: http # Use the same channel name for WebSocket server, e.g.: # $ anycable-go --redis-channel="__anycable__" redis_channel: "__anycable__" @@ -30,10 +30,12 @@ default: &default development: <<: *default + http_rpc_mount_path: "/_anycable" test: <<: *default rpc_pool_size: 5 + http_broadcast_url: "http://localhost:3023/_anycable_rack_broadcast" production: <<: *default diff --git a/config/database.yml b/config/database.yml index dfc41703..fb83db45 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,16 +1,16 @@ default: &default - adapter: postgresql + adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> url: <%= ENV["DATABASE_URL"] %> timeout: 5000 development: <<: *default - database: any_rails_demo_dev + database: db/any_rails_demo_dev.sqlite3 test: <<: *default - database: any_rails_demo_test + database: db/any_rails_demo_test.sqlite3 production: <<: *default diff --git a/config/environments/development.rb b/config/environments/development.rb index 32b532b2..1784c320 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -36,6 +36,8 @@ # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + config.hosts = [] + # Highlight code that triggered database queries in logs. # config.active_record.verbose_query_logs = true diff --git a/config/environments/test.rb b/config/environments/test.rb index 8041ce2e..9aa32bae 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -6,15 +6,17 @@ # and recreated between test runs. Don't rely on the data there! Rails.application.configure do - # Specify AnyCable WebSocket server URL to use by JS client config.after_initialize do - config.action_cable.url = ActionCable.server.config.url = AnyCable.config.websocket_url - # Make test adapter AnyCable-compatible AnyCable::Rails.extend_adapter!(ActionCable.server.pubsub) end + # Specify AnyCable WebSocket server URL to use by JS client + config.action_cable.url = "/rack_cable" + # Disable built-in Action Cable config.action_cable.mount_path = nil + # Run AnyCable Rack server at a custom path + config.any_cable_rack.mount_path = "/rack_cable" # Settings specified here will take precedence over those in config/application.rb. config.cache_classes = true diff --git a/db/schema.rb b/db/schema.rb index fa019da9..7a35f8b4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,11 +11,8 @@ # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema[7.1].define(version: 2020_05_04_092152) do - # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - create_table "items", force: :cascade do |t| - t.bigint "list_id", null: false + t.integer "list_id", null: false t.text "desc", null: false t.boolean "completed", default: false, null: false t.datetime "created_at", null: false @@ -25,7 +22,7 @@ create_table "lists", force: :cascade do |t| t.string "name", null: false - t.bigint "workspace_id", null: false + t.integer "workspace_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["workspace_id"], name: "index_lists_on_workspace_id" diff --git a/dip.yml b/dip.yml deleted file mode 100644 index 6170972a..00000000 --- a/dip.yml +++ /dev/null @@ -1,87 +0,0 @@ -version: '7.1' - -environment: - RAILS_ENV: development - -compose: - files: - - .dockerdev/compose.yml - project_name: anycable_rails_demo - -interaction: - runner: - description: Open a Bash shell within a Rails container (with dependencies up) - service: rails - command: /bin/bash - - bash: - description: Run an arbitrary script within a container (or open a shell without deps) - service: rails - command: /bin/bash - compose_run_options: [ no-deps ] - - bundle: - description: Run Bundler commands - service: rails - command: bundle - compose_run_options: [ no-deps ] - - rspec: - description: Run Rspec commands - service: rails - environment: - RAILS_ENV: test - command: bundle exec rspec --exclude-pattern 'system/**/*_spec.rb' - subcommands: - system: &rails_test_system - description: Run all Rails system tests - service: rspec_system - command: bundle exec rspec --pattern 'system/**/*_spec.rb' - compose: - run_options: [ service-ports, use-aliases ] - # Run Chrome via: - # chrome --remote-debugging-port=3333 --no-sandbox --no-startup-window - # - # NOTE: The command above assumes that you have a `chrome` alias to run Chrome executable. - # For example, on MacOS you can add the following to you shell profile: - # alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome" - system:local: - <<: *rails_test_system - description: Run system tests via the local Chrome - environment: - RAILS_ENV: test - CHROME_URL: http://host.docker.internal:3333 - CABLE_URL: ws://localhost:8081/cable - APP_HOST: localhost:3001 - compose: - run_options: [service-ports, use-aliases] - - rails: - description: Run Rails commands - service: rails - command: bundle exec rails - subcommands: - s: - description: Run Rails server at http://localhost:3000 - service: web - compose: - run_options: [service-ports, use-aliases] - - yarn: - descriptinn: Run yarn commands - service: rails - command: yarn - - psql: - description: Run Postgres psql console - service: postgres - default_args: anycasts_dev - command: psql -h postgres -U postgres - -provision: - - '[[ "$RESET_DOCKER" == "true" ]] && echo "Re-creating the Docker env from scratch..." && dip compose down --volumes || echo "Re-provisioning the Docker env..."' - - dip compose up -d postgres redis - - dip bundle install - - dip rails db:prepare - - dip rails db:test:prepare - - echo "🚀 Ready to rock! Run 'dip rails s' to start a Rails web server w/ AnyCable" diff --git a/etc/wsdirector/chat.yml b/etc/wsdirector/chat.yml index 27b0ef7a..86575dc6 100644 --- a/etc/wsdirector/chat.yml +++ b/etc/wsdirector/chat.yml @@ -14,24 +14,24 @@ <<: *channel - wait_all - sleep: - time: 3 - shift: 2 + time: 2 + shift: 1 - perform: <<: *channel action: speak data: message: "hello" - sleep: - time: 4 - shift: 2 + time: 2 + shift: 1 - perform: <<: *channel action: speak data: message: "hello 2" - sleep: - time: 4 - shift: 2 + time: 2 + shift: 1 - perform: <<: *channel action: speak @@ -53,8 +53,8 @@ <<: *channel - wait_all - sleep: - time: 3 - shift: 2 + time: 4 + shift: 1 - receive: <<: *channel multiplier: ":scale" @@ -62,7 +62,7 @@ action: "newMessage" - sleep: time: 4 - shift: 2 + shift: 1 - receive: <<: *channel multiplier: ":scale" @@ -70,7 +70,7 @@ action: "newMessage" - sleep: time: 4 - shift: 2 + shift: 1 - receive: <<: *channel multiplier: ":scale" @@ -78,4 +78,4 @@ action: "newMessage" - sleep: time: 4 - shift: 2 + shift: 1 diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 0d02bb0c..1668335f 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -5,8 +5,7 @@ module System def login_user(name) page.driver.set_cookie( :uid, - [name, Nanoid.generate(size: 3)].join("/"), - domain: CAPYBARA_COOKIE_DOMAIN + [name, Nanoid.generate(size: 3)].join("/") ) end diff --git a/spec/system/support/capybara_setup.rb b/spec/system/support/capybara_setup.rb index c4363938..6ec75298 100644 --- a/spec/system/support/capybara_setup.rb +++ b/spec/system/support/capybara_setup.rb @@ -2,19 +2,6 @@ # Capybara settings (not covered by Rails system tests) -# Make server listening on all hosts -Capybara.server_host = "0.0.0.0" -Capybara.server_port = 3001 -# Use a hostname accessible from the outside world -Capybara.app_host = "http://#{ENV.fetch("APP_HOST", `hostname`.strip&.downcase || "0.0.0.0")}" - -# Which domain to use when setting cookies directly in tests. -CAPYBARA_COOKIE_DOMAIN = URI.parse(Capybara.app_host).host.then do |host| - # If host is a top-level domain - next host unless host.include?(".") - ".#{host}" -end - # Don't wait too long in `have_xyz` matchers Capybara.default_max_wait_time = 2 @@ -24,6 +11,9 @@ # Where to store artifacts (e.g. screenshots, downloaded files, etc.) Capybara.save_path = ENV.fetch("CAPYBARA_ARTIFACTS", "./tmp/capybara") +# Use fixed server port to configure AnyCable broadcast url +Capybara.server_port = 3023 + Capybara.singleton_class.prepend(Module.new do attr_accessor :last_used_session diff --git a/spec/system/support/cuprite_setup.rb b/spec/system/support/cuprite_setup.rb index 64d26717..d2a48992 100644 --- a/spec/system/support/cuprite_setup.rb +++ b/spec/system/support/cuprite_setup.rb @@ -3,54 +3,19 @@ # Cuprite is a modern Capybara driver which uses Chrome CDP API # instead of Selenium & co. # See https://github.com/rubycdp/cuprite - -remote_chrome_url = ENV["CHROME_URL"] - -# Chrome doesn't allow connecting to CDP by hostnames (other than localhost), -# but allows using IP addresses. -if remote_chrome_url&.match?(/host.docker.internal/) - require "resolv" - - uri = URI.parse(remote_chrome_url) - ip = Resolv.getaddress(uri.host) - - remote_chrome_url = remote_chrome_url.sub("host.docker.internal", ip) -end - -REMOTE_CHROME_URL = remote_chrome_url -REMOTE_CHROME_HOST, REMOTE_CHROME_PORT = - if REMOTE_CHROME_URL - URI.parse(REMOTE_CHROME_URL).yield_self do |uri| - [uri.host, uri.port] - end - end - -# Check whether the remote chrome is running and configure the Capybara -# driver for it. -remote_chrome = - begin - if REMOTE_CHROME_URL.nil? - false - else - Socket.tcp(REMOTE_CHROME_HOST, REMOTE_CHROME_PORT, connect_timeout: 1).close - true - end - rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError - false - end - -remote_options = remote_chrome ? {url: REMOTE_CHROME_URL} : {} - require "capybara/cuprite" Capybara.register_driver(:better_cuprite) do |app| Capybara::Cuprite::Driver.new( app, - **{ - window_size: [1200, 800], - browser_options: remote_chrome ? {"no-sandbox" => nil} : {}, - inspector: true - }.merge(remote_options) + window_size: [1200, 800], + browser_options: {}, + # Increase Chrome startup timeout for CI + process_timeout: 10, + inspector: true, + # Allow running Chrome in a headful mode by setting HEADLESS env + # var to a falsey value + headless: !ENV["HEADLESS"].in?(%w[n 0 no false]) ) end @@ -63,7 +28,7 @@ def pause end def debug(binding = nil) - $stdout.puts "🔎 Open Chrome inspector at http://localhost:3333" + $stdout.puts "🔎 Open Chrome inspector at http://localhost:#{Capybara.server_port}" return binding.break if binding page.driver.pause end