huginn_ruby_agent 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46786fbef6ebd0f956499b17915fa8970f4285795073e3f55a9f6d026e8f9597
4
- data.tar.gz: 21cf1e531eb5652e34eecf0a8b0151458902f4bee65fe69b5c4110cfe5b2c0f5
3
+ metadata.gz: 602117200b2aadebec8c4c6e959c9ab19c4bb585df0a9c72b7926f8b0adc8638
4
+ data.tar.gz: 65d559d7e90b569f74c8cd890786ac830d469fd58923c75f50399af64c914b1e
5
5
  SHA512:
6
- metadata.gz: 2a5c0ebee329f780bdc08637a03803de430cf16753f27f14456380c4cedd598b85a8398a4eb94c1c4355e75a9fc095279e0be90c4032872d8c3159ba934f879b
7
- data.tar.gz: 2ecc2518b29ef5f6edfc432325670f8ad09d7f29bb70cd25bc0d09329a87dae0cf9f8053714fd1a335772ce06fd3e106533d9d273ac29034f607aa6399ed433d
6
+ metadata.gz: 540dd8062b8fed871c15a5f784de8eece0317480a6e59025d4345a86267409660b187f37ca4f03ce48e89b0d8b685b196fc9c095e7ca6c20cb7335b15d42960c
7
+ data.tar.gz: c68d5ef8c376d7af0121378ffc4323cae0bd51a78802716990c0f9b62dd6d11f7646697d74b73934735cc182a6ba12032682b00caaf61a652cd2dcf6dd4f175e
@@ -1,29 +1,238 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
4
+ require 'cgi'
5
+ require 'tempfile'
6
+ require 'base64'
7
+
8
+ # https://stackoverflow.com/questions/23884526/is-there-a-safe-way-to-eval-in-ruby-or-a-better-way-to-do-this
3
9
  module Agents
4
10
  class RubyAgent < Agent
5
- default_schedule '12h'
11
+ include FormConfigurable
12
+
13
+ can_dry_run!
14
+
15
+ default_schedule "never"
16
+
17
+ gem_dependency_check { defined?(MiniRacer) }
6
18
 
7
19
  description <<-MD
