fs.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package decoder
  2. import (
  3. "errors"
  4. "io"
  5. "io/fs"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  10. )
  11. var (
  12. ErrNotDir = errors.New("not a directory")
  13. )
  14. type FSPluginDecoder struct {
  15. PluginDecoder
  16. PluginDecoderHelper
  17. // root directory of the plugin
  18. root string
  19. fs fs.FS
  20. }
  21. func NewFSPluginDecoder(root string) (*FSPluginDecoder, error) {
  22. decoder := &FSPluginDecoder{
  23. root: root,
  24. }
  25. err := decoder.Open()
  26. if err != nil {
  27. return nil, err
  28. }
  29. // read the manifest file
  30. if _, err := decoder.Manifest(); err != nil {
  31. return nil, err
  32. }
  33. return decoder, nil
  34. }
  35. func (d *FSPluginDecoder) Open() error {
  36. d.fs = os.DirFS(d.root)
  37. // try to stat the root directory
  38. s, err := os.Stat(d.root)
  39. if err != nil {
  40. return err
  41. }
  42. if !s.IsDir() {
  43. return ErrNotDir
  44. }
  45. return nil
  46. }
  47. func (d *FSPluginDecoder) Walk(fn func(filename string, dir string) error) error {
  48. return filepath.Walk(d.root, func(path string, info fs.FileInfo, err error) error {
  49. if info.IsDir() {
  50. return nil
  51. }
  52. // trim the first directory path
  53. path = strings.TrimPrefix(path, d.root)
  54. // trim / from the beginning
  55. path = strings.TrimPrefix(path, "/")
  56. if path == "" {
  57. return nil
  58. }
  59. if err != nil {
  60. return err
  61. }
  62. return fn(info.Name(), filepath.Dir(path))
  63. })
  64. }
  65. func (d *FSPluginDecoder) Close() error {
  66. return nil
  67. }
  68. func (d *FSPluginDecoder) Stat(filename string) (fs.FileInfo, error) {
  69. return os.Stat(filepath.Join(d.root, filename))
  70. }
  71. func (d *FSPluginDecoder) ReadFile(filename string) ([]byte, error) {
  72. return os.ReadFile(filepath.Join(d.root, filename))
  73. }
  74. func (d *FSPluginDecoder) ReadDir(dirname string) ([]string, error) {
  75. var files []string
  76. err := filepath.WalkDir(
  77. filepath.Join(d.root, dirname),
  78. func(path string, info fs.DirEntry, err error) error {
  79. if err != nil {
  80. return err
  81. }
  82. if !info.IsDir() {
  83. rel_path, err := filepath.Rel(d.root, path)
  84. if err != nil {
  85. return err
  86. }
  87. files = append(files, rel_path)
  88. }
  89. return nil
  90. },
  91. )
  92. if err != nil {
  93. return nil, err
  94. }
  95. return files, nil
  96. }
  97. func (d *FSPluginDecoder) FileReader(filename string) (io.ReadCloser, error) {
  98. return os.Open(filepath.Join(d.root, filename))
  99. }
  100. func (d *FSPluginDecoder) Signature() (string, error) {
  101. return "", nil
  102. }
  103. func (d *FSPluginDecoder) CreateTime() (int64, error) {
  104. return 0, nil
  105. }
  106. func (d *FSPluginDecoder) Manifest() (plugin_entities.PluginDeclaration, error) {
  107. return d.PluginDecoderHelper.Manifest(d)
  108. }
  109. func (d *FSPluginDecoder) Assets() (map[string][]byte, error) {
  110. return d.PluginDecoderHelper.Assets(d)
  111. }