router.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package bokofs
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "time"
  10. "golang.org/x/net/webdav"
  11. "imuslab.com/bokofs/bokofsd/mod/bokofs/bokoworker"
  12. )
  13. type RootRouter struct {
  14. pathPrefix string
  15. routerType RouterType
  16. parent *Server
  17. }
  18. type RouterType int
  19. const (
  20. RouterType_FS RouterType = iota
  21. RouterType_Thumb
  22. )
  23. type RouterDirHandler interface {
  24. Mkdir(ctx context.Context, name string, perm os.FileMode) error
  25. OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error)
  26. RemoveAll(ctx context.Context, name string) error
  27. Rename(ctx context.Context, oldName, newName string) error
  28. Stat(ctx context.Context, name string) (os.FileInfo, error)
  29. }
  30. // RootRouter implements the webdav.FileSystem interface
  31. // It serves as the root of the file system, routing requests to the appropriate worker
  32. func NewRootRouter(p *Server, prefix string, rType RouterType) (*RootRouter, error) {
  33. return &RootRouter{
  34. pathPrefix: prefix,
  35. routerType: rType,
  36. parent: p,
  37. }, nil
  38. }
  39. /*
  40. Router Internal Implementation
  41. */
  42. // fixpath fix the path to be relative to the root path of this router
  43. func (r *RootRouter) fixpath(name string) string {
  44. if name == r.pathPrefix || name == "" {
  45. return "/"
  46. }
  47. //Trim off the prefix path
  48. name = strings.TrimPrefix(name, r.pathPrefix)
  49. if !strings.HasPrefix(name, "/") {
  50. name = "/" + name
  51. }
  52. return name
  53. }
  54. // getRootDir returns the root directory of the request
  55. func (r *RootRouter) getRootDir(name string) string {
  56. if name == "" || name == "/" {
  57. return "/"
  58. }
  59. name = filepath.ToSlash(filepath.Clean(name))
  60. pathChunks := strings.Split(name, "/")
  61. reqRootPath := "/" + pathChunks[1]
  62. fmt.Println("Requesting Root Path: ", reqRootPath)
  63. name = strings.TrimSuffix(reqRootPath, "/")
  64. return name
  65. }
  66. // GetFileSystemFromWorker returns the file system from the worker
  67. func (r *RootRouter) getWorkerByPath(name string) (*bokoworker.Worker, error) {
  68. reqRootPath := r.getRootDir(name)
  69. targetWorker, ok := r.parent.LoadedWorkers.Load(reqRootPath)
  70. if !ok {
  71. return nil, os.ErrNotExist
  72. }
  73. return targetWorker.(*bokoworker.Worker), nil
  74. }
  75. // getFileSystemFromWorker returns the file system from the worker
  76. func (r *RootRouter) getFileSystemFromWorker(worker *bokoworker.Worker) (RouterDirHandler, error) {
  77. if r.routerType == RouterType_FS {
  78. return worker.Filesystem, nil
  79. } else if r.routerType == RouterType_Thumb {
  80. return worker.Thumbnails, nil
  81. }
  82. return nil, errors.New("Invalid router type")
  83. }
  84. /*
  85. WebDAV FileSystem Interface Implementation
  86. */
  87. func (r *RootRouter) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
  88. // Implement the Mkdir method
  89. name = r.fixpath(name)
  90. fmt.Println("Mkdir called to " + name)
  91. return nil
  92. }
  93. func (r *RootRouter) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
  94. // Implement the OpenFile method
  95. name = r.fixpath(name)
  96. fmt.Println("OpenFile called to " + name)
  97. if filepath.ToSlash(filepath.Base(name)) == "/" {
  98. //Request to the vObject base path
  99. thisVirtualObject := r.newVirtualObject(&vObjectProperties{
  100. name: name,
  101. size: 0,
  102. mode: os.ModeDir,
  103. modTime: time.Now(),
  104. isDir: true,
  105. })
  106. return thisVirtualObject, nil
  107. }
  108. targetWorker, err := r.getWorkerByPath(name)
  109. if err != nil {
  110. return nil, err
  111. }
  112. targetFileSystem, err := r.getFileSystemFromWorker(targetWorker)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return targetFileSystem.OpenFile(ctx, name, flag, perm)
  117. }
  118. func (r *RootRouter) RemoveAll(ctx context.Context, name string) error {
  119. // Implement the RemoveAll method
  120. name = r.fixpath(name)
  121. fmt.Println("RemoveAll called to " + name)
  122. return nil
  123. }
  124. func (r *RootRouter) Rename(ctx context.Context, oldName, newName string) error {
  125. // Implement the Rename method
  126. oldName = r.fixpath(oldName)
  127. newName = r.fixpath(newName)
  128. fmt.Println("Rename called from " + oldName + " to " + newName)
  129. return nil
  130. }
  131. func (r *RootRouter) Stat(ctx context.Context, name string) (os.FileInfo, error) {
  132. // Implement the Stat method
  133. name = r.fixpath(name)
  134. fmt.Println("Stat called to " + name)
  135. if filepath.ToSlash(filepath.Base(name)) == "/" {
  136. //Create an emulated file system to serve the mounted workers
  137. thisVirtualObject := r.newVirtualObject(&vObjectProperties{
  138. name: name,
  139. size: 0,
  140. mode: os.ModeDir,
  141. modTime: time.Now(),
  142. isDir: true,
  143. })
  144. thisVirtualObjectFileInfo := thisVirtualObject.GetFileInfo()
  145. return thisVirtualObjectFileInfo, nil
  146. }
  147. //Load the target worker from the path
  148. targetWorker, err := r.getWorkerByPath(name)
  149. fmt.Println("Target Worker: ", targetWorker, name)
  150. if err != nil {
  151. return nil, err
  152. }
  153. targetFileSystem, err := r.getFileSystemFromWorker(targetWorker)
  154. if err != nil {
  155. return nil, err
  156. }
  157. return targetFileSystem.Stat(ctx, name)
  158. }
  159. // Ensure RootRouter implements the FileSystem interface
  160. var _ webdav.FileSystem = (*RootRouter)(nil)