shareEntry.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package shareEntry
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "path/filepath"
  7. "strings"
  8. "sync"
  9. uuid "github.com/satori/go.uuid"
  10. "imuslab.com/arozos/mod/database"
  11. "imuslab.com/arozos/mod/filesystem"
  12. fs "imuslab.com/arozos/mod/filesystem"
  13. )
  14. /*
  15. Share Entry
  16. This module is designed to isolate the entry operatiosn with the
  17. handle operations so as to reduce the complexity of recursive import
  18. during development
  19. */
  20. type ShareEntryTable struct {
  21. FileToUrlMap *sync.Map
  22. UrlToFileMap *sync.Map
  23. Database *database.Database
  24. }
  25. type ShareOption struct {
  26. UUID string
  27. FileRealPath string
  28. Owner string
  29. Accessibles []string //Use to store username or group names if permission is groups or users
  30. Permission string //Access permission, allow {anyone / signedin / samegroup / groups / users}
  31. AllowLivePreview bool
  32. }
  33. func NewShareEntryTable(db *database.Database) *ShareEntryTable {
  34. //Create the share table if not exists
  35. db.NewTable("share")
  36. FileToUrlMap := sync.Map{}
  37. UrlToFileMap := sync.Map{}
  38. //Load the old share links
  39. entries, _ := db.ListTable("share")
  40. for _, keypairs := range entries {
  41. shareObject := new(ShareOption)
  42. json.Unmarshal(keypairs[1], &shareObject)
  43. if shareObject != nil {
  44. //Append this to the maps
  45. FileToUrlMap.Store(shareObject.FileRealPath, shareObject)
  46. UrlToFileMap.Store(shareObject.UUID, shareObject)
  47. }
  48. }
  49. return &ShareEntryTable{
  50. FileToUrlMap: &FileToUrlMap,
  51. UrlToFileMap: &UrlToFileMap,
  52. Database: db,
  53. }
  54. }
  55. func (s *ShareEntryTable) CreateNewShare(rpath string, username string, usergroups []string) (*ShareOption, error) {
  56. rpath = filepath.ToSlash(filepath.Clean(rpath))
  57. //Check if source file exists
  58. if !fs.FileExists(rpath) {
  59. return nil, errors.New("Unable to find the file on disk")
  60. }
  61. //Check if the share already exists. If yes, use the previous link
  62. val, ok := s.FileToUrlMap.Load(rpath)
  63. if ok {
  64. //Exists. Send back the old share url
  65. ShareOption := val.(*ShareOption)
  66. return ShareOption, nil
  67. } else {
  68. //Create new link for this file
  69. shareUUID := uuid.NewV4().String()
  70. //Create a share object
  71. shareOption := ShareOption{
  72. UUID: shareUUID,
  73. FileRealPath: rpath,
  74. Owner: username,
  75. Accessibles: usergroups,
  76. Permission: "anyone",
  77. AllowLivePreview: true,
  78. }
  79. //Store results on two map to make sure O(1) Lookup time
  80. s.FileToUrlMap.Store(rpath, &shareOption)
  81. s.UrlToFileMap.Store(shareUUID, &shareOption)
  82. //Write object to database
  83. s.Database.Write("share", shareUUID, shareOption)
  84. return &shareOption, nil
  85. }
  86. }
  87. //Delete the share on this vpath
  88. func (s *ShareEntryTable) DeleteShare(rpath string) error {
  89. rpath = filepath.ToSlash(filepath.Clean(rpath))
  90. //Check if the share already exists. If yes, use the previous link
  91. val, ok := s.FileToUrlMap.Load(rpath)
  92. if ok {
  93. //Exists. Send back the old share url
  94. uuid := val.(*ShareOption).UUID
  95. //Remove this from the database
  96. err := s.Database.Delete("share", uuid)
  97. if err != nil {
  98. return err
  99. }
  100. //Remove this form the current sync map
  101. s.UrlToFileMap.Delete(uuid)
  102. s.FileToUrlMap.Delete(rpath)
  103. return nil
  104. } else {
  105. //Already deleted from buffered record.
  106. return nil
  107. }
  108. }
  109. func (s *ShareEntryTable) GetShareUUIDFromPath(rpath string) string {
  110. targetShareObject := s.GetShareObjectFromRealPath(rpath)
  111. if (targetShareObject) != nil {
  112. return targetShareObject.UUID
  113. }
  114. return ""
  115. }
  116. func (s *ShareEntryTable) GetShareObjectFromRealPath(rpath string) *ShareOption {
  117. rpath = filepath.ToSlash(filepath.Clean(rpath))
  118. var targetShareOption *ShareOption
  119. s.FileToUrlMap.Range(func(k, v interface{}) bool {
  120. filePath := k.(string)
  121. shareObject := v.(*ShareOption)
  122. if filepath.ToSlash(filepath.Clean(filePath)) == rpath {
  123. targetShareOption = shareObject
  124. }
  125. return true
  126. })
  127. return targetShareOption
  128. }
  129. func (s *ShareEntryTable) GetShareObjectFromUUID(uuid string) *ShareOption {
  130. var targetShareOption *ShareOption
  131. s.UrlToFileMap.Range(func(k, v interface{}) bool {
  132. thisUuid := k.(string)
  133. shareObject := v.(*ShareOption)
  134. if thisUuid == uuid {
  135. targetShareOption = shareObject
  136. }
  137. return true
  138. })
  139. return targetShareOption
  140. }
  141. func (s *ShareEntryTable) FileIsShared(rpath string) bool {
  142. shareUUID := s.GetShareUUIDFromPath(rpath)
  143. return shareUUID != ""
  144. }
  145. func (s *ShareEntryTable) RemoveShareByRealpath(rpath string) error {
  146. so, ok := s.FileToUrlMap.Load(rpath)
  147. if ok {
  148. shareUUID := so.(*ShareOption).UUID
  149. s.UrlToFileMap.Delete(shareUUID)
  150. s.FileToUrlMap.Delete(rpath)
  151. s.Database.Delete("share", shareUUID)
  152. } else {
  153. return errors.New("Share with given realpath not exists")
  154. }
  155. return nil
  156. }
  157. func (s *ShareEntryTable) RemoveShareByUUID(uuid string) error {
  158. so, ok := s.UrlToFileMap.Load(uuid)
  159. if ok {
  160. s.FileToUrlMap.Delete(so.(*ShareOption).FileRealPath)
  161. s.UrlToFileMap.Delete(uuid)
  162. s.Database.Delete("share", uuid)
  163. } else {
  164. return errors.New("Share with given uuid not exists")
  165. }
  166. return nil
  167. }
  168. func (s *ShareEntryTable) ResolveShareOptionFromVpath(vpath string) (*ShareOption, error) {
  169. vrootID, subpath, err := filesystem.GetIDFromVirtualPath(vpath)
  170. if err != nil {
  171. return nil, errors.New("Unable to resolve virtual path")
  172. }
  173. if vrootID != "share" {
  174. return nil, errors.New("Given path is not share vroot path")
  175. }
  176. return s.ResolveShareOptionFromShareSubpath(subpath)
  177. }
  178. func (s *ShareEntryTable) ResolveShareOptionFromShareSubpath(subpath string) (*ShareOption, error) {
  179. subpathElements := strings.Split(filepath.ToSlash(filepath.Clean(subpath))[1:], "/")
  180. if len(subpathElements) >= 1 {
  181. shareObject := s.GetShareObjectFromUUID(subpathElements[0])
  182. if shareObject == nil {
  183. return nil, errors.New("Invalid subpath")
  184. } else {
  185. return shareObject, nil
  186. }
  187. } else {
  188. return nil, errors.New("Invalid subpath")
  189. }
  190. }
  191. func (s *ShareEntryTable) ResolveShareVrootPath(subpath string, username string, usergroup []string) (string, error) {
  192. //Get a list of accessible files from this user
  193. subpathElements := strings.Split(filepath.ToSlash(filepath.Clean(subpath))[1:], "/")
  194. if len(subpathElements) == 0 {
  195. //Requesting root folder.
  196. return "", errors.New("This virtual file system router do not support root listing")
  197. }
  198. //Analysis the subpath elements
  199. if len(subpathElements) == 1 {
  200. return "", errors.New("Redirect: parent")
  201. } else if len(subpathElements) == 2 {
  202. //ID only or ID with the target filename
  203. shareObject := s.GetShareObjectFromUUID(subpathElements[0])
  204. if shareObject == nil {
  205. return "", errors.New("Share file not found")
  206. }
  207. return shareObject.FileRealPath, nil
  208. } else if len(subpathElements) > 2 {
  209. //Loading folder / files inside folder type shares
  210. shareObject := s.GetShareObjectFromUUID(subpathElements[0])
  211. folderSubpaths := append([]string{shareObject.FileRealPath}, subpathElements[2:]...)
  212. targetFolder := filepath.Join(folderSubpaths...)
  213. return targetFolder, nil
  214. }
  215. return "", errors.New("Not implemented")
  216. }
  217. func (s *ShareEntryTable) RouteShareVroot(subpath string, username string, usergroup []string) ([]fs.FileData, error) {
  218. if subpath == "" {
  219. return s.listRootForUser(username, usergroup), nil
  220. } else {
  221. log.Println("Checkpoint!", subpath)
  222. return []fs.FileData{}, nil
  223. }
  224. }
  225. func (s *ShareEntryTable) listRootForUser(username string, usergroup []string) []fs.FileData {
  226. //Iterate through all shares in the system to see which of the share is user accessible
  227. userAccessiableShare := []*ShareOption{}
  228. s.FileToUrlMap.Range(func(fp, so interface{}) bool {
  229. fileRealpath := fp.(string)
  230. thisShareOption := so.(*ShareOption)
  231. if fs.FileExists(fileRealpath) {
  232. if thisShareOption.IsAccessibleBy(username, usergroup) {
  233. userAccessiableShare = append(userAccessiableShare, thisShareOption)
  234. }
  235. }
  236. return true
  237. })
  238. results := []fs.FileData{}
  239. for _, thisShareObject := range userAccessiableShare {
  240. rpath := thisShareObject.FileRealPath
  241. thisFile := fs.GetFileDataFromPath("share:/"+thisShareObject.UUID+"/"+filepath.Base(rpath), rpath, 2)
  242. if thisShareObject.Owner == username {
  243. thisFile.IsShared = true
  244. }
  245. results = append(results, thisFile)
  246. }
  247. return results
  248. }