-
Notifications
You must be signed in to change notification settings - Fork 1
/
new_file_save.go
213 lines (176 loc) · 5.54 KB
/
new_file_save.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package gofm
import (
"errors"
"github.com/google/uuid"
"github.com/kyaxcorp/gofile/driver"
"github.com/kyaxcorp/gofile/driver/filesystem"
"github.com/kyaxcorp/gofile/driver/filesystem/helper"
"path/filepath"
"reflect"
)
/*
We should have functions that:
- Allow us to read and save a file in chunks, the reading will not be performed instantly in the memory, but it will be read
in chunks... and also save in chunks!
- Allow us to save files from memory
*/
// Save -> saves the input file to the location (destination)
func (f *NewFile) Save() error {
fileModelVal := reflect.ValueOf(f.FileModel)
// first of all, check if the FileModel is a pointer of a struct!
if fileModelVal.Kind() != reflect.Ptr {
return ErrFileModelShouldBePointerOfAStruct
}
fieldModelIndirect := reflect.Indirect(fileModelVal)
currentLocation := filesystem.Location{DirPath: ""}
var fileMetaData driver.FileInfoInterface
var srcFile driver.FileInterface
var _err error
if f.InputFilePath != "" {
//log.Println(f.InputFilePath)
srcFile, _err = currentLocation.FindFile(f.InputFilePath)
} else if f.GraphQLFile != nil {
// save to a tmp path and then delete it
graphFile := f.GraphQLFile
fileData := make([]byte, graphFile.Size)
// Read the file, ano now let's save it
_, _err = graphFile.File.Read(fileData)
if _err != nil {
return _err
}
// Generate a random folder id (name)
tmpFileFullPath, _err := generateTmpFile(temporaryFileOptions{
FileName: graphFile.Filename,
FileData: fileData,
})
if _err != nil {
return _err
}
defer helper.FolderDelete(filepath.Dir(tmpFileFullPath))
srcFile, _err = currentLocation.FindFile(tmpFileFullPath)
} else {
return ErrFmNoInputFile
}
if _err != nil {
return _err
}
fileMetaData = srcFile.Info()
/*fileMetaData, _err := filesystem.NewFileInfo(f.InputFilePath)
if _err != nil {
return nil, _err
}*/
updatedAt := fileMetaData.UpdatedAt()
createdAt := fileMetaData.CreatedAt()
if !structFieldExists(fieldModelIndirect, "Name") {
return errors.New("field Name doesn't exist in the file model")
}
fileName := fileMetaData.Name()
// Check if the user has set any value for Name
nameVal := fieldModelIndirect.FieldByName("Name").String()
if nameVal != "" {
fileName = nameVal
}
// Set Name
/*_err = structSetFieldVal(fieldModelIndirect, "Name", fileName)
if _err != nil {
return _err
}*/
// Generate a new file id
id, _err := uuid.NewRandom()
if _err != nil {
return _err
}
//_err = structSetFieldVal(fieldModelIndirect, "ID", UUID(id))
//if _err != nil {
// return _err
//}
structValues := map[string]interface{}{
"ID": UUID(id),
"FMInstance": f.fileManager.Name,
"Name": fileName,
"FullName": fileMetaData.FullName(),
"OriginalName": fileMetaData.FullName(),
"Size": fileMetaData.Size(),
"Extension": fileMetaData.Extension(),
"ContentType": fileMetaData.ContentType(),
"FileUpdatedAt": &updatedAt,
"FileCreatedAt": &createdAt,
}
// Set struct values
for fieldName, fieldVal := range structValues {
_err = structSetFieldVal(fieldModelIndirect, fieldName, fieldVal)
if _err != nil {
return _err
}
}
// Set file manager
if _model, ok := f.FileModel.(interface{ SetFileManager(fm *FileManager) }); ok {
_model.SetFileManager(f.fileManager)
}
// TODO: call SetFileManager
/*file := &File{
ID: UUID(id),
FMInstance: f.fileManager.Name,
Name: fileName,
Description: f.Description,
CategoryID: f.CategoryID,
FullName: fileMetaData.FullName(),
OriginalName: fileMetaData.FullName(),
Size: fileMetaData.Size(),
Extension: fileMetaData.Extension(),
ContentType: fileMetaData.ContentType(),
FileUpdatedAt: &updatedAt,
FileCreatedAt: &createdAt,
// helpers
fileManager: f.fileManager,
}*/
// we will first copy the files to the locations (destinations) and after that make an insert into the DB if success!
if len(f.Locations) == 0 {
return ErrFmNewFileLocationMissing
}
var fileLocationsMeta FileLocationsMeta
locationFileName := id.String() + "_" + fileMetaData.FullName()
// Copy in all mentioned locations
for _, destLoc := range f.Locations {
// Check if the defined location exists
if loc, ok := f.fileManager.LocationsIndexed[destLoc.LocationName]; ok {
// if the location is found in the file manager, let's copy the file to it
newFile, _err := loc.Driver.CopyFile(srcFile, driver.FileDestination{
// the path may be empty...
FileName: locationFileName,
FilePath: destLoc.FilePath,
DirPath: destLoc.DirPath,
// that contains path
})
if _err != nil {
// Failed to copy...
return _err
}
fileLocationsMeta = append(fileLocationsMeta, FileLocationMeta{
LocationName: destLoc.LocationName,
FileInfo: newFile.Info().ToStruct(),
})
}
}
// in DB ar fi bine sa se salveze location instance name si + FileInfo
// apoi o sa fie nevoie de restabilit Fisierul pe baza la FileInfo cu ajutorul functiei FindFile
//
_err = structSetFieldVal(fieldModelIndirect, "Locations", fileLocationsMeta)
if _err != nil {
return _err
}
//file.Locations = fileLocationsMeta
//log.Println("saving file")
dbResult := f.db().Save(f.FileModel)
if dbResult.Error != nil {
// TODO: set the error...
return dbResult.Error
}
return nil
}
// TODO: we can do later a BackgroundSave which in case of failure (because of storage failure or interconnection failure)
// will retry the saving in specific locations
// BgSave -> background save
func (f *NewFile) BgSave() (*File, error) {
return nil, nil
}