8
- Add a Agent description here
20
+ The Ruby Agent allows you to write code in Ruby that can create and receive events. If other Agents aren't meeting your needs, try this one!
21
+
22
+ You should put code in the `code` option.
23
+
24
+ You can implement `Agent.check` and `Agent.receive` as you see fit. The following methods will be available on Agent:
25
+
26
+ * `createEvent(payload)`
27
+ * `incomingEvents()` (the returned event objects will each have a `payload` property)
28
+ * `memory()`
29
+ * `memory(key)`
30
+ * `memory(keyToSet, valueToSet)`
31
+ * `setMemory(object)` (replaces the Agent's memory with the provided object)
32
+ * `deleteKey(key)` (deletes a key from memory and returns the value)
33
+ * `credential(name)`
34
+ * `credential(name, valueToSet)`
35
+ * `options()`
36
+ * `options(key)`
37
+ * `log(message)`
38
+ * `error(message)`
9
39
  MD
10
40
 
41
+ form_configurable :code, type: :text, ace: true
42
+ form_configurable :expected_receive_period_in_days
43
+ form_configurable :expected_update_period_in_days
44
+
45
+ def validate_options
46
+ errors.add(:base, "The 'code' option is required") unless options['code'].present?
47
+ end
48
+
49
+ def working?
50
+ return false if recent_error_logs?
51
+
52
+ if interpolated['expected_update_period_in_days'].present?
53
+ return false unless event_created_within?(interpolated['expected_update_period_in_days'])
54
+ end
55
+
56
+ if interpolated['expected_receive_period_in_days'].present?
57
+ return false unless last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago
58
+ end
59
+
60
+ true
61
+ end
62
+
63
+ def check
64
+ log_errors do
65
+ execute_check
66
+ end
67
+ end
68
+
69
+ def receive(events)
70
+ log_errors do
71
+ execute_receive(events)
72
+ end
73
+ end
74
+
11
75
  def default_options
12
- {}
76
+ code = <<~CODE
77
+
78
+ require "bundler/inline"
79
+
80
+ gemfile do
81
+ source "https://rubygems.org"
82
+
83
+ # gem "mechanize"
84
+ end
85
+
86
+ class Agent
87
+ def initialize(api)
88
+ @api = api
89
+ end
90
+
91
+ def check
92
+ @api.create_event({ message: 'I made an event!' })
93
+ end
94
+
95
+ def receive(incoming_events)
96
+ incoming_events.each do |event|
97
+ @api.create_event({ message: 'new event', event_was: event[:payload] })
98
+ end
99
+ end
100
+ end
101
+ CODE
102
+
103
+ {
104
+ 'code' => code,
105
+ 'expected_receive_period_in_days' => '2',
106
+ 'expected_update_period_in_days' => '2'
107
+ }
13
108
  end
14
109
 
15
- def validate_options; end
110
+ private
16
111
 
17
- def working?
18
- # Implement me! Maybe one of these next two lines would be a good fit?
19
- # checked_without_error?
20
- # received_event_without_error?
112
+ def execute_check
113
+ Bundler.with_original_env do
114
+ Open3.popen3("ruby", chdir: '/') do |input, output, err, thread|
115
+ input.write sdk_code
116
+ input.write code
117
+ input.write <<~CODE
118
+
119
+ Agent.new(Huginn::API.new).check
120
+
121
+ CODE
122
+ input.close
123
+
124
+
125
+ output.readlines.map { |line| JSON.parse(line, symbolize_names: true) }.each do |data|
126
+ case data[:action]
127
+ when 'create_event'
128
+ create_event(payload: data[:payload])
129
+ when 'log'
130
+ log data[:payload]
131
+ when 'error'
132
+ error data[:payload]
133
+ end
134
+ end
135
+
136
+ errors = err.read
137
+
138
+ error err.read
139
+ log "thread #{thread.value}"
140
+ end
141
+ end
142
+ end
143
+
144
+ def execute_receive(events)
145
+ Bundler.with_original_env do
146
+ Open3.popen3("ruby", chdir: '/') do |input, output, err, thread|
147
+ input.write sdk_code
148
+ input.write code
149
+ input.write <<~CODE
150
+
151
+ api = Huginn::API.new
152
+ begin
153
+ Agent.new(api).receive(
154
+ JSON.parse(
155
+ Base64.decode64(
156
+ "#{Base64.encode64(events.to_json)}"
157
+ ),
158
+ symbolize_names: true
159
+ )
160
+ )
161
+ rescue StandardError => ex
162
+ api.error ex
163
+ end
164
+
165
+ CODE
166
+ input.close
167
+
168
+
169
+ output.readlines.map { |line| JSON.parse(line, symbolize_names: true) }.each do |data|
170
+ case data[:action]
171
+ when 'create_event'
172
+ create_event(payload: data[:payload])
173
+ when 'log'
174
+ log data[:payload]
175
+ when 'error'
176
+ error data[:payload]
177
+ end
178
+ end
179
+
180
+ errors = err.read
181
+
182
+ error err.read
183
+ log "thread #{thread.value}"
184
+ end
185
+ end
186
+ end
187
+
188
+ def code
189
+ interpolated['code']
21
190
  end
22
191
 
23
- # def check
24
- # end
192
+ def sdk_code
193
+ <<~CODE
194
+ require 'json'
195
+ require 'base64'
196
+
197
+ module Huginn
198
+ class API
199
+ def create_event(payload)
200
+ puts(
201
+ {
202
+ action: :create_event,
203
+ payload: payload
204
+ }.to_json
205
+ )
206
+ end
207
+
208
+ def log(message)
209
+ puts(
210
+ {
211
+ action: :log,
212
+ payload: message
213
+ }.to_json
214
+ )
215
+ end
25
216
 
26
- # def receive(incoming_events)
27
- # end
217
+ def error(message)
218
+ puts(
219
+ {
220
+ action: :error,
221
+ payload: message
222
+ }.to_json
223
+ )
224
+ end
225
+ end
226
+ end
227
+ CODE
228
+ end
229
+
230
+ def log_errors
231
+ begin
232
+ yield
233
+ rescue StandardError => e
234
+ error "Runtime error: #{e.message}"
235
+ end
236
+ end
28
237
  end
29
238
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: huginn_ruby_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergei O. Udalov
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: huginn_agent
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
108
  - !ruby/object:Gem::Version
95
109
  version: '0'
96
110
  requirements: []
97
- rubygems_version: 3.3.7
111
+ rubygems_version: 3.1.6
98
112
  signing_key:
99
113
  specification_version: 4
100
114
  summary: Ruby Agent for Huginn automation platform