|
|
|
@ -89,6 +89,18 @@ func (f *Functionality) DownloadFile(profile peer.CwtchPeer, conversationID int,
|
|
|
|
|
profile.SendScopedZonedGetValToContact(conversationID, attr.ConversationScope, attr.FilesharingZone, fmt.Sprintf("%s.manifest.size", key))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RestartFileShare takes in an existing filekey and, assuming the manifest exists, restarts sharing of the manifest
|
|
|
|
|
func (f *Functionality) RestartFileShare(profile peer.CwtchPeer, filekey string) error {
|
|
|
|
|
// check that a manifest exists
|
|
|
|
|
manifest, manifestExists := profile.GetScopedZonedAttribute(attr.ConversationScope, attr.FilesharingZone, fmt.Sprintf("%s.manifest", filekey))
|
|
|
|
|
if manifestExists {
|
|
|
|
|
// everything is in order, so reshare this file with the engine
|
|
|
|
|
profile.ShareFile(filekey, manifest)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return fmt.Errorf("manifest does not exist for filekey: %v", filekey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ReShareFiles given a profile we iterate through all existing fileshares and re-share them
|
|
|
|
|
// if the time limit has not expired
|
|
|
|
|
func (f *Functionality) ReShareFiles(profile peer.CwtchPeer) error {
|
|
|
|
@ -109,34 +121,14 @@ func (f *Functionality) ReShareFiles(profile peer.CwtchPeer) error {
|
|
|
|
|
if len(keyparts) == 3 && keyparts[2] == "ts" {
|
|
|
|
|
// fetch the timestamp key
|
|
|
|
|
filekey := strings.Join(keyparts[:2], ".")
|
|
|
|
|
timestampString, tsExists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.ts", filekey))
|
|
|
|
|
|
|
|
|
|
// assert that the timestamp actually exists
|
|
|
|
|
if !tsExists {
|
|
|
|
|
log.Errorf("could not find expected timestamp for %v", filekey)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assert this is an actual timestamp
|
|
|
|
|
timestamp, err := strconv.Atoi(timestampString)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Errorf("error parsing timestamp for %v: %v", filekey, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dateShared := time.Unix(int64(timestamp), 0)
|
|
|
|
|
if time.Since(dateShared) > time.Hour*24*30 {
|
|
|
|
|
log.Debugf("ignored expired file share for %v", filekey)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
sharedFile, err := f.GetFileShareInfo(profile, filekey)
|
|
|
|
|
|
|
|
|
|
// If we haven't explicitly stopped sharing the file AND
|
|
|
|
|
// If fewer than 30 days have passed since we originally shared this file,
|
|
|
|
|
// then attempt to share this file again...
|
|
|
|
|
// Then attempt to share this file again...
|
|
|
|
|
// TODO: In the future this would be the point to change the timestamp and reshare the file...
|
|
|
|
|
manifest, manifestExists := profile.GetScopedZonedAttribute(attr.ConversationScope, attr.FilesharingZone, fmt.Sprintf("%s.manifest", filekey))
|
|
|
|
|
if manifestExists {
|
|
|
|
|
// everything is in order, so reshare this file with the engine
|
|
|
|
|
profile.ShareFile(filekey, manifest)
|
|
|
|
|
if err == nil && sharedFile.Active {
|
|
|
|
|
f.RestartFileShare(profile, filekey)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -144,6 +136,31 @@ func (f *Functionality) ReShareFiles(profile peer.CwtchPeer) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetFileShareInfo returns information related to a known fileshare.
|
|
|
|
|
// An error is returned if the data is incomplete
|
|
|
|
|
func (f *Functionality) GetFileShareInfo(profile peer.CwtchPeer, filekey string) (*SharedFile, error) {
|
|
|
|
|
timestampString, tsExists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.ts", filekey))
|
|
|
|
|
pathString, pathExists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", filekey))
|
|
|
|
|
activeString, activeExists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.active", filekey))
|
|
|
|
|
if tsExists && pathExists && activeExists {
|
|
|
|
|
timestamp, err := strconv.Atoi(timestampString)
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
|
|
dateShared := time.Unix(int64(timestamp), 0)
|
|
|
|
|
expired := time.Since(dateShared) >= time.Hour*24*30
|
|
|
|
|
|
|
|
|
|
return &SharedFile{
|
|
|
|
|
FileKey: filekey,
|
|
|
|
|
Path: pathString,
|
|
|
|
|
DateShared: dateShared,
|
|
|
|
|
Active: !expired && activeString == constants.True,
|
|
|
|
|
Expired: expired,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("nonexistant or malformed fileshare %v", filekey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ShareFile given a profile and a conversation handle, sets up a file sharing process to share the file
|
|
|
|
|
// at filepath
|
|
|
|
|
func (f *Functionality) ShareFile(filepath string, profile peer.CwtchPeer) (string, string, error) {
|
|
|
|
@ -199,6 +216,50 @@ func (f *Functionality) ShareFile(filepath string, profile peer.CwtchPeer) (stri
|
|
|
|
|
return key, string(wrapperJSON), err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SharedFile encapsulates information about a shared file
|
|
|
|
|
// including the file key, file path, the original share date and the
|
|
|
|
|
// current sharing status
|
|
|
|
|
type SharedFile struct {
|
|
|
|
|
|
|
|
|
|
// The roothash.nonce identifier derived for this file share
|
|
|
|
|
FileKey string
|
|
|
|
|
|
|
|
|
|
// Path is the OS specific location of the file
|
|
|
|
|
Path string
|
|
|
|
|
|
|
|
|
|
// DateShared is the original datetime the file was shared
|
|
|
|
|
DateShared time.Time
|
|
|
|
|
|
|
|
|
|
// Active is true if the file is currently being shared, false otherwise
|
|
|
|
|
Active bool
|
|
|
|
|
|
|
|
|
|
// Expired is true if the file is not eligible to be shared (because e.g. it has been too long since the file was originally shared,
|
|
|
|
|
// or the file no longer exists).
|
|
|
|
|
Expired bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetSharedFiles returns all file shares associated with a given conversation
|
|
|
|
|
func (f *Functionality) GetSharedFiles(profile peer.CwtchPeer, conversationID int) []SharedFile {
|
|
|
|
|
sharedFiles := []SharedFile{}
|
|
|
|
|
ci, err := profile.GetConversationInfo(conversationID)
|
|
|
|
|
if err == nil {
|
|
|
|
|
for k := range ci.Attributes {
|
|
|
|
|
// when we share a file with a conversation we set a single attribute conversation.filesharing.<filekey>
|
|
|
|
|
if strings.HasPrefix(k, "conversation.filesharing") {
|
|
|
|
|
parts := strings.SplitN(k, ".", 3)
|
|
|
|
|
if len(parts) == 3 {
|
|
|
|
|
key := parts[2]
|
|
|
|
|
sharedFile, err := f.GetFileShareInfo(profile, key)
|
|
|
|
|
if err == nil {
|
|
|
|
|
sharedFiles = append(sharedFiles, *sharedFile)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return sharedFiles
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateDownloadPath creates a file path that doesn't currently exist on the filesystem
|
|
|
|
|
func GenerateDownloadPath(basePath, fileName string, overwrite bool) (filePath, manifestPath string) {
|
|
|
|
|
// avoid all kina funky shit
|
|
|
|
|