cyclone_lariat 0.4.0 → 1.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
 - data/.github/workflows/gem-push.yml +4 -4
 - data/.rubocop.yml +9 -5
 - data/CHANGELOG.md +7 -1
 - data/Gemfile.lock +123 -21
 - data/Guardfile +42 -0
 - data/README.md +420 -223
 - data/bin/cyclone_lariat +75 -43
 - data/cyclone_lariat.gemspec +10 -3
 - data/lib/cyclone_lariat/clients/abstract.rb +40 -0
 - data/lib/cyclone_lariat/clients/sns.rb +163 -0
 - data/lib/cyclone_lariat/clients/sqs.rb +114 -0
 - data/lib/cyclone_lariat/core.rb +21 -0
 - data/lib/cyclone_lariat/errors.rb +16 -0
 - data/lib/cyclone_lariat/fake.rb +19 -0
 - data/lib/cyclone_lariat/generators/command.rb +53 -0
 - data/lib/cyclone_lariat/generators/event.rb +52 -0
 - data/lib/cyclone_lariat/generators/queue.rb +30 -0
 - data/lib/cyclone_lariat/generators/topic.rb +29 -0
 - data/lib/cyclone_lariat/messages/v1/abstract.rb +139 -0
 - data/lib/cyclone_lariat/messages/v1/command.rb +20 -0
 - data/lib/cyclone_lariat/messages/v1/event.rb +20 -0
 - data/lib/cyclone_lariat/messages/v1/validator.rb +31 -0
 - data/lib/cyclone_lariat/messages/v2/abstract.rb +149 -0
 - data/lib/cyclone_lariat/messages/v2/command.rb +20 -0
 - data/lib/cyclone_lariat/messages/v2/event.rb +20 -0
 - data/lib/cyclone_lariat/messages/v2/validator.rb +39 -0
 - data/lib/cyclone_lariat/middleware.rb +9 -6
 - data/lib/cyclone_lariat/migration.rb +54 -117
 - data/lib/cyclone_lariat/options.rb +52 -0
 - data/lib/cyclone_lariat/presenters/graph.rb +54 -0
 - data/lib/cyclone_lariat/presenters/queues.rb +41 -0
 - data/lib/cyclone_lariat/presenters/subscriptions.rb +34 -0
 - data/lib/cyclone_lariat/presenters/topics.rb +40 -0
 - data/lib/cyclone_lariat/publisher.rb +25 -0
 - data/lib/cyclone_lariat/repo/active_record/messages.rb +92 -0
 - data/lib/cyclone_lariat/repo/active_record/versions.rb +28 -0
 - data/lib/cyclone_lariat/repo/messages.rb +43 -0
 - data/lib/cyclone_lariat/repo/messages_mapper.rb +49 -0
 - data/lib/cyclone_lariat/repo/sequel/messages.rb +73 -0
 - data/lib/cyclone_lariat/repo/sequel/versions.rb +28 -0
 - data/lib/cyclone_lariat/repo/versions.rb +42 -0
 - data/lib/cyclone_lariat/resources/queue.rb +167 -0
 - data/lib/cyclone_lariat/resources/topic.rb +132 -0
 - data/lib/cyclone_lariat/services/migrate.rb +51 -0
 - data/lib/cyclone_lariat/services/rollback.rb +51 -0
 - data/lib/cyclone_lariat/version.rb +1 -1
 - data/lib/cyclone_lariat.rb +5 -11
 - data/lib/tasks/console.rake +1 -1
 - data/lib/tasks/cyclone_lariat.rake +10 -12
 - data/lib/tasks/db.rake +0 -15
 - metadata +127 -27
 - data/config/db.example.rb +0 -9
 - data/config/initializers/sequel.rb +0 -7
 - data/db/migrate/01_add_uuid_extensions.rb +0 -15
 - data/db/migrate/02_add_events.rb +0 -19
 - data/db/migrate/03_add_versions.rb +0 -9
 - data/docs/_imgs/graphviz_01.png +0 -0
 - data/docs/_imgs/graphviz_02.png +0 -0
 - data/docs/_imgs/graphviz_03.png +0 -0
 - data/docs/_imgs/lariat.jpg +0 -0
 - data/docs/_imgs/logic.png +0 -0
 - data/docs/_imgs/sqs_sns_diagram.png +0 -0
 - data/lib/cyclone_lariat/abstract/client.rb +0 -112
 - data/lib/cyclone_lariat/abstract/message.rb +0 -98
 - data/lib/cyclone_lariat/command.rb +0 -13
 - data/lib/cyclone_lariat/configure.rb +0 -15
 - data/lib/cyclone_lariat/event.rb +0 -13
 - data/lib/cyclone_lariat/messages_mapper.rb +0 -46
 - data/lib/cyclone_lariat/messages_repo.rb +0 -60
 - data/lib/cyclone_lariat/queue.rb +0 -147
 - data/lib/cyclone_lariat/sns_client.rb +0 -149
 - data/lib/cyclone_lariat/sqs_client.rb +0 -93
 - data/lib/cyclone_lariat/topic.rb +0 -113
 
