Coder Social home page Coder Social logo

Comments (4)

kukhariev avatar kukhariev commented on July 20, 2024

possible implementation

import { Metadata, Uploader } from 'ngx-uploadx';
export interface S3SigObject {
  chunkSize: number;
  url: string;
  uploadId: string;
  urls: string[];
  parts: Part[];
  metadata: Metadata;
}
interface Part {
  ETag: string;
  PartNumber: number;
}
export class S3 extends Uploader {
  s3Sig = { metadata: this.metadata } as S3SigObject;

  protected async getFileUrl(): Promise<string> {
    this.offset = 0;
    await this._serverRequest(this.endpoint);
    this.chunkSize = this.s3Sig.chunkSize;
    return this.s3Sig.url;
  }

  protected async sendFileContent(): Promise<number> {
    const index = this.s3Sig.parts.length;
    const { body, end } = this.getChunk();
    await this.request({ method: 'PUT', body, url: this.s3Sig.urls[index] });
    const etag = this.getValueFromResponse('etag') || '';
    const part: Part = { ETag: etag, PartNumber: index + 1 };
    this.s3Sig.parts = [...this.s3Sig.parts, part];
    if (end === this.size) {
      await this._serverRequest(this.url);
      return end;
    }
    return end + 1;
  }

  protected async getOffset(): Promise<number | undefined> {
    await this._serverRequest(this.url);
    return Math.min(this.s3Sig.parts.length * this.chunkSize, this.size);
  }

  private async _serverRequest(url: string): Promise<S3SigObject> {
    const body: FormData = new FormData();
    body.set('s3Sig', JSON.stringify(this.s3Sig));
    await this.request({
      method: 'POST',
      body,
      url
    });
    return (this.response as object) as S3SigObject;
  }
}

But first we need a smart server API...

from ngx-uploadx.

reyx avatar reyx commented on July 20, 2024

possible implementation

import { Metadata, Uploader } from 'ngx-uploadx';
export interface S3SigObject {
  chunkSize: number;
  url: string;
  uploadId: string;
  urls: string[];
  parts: Part[];
  metadata: Metadata;
}
interface Part {
  ETag: string;
  PartNumber: number;
}
export class S3 extends Uploader {
  s3Sig = { metadata: this.metadata } as S3SigObject;

  protected async getFileUrl(): Promise<string> {
    this.offset = 0;
    await this._serverRequest(this.endpoint);
    this.chunkSize = this.s3Sig.chunkSize;
    return this.s3Sig.url;
  }

  protected async sendFileContent(): Promise<number> {
    const index = this.s3Sig.parts.length;
    const { body, end } = this.getChunk();
    await this.request({ method: 'PUT', body, url: this.s3Sig.urls[index] });
    const etag = this.getValueFromResponse('etag') || '';
    const part: Part = { ETag: etag, PartNumber: index + 1 };
    this.s3Sig.parts = [...this.s3Sig.parts, part];
    if (end === this.size) {
      await this._serverRequest(this.url);
      return end;
    }
    return end + 1;
  }

  protected async getOffset(): Promise<number | undefined> {
    await this._serverRequest(this.url);
    return Math.min(this.s3Sig.parts.length * this.chunkSize, this.size);
  }

  private async _serverRequest(url: string): Promise<S3SigObject> {
    const body: FormData = new FormData();
    body.set('s3Sig', JSON.stringify(this.s3Sig));
    await this.request({
      method: 'POST',
      body,
      url
    });
    return (this.response as object) as S3SigObject;
  }
}

But first we need a smart server API...

Just remove the "+ 1" on "return end + 1"

from ngx-uploadx.

kukhariev avatar kukhariev commented on July 20, 2024

updated version:

import { store, UploaderX } from 'ngx-uploadx';
export interface S3Multipart {
  partSize: number;
  name: string;
  UploadId: string;
  partsUrls: string[];
  Parts?: Part[];
}
interface Part {
  ETag: string;
  PartNumber: number;
}
export class UploaderXS3 extends UploaderX {
  s3 = {} as S3Multipart;

  async getFileUrl(): Promise<string> {
    const url = await super.getFileUrl();
    if (this.response?.partSize) {
      this.s3 = { ...this.response };
      this.s3.Parts ??= [];
      store.set(url, JSON.stringify(this.s3));
      this.offset = this.s3.Parts.length * this.s3.partSize;
      if (this.s3?.partsUrls.length === this.s3?.Parts.length) {
        await this.setMetadata(this.url);
      }
    }
    return url;
  }

  async sendFileContent(): Promise<number | undefined> {
    if (this.s3.partsUrls) {
      this.s3.Parts ??= [];
      const i = this.s3.Parts.length;
      const { body, end } = this.getChunk(this.offset, this.s3.partSize);
      await this.request({
        method: 'PUT',
        body,
        url: this.s3.partsUrls[i],
        skipAuthorization: true
      });

      const ETag = this.getValueFromResponse('etag');
      if (!ETag) {
        return this.offset;
      }
      const part: Part = { ETag, PartNumber: i + 1 };
      this.s3.Parts.push(part);
      if (end === this.size) {
        await this.setMetadata(this.url);
      }
      return end;
    } else {
      return super.sendFileContent();
    }
  }

  async getOffset(): Promise<number | undefined> {
    const _s3 = store.get(this.url);
    if (_s3) {
      this.s3 = JSON.parse(_s3);
      await this.setMetadata(this.url);
      if (this.response.UploadId) {
        this.s3 = { ...this.response };
      }
      this.s3.Parts ??= [];
      return Math.min(this.s3.Parts.length * this.s3.partSize, this.size);
    }
    return super.getOffset();
  }

  private async setMetadata(url: string): Promise<S3Multipart> {
    const body = JSON.stringify(this.s3);
    await this.request({
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json; charset=utf-8' },
      body,
      url
    });
    if (this.response?.partsUrls) {
      this.s3 = { ...this.response };
    }
    return this.s3;
  }
}

from ngx-uploadx.

kukhariev avatar kukhariev commented on July 20, 2024

For proper operation, at least "exposeHeaders" : ["etag"] and "AllowedMethods": ["PUT"] must be set in the cors configuration.

b2 example:

[
  {
    "corsRuleName": "ngx-uploadx",
    "allowedOrigins": [
      "*"
    ],
    "allowedHeaders": [
      "*"
    ],
    "allowedOperations": [
      "s3_put"
    ],
    "exposeHeaders": ["etag"],
    "maxAgeSeconds": 3600
  }
]

from ngx-uploadx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.