core.go 3.3 KB

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