| 
         @@ -2,19 +2,24 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'fileutils'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'forwardable'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'cyclone_lariat/clients/sns'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'cyclone_lariat/clients/sqs'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'cyclone_lariat/repo/versions'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'cyclone_lariat/services/migrate'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'cyclone_lariat/services/rollback'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'cyclone_lariat/presenters/topics'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'cyclone_lariat/presenters/queues'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'cyclone_lariat/presenters/subscriptions'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'cyclone_lariat/presenters/graph'
         
     | 
| 
       7 
14 
     | 
    
         
             
            require 'luna_park/errors'
         
     | 
| 
       8 
     | 
    
         
            -
            require 'terminal-table'
         
     | 
| 
       9 
     | 
    
         
            -
            require 'set'
         
     | 
| 
       10 
15 
     | 
    
         | 
| 
       11 
16 
     | 
    
         
             
            module CycloneLariat
         
     | 
| 
       12 
17 
     | 
    
         
             
              class Migration
         
     | 
| 
       13 
18 
     | 
    
         
             
                extend Forwardable
         
     | 
| 
       14 
19 
     | 
    
         
             
                include LunaPark::Extensions::Injector
         
     | 
| 
       15 
20 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                dependency(:sns) { CycloneLariat:: 
     | 
| 
       17 
     | 
    
         
            -
                dependency(:sqs) { CycloneLariat:: 
     | 
| 
      
 21 
     | 
    
         
            +
                dependency(:sns) { CycloneLariat::Clients::Sns.new }
         
     | 
| 
      
 22 
     | 
    
         
            +
                dependency(:sqs) { CycloneLariat::Clients::Sqs.new }
         
     | 
| 
       18 
23 
     | 
    
         | 
| 
       19 
24 
     | 
    
         
             
                DIR = './lariat/migrate'
         
     | 
| 
       20 
25 
     | 
    
         | 
| 
         @@ -56,7 +61,9 @@ module CycloneLariat 
     | 
|
| 
       56 
61 
     | 
    
         
             
                  )
         
     | 
| 
       57 
62 
     | 
    
         
             
                end
         
     | 
| 
       58 
63 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                def subscribe(topic:, endpoint:)
         
     | 
| 
      
 64 
     | 
    
         
            +
                def subscribe(topic:, endpoint:, policy: nil)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  policy ||= default_policy(endpoint)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  sqs.add_policy(queue: endpoint, policy: policy) if endpoint.queue?
         
     | 
| 
       60 
67 
     | 
    
         
             
                  sns.subscribe topic: topic, endpoint: endpoint
         
     | 
| 
       61 
68 
     | 
    
         
             
                  puts "  Subscription was created `#{topic.name} -> #{endpoint.name}`"
         
     | 
| 
       62 
69 
     | 
    
         
             
                end
         
     | 
| 
         @@ -66,6 +73,23 @@ module CycloneLariat 
     | 
|
| 
       66 
73 
     | 
    
         
             
                  puts "  Subscription was deleted `#{topic.name} -> #{endpoint.name}`"
         
     | 
| 
       67 
74 
     | 
    
         
             
                end
         
     | 
| 
       68 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                def default_policy(queue)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  {
         
     | 
| 
      
 78 
     | 
    
         
            +
                    'Sid' => queue.arn,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    'Effect' => 'Allow',
         
     | 
| 
      
 80 
     | 
    
         
            +
                    'Principal' => {
         
     | 
| 
      
 81 
     | 
    
         
            +
                      'AWS' => '*'
         
     | 
| 
      
 82 
     | 
    
         
            +
                    },
         
     | 
| 
      
 83 
     | 
    
         
            +
                    'Action' => 'SQS:*',
         
     | 
| 
      
 84 
     | 
    
         
            +
                    'Resource' => queue.arn,
         
     | 
| 
      
 85 
     | 
    
         
            +
                    'Condition' => {
         
     | 
| 
      
 86 
     | 
    
         
            +
                      'ArnEquals' => {
         
     | 
| 
      
 87 
     | 
    
         
            +
                        'aws:SourceArn' => fanout_arn_pattern
         
     | 
| 
      
 88 
     | 
    
         
            +
                      }
         
     | 
| 
      
 89 
     | 
    
         
            +
                    }
         
     | 
| 
      
 90 
     | 
    
         
            +
                  }
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
       69 
93 
     | 
    
         
             
                def topics
         
     | 
| 
       70 
94 
     | 
    
         
             
                  sns.list_all
         
     | 
| 
       71 
95 
     | 
    
         
             
                end
         
     | 
| 
         @@ -82,132 +106,45 @@ module CycloneLariat 
     | 
|
| 
       82 
106 
     | 
    
         | 
| 
       83 
107 
     | 
    
         
             
                def process(resource:, for_topic:, for_queue:)
         
     | 
| 
       84 
108 
     | 
    
         
             
                  case resource
         
     | 
| 
       85 
     | 
    
         
            -
                  when Topic then for_topic.call(resource)
         
     | 
| 
       86 
     | 
    
         
            -
                  when Queue then for_queue.call(resource)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  when Resources::Topic then for_topic.call(resource)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  when Resources::Queue then for_queue.call(resource)
         
     | 
| 
       87 
111 
     | 
    
         
             
                  else
         
     | 
| 
       88 
112 
     | 
    
         
             
                    raise ArgumentError, "Unknown resource class #{resource.class}"
         
     | 
| 
       89 
113 
     | 
    
         
             
                  end
         
     | 
| 
       90 
114 
     | 
    
         
             
                end
         
     | 
| 
       91 
115 
     | 
    
         | 
| 
      
 116 
     | 
    
         
            +
                def fanout_arn_pattern
         
     | 
| 
      
 117 
     | 
    
         
            +
                  @fanout_arn_pattern ||= [
         
     | 
| 
      
 118 
     | 
    
         
            +
                    'arn:aws:sns',
         
     | 
| 
      
 119 
     | 
    
         
            +
                    CycloneLariat.config.aws_region,
         
     | 
| 
      
 120 
     | 
    
         
            +
                    CycloneLariat.config.aws_account_id,
         
     | 
| 
      
 121 
     | 
    
         
            +
                    "#{CycloneLariat.config.instance}-*-fanout-*"
         
     | 
| 
      
 122 
     | 
    
         
            +
                  ].join(':')
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       92 
125 
     | 
    
         
             
                class << self
         
     | 
| 
       93 
     | 
    
         
            -
                  def migrate( 
     | 
| 
       94 
     | 
    
         
            -
                     
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
                    Dir.glob("#{dir}/*.rb") do |path|
         
     | 
| 
       97 
     | 
    
         
            -
                      filename = File.basename(path, '.rb')
         
     | 
| 
       98 
     | 
    
         
            -
                      version, title = filename.split('_', 2)
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                      existed_migrations = dataset.all.map { |row| row[:version] }
         
     | 
| 
       101 
     | 
    
         
            -
                      unless existed_migrations.include? version.to_i
         
     | 
| 
       102 
     | 
    
         
            -
                        class_name = title.split('_').collect(&:capitalize).join
         
     | 
| 
       103 
     | 
    
         
            -
                        puts "Up - #{version} #{class_name} #{path}"
         
     | 
| 
       104 
     | 
    
         
            -
                        require_relative Pathname.new(Dir.pwd) + Pathname.new(path)
         
     | 
| 
       105 
     | 
    
         
            -
                        Object.const_get(class_name).new.up
         
     | 
| 
       106 
     | 
    
         
            -
                        dataset.insert(version: version)
         
     | 
| 
       107 
     | 
    
         
            -
                      end
         
     | 
| 
       108 
     | 
    
         
            -
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
                  def migrate(repo: CycloneLariat::Repo::Versions.new, dir: DIR, service: Services::Migrate)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    puts service.new(repo: repo, dir: dir).call
         
     | 
| 
       109 
128 
     | 
    
         
             
                  end
         
     | 
| 
       110 
129 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                  def rollback(version = nil,  
     | 
| 
       112 
     | 
    
         
            -
                     
     | 
| 
       113 
     | 
    
         
            -
                    version ||= existed_migrations[-1]
         
     | 
| 
       114 
     | 
    
         
            -
                    migrations_to_downgrade = existed_migrations.select { |migration| migration >= version }
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                    paths = []
         
     | 
| 
       117 
     | 
    
         
            -
                    migrations_to_downgrade.each do |migration|
         
     | 
| 
       118 
     | 
    
         
            -
                      path = Pathname.new(Dir.pwd) + Pathname.new(dir)
         
     | 
| 
       119 
     | 
    
         
            -
                      founded = Dir.glob("#{path}/#{migration}_*.rb")
         
     | 
| 
       120 
     | 
    
         
            -
                      raise "Could not found migration: `#{migration}` in #{path}" if founded.empty?
         
     | 
| 
       121 
     | 
    
         
            -
                      raise "Found lot of migration: `#{migration}` in #{path}"    if founded.size > 1
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                      paths += founded
         
     | 
| 
       124 
     | 
    
         
            -
                    end
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                    paths.each do |path|
         
     | 
| 
       127 
     | 
    
         
            -
                      filename       = File.basename(path, '.rb')
         
     | 
| 
       128 
     | 
    
         
            -
                      version, title = filename.split('_', 2)
         
     | 
| 
       129 
     | 
    
         
            -
                      class_name     = title.split('_').collect(&:capitalize).join
         
     | 
| 
       130 
     | 
    
         
            -
                      puts "Down - #{version} #{class_name} #{path}"
         
     | 
| 
       131 
     | 
    
         
            -
                      require_relative Pathname.new(Dir.pwd) + Pathname.new(path)
         
     | 
| 
       132 
     | 
    
         
            -
                      Object.const_get(class_name).new.down
         
     | 
| 
       133 
     | 
    
         
            -
                      dataset.filter(version: version).delete
         
     | 
| 
       134 
     | 
    
         
            -
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  def rollback(version = nil, repo: CycloneLariat::Repo::Versions.new, dir: DIR, service: Services::Rollback)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    puts service.new(repo: repo, dir: dir).call(version)
         
     | 
| 
       135 
132 
     | 
    
         
             
                  end
         
     | 
| 
       136 
133 
     | 
    
         | 
| 
       137 
     | 
    
         
            -
                  def list_topics
         
     | 
| 
       138 
     | 
    
         
            -
                     
     | 
| 
       139 
     | 
    
         
            -
                    new.topics.each do |topic|
         
     | 
| 
       140 
     | 
    
         
            -
                      rows << [
         
     | 
| 
       141 
     | 
    
         
            -
                        topic.custom? ? 'custom' : 'standard',
         
     | 
| 
       142 
     | 
    
         
            -
                        topic.region,
         
     | 
| 
       143 
     | 
    
         
            -
                        topic.account_id,
         
     | 
| 
       144 
     | 
    
         
            -
                        topic.name,
         
     | 
| 
       145 
     | 
    
         
            -
                        topic.instance,
         
     | 
| 
       146 
     | 
    
         
            -
                        topic.kind,
         
     | 
| 
       147 
     | 
    
         
            -
                        topic.publisher,
         
     | 
| 
       148 
     | 
    
         
            -
                        topic.type,
         
     | 
| 
       149 
     | 
    
         
            -
                        topic.fifo
         
     | 
| 
       150 
     | 
    
         
            -
                      ]
         
     | 
| 
       151 
     | 
    
         
            -
                    end
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    puts Terminal::Table.new rows: rows, headings: %w[valid region account_id name instance kind publisher type fifo]
         
     | 
| 
      
 134 
     | 
    
         
            +
                  def list_topics(presenter: Presenters::Topics)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    puts presenter.call(new.topics)
         
     | 
| 
       154 
136 
     | 
    
         
             
                  end
         
     | 
| 
       155 
137 
     | 
    
         | 
| 
       156 
     | 
    
         
            -
                  def list_queues
         
     | 
| 
       157 
     | 
    
         
            -
                     
     | 
| 
       158 
     | 
    
         
            -
                    new.queues.each do |queue|
         
     | 
| 
       159 
     | 
    
         
            -
                      rows << [
         
     | 
| 
       160 
     | 
    
         
            -
                        queue.custom? ? 'custom' : 'standard',
         
     | 
| 
       161 
     | 
    
         
            -
                        queue.region,
         
     | 
| 
       162 
     | 
    
         
            -
                        queue.account_id,
         
     | 
| 
       163 
     | 
    
         
            -
                        queue.name,
         
     | 
| 
       164 
     | 
    
         
            -
                        queue.instance,
         
     | 
| 
       165 
     | 
    
         
            -
                        queue.kind,
         
     | 
| 
       166 
     | 
    
         
            -
                        queue.publisher,
         
     | 
| 
       167 
     | 
    
         
            -
                        queue.type,
         
     | 
| 
       168 
     | 
    
         
            -
                        queue.dest,
         
     | 
| 
       169 
     | 
    
         
            -
                        queue.fifo
         
     | 
| 
       170 
     | 
    
         
            -
                      ]
         
     | 
| 
       171 
     | 
    
         
            -
                    end
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
                    puts Terminal::Table.new rows: rows, headings: %w[valid region account_id name instance kind publisher type destination fifo]
         
     | 
| 
      
 138 
     | 
    
         
            +
                  def list_queues(presenter: Presenters::Queues)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    puts presenter.call(new.queues)
         
     | 
| 
       174 
140 
     | 
    
         
             
                  end
         
     | 
| 
       175 
141 
     | 
    
         | 
| 
       176 
     | 
    
         
            -
                  def list_subscriptions
         
     | 
| 
       177 
     | 
    
         
            -
                     
     | 
| 
       178 
     | 
    
         
            -
                    new.subscriptions.each do |subscription|
         
     | 
| 
       179 
     | 
    
         
            -
                      rows << [
         
     | 
| 
       180 
     | 
    
         
            -
                        subscription[:topic].name,
         
     | 
| 
       181 
     | 
    
         
            -
                        subscription[:endpoint].name,
         
     | 
| 
       182 
     | 
    
         
            -
                        subscription[:arn]
         
     | 
| 
       183 
     | 
    
         
            -
                      ]
         
     | 
| 
       184 
     | 
    
         
            -
                    end
         
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
                    puts Terminal::Table.new rows: rows, headings: %w[topic endpoint subscription_arn]
         
     | 
| 
      
 142 
     | 
    
         
            +
                  def list_subscriptions(presenter: Presenters::Subscriptions)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    puts presenter.call(new.subscriptions)
         
     | 
| 
       187 
144 
     | 
    
         
             
                  end
         
     | 
| 
       188 
145 
     | 
    
         | 
| 
       189 
     | 
    
         
            -
                  def build_graph
         
     | 
| 
       190 
     | 
    
         
            -
                     
     | 
| 
       191 
     | 
    
         
            -
                    resources_set = Set.new
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                    subscriptions.each do |subscription|
         
     | 
| 
       194 
     | 
    
         
            -
                      resources_set << subscription[:topic]
         
     | 
| 
       195 
     | 
    
         
            -
                      resources_set << subscription[:endpoint]
         
     | 
| 
       196 
     | 
    
         
            -
                    end
         
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                    puts 'digraph G {'
         
     | 
| 
       199 
     | 
    
         
            -
                    puts '  rankdir=LR;'
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
                    resources_set.each do |resource|
         
     | 
| 
       202 
     | 
    
         
            -
                      color = resource.custom? ? ', fillcolor=grey' : ', fillcolor=white'
         
     | 
| 
       203 
     | 
    
         
            -
                      style = resource.topic? ? "[shape=component style=filled#{color}]" : "[shape=record, style=\"rounded,filled\"#{color}]"
         
     | 
| 
       204 
     | 
    
         
            -
                      puts "  \"#{resource.name}\" #{style};"
         
     | 
| 
       205 
     | 
    
         
            -
                    end
         
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
                    subscriptions.each do |subscription|
         
     | 
| 
       208 
     | 
    
         
            -
                      puts "  \"#{subscription[:topic].name}\" -> \"#{subscription[:endpoint].name}\";"
         
     | 
| 
       209 
     | 
    
         
            -
                    end
         
     | 
| 
       210 
     | 
    
         
            -
                    puts '}'
         
     | 
| 
      
 146 
     | 
    
         
            +
                  def build_graph(presenter: Presenters::Graph)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    puts presenter.call(new.subscriptions)
         
     | 
| 
       211 
148 
     | 
    
         
             
                  end
         
     | 
| 
       212 
149 
     | 
    
         
             
                end
         
     | 
| 
       213 
150 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'luna_park/values/compound'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Options < LunaPark::Values::Compound
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :aws_key, :aws_secret_key, :publisher,
         
     | 
| 
      
 8 
     | 
    
         
            +
                              :aws_region, :instance, :aws_account_id,
         
     | 
| 
      
 9 
     | 
    
         
            +
                              :messages_dataset, :version, :versions_dataset,
         
     | 
| 
      
 10 
     | 
    
         
            +
                              :driver, :fake_publish
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # @param [CycloneLariat::Options, Hash] other
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @return [CycloneLariat::Options]
         
     | 
| 
      
 14 
     | 
    
         
            +
                def merge!(other)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  other = self.class.wrap(other)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  self.aws_key          ||= other.aws_key
         
     | 
| 
      
 18 
     | 
    
         
            +
                  self.aws_secret_key   ||= other.aws_secret_key
         
     | 
| 
      
 19 
     | 
    
         
            +
                  self.publisher        ||= other.publisher
         
     | 
| 
      
 20 
     | 
    
         
            +
                  self.aws_region       ||= other.aws_region
         
     | 
| 
      
 21 
     | 
    
         
            +
                  self.instance         ||= other.instance
         
     | 
| 
      
 22 
     | 
    
         
            +
                  self.aws_account_id   ||= other.aws_account_id
         
     | 
| 
      
 23 
     | 
    
         
            +
                  self.messages_dataset ||= other.messages_dataset
         
     | 
| 
      
 24 
     | 
    
         
            +
                  self.version          ||= other.version
         
     | 
| 
      
 25 
     | 
    
         
            +
                  self.versions_dataset ||= other.versions_dataset
         
     | 
| 
      
 26 
     | 
    
         
            +
                  self.driver           ||= other.driver
         
     | 
| 
      
 27 
     | 
    
         
            +
                  self.fake_publish     ||= other.fake_publish
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  self
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def merge(other)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  dup.merge!(other)
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def to_h
         
     | 
| 
      
 37 
     | 
    
         
            +
                  {
         
     | 
| 
      
 38 
     | 
    
         
            +
                    aws_key: aws_key,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    aws_secret_key: aws_secret_key,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    publisher: publisher,
         
     | 
| 
      
 41 
     | 
    
         
            +
                    aws_region: aws_region,
         
     | 
| 
      
 42 
     | 
    
         
            +
                    instance: instance,
         
     | 
| 
      
 43 
     | 
    
         
            +
                    aws_account_id: aws_account_id,
         
     | 
| 
      
 44 
     | 
    
         
            +
                    messages_dataset: messages_dataset,
         
     | 
| 
      
 45 
     | 
    
         
            +
                    version: version,
         
     | 
| 
      
 46 
     | 
    
         
            +
                    versions_dataset: versions_dataset,
         
     | 
| 
      
 47 
     | 
    
         
            +
                    driver: driver,
         
     | 
| 
      
 48 
     | 
    
         
            +
                    fake_publish: fake_publish
         
     | 
| 
      
 49 
     | 
    
         
            +
                  }
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Presenters
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Graph
         
     | 
| 
      
 8 
     | 
    
         
            +
                  HEADS = %w[topic endpoint subscription_arn].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def self.call(subscriptions)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    new.call(subscriptions)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def call(subscriptions)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    return '' if subscriptions.empty?
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    resources_set = Set.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    subscriptions.each do |subscription|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      resources_set << subscription[:topic]
         
     | 
| 
      
 20 
     | 
    
         
            +
                      resources_set << subscription[:endpoint]
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    [].tap do |output|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      output << open_graph
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                      resources_set.each { |resource| output << present_resource(resource) }
         
     | 
| 
      
 27 
     | 
    
         
            +
                      subscriptions.each { |subscription| output << present_subscription(subscription) }
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                      output << close_graph
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  private
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def present_resource(resource)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    color = resource.custom? ? ', fillcolor=grey' : ', fillcolor=white'
         
     | 
| 
      
 37 
     | 
    
         
            +
                    style = resource.topic? ? "[shape=component style=filled#{color}]" : "[shape=record, style=\"rounded,filled\"#{color}]"
         
     | 
| 
      
 38 
     | 
    
         
            +
                    "  \"#{resource.name}\" #{style};"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def present_subscription(subscription)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    "  \"#{subscription[:topic].name}\" -> \"#{subscription[:endpoint].name}\";"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def open_graph
         
     | 
| 
      
 46 
     | 
    
         
            +
                    "digraph G {\n  rankdir=LR;"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def close_graph
         
     | 
| 
      
 50 
     | 
    
         
            +
                    '}'
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'terminal-table'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Presenters
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Queues
         
     | 
| 
      
 8 
     | 
    
         
            +
                  HEADS = %w[valid region account_id name instance kind publisher type destination fifo].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.call(queues)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    new.call(queues)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def call(queues)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    rows = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                    queues.each do |queue|
         
     | 
| 
      
 17 
     | 
    
         
            +
                      rows << row(queue)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    Terminal::Table.new rows: rows, headings: HEADS
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def row(queue)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    [
         
     | 
| 
      
 27 
     | 
    
         
            +
                      queue.custom? ? 'custom' : 'standard',
         
     | 
| 
      
 28 
     | 
    
         
            +
                      queue.region,
         
     | 
| 
      
 29 
     | 
    
         
            +
                      queue.account_id,
         
     | 
| 
      
 30 
     | 
    
         
            +
                      queue.name,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      queue.instance,
         
     | 
| 
      
 32 
     | 
    
         
            +
                      queue.kind,
         
     | 
| 
      
 33 
     | 
    
         
            +
                      queue.publisher,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      queue.type,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      queue.dest,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      queue.fifo
         
     | 
| 
      
 37 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'terminal-table'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Presenters
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Subscriptions
         
     | 
| 
      
 8 
     | 
    
         
            +
                  HEADS = %w[topic endpoint subscription_arn].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.call(subscriptions)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    new.call(subscriptions)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def call(subscriptions)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    rows = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                    subscriptions.each do |subscription|
         
     | 
| 
      
 17 
     | 
    
         
            +
                      rows << row(subscription)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    Terminal::Table.new rows: rows, headings: HEADS
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def row(subscription)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    [
         
     | 
| 
      
 27 
     | 
    
         
            +
                      subscription[:topic].name,
         
     | 
| 
      
 28 
     | 
    
         
            +
                      subscription[:endpoint].name,
         
     | 
| 
      
 29 
     | 
    
         
            +
                      subscription[:arn]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'terminal-table'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Presenters
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Topics
         
     | 
| 
      
 8 
     | 
    
         
            +
                  HEADS = %w[valid region account_id name instance kind publisher type fifo].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.call(topics)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    new.call(topics)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def call(topics)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    rows = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                    topics.each do |topic|
         
     | 
| 
      
 17 
     | 
    
         
            +
                      rows << row(topic)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    Terminal::Table.new rows: rows, headings: HEADS
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def row(topic)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    [
         
     | 
| 
      
 27 
     | 
    
         
            +
                      topic.custom? ? 'custom' : 'standard',
         
     | 
| 
      
 28 
     | 
    
         
            +
                      topic.region,
         
     | 
| 
      
 29 
     | 
    
         
            +
                      topic.account_id,
         
     | 
| 
      
 30 
     | 
    
         
            +
                      topic.name,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      topic.instance,
         
     | 
| 
      
 32 
     | 
    
         
            +
                      topic.kind,
         
     | 
| 
      
 33 
     | 
    
         
            +
                      topic.publisher,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      topic.type,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      topic.fifo
         
     | 
| 
      
 36 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'cyclone_lariat/clients/sns'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'cyclone_lariat/clients/sqs'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Publisher
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Generators::Event
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Generators::Command
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :config
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(**options)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @config = CycloneLariat::Options.wrap(options).merge!(CycloneLariat.config)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def sqs
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @sqs ||= Clients::Sqs.new(**config.to_h)
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def sns
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @sns ||= Clients::Sns.new(**config.to_h)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,92 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'cyclone_lariat/messages/v1/event'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'cyclone_lariat/messages/v1/command'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'cyclone_lariat/repo/messages_mapper'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Repo
         
     | 
| 
      
 9 
     | 
    
         
            +
                module ActiveRecord
         
     | 
| 
      
 10 
     | 
    
         
            +
                  class Messages
         
     | 
| 
      
 11 
     | 
    
         
            +
                    attr_reader :dataset
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    def initialize(dataset)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @dataset = dataset
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    def enabled?
         
     | 
| 
      
 18 
     | 
    
         
            +
                      !dataset.nil?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    def disabled?
         
     | 
| 
      
 22 
     | 
    
         
            +
                      dataset.nil?
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def create(msg)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      dataset.create(MessagesMapper.to_row(msg)).uuid
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def exists?(uuid:)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      dataset.exists?(uuid: uuid)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def processed!(uuid:, error: nil)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      data = { processed_at: current_timestamp_from_db }
         
     | 
| 
      
 35 
     | 
    
         
            +
                      data.merge!(client_error_message: error.message, client_error_details: JSON.generate(error.details)) if error
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      message = dataset.where(uuid: uuid).first
         
     | 
| 
      
 38 
     | 
    
         
            +
                      return false unless message
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                      message.update(data)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    def find(uuid:)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      row = dataset.where(uuid: uuid).first
         
     | 
| 
      
 45 
     | 
    
         
            +
                      return if row.nil?
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                      build_message_from_ar_row(row)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def each_unprocessed
         
     | 
| 
      
 51 
     | 
    
         
            +
                      dataset.where(processed_at: nil).each do |row|
         
     | 
| 
      
 52 
     | 
    
         
            +
                        msg = build_message_from_ar_row(row)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        yield(msg)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    def each_with_client_errors
         
     | 
| 
      
 58 
     | 
    
         
            +
                      dataset
         
     | 
| 
      
 59 
     | 
    
         
            +
                        .where.not(processed_at: nil)
         
     | 
| 
      
 60 
     | 
    
         
            +
                        .where.not(client_error_message: nil)
         
     | 
| 
      
 61 
     | 
    
         
            +
                        .each do |row|
         
     | 
| 
      
 62 
     | 
    
         
            +
                          msg = build_message_from_ar_row(row)
         
     | 
| 
      
 63 
     | 
    
         
            +
                          yield(msg)
         
     | 
| 
      
 64 
     | 
    
         
            +
                        end
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    private
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    def build_message_from_ar_row(row)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      build MessagesMapper.from_row(row.attributes.symbolize_keys)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    def current_timestamp_from_db
         
     | 
| 
      
 74 
     | 
    
         
            +
                      time_from_db =
         
     | 
| 
      
 75 
     | 
    
         
            +
                        ::ActiveRecord::Base
         
     | 
| 
      
 76 
     | 
    
         
            +
                        .connection.execute('select current_timestamp;')
         
     | 
| 
      
 77 
     | 
    
         
            +
                        .first
         
     | 
| 
      
 78 
     | 
    
         
            +
                      time = time_from_db.is_a?(Hash) ? time_from_db['current_timestamp'] : time_from_db[0]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      time.is_a?(Time) ? time : Time.parse(time)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    def build(raw)
         
     | 
| 
      
 83 
     | 
    
         
            +
                      case kind = raw.delete(:kind)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      when 'event'   then CycloneLariat::Messages::V1::Event.wrap raw
         
     | 
| 
      
 85 
     | 
    
         
            +
                      when 'command' then CycloneLariat::Messages::V1::Command.wrap raw
         
     | 
| 
      
 86 
     | 
    
         
            +
                      else raise ArgumentError, "Unknown kind `#{kind}` of message"
         
     | 
| 
      
 87 
     | 
    
         
            +
                      end
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Repo
         
     | 
| 
      
 5 
     | 
    
         
            +
                module ActiveRecord
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class Versions
         
     | 
| 
      
 7 
     | 
    
         
            +
                    attr_reader :dataset
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    def initialize(dataset)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      @dataset = dataset
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    def add(version)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      dataset.create(version: version)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      true
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    def remove(version)
         
     | 
| 
      
 19 
     | 
    
         
            +
                      dataset.where(version: version).delete_all.positive?
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def all
         
     | 
| 
      
 23 
     | 
    
         
            +
                      dataset.pluck(:version).map { |version| { version: version } }
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'luna_park/extensions/injector'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'cyclone_lariat/core'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'cyclone_lariat/repo/sequel/messages'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'cyclone_lariat/repo/active_record/messages'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 10 
     | 
    
         
            +
              module Repo
         
     | 
| 
      
 11 
     | 
    
         
            +
                class Messages
         
     | 
| 
      
 12 
     | 
    
         
            +
                  include LunaPark::Extensions::Injector
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  attr_reader :config
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  dependency(:sequel_messages_class) { Repo::Sequel::Messages }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  dependency(:active_record_messages_class) { Repo::ActiveRecord::Messages }
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  extend Forwardable
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def_delegators :driver, :create, :exists?, :processed!, :find, :each_unprocessed, :each_with_client_errors,
         
     | 
| 
      
 22 
     | 
    
         
            +
                                 :enabled?, :disabled?
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def initialize(**options)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @config = CycloneLariat::Options.wrap(options).merge!(CycloneLariat.config)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def driver
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @driver ||= select(driver: config.driver)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  private
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def select(driver:)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    case driver
         
     | 
| 
      
 36 
     | 
    
         
            +
                    when :sequel then sequel_messages_class.new(config.messages_dataset)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    when :active_record then active_record_messages_class.new(config.messages_dataset)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    else raise ArgumentError, "Undefined driver `#{driver}`"
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module CycloneLariat
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Repo
         
     | 
| 
      
 5 
     | 
    
         
            +
                class MessagesMapper
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def from_row(row)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      return if row.nil?
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                      row[:data] = hash_from_json_column(row[:data])
         
     | 
| 
      
 11 
     | 
    
         
            +
                      row[:client_error_details] = hash_from_json_column(row[:client_error_details]) if row[:client_error_details]
         
     | 
| 
      
 12 
     | 
    
         
            +
                      row
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    def to_row(input)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      {
         
     | 
| 
      
 17 
     | 
    
         
            +
                        uuid: input.uuid,
         
     | 
| 
      
 18 
     | 
    
         
            +
                        kind: input.kind,
         
     | 
| 
      
 19 
     | 
    
         
            +
                        type: input.type,
         
     | 
| 
      
 20 
     | 
    
         
            +
                        publisher: input.publisher,
         
     | 
| 
      
 21 
     | 
    
         
            +
                        data: JSON.generate(input.data),
         
     | 
| 
      
 22 
     | 
    
         
            +
                        client_error_message: input.client_error&.message,
         
     | 
| 
      
 23 
     | 
    
         
            +
                        client_error_details: JSON.generate(input.client_error&.details),
         
     | 
| 
      
 24 
     | 
    
         
            +
                        version: input.version,
         
     | 
| 
      
 25 
     | 
    
         
            +
                        sent_at: input.sent_at
         
     | 
| 
      
 26 
     | 
    
         
            +
                      }
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def hash_from_json_column(data)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      return data if data.is_a?(Hash)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      return JSON.parse(data) if data.is_a?(String)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                      if pg_json_extension_enabled?
         
     | 
| 
      
 36 
     | 
    
         
            +
                        return data.to_h             if data.is_a?(::Sequel::Postgres::JSONHash)
         
     | 
| 
      
 37 
     | 
    
         
            +
                        return JSON.parse(data.to_s) if data.is_a?(::Sequel::Postgres::JSONString)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                      raise ArgumentError, "Unknown type of `#{data}`"
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    def pg_json_extension_enabled?
         
     | 
| 
      
 44 
     | 
    
         
            +
                      Object.const_defined?('Sequel::Postgres::JSONHash')
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     |