core.go 2.6 KB

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