Notes2/file.go

188 lines
3.7 KiB
Go

package main
import (
// External
"github.com/jmoiron/sqlx"
// Standard
"fmt"
"os"
"path"
"time"
)
type File struct {
ID int
UUID string
UserID int `db:"user_id"`
Name string `db:"name"`
Size int
Type string `db:"type"`
Modified time.Time
UploadComplete bool `db:"upload_complete"`
}
var (
fileUUIDCache map[string]int
)
func init() {
fileUUIDCache = make(map[string]int)
}
func AddFileToDb(userID int, file *File) (err error) { // {{{
file.UserID = userID
var rows *sqlx.Rows
rows, err = db.Queryx(`
INSERT INTO public.file(user_id, uuid, name, size, type, modified, upload_complete)
VALUES($1, $2, $3, $4, $5, $6, false)
ON CONFLICT (user_id, uuid) DO UPDATE set name = public.file.name
RETURNING id
`,
file.UserID,
file.UUID,
file.Name,
file.Size,
file.Type,
file.Modified,
)
if err != nil {
return
}
defer rows.Close()
rows.Next()
err = rows.Scan(&file.ID)
return
} // }}}
func Files(userID int, nodeUUID string, fileID int) (files []File, err error) { // {{{
var rows *sqlx.Rows
rows, err = db.Queryx(
`SELECT *
FROM file
WHERE
user_id = $1 AND
node_uuid = $2 AND
CASE $3::int
WHEN 0 THEN true
ELSE id = $3
END`,
userID,
nodeUUID,
fileID,
)
if err != nil {
return
}
defer rows.Close()
files = []File{}
for rows.Next() {
file := File{}
if err = rows.StructScan(&file); err != nil {
return
}
files = append(files, file)
}
return
} // }}}
func FileIDToPath(id int) (string, string) { // {{{
str := fmt.Sprintf("%012d", id)
dir := path.Join(config.Storage.Files, str[0:4], str[4:8])
fpath := path.Join(config.Storage.Files, str[0:4], str[4:8], str[8:12])
return dir, fpath
} // }}}
func FileWriteData(userID int, dbID int, data []byte, create bool) (err error) { // {{{
dir, fpath := FileIDToPath(dbID)
err = os.MkdirAll(dir, 0700)
if err != nil {
Log.Error("file", "error", err)
return
}
var f *os.File
if create {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
}
if err != nil {
Log.Error("file", "error", err)
return
}
defer f.Close()
_, err = f.Write(data)
if err != nil {
Log.Error("file", "error", err)
return
}
return
} // }}}
func FileCountForUser(userID int) (count int, err error) { // {{{
row := db.QueryRowx(`SELECT COUNT(*) FROM public.file WHERE user_id = $1`, userID)
err = row.Scan(&count)
return
} // }}}
func FileServerUUIDsForUser(userID, page int) (uuids []string, more bool, err error) { // {{{
uuids = []string{}
var rows *sqlx.Rows
rows, err = db.Queryx(`
SELECT
uuid
FROM public.file
WHERE
user_id = $1
ORDER BY
uuid ASC
LIMIT $2 OFFSET $3
`,
userID,
SYNC_PAGINATION+1,
page*SYNC_PAGINATION,
)
if err != nil {
return
}
defer rows.Close()
var uuid string
for rows.Next() {
err = rows.Scan(&uuid)
if err != nil {
return
}
uuids = append(uuids, uuid)
}
more = len(uuids) > SYNC_PAGINATION
uuids = uuids[0:min(SYNC_PAGINATION, len(uuids))]
return
} // }}}
func FileMetadata(userID int, uuid string) (f File, err error) { // {{{
row := db.QueryRowx(`SELECT * FROM public.file WHERE user_id = $1 AND "uuid" = $2`, userID, uuid)
err = row.StructScan(&f)
return
} // }}}
func FileForUser(userID int, uuid string) (f *os.File, md File, err error) { // {{{
row := db.QueryRowx(`SELECT * FROM public.file WHERE user_id = $1 AND "uuid" = $2`, userID, uuid)
err = row.StructScan(&md)
if err != nil {
return
}
_, fpath := FileIDToPath(md.ID)
f, err = os.OpenFile(fpath, os.O_RDONLY, 0600)
return
} // }}}
// vim: foldmethod=marker