nodejs.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package nodejs
  2. import (
  3. "embed"
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "path"
  8. "strconv"
  9. "time"
  10. "github.com/langgenius/dify-sandbox/internal/core/runner"
  11. "github.com/langgenius/dify-sandbox/internal/core/runner/types"
  12. "github.com/langgenius/dify-sandbox/internal/static"
  13. "github.com/langgenius/dify-sandbox/internal/utils/log"
  14. )
  15. type NodeJsRunner struct {
  16. runner.TempDirRunner
  17. }
  18. //go:embed prescript.js
  19. var nodejs_sandbox_fs []byte
  20. //go:embed nodejs.so
  21. var nodejs_lib []byte
  22. //go:embed dependens
  23. var nodejs_dependens embed.FS // it's a directory
  24. func init() {
  25. log.Info("initializing nodejs runner environment...")
  26. os.RemoveAll("/tmp/sandbox-nodejs")
  27. os.Remove("/tmp/sandbox-nodejs")
  28. err := os.MkdirAll("/tmp/sandbox-nodejs", 0755)
  29. if err != nil {
  30. log.Panic("failed to create /tmp/sandbox-nodejs")
  31. }
  32. err = os.WriteFile("/tmp/sandbox-nodejs/nodejs.so", nodejs_lib, 0755)
  33. if err != nil {
  34. log.Panic("failed to write /tmp/sandbox-nodejs/nodejs.so")
  35. }
  36. // remove /tmp/sandbox-nodejs-project
  37. os.RemoveAll("/tmp/sandbox-nodejs-project")
  38. os.Remove("/tmp/sandbox-nodejs-project")
  39. // copy the nodejs project into /tmp/sandbox-nodejs-project
  40. err = os.MkdirAll("/tmp/sandbox-nodejs-project", 0755)
  41. if err != nil {
  42. log.Panic("failed to create /tmp/sandbox-nodejs-project")
  43. }
  44. // copy the nodejs project into /tmp/sandbox-nodejs-project
  45. var recursively_copy func(src string, dst string) error
  46. recursively_copy = func(src string, dst string) error {
  47. entries, err := nodejs_dependens.ReadDir(src)
  48. if err != nil {
  49. return err
  50. }
  51. for _, entry := range entries {
  52. src_path := src + "/" + entry.Name()
  53. dst_path := dst + "/" + entry.Name()
  54. if entry.IsDir() {
  55. err = os.Mkdir(dst_path, 0755)
  56. if err != nil {
  57. return err
  58. }
  59. err = recursively_copy(src_path, dst_path)
  60. if err != nil {
  61. return err
  62. }
  63. } else {
  64. data, err := nodejs_dependens.ReadFile(src_path)
  65. if err != nil {
  66. return err
  67. }
  68. err = os.WriteFile(dst_path, data, 0755)
  69. if err != nil {
  70. return err
  71. }
  72. }
  73. }
  74. return nil
  75. }
  76. err = recursively_copy("dependens", "/tmp/sandbox-nodejs-project")
  77. if err != nil {
  78. log.Panic("failed to copy nodejs project")
  79. }
  80. log.Info("nodejs runner environment initialized")
  81. }
  82. var (
  83. NODEJS_REQUIRED_FS = []string{
  84. "/tmp/sandbox-nodejs-project/node_temp",
  85. "/tmp/sandbox-nodejs/nodejs.so",
  86. "/etc/ssl/certs/ca-certificates.crt",
  87. "/etc/nsswitch.conf",
  88. "/etc/resolv.conf",
  89. "/run/systemd/resolve/stub-resolv.conf",
  90. "/etc/hosts",
  91. }
  92. )
  93. func (p *NodeJsRunner) Run(
  94. code string,
  95. timeout time.Duration,
  96. stdin []byte,
  97. preload string,
  98. options *types.RunnerOptions,
  99. ) (chan []byte, chan []byte, chan bool, error) {
  100. // capture the output
  101. output_handler := runner.NewOutputCaptureRunner()
  102. output_handler.SetTimeout(timeout)
  103. err := p.WithTempDir(NODEJS_REQUIRED_FS, func(root_path string) error {
  104. output_handler.SetAfterExitHook(func() {
  105. os.RemoveAll(root_path)
  106. os.Remove(root_path)
  107. })
  108. // initialize the environment
  109. script_path, err := p.InitializeEnvironment(code, preload, root_path)
  110. if err != nil {
  111. return err
  112. }
  113. // create a new process
  114. cmd := exec.Command(
  115. static.GetDifySandboxGlobalConfigurations().NodejsPath,
  116. script_path,
  117. strconv.Itoa(static.SANDBOX_USER_UID),
  118. strconv.Itoa(static.SANDBOX_GROUP_ID),
  119. options.Json(),
  120. )
  121. cmd.Env = []string{}
  122. // capture the output
  123. err = output_handler.CaptureOutput(cmd)
  124. if err != nil {
  125. return err
  126. }
  127. return nil
  128. })
  129. if err != nil {
  130. return nil, nil, nil, err
  131. }
  132. return output_handler.GetStdout(), output_handler.GetStderr(), output_handler.GetDone(), nil
  133. }
  134. func (p *NodeJsRunner) InitializeEnvironment(code string, preload string, root_path string) (string, error) {
  135. node_sandbox_file := string(nodejs_sandbox_fs)
  136. if preload != "" {
  137. node_sandbox_file = fmt.Sprintf("%s\n%s", preload, node_sandbox_file)
  138. }
  139. // join nodejs_sandbox_fs and code
  140. code = node_sandbox_file + code
  141. // override root_path/tmp/sandbox-nodejs-project/prescript.js
  142. script_path := path.Join(root_path, "tmp/sandbox-nodejs-project/node_temp/node_temp/test.js")
  143. err := os.WriteFile(script_path, []byte(code), 0755)
  144. if err != nil {
  145. return "", err
  146. }
  147. return script_path, nil
  148. }