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.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -3
  3. data/Gemfile.lock +28 -4
  4. data/README.md +63 -5
  5. data/faastruby.gemspec +5 -1
  6. data/lib/faastruby.rb +1 -0
  7. data/lib/faastruby/api.rb +154 -6
  8. data/lib/faastruby/base.rb +3 -9
  9. data/lib/faastruby/cli.rb +39 -12
  10. data/lib/faastruby/cli/base_command.rb +66 -0
  11. data/lib/faastruby/cli/commands.rb +122 -59
  12. data/lib/faastruby/cli/commands/account/base_command.rb +10 -0
  13. data/lib/faastruby/cli/commands/account/confirm.rb +94 -0
  14. data/lib/faastruby/cli/commands/account/login.rb +86 -0
  15. data/lib/faastruby/cli/commands/account/logout.rb +59 -0
  16. data/lib/faastruby/cli/commands/account/signup.rb +76 -0
  17. data/lib/faastruby/cli/commands/{function.rb → function/base_command.rb} +2 -11
  18. data/lib/faastruby/cli/commands/function/build.rb +18 -11
  19. data/lib/faastruby/cli/commands/function/deploy_to.rb +100 -37
  20. data/lib/faastruby/cli/commands/function/new.rb +89 -36
  21. data/lib/faastruby/cli/commands/function/remove_from.rb +21 -6
  22. data/lib/faastruby/cli/commands/function/run.rb +15 -15
  23. data/lib/faastruby/cli/commands/function/test.rb +5 -4
  24. data/lib/faastruby/cli/commands/function/update_context.rb +10 -3
  25. data/lib/faastruby/cli/commands/function/upgrade.rb +62 -61
  26. data/lib/faastruby/cli/commands/help.rb +33 -20
  27. data/lib/faastruby/cli/commands/project/base_command.rb +14 -0
  28. data/lib/faastruby/cli/commands/project/deploy.rb +114 -0
  29. data/lib/faastruby/cli/commands/project/down.rb +58 -0
  30. data/lib/faastruby/cli/commands/project/new.rb +237 -0
  31. data/lib/faastruby/cli/commands/workspace/cp.rb +107 -0
  32. data/lib/faastruby/cli/commands/workspace/create.rb +35 -27
  33. data/lib/faastruby/cli/commands/workspace/destroy.rb +14 -7
  34. data/lib/faastruby/cli/commands/workspace/list.rb +15 -6
  35. data/lib/faastruby/cli/commands/workspace/migrate.rb +93 -0
  36. data/lib/faastruby/cli/commands/workspace/rm.rb +81 -0
  37. data/lib/faastruby/cli/commands/workspace/update.rb +62 -0
  38. data/lib/faastruby/cli/credentials.rb +58 -57
  39. data/lib/faastruby/cli/new_credentials.rb +63 -0
  40. data/lib/faastruby/cli/package.rb +1 -0
  41. data/lib/faastruby/cli/template.rb +7 -7
  42. data/lib/faastruby/local.rb +188 -0
  43. data/lib/faastruby/local/crystal_runtime.cr +170 -0
  44. data/lib/faastruby/local/functions.rb +7 -0
  45. data/lib/faastruby/local/functions/crystal.rb +64 -0
  46. data/lib/faastruby/local/functions/function.rb +173 -0
  47. data/lib/faastruby/local/functions/ruby.rb +28 -0
  48. data/lib/faastruby/local/listeners.rb +5 -0
  49. data/lib/faastruby/local/listeners/listener.rb +104 -0
  50. data/lib/faastruby/local/logger.rb +37 -0
  51. data/lib/faastruby/local/monkey_patch.rb +38 -0
  52. data/lib/faastruby/local/processors.rb +7 -0
  53. data/lib/faastruby/local/processors/function.rb +151 -0
  54. data/lib/faastruby/local/processors/processor.rb +116 -0
  55. data/lib/faastruby/local/processors/static_file.rb +48 -0
  56. data/lib/faastruby/local/static_files.rb +5 -0
  57. data/lib/faastruby/local/static_files/static_file.rb +59 -0
  58. data/lib/faastruby/server.rb +44 -3
  59. data/lib/faastruby/server/app.rb +107 -0
  60. data/lib/faastruby/server/concurrency_controller.rb +50 -50
  61. data/lib/faastruby/server/config.ru +2 -0
  62. data/lib/faastruby/server/event.rb +3 -0
  63. data/lib/faastruby/server/event_hub.rb +7 -6
  64. data/lib/faastruby/server/local.rb +22 -0
  65. data/lib/faastruby/server/logger.rb +50 -0
  66. data/lib/faastruby/server/project_config.rb +44 -0
  67. data/lib/faastruby/server/puma.rb +4 -0
  68. data/lib/faastruby/server/response.rb +40 -0
  69. data/lib/faastruby/server/runner.rb +116 -21
  70. data/lib/faastruby/server/runner_methods.rb +17 -16
  71. data/lib/faastruby/server/sentinel.rb +496 -0
  72. data/lib/faastruby/supported_runtimes.rb +8 -0
  73. data/lib/faastruby/user.rb +77 -0
  74. data/lib/faastruby/version.rb +1 -1
  75. data/lib/faastruby/workspace.rb +36 -3
  76. data/templates/crystal/example-blank/handler.cr +3 -0
  77. data/templates/crystal/example/spec/handler_spec.cr +11 -6
  78. data/templates/public-web/assets/images/background.png +0 -0
  79. data/templates/public-web/assets/images/ruby.png +0 -0
  80. data/templates/public-web/assets/javascripts/main.js +1 -0
  81. data/templates/public-web/assets/stylesheets/main.css +70 -0
  82. data/templates/public-web/favicon.ico +0 -0
  83. data/templates/ruby/api-404/handler.rb +6 -0
  84. data/templates/ruby/api-root/handler.rb +6 -0
  85. data/templates/ruby/example-blank/handler.rb +0 -23
  86. data/templates/ruby/web-404/404.html +36 -0
  87. data/templates/ruby/web-404/handler.rb +3 -0
  88. data/templates/ruby/web-root/handler.rb +10 -0
  89. data/templates/ruby/web-root/index.html.erb +37 -0
  90. data/templates/ruby/web-root/template.rb +13 -0
  91. metadata +102 -21
  92. data/exe/faastruby-server +0 -76
  93. data/lib/faastruby/cli/commands/credentials.rb +0 -11
  94. data/lib/faastruby/cli/commands/credentials/add.rb +0 -58
  95. data/lib/faastruby/cli/commands/credentials/list.rb +0 -58
  96. data/lib/faastruby/cli/commands/workspace.rb +0 -13
  97. data/lib/faastruby/cli/commands/workspace/deploy.rb +0 -50
  98. data/templates/crystal/example-blank/README.md +0 -22
  99. data/templates/crystal/example-blank/spec/handler_spec.cr +0 -8
  100. data/templates/crystal/example-blank/spec/spec_helper.cr +0 -4
  101. data/templates/crystal/example-blank/src/handler.cr +0 -25
  102. data/templates/ruby/example-blank/Gemfile +0 -7
  103. data/templates/ruby/example-blank/README.md +0 -22
  104. data/templates/ruby/example-blank/spec/handler_spec.rb +0 -16
  105. 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
@@ -1,3 +1,4 @@
1
+ require 'zip'
1
2
  module FaaStRuby
2
3
  class Package
3
4
  # Initialize with the directory to zip and the location of the output archive.
@@ -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