Skip to content

Commit

Permalink
Refactor upload config and options
Browse files Browse the repository at this point in the history
  • Loading branch information
floodfx committed Jan 12, 2023
1 parent 4a74bc9 commit 809c299
Show file tree
Hide file tree
Showing 19 changed files with 287 additions and 265 deletions.
290 changes: 145 additions & 145 deletions packages/core/coverage/clover.xml

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions packages/core/coverage/coverage-final.json

Large diffs are not rendered by default.

30 changes: 17 additions & 13 deletions packages/core/dist/liveview.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,26 @@ declare type UploadConfigOptions = {
/**
* "accept" contains the unique file type specifiers that can be uploaded.
* See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
* An empty array will allow all file types.
*/
accept?: string[];
/**
* the maximum number of files that can be uploaded at once. Defaults to 1.
*/
maxEntries?: number;
max_entries?: number;
/**
* the maximum size of each file in bytes. Defaults to 10MB.
*/
maxFileSize?: number;
max_file_size?: number;
/**
* Whether to upload the selected files automatically when the user selects them.
* Defaults to false.
*/
autoUpload?: boolean;
auto_upload?: boolean;
/**
* The size of each chunk in bytes. Defaults to 64kb.
*/
chunk_size?: number;
};
/**
* The configuration and entry related details for uploading files.
Expand All @@ -89,16 +94,20 @@ interface UploadConfig {
/**
* the maximum number of files that can be uploaded at once. Defaults to 1.
*/
maxEntries: number;
max_entries: number;
/**
* the maximum size of each file in bytes. Defaults to 10MB.
*/
maxFileSize: number;
max_file_size: number;
/**
* Whether to upload the selected files automatically when the user selects them.
* Defaults to false.
*/
autoUpload: boolean;
auto_upload: boolean;
/**
* The size of each chunk in bytes. Defaults to 64kb.
*/
chunk_size: number;
/**
* The files selected for upload.
*/
Expand Down Expand Up @@ -796,9 +805,6 @@ declare namespace Phx {
declare type AllowUploadEntries = {
[key: string]: string;
};
declare type AllowUploadConstraints = {
[key: string]: number;
};

declare function deepDiff(oldParts: Parts, newParts: Parts): Parts;
declare function diffArrays(oldArray: unknown[], newArray: unknown[]): boolean;
Expand Down Expand Up @@ -1159,9 +1165,7 @@ declare namespace PhxReply {
diff?: {
[key: string]: unknown;
};
config?: {
[key: string]: unknown;
};
config?: UploadConfigOptions;
entries?: {
[key: string]: unknown;
};
Expand All @@ -1170,7 +1174,7 @@ declare namespace PhxReply {
function renderedReply(msg: Phx.Msg, parts: Parts): Reply;
function diff(joinRef: string | null, topic: string, diff: Parts): Reply;
function diffReply(msg: Phx.Msg, diff: Parts): Reply;
function allowUploadReply(msg: Phx.Msg, diff: Parts, config: AllowUploadConstraints, entries: AllowUploadEntries): Reply;
function allowUploadReply(msg: Phx.Msg, diff: Parts, config: UploadConfigOptions, entries: AllowUploadEntries): Reply;
function heartbeat(msg: Phx.Msg): Reply;
function serialize(msg: Reply): string;
}
Expand Down
47 changes: 25 additions & 22 deletions packages/core/dist/liveview.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,10 @@ class UploadConfig {
constructor(name, options) {
this.name = name;
this.accept = options?.accept ?? [];
this.maxEntries = options?.maxEntries ?? 1;
this.maxFileSize = options?.maxFileSize ?? 10 * 1024 * 1024; // 8MB
this.autoUpload = options?.autoUpload ?? false;
this.max_entries = options?.max_entries ?? 1;
this.max_file_size = options?.max_file_size ?? 10 * 1024 * 1024; // 10MB
this.auto_upload = options?.auto_upload ?? false;
this.chunk_size = options?.chunk_size ?? 64 * 1024; // 64kb
this.entries = [];
this.ref = `phx-${nanoid.nanoid()}`;
this.errors = [];
Expand Down Expand Up @@ -203,7 +204,7 @@ class UploadConfig {
}
validate() {
this.errors = [];
if (this.entries.length > this.maxEntries) {
if (this.entries.length > this.max_entries) {
this.errors.push("Too many files");
}
// add errors from entries
Expand Down Expand Up @@ -342,7 +343,7 @@ class UploadEntry {
validate() {
this.errors = [];
// validate file size
if (this.client_size > this.#config.maxFileSize) {
if (this.client_size > this.#config.max_file_size) {
this.errors.push("Too large");
}
// validate mime type is allowed
Expand Down Expand Up @@ -973,7 +974,7 @@ const error_tag = (changeset, key, options) => {
* @returns the html for the file input
*/
function live_file_input(uploadConfig) {
const { name, accept, maxEntries, ref, entries } = uploadConfig;
const { name, accept, max_entries: maxEntries, ref, entries } = uploadConfig;
const multiple = maxEntries > 1 ? "multiple" : "";
const activeRefs = entries.map((entry) => entry.ref).join(",");
const doneRefs = entries
Expand Down Expand Up @@ -2956,14 +2957,12 @@ async function onProgressUpload(ctx, payload) {
}
async function onAllowUpload(ctx, payload) {
const { ref, entries } = payload;
// console.log("onAllowUpload handle", ref, entries);
ctx.activeUploadRef = ref;
// TODO allow configuration settings for server
const config = {
chunk_size: 64000,
max_entries: 10,
max_file_size: 10 * 1024 * 1024, // 10MB
};
const uc = Object.values(ctx.uploadConfigs).find((c) => c.ref === ref);
if (!uc) {
// istanbul ignore next
throw Error(`Could not find upload config for ref ${ref}`);
}
const entriesReply = {
ref,
};
Expand All @@ -2980,7 +2979,7 @@ async function onAllowUpload(ctx, payload) {
const view = await ctx.liveView.render(ctx.socket.context, ctx.defaultLiveViewMeta());
return {
entries: entriesReply,
config,
config: uc,
view,
};
// // wrap in root template if there is one
Expand Down Expand Up @@ -3146,12 +3145,11 @@ class WsHandler {
this.cleanupPostReply();
}
else if (topic.startsWith("lvu:")) {
// TODO? send more than ack?
// perhaps we should check this token matches the entry sent earlier?
const payload = msg[exports.Phx.MsgIdx.payload];
console.log("upload join payload", payload);
// const payload = msg[Phx.MsgIdx.payload] as Phx.JoinUploadPayload;
// perhaps we should check this token matches entries send in the "allow_upload" event?
// const { token } = payload;
// send ACK
// TODO? send more than ack? what?
this.send(PhxReply.renderedReply(msg, {}));
}
else {
Expand All @@ -3176,8 +3174,14 @@ class WsHandler {
break;
case "live_patch":
case "phx_leave":
// try {
// if (this.#ctx) {
// await this.#ctx.liveView.shutdown(this.#ctx);
// }
// } catch (e) {
// console.error("error handling phx_leave", e);
// }
case "allow_upload":
console.log("allow_upload", msg);
try {
const payload = msg[exports.Phx.MsgIdx.payload];
const { view, config, entries } = await onAllowUpload(this.#ctx, payload);
Expand Down Expand Up @@ -3217,15 +3221,14 @@ class WsHandler {
}
async handleInfo(info) {
try {
// info can be a string or an object
// info can be a string or an object so check it
// if it's a string, we need to convert it to a LiveInfo object
if (typeof info === "string") {
info = { type: info };
}
// lifecycle handleInfo => render
await this.#ctx.liveView.handleInfo(info, this.#ctx.socket);
const view = await this.#ctx.liveView.render(this.#ctx.socket.context, this.#ctx.defaultLiveViewMeta());
// diff and send
const diff = await this.viewToDiff(view);
this.send(PhxReply.diff(null, this.#ctx.joinId, diff));
this.cleanupPostReply();
Expand Down Expand Up @@ -3330,7 +3333,6 @@ class WsHandler {
async (topic) => { },
// allowUploadCallback
async (name, options) => {
// console.log("allowUpload", name, options);
this.#ctx.uploadConfigs[name] = new UploadConfig(name, options);
},
// cancelUploadCallback
Expand All @@ -3356,6 +3358,7 @@ class WsHandler {
}
// noting is in progress so we can consume
const entries = uploadConfig.consumeEntries();
console.log("entries", entries);
return await Promise.all(entries.map(async (entry) => await fn({ path: entry.getTempFile(), fileSystem: this.#config.fileSysAdaptor }, entry)));
}
console.warn(`Upload config ${configName} not found for consumeUploadedEntries`);
Expand Down
47 changes: 25 additions & 22 deletions packages/core/dist/liveview.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ class UploadConfig {
constructor(name, options) {
this.name = name;
this.accept = options?.accept ?? [];
this.maxEntries = options?.maxEntries ?? 1;
this.maxFileSize = options?.maxFileSize ?? 10 * 1024 * 1024; // 8MB
this.autoUpload = options?.autoUpload ?? false;
this.max_entries = options?.max_entries ?? 1;
this.max_file_size = options?.max_file_size ?? 10 * 1024 * 1024; // 10MB
this.auto_upload = options?.auto_upload ?? false;
this.chunk_size = options?.chunk_size ?? 64 * 1024; // 64kb
this.entries = [];
this.ref = `phx-${nanoid()}`;
this.errors = [];
Expand Down Expand Up @@ -196,7 +197,7 @@ class UploadConfig {
}
validate() {
this.errors = [];
if (this.entries.length > this.maxEntries) {
if (this.entries.length > this.max_entries) {
this.errors.push("Too many files");
}
// add errors from entries
Expand Down Expand Up @@ -335,7 +336,7 @@ class UploadEntry {
validate() {
this.errors = [];
// validate file size
if (this.client_size > this.#config.maxFileSize) {
if (this.client_size > this.#config.max_file_size) {
this.errors.push("Too large");
}
// validate mime type is allowed
Expand Down Expand Up @@ -966,7 +967,7 @@ const error_tag = (changeset, key, options) => {
* @returns the html for the file input
*/
function live_file_input(uploadConfig) {
const { name, accept, maxEntries, ref, entries } = uploadConfig;
const { name, accept, max_entries: maxEntries, ref, entries } = uploadConfig;
const multiple = maxEntries > 1 ? "multiple" : "";
const activeRefs = entries.map((entry) => entry.ref).join(",");
const doneRefs = entries
Expand Down Expand Up @@ -2949,14 +2950,12 @@ async function onProgressUpload(ctx, payload) {
}
async function onAllowUpload(ctx, payload) {
const { ref, entries } = payload;
// console.log("onAllowUpload handle", ref, entries);
ctx.activeUploadRef = ref;
// TODO allow configuration settings for server
const config = {
chunk_size: 64000,
max_entries: 10,
max_file_size: 10 * 1024 * 1024, // 10MB
};
const uc = Object.values(ctx.uploadConfigs).find((c) => c.ref === ref);
if (!uc) {
// istanbul ignore next
throw Error(`Could not find upload config for ref ${ref}`);
}
const entriesReply = {
ref,
};
Expand All @@ -2973,7 +2972,7 @@ async function onAllowUpload(ctx, payload) {
const view = await ctx.liveView.render(ctx.socket.context, ctx.defaultLiveViewMeta());
return {
entries: entriesReply,
config,
config: uc,
view,
};
// // wrap in root template if there is one
Expand Down Expand Up @@ -3139,12 +3138,11 @@ class WsHandler {
this.cleanupPostReply();
}
else if (topic.startsWith("lvu:")) {
// TODO? send more than ack?
// perhaps we should check this token matches the entry sent earlier?
const payload = msg[Phx.MsgIdx.payload];
console.log("upload join payload", payload);
// const payload = msg[Phx.MsgIdx.payload] as Phx.JoinUploadPayload;
// perhaps we should check this token matches entries send in the "allow_upload" event?
// const { token } = payload;
// send ACK
// TODO? send more than ack? what?
this.send(PhxReply.renderedReply(msg, {}));
}
else {
Expand All @@ -3169,8 +3167,14 @@ class WsHandler {
break;
case "live_patch":
case "phx_leave":
// try {
// if (this.#ctx) {
// await this.#ctx.liveView.shutdown(this.#ctx);
// }
// } catch (e) {
// console.error("error handling phx_leave", e);
// }
case "allow_upload":
console.log("allow_upload", msg);
try {
const payload = msg[Phx.MsgIdx.payload];
const { view, config, entries } = await onAllowUpload(this.#ctx, payload);
Expand Down Expand Up @@ -3210,15 +3214,14 @@ class WsHandler {
}
async handleInfo(info) {
try {
// info can be a string or an object
// info can be a string or an object so check it
// if it's a string, we need to convert it to a LiveInfo object
if (typeof info === "string") {
info = { type: info };
}
// lifecycle handleInfo => render
await this.#ctx.liveView.handleInfo(info, this.#ctx.socket);
const view = await this.#ctx.liveView.render(this.#ctx.socket.context, this.#ctx.defaultLiveViewMeta());
// diff and send
const diff = await this.viewToDiff(view);
this.send(PhxReply.diff(null, this.#ctx.joinId, diff));
this.cleanupPostReply();
Expand Down Expand Up @@ -3323,7 +3326,6 @@ class WsHandler {
async (topic) => { },
// allowUploadCallback
async (name, options) => {
// console.log("allowUpload", name, options);
this.#ctx.uploadConfigs[name] = new UploadConfig(name, options);
},
// cancelUploadCallback
Expand All @@ -3349,6 +3351,7 @@ class WsHandler {
}
// noting is in progress so we can consume
const entries = uploadConfig.consumeEntries();
console.log("entries", entries);
return await Promise.all(entries.map(async (entry) => await fn({ path: entry.getTempFile(), fileSystem: this.#config.fileSysAdaptor }, entry)));
}
console.warn(`Upload config ${configName} not found for consumeUploadedEntries`);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
coverageThreshold: {
global: {
branches: 80,
functions: 80,
functions: 75,
lines: 80,
statements: 80,
},
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/server/protocol/reply.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AllowUploadConstraints, AllowUploadEntries } from "../socket/ws/wsUploadHandler";
import { AllowUploadEntries } from "../socket/ws/wsUploadHandler";
import { Parts } from "../templates";
import { UploadConfigOptions } from "../upload";
import { Phx } from "./phx";

export namespace PhxReply {
Expand All @@ -19,7 +20,7 @@ export namespace PhxReply {
export type Response = {
rendered?: { [key: string]: unknown };
diff?: { [key: string]: unknown };
config?: { [key: string]: unknown };
config?: UploadConfigOptions;
entries?: { [key: string]: unknown };
};

Expand Down Expand Up @@ -62,7 +63,7 @@ export namespace PhxReply {
export function allowUploadReply(
msg: Phx.Msg,
diff: Parts,
config: AllowUploadConstraints,
config: UploadConfigOptions,
entries: AllowUploadEntries
): Reply {
return [
Expand Down
Loading

0 comments on commit 809c299

Please sign in to comment.