fixed uploads
This commit is contained in:
parent
a0fcc376b7
commit
30ff3dbdcd
7 changed files with 86 additions and 46 deletions
|
@ -1,12 +1,15 @@
|
||||||
import Controller from "./Controller";
|
import Controller from "./Controller";
|
||||||
import type DashboardViewModel from "../models/home/DashboardViewModel";
|
import type DashboardViewModel from "../models/home/DashboardViewModel";
|
||||||
import UserService from "../services/UserService";
|
import UserService from "../services/UserService";
|
||||||
|
import DomainService from "../services/DomainService";
|
||||||
|
import ArrayUtility from "../utilities/ArrayUtility";
|
||||||
|
|
||||||
export default class HomeController extends Controller {
|
export default class HomeController extends Controller {
|
||||||
public async Index_Get_AllowAnonymous() {
|
public async Index_Get_AllowAnonymous() {
|
||||||
if (this.session) {
|
if (this.session) {
|
||||||
const dashboardViewModel: DashboardViewModel = {
|
const dashboardViewModel: DashboardViewModel = {
|
||||||
recentUploads: await UserService.GetRecentUploads(this.session.userId)
|
recentUploads: await UserService.GetRecentUploads(this.session.userId),
|
||||||
|
domains: ArrayUtility.ToIdKeyedDict(await DomainService.LoadDomains())
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.view("dashboard",dashboardViewModel);
|
return this.view("dashboard",dashboardViewModel);
|
||||||
|
|
7
index.ts
7
index.ts
|
@ -35,7 +35,12 @@ fastify.register(FastifyView, {
|
||||||
|
|
||||||
fastify.register(FastifyFormBody);
|
fastify.register(FastifyFormBody);
|
||||||
|
|
||||||
fastify.register(FastifyMultipart);
|
fastify.register(FastifyMultipart, {
|
||||||
|
limits: {
|
||||||
|
files: 1,
|
||||||
|
fileSize: 104857600
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fastify.register(FastifyCookie, {
|
fastify.register(FastifyCookie, {
|
||||||
secret: Config.session.secret,
|
secret: Config.session.secret,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import type Domain from "../../entities/Domain";
|
||||||
import Media from "../../entities/Media";
|
import Media from "../../entities/Media";
|
||||||
|
|
||||||
export default interface DashboardViewModel {
|
export default interface DashboardViewModel {
|
||||||
recentUploads: Array<Media>
|
recentUploads: Array<Media>,
|
||||||
|
domains: { [key: string]: Domain }
|
||||||
}
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
// ! Hashed File Store (not file system!!)
|
// ! Hashed File Store (not file system!!)
|
||||||
|
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { existsSync, mkdirSync, createWriteStream, rename, stat, writeFile, rm, rmSync, } from "fs";
|
import { existsSync, mkdirSync, createWriteStream, rename, stat, writeFile, rm, rmSync, createReadStream } from "fs";
|
||||||
import { Console } from "hsconsole";
|
import { Console } from "hsconsole";
|
||||||
import { yellow } from "dyetty";
|
import { yellow } from "dyetty";
|
||||||
import { createHash, randomBytes } from "crypto";
|
import { createHash, randomBytes } from "crypto";
|
||||||
import FunkyArray from "funky-array";
|
import FunkyArray from "funky-array";
|
||||||
import HashFSFileInformation from "./HashFSFileInformation";
|
import HashFSFileInformation from "./HashFSFileInformation";
|
||||||
import type { BusboyFileStream } from "@fastify/busboy";
|
import type { BusboyFileStream } from "@fastify/busboy";
|
||||||
|
import { pipeline } from "stream/promises";
|
||||||
|
|
||||||
export default class HashFS {
|
export default class HashFS {
|
||||||
public static STARTUP_DIR: string;
|
public static STARTUP_DIR: string;
|
||||||
|
@ -104,49 +105,50 @@ export default class HashFS {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(fileInfo);
|
resolve(fileInfo);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddFromStream(stream: BusboyFileStream) {
|
public AddFromStream(stream: BusboyFileStream) {
|
||||||
return new Promise<HashFSFileInformation>(async (resolve, reject) => {
|
return new Promise<HashFSFileInformation>(async (resolve, reject) => {
|
||||||
const hasher = createHash("sha1");
|
const hasher = createHash("sha1");
|
||||||
hasher.setEncoding("hex");
|
hasher.setEncoding("hex");
|
||||||
|
|
||||||
const tempFilePath = join(this.tempPath, randomBytes(16).toString("base64url"));
|
|
||||||
const tempFile = createWriteStream(tempFilePath);
|
|
||||||
tempFile.on("close", async () => {
|
|
||||||
const hash: string = hasher.read();
|
|
||||||
const fileInfo = new HashFSFileInformation();
|
|
||||||
fileInfo.fileHash = hash;
|
|
||||||
fileInfo.fileSize = fileSize;
|
|
||||||
if (await this.FileExists(hash)) {
|
|
||||||
fileInfo.fileExistsAlready = true;
|
|
||||||
rm(tempFilePath, err => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logInfo(`File with hash "${hash}" already exists.`);
|
|
||||||
resolve(fileInfo);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rename(tempFilePath, this.GetFilePath(hash), err => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logInfo(`Stored file as ${hash}`);
|
|
||||||
resolve(fileInfo);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stream.pipe(tempFile);
|
|
||||||
stream.pipe(hasher);
|
|
||||||
let fileSize = 0;
|
let fileSize = 0;
|
||||||
stream.on("data", chunk => fileSize += chunk.length);
|
const tempFilePath = join(this.tempPath, randomBytes(16).toString("base64url"));
|
||||||
|
await pipeline(stream, createWriteStream(tempFilePath));
|
||||||
|
const readStream = createReadStream(tempFilePath);
|
||||||
|
for await (const chunk of readStream) {
|
||||||
|
fileSize += chunk.length;
|
||||||
|
hasher.write(chunk)
|
||||||
|
}
|
||||||
|
hasher.end();
|
||||||
|
const hash: string = hasher.read();
|
||||||
|
const fileInfo = new HashFSFileInformation();
|
||||||
|
fileInfo.fileHash = hash;
|
||||||
|
fileInfo.fileSize = fileSize;
|
||||||
|
if (await this.FileExists(hash)) {
|
||||||
|
fileInfo.fileExistsAlready = true;
|
||||||
|
rm(tempFilePath, err => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logInfo(`File with hash "${hash}" already exists.`);
|
||||||
|
resolve(fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rename(tempFilePath, this.GetFilePath(hash), err => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logInfo(`Stored file as ${hash}`);
|
||||||
|
resolve(fileInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
services/DomainService.ts
Normal file
13
services/DomainService.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { Console } from "hsconsole";
|
||||||
|
import DomainRepo from "../repos/DomainRepo";
|
||||||
|
|
||||||
|
export default abstract class DomainService {
|
||||||
|
public static async LoadDomains() {
|
||||||
|
try {
|
||||||
|
return await DomainRepo.SelectAll();
|
||||||
|
} catch (e) {
|
||||||
|
Console.printError(`EUS server service error:\n${e}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
utilities/ArrayUtility.ts
Normal file
10
utilities/ArrayUtility.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export default abstract class ArrayUtility {
|
||||||
|
public static ToIdKeyedDict(array: Array<any>) {
|
||||||
|
const dict: { [key: string]: any } = {};
|
||||||
|
for (const item of array) {
|
||||||
|
dict[item.Id] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,15 +11,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table>
|
<div class="row row-cols-1">
|
||||||
<tbody>
|
<% for (const upload of recentUploads) { %>
|
||||||
<% for (const upload of recentUploads) { %>
|
<div class="col">
|
||||||
<tr>
|
<div class="row">
|
||||||
<td><%= upload.FileName %></td>
|
<div class="col-auto">
|
||||||
</tr>
|
<% if (upload.MediaType.startsWith("image/")) { %>
|
||||||
<% } %>
|
<img src="<%= domains[upload.DomainId].HasHttps ? "https" : "http" %>://<%= domains[upload.DomainId].Domain %>/<%= upload.MediaTag %>" height="30" width="50">
|
||||||
</tbody>
|
<% } %>
|
||||||
</table>
|
</div>
|
||||||
|
<div class="col"><%= upload.FileName %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue