faastruby 0.4.18 → 0.5.0
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 +4 -4
- data/CHANGELOG.md +6 -3
- data/Gemfile.lock +28 -4
- data/README.md +63 -5
- data/faastruby.gemspec +5 -1
- data/lib/faastruby.rb +1 -0
- data/lib/faastruby/api.rb +154 -6
- data/lib/faastruby/base.rb +3 -9
- data/lib/faastruby/cli.rb +39 -12
- data/lib/faastruby/cli/base_command.rb +66 -0
- data/lib/faastruby/cli/commands.rb +122 -59
- data/lib/faastruby/cli/commands/account/base_command.rb +10 -0
- data/lib/faastruby/cli/commands/account/confirm.rb +94 -0
- data/lib/faastruby/cli/commands/account/login.rb +86 -0
- data/lib/faastruby/cli/commands/account/logout.rb +59 -0
- data/lib/faastruby/cli/commands/account/signup.rb +76 -0
- data/lib/faastruby/cli/commands/{function.rb → function/base_command.rb} +2 -11
- data/lib/faastruby/cli/commands/function/build.rb +18 -11
- data/lib/faastruby/cli/commands/function/deploy_to.rb +100 -37
- data/lib/faastruby/cli/commands/function/new.rb +89 -36
- data/lib/faastruby/cli/commands/function/remove_from.rb +21 -6
- data/lib/faastruby/cli/commands/function/run.rb +15 -15
- data/lib/faastruby/cli/commands/function/test.rb +5 -4
- data/lib/faastruby/cli/commands/function/update_context.rb +10 -3
- data/lib/faastruby/cli/commands/function/upgrade.rb +62 -61
- data/lib/faastruby/cli/commands/help.rb +33 -20
- data/lib/faastruby/cli/commands/project/base_command.rb +14 -0
- data/lib/faastruby/cli/commands/project/deploy.rb +114 -0
- data/lib/faastruby/cli/commands/project/down.rb +58 -0
- data/lib/faastruby/cli/commands/project/new.rb +237 -0
- data/lib/faastruby/cli/commands/workspace/cp.rb +107 -0
- data/lib/faastruby/cli/commands/workspace/create.rb +35 -27
- data/lib/faastruby/cli/commands/workspace/destroy.rb +14 -7
- data/lib/faastruby/cli/commands/workspace/list.rb +15 -6
- data/lib/faastruby/cli/commands/workspace/migrate.rb +93 -0
- data/lib/faastruby/cli/commands/workspace/rm.rb +81 -0
- data/lib/faastruby/cli/commands/workspace/update.rb +62 -0
- data/lib/faastruby/cli/credentials.rb +58 -57
- data/lib/faastruby/cli/new_credentials.rb +63 -0
- data/lib/faastruby/cli/package.rb +1 -0
- data/lib/faastruby/cli/template.rb +7 -7
- data/lib/faastruby/local.rb +188 -0
- data/lib/faastruby/local/crystal_runtime.cr +170 -0
- data/lib/faastruby/local/functions.rb +7 -0
- data/lib/faastruby/local/functions/crystal.rb +64 -0
- data/lib/faastruby/local/functions/function.rb +173 -0
- data/lib/faastruby/local/functions/ruby.rb +28 -0
- data/lib/faastruby/local/listeners.rb +5 -0
- data/lib/faastruby/local/listeners/listener.rb +104 -0
- data/lib/faastruby/local/logger.rb +37 -0
- data/lib/faastruby/local/monkey_patch.rb +38 -0
- data/lib/faastruby/local/processors.rb +7 -0
- data/lib/faastruby/local/processors/function.rb +151 -0
- data/lib/faastruby/local/processors/processor.rb +116 -0
- data/lib/faastruby/local/processors/static_file.rb +48 -0
- data/lib/faastruby/local/static_files.rb +5 -0
- data/lib/faastruby/local/static_files/static_file.rb +59 -0
- data/lib/faastruby/server.rb +44 -3
- data/lib/faastruby/server/app.rb +107 -0
- data/lib/faastruby/server/concurrency_controller.rb +50 -50
- data/lib/faastruby/server/config.ru +2 -0
- data/lib/faastruby/server/event.rb +3 -0
- data/lib/faastruby/server/event_hub.rb +7 -6
- data/lib/faastruby/server/local.rb +22 -0
- data/lib/faastruby/server/logger.rb +50 -0
- data/lib/faastruby/server/project_config.rb +44 -0
- data/lib/faastruby/server/puma.rb +4 -0
- data/lib/faastruby/server/response.rb +40 -0
- data/lib/faastruby/server/runner.rb +116 -21
- data/lib/faastruby/server/runner_methods.rb +17 -16
- data/lib/faastruby/server/sentinel.rb +496 -0
- data/lib/faastruby/supported_runtimes.rb +8 -0
- data/lib/faastruby/user.rb +77 -0
- data/lib/faastruby/version.rb +1 -1
- data/lib/faastruby/workspace.rb +36 -3
- data/templates/crystal/example-blank/handler.cr +3 -0
- data/templates/crystal/example/spec/handler_spec.cr +11 -6
- data/templates/public-web/assets/images/background.png +0 -0
- data/templates/public-web/assets/images/ruby.png +0 -0
- data/templates/public-web/assets/javascripts/main.js +1 -0
- data/templates/public-web/assets/stylesheets/main.css +70 -0
- data/templates/public-web/favicon.ico +0 -0
- data/templates/ruby/api-404/handler.rb +6 -0
- data/templates/ruby/api-root/handler.rb +6 -0
- data/templates/ruby/example-blank/handler.rb +0 -23
- data/templates/ruby/web-404/404.html +36 -0
- data/templates/ruby/web-404/handler.rb +3 -0
- data/templates/ruby/web-root/handler.rb +10 -0
- data/templates/ruby/web-root/index.html.erb +37 -0
- data/templates/ruby/web-root/template.rb +13 -0
- metadata +102 -21
- data/exe/faastruby-server +0 -76
- data/lib/faastruby/cli/commands/credentials.rb +0 -11
- data/lib/faastruby/cli/commands/credentials/add.rb +0 -58
- data/lib/faastruby/cli/commands/credentials/list.rb +0 -58
- data/lib/faastruby/cli/commands/workspace.rb +0 -13
- data/lib/faastruby/cli/commands/workspace/deploy.rb +0 -50
- data/templates/crystal/example-blank/README.md +0 -22
- data/templates/crystal/example-blank/spec/handler_spec.cr +0 -8
- data/templates/crystal/example-blank/spec/spec_helper.cr +0 -4
- data/templates/crystal/example-blank/src/handler.cr +0 -25
- data/templates/ruby/example-blank/Gemfile +0 -7
- data/templates/ruby/example-blank/README.md +0 -22
- data/templates/ruby/example-blank/spec/handler_spec.rb +0 -16
- data/templates/ruby/example-blank/spec/spec_helper.rb +0 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module FaaStRuby
|
|
2
|
+
module NewCredentials
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
class CredentialsFile
|
|
6
|
+
def initialize
|
|
7
|
+
@folder = File.expand_path("~/.faastruby")
|
|
8
|
+
@file = "#{@folder}/credentials.yml"
|
|
9
|
+
rename_if_old_file_exists
|
|
10
|
+
create_credentials_folder
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def rename_if_old_file_exists
|
|
14
|
+
old_file = File.expand_path("~/.faastruby")
|
|
15
|
+
return true unless File.file?(old_file)
|
|
16
|
+
new_file = File.expand_path("~/.faastruby.tor1")
|
|
17
|
+
FileUtils.mv(old_file, new_file)
|
|
18
|
+
return true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_credentials_folder
|
|
22
|
+
return true if File.file?(@file)
|
|
23
|
+
FileUtils.mkdir_p(@folder)
|
|
24
|
+
clear
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def read
|
|
28
|
+
YAML.load(File.read(@file)) rescue {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get
|
|
32
|
+
creds = read['credentials'] || {}
|
|
33
|
+
unless creds['email'] && creds['api_key'] && creds['api_secret']
|
|
34
|
+
FaaStRuby::CLI.error("\nYou are not logged in. To login, run: faastruby login\n\nIf you don't have an account, run 'faastruby signup' to create one.\n", color: nil)
|
|
35
|
+
end
|
|
36
|
+
creds
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_user_logged_in?
|
|
40
|
+
creds = read['credentials'] || {}
|
|
41
|
+
creds['email'] && creds['api_key'] && creds['api_secret']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def save(email:, api_key:, api_secret:)
|
|
45
|
+
yaml = {
|
|
46
|
+
'credentials' => {
|
|
47
|
+
'email' => email,
|
|
48
|
+
'api_key' => api_key,
|
|
49
|
+
'api_secret' => api_secret
|
|
50
|
+
}
|
|
51
|
+
}.to_yaml
|
|
52
|
+
File.write(@file, yaml)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def clear
|
|
56
|
+
yaml = {
|
|
57
|
+
'credentials' => {}
|
|
58
|
+
}.to_yaml
|
|
59
|
+
File.write(@file, yaml)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -12,7 +12,8 @@ module FaaStRuby
|
|
|
12
12
|
@source = source
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def install(to:, force: false)
|
|
15
|
+
def install(to:, force: false, print_base_dir: false)
|
|
16
|
+
@output_prefix = print_base_dir ? "#{print_base_dir}/" : ""
|
|
16
17
|
@target = to
|
|
17
18
|
@force = force
|
|
18
19
|
FaaStRuby::CLI.error("Could not determine the target path for template '#{type}:#{source}'. Please report this bug at https://github.com/FaaStRuby/faastruby-cli/issues", color: nil) unless target
|
|
@@ -40,12 +41,11 @@ module FaaStRuby
|
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def install_from_folder(folder)
|
|
43
|
-
# puts "installing from folder #{folder}"
|
|
44
44
|
if File.directory?(target)
|
|
45
|
-
puts "! d #{target}".yellow
|
|
45
|
+
puts "! d #{@output_prefix}#{target}".yellow
|
|
46
46
|
else
|
|
47
47
|
FileUtils.mkdir_p(target)
|
|
48
|
-
puts "+ d #{target}".green
|
|
48
|
+
puts "+ d #{@output_prefix}#{target}".green
|
|
49
49
|
end
|
|
50
50
|
Dir.glob("**/*", base: folder).each do |entry|
|
|
51
51
|
full_source_path = "#{folder}/#{entry}"
|
|
@@ -58,10 +58,10 @@ module FaaStRuby
|
|
|
58
58
|
|
|
59
59
|
def create_dir(dir)
|
|
60
60
|
if File.directory?(dir)
|
|
61
|
-
puts "! d #{dir}".yellow
|
|
61
|
+
puts "! d #{@output_prefix}#{dir}".yellow
|
|
62
62
|
else
|
|
63
63
|
FileUtils.mkdir_p(dir)
|
|
64
|
-
puts "+ d #{dir}".green
|
|
64
|
+
puts "+ d #{@output_prefix}#{dir}".green
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -72,7 +72,7 @@ module FaaStRuby
|
|
|
72
72
|
return(puts "[skipped] #{destination}") unless ['y', 'Y'].include?(answer)
|
|
73
73
|
end
|
|
74
74
|
FileUtils.cp(source, destination)
|
|
75
|
-
puts "+ f #{destination}".green
|
|
75
|
+
puts "+ f #{@output_prefix}#{destination}".green
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def local?
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
module FaaStRuby
|
|
2
|
+
module Local
|
|
3
|
+
require 'listen'
|
|
4
|
+
require 'colorize'
|
|
5
|
+
require 'open3'
|
|
6
|
+
require 'oj'
|
|
7
|
+
require 'yaml'
|
|
8
|
+
require 'pathname'
|
|
9
|
+
require 'securerandom'
|
|
10
|
+
require 'faastruby/version'
|
|
11
|
+
require 'faastruby/supported_runtimes'
|
|
12
|
+
require 'faastruby/local/logger'
|
|
13
|
+
require 'faastruby/local/functions'
|
|
14
|
+
require 'faastruby/local/static_files'
|
|
15
|
+
require 'faastruby/local/listeners'
|
|
16
|
+
require 'faastruby/local/processors'
|
|
17
|
+
require 'faastruby/local/monkey_patch'
|
|
18
|
+
extend Local::Logger
|
|
19
|
+
|
|
20
|
+
def self.get_crystal_version
|
|
21
|
+
debug "self.get_crystal_version"
|
|
22
|
+
ver = `crystal -v|head -n1|cut -f2 -d' ' 2>/dev/null`&.chomp
|
|
23
|
+
ver == '' ? CRYSTAL_LATEST : ver
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.crystal_present_and_supported?
|
|
27
|
+
debug "self.crystal_present_and_supported?"
|
|
28
|
+
system("which crystal >/dev/null") && SUPPORTED_CRYSTAL.include?(get_crystal_version)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.ruby_present_and_supported?
|
|
32
|
+
debug "self.ruby_present_and_supported?"
|
|
33
|
+
system("which ruby >/dev/null") && SUPPORTED_RUBY.include?(RUBY_VERSION)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.check_if_logged_in
|
|
37
|
+
creds_file = File.expand_path("~/.faastruby/credentials.yml")
|
|
38
|
+
yaml = YAML.load(File.read(creds_file)) rescue {}
|
|
39
|
+
unless yaml['credentials'] && yaml['credentials']['email']
|
|
40
|
+
STDOUT.puts "@@@ WARNING @@@ | You need to be logged in to use FaaStRuby Local with sync mode.".red
|
|
41
|
+
STDOUT.puts "@@@ WARNING @@@ | To login, run: faastruby login".red
|
|
42
|
+
STDOUT.puts "@@@ WARNING @@@ | Sync mode is *NOT* enabled!".red
|
|
43
|
+
STDOUT.puts "---".red
|
|
44
|
+
return false
|
|
45
|
+
end
|
|
46
|
+
return true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
DEBUG = ENV['DEBUG']
|
|
50
|
+
CRYSTAL_ENABLED = crystal_present_and_supported?
|
|
51
|
+
RUBY_ENABLED = ruby_present_and_supported?
|
|
52
|
+
unless RUBY_ENABLED || CRYSTAL_ENABLED
|
|
53
|
+
puts "\n[ERROR] You need to have one of the following 'language:version' pairs in order to use FaaStRuby Local."
|
|
54
|
+
puts SUPPORTED_RUNTIMES.join(', ') + "\n"*2
|
|
55
|
+
exit 1
|
|
56
|
+
end
|
|
57
|
+
SERVER_ROOT = Dir.pwd
|
|
58
|
+
PROJECT_YAML_FILE = "#{SERVER_ROOT}/project.yml"
|
|
59
|
+
SECRETS_YAML_FILE = "#{SERVER_ROOT}/secrets.yml"
|
|
60
|
+
DEPLOY_ENVIRONMENT = ENV['DEPLOY_ENVIRONMENT'] || 'stage'
|
|
61
|
+
SYNC_ENABLED = ENV['SYNC'] && check_if_logged_in
|
|
62
|
+
CRYSTAL_VERSION = get_crystal_version.freeze
|
|
63
|
+
DEFAULT_CRYSTAL_RUNTIME = "crystal:#{CRYSTAL_VERSION}".freeze
|
|
64
|
+
DEFAULT_RUBY_RUNTIME = "ruby:#{RUBY_VERSION}".freeze
|
|
65
|
+
FUNCTIONS_EVENT_QUEUE = Queue.new
|
|
66
|
+
PUBLIC_EVENT_QUEUE = Queue.new
|
|
67
|
+
|
|
68
|
+
def self.workspace
|
|
69
|
+
debug "self.workspace"
|
|
70
|
+
return "#{project_config['name']}-#{DEPLOY_ENVIRONMENT}-#{project_config['identifier']}" if project_config['identifier']
|
|
71
|
+
"#{project_config['name']}-#{DEPLOY_ENVIRONMENT}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.project_config
|
|
75
|
+
debug "self.project_config"
|
|
76
|
+
yaml = YAML.load(File.read(PROJECT_YAML_FILE))['project']
|
|
77
|
+
end
|
|
78
|
+
def self.functions_dir
|
|
79
|
+
debug "self.functions_dir"
|
|
80
|
+
"#{SERVER_ROOT}/#{project_config['functions_dir'] || 'functions'}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.public_dir
|
|
84
|
+
debug "self.public_dir"
|
|
85
|
+
"#{SERVER_ROOT}/#{project_config['public_dir'] || 'public'}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.root_to
|
|
89
|
+
debug "self.root_to"
|
|
90
|
+
project_config['root_to'] || 'root'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.catch_all
|
|
94
|
+
debug "self.catch_all"
|
|
95
|
+
project_config['catch_all'] || 'catch-all'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.functions
|
|
99
|
+
debug "self.functions"
|
|
100
|
+
@@functions ||= []
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.functions_listener
|
|
104
|
+
debug "self.functions_listener"
|
|
105
|
+
@@functions_listener
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.public_listener
|
|
109
|
+
debug "self.public_listener"
|
|
110
|
+
@@public_listener
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.secrets_for_function(function_name)
|
|
114
|
+
debug "self.secrets_for_function(#{function_name.inspect})"
|
|
115
|
+
deploy_environment_secrets[function_name] || {}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.deploy_environment_secrets
|
|
119
|
+
debug "self.deploy_environment_secrets"
|
|
120
|
+
secrets[DEPLOY_ENVIRONMENT] || {}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def self.secrets
|
|
124
|
+
debug "self.secrets"
|
|
125
|
+
YAML.load(File.read(SECRETS_YAML_FILE))['secrets'] || {}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def self.start!
|
|
129
|
+
Listen::Adapter::Linux::DEFAULTS[:events] << :modify
|
|
130
|
+
debug "self.start!"
|
|
131
|
+
sync_mode_enabled if SYNC_ENABLED
|
|
132
|
+
@@functions = Function.find_all_in(functions_dir)
|
|
133
|
+
ruby_functions = @@functions.map{|f| f.name if f.language == "ruby"}.compact
|
|
134
|
+
crystal_functions = @@functions.map{|f| f.name if f.language == "crystal"}.compact
|
|
135
|
+
puts "Detecting existing functions."
|
|
136
|
+
puts "Ruby functions: #{ruby_functions.inspect}"
|
|
137
|
+
puts "Crystal functions: #{crystal_functions.inspect}"
|
|
138
|
+
listen_on_functions_dir
|
|
139
|
+
listen_on_public_dir if SYNC_ENABLED
|
|
140
|
+
initial_compile_and_deploy(crystal_functions)
|
|
141
|
+
puts "Listening for changes."
|
|
142
|
+
FunctionProcessor.new(FUNCTIONS_EVENT_QUEUE).start
|
|
143
|
+
StaticFileProcessor.new(PUBLIC_EVENT_QUEUE).start if SYNC_ENABLED
|
|
144
|
+
sleep
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.initial_compile_and_deploy(crystal_functions)
|
|
148
|
+
debug "initial_compile_and_deploy(#{crystal_functions.inspect})"
|
|
149
|
+
puts "Triggering 'compile' on Crystal functions." if crystal_functions.any?
|
|
150
|
+
if SYNC_ENABLED
|
|
151
|
+
puts "Running initial cloud sync."
|
|
152
|
+
StaticFile.full_sync
|
|
153
|
+
end
|
|
154
|
+
sleep 1
|
|
155
|
+
@@functions.each {|f| FileUtils.touch("#{f.absolute_folder}/faastruby.yml")}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def self.sync_mode_enabled
|
|
159
|
+
debug __method__
|
|
160
|
+
puts "Sync mode enabled."
|
|
161
|
+
print "Connecting to workspace '#{workspace}'... "
|
|
162
|
+
try_to_create = Proc.new {system("faastruby create-workspace #{workspace}")}
|
|
163
|
+
has_credentials = system("faastruby list-workspace #{workspace} > /dev/null 2>&1")
|
|
164
|
+
continue = has_credentials || try_to_create.call
|
|
165
|
+
unless continue
|
|
166
|
+
puts "[FATAL] Unable to setup project workspace '#{workspace}'. Make sure you have the credentials, or try a different environment name.\nExample: faastruby local --sync --deploy-env #{DEPLOY_ENVIRONMENT}-#{(rand * 100).to_i}".red
|
|
167
|
+
exit 1
|
|
168
|
+
end
|
|
169
|
+
STDOUT.puts "connected!\n".yellow
|
|
170
|
+
puts "Your local environment will be synced to https://#{workspace}.tor1.faast.cloud"
|
|
171
|
+
true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def self.listen_on_functions_dir
|
|
175
|
+
debug "self.listen_on_functions_dir"
|
|
176
|
+
debug "Listening for changes in '#{functions_dir}'"
|
|
177
|
+
@@functions_listener = Listener.new(directory: functions_dir, queue: FUNCTIONS_EVENT_QUEUE)
|
|
178
|
+
@@functions_listener.start
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def self.listen_on_public_dir
|
|
182
|
+
debug "self.listen_on_public_dir"
|
|
183
|
+
debug "Listening for changes in '#{public_dir}'"
|
|
184
|
+
@@public_listener = Listener.new(directory: public_dir, queue: PUBLIC_EVENT_QUEUE)
|
|
185
|
+
@@public_listener.start
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
require "base64"
|
|
2
|
+
require "json"
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
module FaaStRuby
|
|
6
|
+
macro require_handler
|
|
7
|
+
require {{env("HANDLER_PATH")}}
|
|
8
|
+
end
|
|
9
|
+
class Event
|
|
10
|
+
JSON.mapping(
|
|
11
|
+
body: String?,
|
|
12
|
+
headers: Hash(String, String | Nil),
|
|
13
|
+
context: String?,
|
|
14
|
+
query_params: Hash(String, String | Nil)
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Response
|
|
19
|
+
@@rendered = false
|
|
20
|
+
property "body"
|
|
21
|
+
property "status"
|
|
22
|
+
property "headers"
|
|
23
|
+
property "io"
|
|
24
|
+
property "binary"
|
|
25
|
+
def initialize(@body : String?, @status : Int32, @headers : Hash(String, String), @binary : Bool = false)
|
|
26
|
+
@io = nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(@io : Bytes, @status : Int32, @headers : Hash(String, String), @binary : Bool = true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def payload
|
|
33
|
+
if io
|
|
34
|
+
hash = {
|
|
35
|
+
"response" => Base64.encode(io.not_nil!),
|
|
36
|
+
"status" => status,
|
|
37
|
+
"headers" => headers,
|
|
38
|
+
"binary" => binary
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
hash = {
|
|
42
|
+
"response" => body,
|
|
43
|
+
"status" => status,
|
|
44
|
+
"headers" => headers,
|
|
45
|
+
"binary" => binary
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
hash
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
class Payload
|
|
52
|
+
JSON.mapping(
|
|
53
|
+
args: Array(JSON::Any)?,
|
|
54
|
+
event: Event
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
module Function
|
|
58
|
+
def self.run(@@event : Event)
|
|
59
|
+
begin
|
|
60
|
+
output = handler(event)
|
|
61
|
+
rescue e
|
|
62
|
+
backtrace = e.backtrace.reverse.join("\n")
|
|
63
|
+
puts backtrace
|
|
64
|
+
puts "#{e.class.name}: #{e.message}"
|
|
65
|
+
output = render json: {"error" => e.message, "location" => backtrace}.to_json, status: 500
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
FaaStRuby.require_handler
|
|
72
|
+
|
|
73
|
+
def render(icon : String? = nil, jpeg : String? = nil, gif : String? = nil, png : String? = nil, io : Bytes? = nil, css : String? = nil, svg : String? = nil, js : String? = nil, inline : String? = nil, html : String? = nil, json : String? = nil, yaml : String? = nil, text : String? = nil, status : Int32 = 200, headers : Hash(String, String) = {} of String => String, content_type : String? = nil, binary : Bool = false)
|
|
74
|
+
headers["Content-Type"] = content_type if content_type
|
|
75
|
+
bin = false
|
|
76
|
+
case
|
|
77
|
+
when json
|
|
78
|
+
headers["Content-Type"] ||= "application/json"
|
|
79
|
+
resp_body = json
|
|
80
|
+
when html, inline
|
|
81
|
+
headers["Content-Type"] ||= "text/html"
|
|
82
|
+
resp_body = html
|
|
83
|
+
when text
|
|
84
|
+
headers["Content-Type"] ||= "text/plain"
|
|
85
|
+
resp_body = text
|
|
86
|
+
when yaml
|
|
87
|
+
headers["Content-Type"] ||= "text/yaml"
|
|
88
|
+
resp_body = yaml
|
|
89
|
+
when js
|
|
90
|
+
headers["Content-Type"] ||= "text/javascript"
|
|
91
|
+
resp_body = js
|
|
92
|
+
when io
|
|
93
|
+
headers["Content-Type"] ||= "application/octet-stream"
|
|
94
|
+
bin = binary
|
|
95
|
+
return FaaStRuby::Response.new(io: io, status: status, headers: headers, binary: bin)
|
|
96
|
+
when png
|
|
97
|
+
headers["Content-Type"] ||= "image/png"
|
|
98
|
+
file = File.open(png, "rb"){|f| f.gets_to_end}
|
|
99
|
+
resp_body = Base64.urlsafe_encode(file, false)
|
|
100
|
+
bin = true
|
|
101
|
+
when svg
|
|
102
|
+
headers["Content-Type"] ||= "image/svg+xml"
|
|
103
|
+
resp_body = svg
|
|
104
|
+
when jpeg
|
|
105
|
+
headers["Content-Type"] ||= "image/jpeg"
|
|
106
|
+
file = File.open(jpeg, "rb"){|f| f.gets_to_end}
|
|
107
|
+
resp_body = Base64.urlsafe_encode(file, false)
|
|
108
|
+
bin = true
|
|
109
|
+
when gif
|
|
110
|
+
headers["Content-Type"] ||= "image/gif"
|
|
111
|
+
file = File.open(gif, "rb"){|f| f.gets_to_end}
|
|
112
|
+
resp_body = Base64.urlsafe_encode(file, false)
|
|
113
|
+
bin = true
|
|
114
|
+
when icon
|
|
115
|
+
headers["Content-Type"] ||= "image/x-icon"
|
|
116
|
+
file = File.read(icon)
|
|
117
|
+
resp_body = Base64.urlsafe_encode(file, false)
|
|
118
|
+
bin = true
|
|
119
|
+
when css
|
|
120
|
+
headers["Content-Type"] ||= "text/css"
|
|
121
|
+
resp_body = css
|
|
122
|
+
end
|
|
123
|
+
FaaStRuby::Response.new(body: resp_body, status: status, headers: headers, binary: bin)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def redirect_to(function : String, status : Int32 = 303)
|
|
127
|
+
headers = {"Location" => function}
|
|
128
|
+
FaaStRuby::Response.new(body: nil, status: status, headers: headers)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def redirect_to(url : String, status : Int32 = 303)
|
|
132
|
+
headers = {"Location" => url}
|
|
133
|
+
FaaStRuby::Response.new(body: nil, status: status, headers: headers)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def respond_with(body : String? = nil, status : Int32 = 200, headers : Hash(String, String) = {} of String => String, binary : Bool = false)
|
|
137
|
+
FaaStRuby::Response.new(body: body, status: status, headers: headers)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def respond_with(io : Bytes, status : Int32 = 200, headers : Hash(String, String) = {} of String => String, binary : Bool = false)
|
|
141
|
+
FaaStRuby::Response.new(io: io, status: status, headers: headers, binary: binary)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def error(msg : String, status : Int32)
|
|
145
|
+
hash = {
|
|
146
|
+
"response" => msg,
|
|
147
|
+
"status" => status,
|
|
148
|
+
"headers" => {"Content-Type" => "application/json"}
|
|
149
|
+
}
|
|
150
|
+
puts "R,#{Base64.urlsafe_encode(hash.to_json, false)}"
|
|
151
|
+
exit 1
|
|
152
|
+
end
|
|
153
|
+
encoded_input = STDIN.gets.not_nil!.chomp
|
|
154
|
+
begin
|
|
155
|
+
decoded_input = Base64.decode_string(encoded_input)
|
|
156
|
+
payload = FaaStRuby::Payload.from_json(decoded_input)
|
|
157
|
+
rescue e
|
|
158
|
+
puts e.message
|
|
159
|
+
error(msg: "Runtime Error. What are you trying to do?", status: 500)
|
|
160
|
+
exit 1
|
|
161
|
+
end
|
|
162
|
+
spawn do
|
|
163
|
+
response = FaaStRuby::Function.run(event: payload.event)
|
|
164
|
+
puts "R,#{Base64.urlsafe_encode(response.payload.to_json)}"
|
|
165
|
+
exit 0
|
|
166
|
+
end
|
|
167
|
+
max_time = ENV["MAX_EXECUTION_TIME"]? ? ENV["MAX_EXECUTION_TIME"].not_nil!.to_f : 60.0
|
|
168
|
+
sleep max_time
|
|
169
|
+
error(msg: "Execution expired", status: 504)
|
|
170
|
+
exit 1
|