Class: WebSandboxConsole::Sandbox

Inherits:
Object
  • Object
show all
Defined in:
lib/web_sandbox_console/sandbox.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(code = nil, pass_auth = false) ⇒ Sandbox

Returns a new instance of Sandbox.



8
9
10
11
12
13
# File 'lib/web_sandbox_console/sandbox.rb', line 8

def initialize(code = nil, pass_auth = false)
  @code         = code
  @uuid         = SecureRandom.uuid
  @pass_auth    = pass_auth.presence || false
  @exe_tmp_file = "#{Rails.root}/tmp/sandbox/#{uuid}.rb"
end

Instance Attribute Details

#codeObject

代码



3
4
5
# File 'lib/web_sandbox_console/sandbox.rb', line 3

def code
  @code
end

#exe_tmp_fileObject

执行临时文件(由code 组成的运行代码)



6
7
8
# File 'lib/web_sandbox_console/sandbox.rb', line 6

def exe_tmp_file
  @exe_tmp_file
end

#pass_authObject

是否通过授权



5
6
7
# File 'lib/web_sandbox_console/sandbox.rb', line 5

def pass_auth
  @pass_auth
end

#uuidObject

唯一标识



4
5
6
# File 'lib/web_sandbox_console/sandbox.rb', line 4

def uuid
  @uuid
end

Instance Method Details

#add_tmp_file_dirObject

添加临时文件目录



84
85
86
# File 'lib/web_sandbox_console/sandbox.rb', line 84

def add_tmp_file_dir
  FileUtils.mkdir_p(tmp_file_dir)  unless File.directory?(tmp_file_dir)
end

#asyn_evalotorObject

异步后台执行



24
25
26
27
28
29
# File 'lib/web_sandbox_console/sandbox.rb', line 24

def asyn_evalotor
  evalotor_block do
    Thread.new {exec_rails_runner}
    ["已在后台执行,请耐心等待😊"]
  end
end

#auto_clean_tmp_fileObject

自动删除临时文件



94
95
96
# File 'lib/web_sandbox_console/sandbox.rb', line 94

def auto_clean_tmp_file
  FileUtils.rm_rf(Dir["#{tmp_file_dir}/*"]) if tmp_file_need_clean?
end

#check_syntaxObject

检查 语法



112
113
114
115
116
117
# File 'lib/web_sandbox_console/sandbox.rb', line 112

def check_syntax
  prepare_check_syntax
  unless `ruby -c #{self.exe_tmp_file}`.include?('Syntax OK')
    raise SandboxError, "存在语法错误"
  end
end

#evalotorObject

同步执行



16
17
18
19
20
21
# File 'lib/web_sandbox_console/sandbox.rb', line 16

def evalotor
  evalotor_block do
    exec_rails_runner
    get_result
  end
end

#evalotor_blockObject

执行结构块



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/web_sandbox_console/sandbox.rb', line 32

def evalotor_block
  begin
    check_syntax
    write_exe_tmp_file
    yield
  rescue SandboxError => e
    [e.message]
  rescue Exception => e
    ["发生未知错误: #{e.inspect};#{e.backtrace[0..2].join('\r\n')}"]
  end
end

#exec_rails_runnerObject

运行rails runner



120
121
122
# File 'lib/web_sandbox_console/sandbox.rb', line 120

def exec_rails_runner
  @stdout = `RAILS_ENV=#{Rails.env} bundle exec rails runner #{self.exe_tmp_file}`
end

#get_resultObject

最终结果



134
135
136
137
138
139
140
141
142
143
# File 'lib/web_sandbox_console/sandbox.rb', line 134

def get_result
  if @stdout.present?
    stdout_arr = ['------------ 打印值 ----------']
    stdout_arr.concat(@stdout.to_s.split("\n"))
    stdout_arr << '------------ 返回值 ----------'
    stdout_arr.concat(return_result_arr)
  else
    return_result_arr
  end
end

#no_rollback_codeObject

不回滚code



72
73
74
75
76
# File 'lib/web_sandbox_console/sandbox.rb', line 72

def no_rollback_code
  "    result = eval(\#{self.code.inspect})\n  EOF\nend\n"

#prepare_check_syntaxObject

准备检查语法



106
107
108
109
# File 'lib/web_sandbox_console/sandbox.rb', line 106

def prepare_check_syntax
  add_tmp_file_dir
  File.open(self.exe_tmp_file, 'w'){|f| f << self.code}
end

#return_result_arrObject

返回结果



125
126
127
128
129
130
131
# File 'lib/web_sandbox_console/sandbox.rb', line 125

def return_result_arr
  last_10_lines = `tail -n 100 #{WebSandboxConsole.log_path} | grep #{self.uuid}`
  
  last_10_lines.split("\n").map do |line|
    line.split("#{self.uuid}:").last.split("|||")
  end.flatten
end

#rollback_codeObject

回滚code



62
63
64
65
66
67
68
69
# File 'lib/web_sandbox_console/sandbox.rb', line 62

def rollback_code
  "    ActiveRecord::Base.transaction(requires_new: true) do\n      result = eval(\#{self.code.inspect})\n      raise ActiveRecord::Rollback\n    end\n  EOF\nend\n"

#runner_codeObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/web_sandbox_console/sandbox.rb', line 44

def runner_code
  str ="    result = nil\n    begin\n      WebSandboxConsole.current_uuid(\"\#{self.uuid}\")\n      WebSandboxConsole.init_safe_env\n      WebSandboxConsole.logger_sql\n      \#{self.pass_auth ? no_rollback_code : rollback_code}\n    rescue Exception => e\n      WebSandboxConsole.log_p(e)\n    rescue SyntaxError => e\n      WebSandboxConsole.log_p(e)\n    end\n    WebSandboxConsole.log_p(result)\n  CODE\nend\n"

#tmp_file_dirObject

临时文件目录



79
80
81
# File 'lib/web_sandbox_console/sandbox.rb', line 79

def tmp_file_dir
  File.dirname(self.exe_tmp_file)
end

#tmp_file_need_clean?Boolean

临时文件 需要清理?

Returns:

  • (Boolean)


89
90
91
# File 'lib/web_sandbox_console/sandbox.rb', line 89

def tmp_file_need_clean?
  Dir["#{tmp_file_dir}/*"].count > 6
end

#write_exe_tmp_fileObject

写入 执行临时文件



99
100
101
102
103
# File 'lib/web_sandbox_console/sandbox.rb', line 99

def write_exe_tmp_file
  add_tmp_file_dir
  auto_clean_tmp_file
  File.open(self.exe_tmp_file, 'w'){|f| f << runner_code}
end