core.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package core
  2. import (
  3. "context"
  4. "flag"
  5. "os"
  6. "os/signal"
  7. "os/user"
  8. "path/filepath"
  9. "runtime"
  10. "strconv"
  11. "syscall"
  12. "time"
  13. "dev.hexasoftware.com/hxs/prettylog"
  14. "github.com/jacobsa/fuse"
  15. "github.com/jacobsa/fuse/fuseutil"
  16. )
  17. var (
  18. log = prettylog.New("cloudmount")
  19. )
  20. // Core struct
  21. type Core struct {
  22. Config Config
  23. Drivers map[string]DriverFactory
  24. CurrentFS DriverFS
  25. }
  26. // New create a New cloudmount core
  27. func New() *Core {
  28. // TODO: friendly panics
  29. usr, err := user.Current()
  30. if err != nil {
  31. panic(err)
  32. }
  33. uid, err := strconv.Atoi(usr.Uid)
  34. if err != nil {
  35. panic(err)
  36. }
  37. gid, err := strconv.Atoi(usr.Gid)
  38. if err != nil {
  39. panic(gid)
  40. }
  41. return &Core{
  42. Drivers: map[string]DriverFactory{},
  43. Config: Config{
  44. Daemonize: false,
  45. Type: "gdrive",
  46. VerboseLog: false,
  47. RefreshTime: 5 * time.Second,
  48. HomeDir: filepath.Join(usr.HomeDir, ".cloudmount"),
  49. Source: filepath.Join(usr.HomeDir, ".cloudmount", "gdrive.json"),
  50. UID: uint32(uid),
  51. GID: uint32(gid),
  52. },
  53. }
  54. }
  55. // Init to be run after configuration
  56. func (c *Core) Init() (err error) {
  57. fsFactory, ok := c.Drivers[c.Config.Type]
  58. if !ok {
  59. log.Fatal("CloudFS not supported")
  60. }
  61. c.CurrentFS = fsFactory(c) // Factory
  62. return
  63. }
  64. func (c *Core) Mount() {
  65. // Start Selected driveFS
  66. c.CurrentFS.Start() // Should not block
  67. //////////////
  68. // Server
  69. /////////
  70. ctx := context.Background()
  71. server := fuseutil.NewFileSystemServer(c.CurrentFS)
  72. mountPath := c.Config.Target
  73. var err error
  74. var mfs *fuse.MountedFileSystem
  75. if c.Config.VerboseLog {
  76. mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{DebugLogger: prettylog.New("fuse"), ErrorLogger: prettylog.New("fuse-err")})
  77. } else {
  78. mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{})
  79. }
  80. if err != nil {
  81. log.Fatal("Failed mounting path", flag.Arg(0), err)
  82. }
  83. // Signal handling to refresh Drives
  84. sigs := make(chan os.Signal, 2)
  85. signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGHUP, syscall.SIGINT, os.Interrupt, syscall.SIGTERM)
  86. go func() {
  87. for sig := range sigs {
  88. log.Println("Signal:", sig)
  89. switch sig {
  90. //case syscall.SIGUSR1:
  91. //log.Println("Manually Refresh drive")
  92. //go c.CurrentFS.Refresh()
  93. case syscall.SIGHUP:
  94. log.Println("GC")
  95. mem := runtime.MemStats{}
  96. runtime.ReadMemStats(&mem)
  97. log.Printf("Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
  98. runtime.GC()
  99. runtime.ReadMemStats(&mem)
  100. log.Printf("After gc: Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
  101. case os.Interrupt:
  102. log.Println("Graceful unmount")
  103. fuse.Unmount(mountPath)
  104. os.Exit(1)
  105. case syscall.SIGTERM:
  106. log.Println("Graceful unmount")
  107. fuse.Unmount(mountPath)
  108. os.Exit(1)
  109. }
  110. }
  111. }()
  112. if err := mfs.Join(ctx); err != nil {
  113. log.Fatalf("Joining: %v", err)
  114. }
  115. }