Skip to content

Commit 8bcaaa4

Browse files
authored
Merge pull request #255 from Sofie-Automation/feat/s3
feat: Add support for S3
2 parents 7cfc86b + c2e4a6b commit 8bcaaa4

File tree

24 files changed

+2651
-271
lines changed

24 files changed

+2651
-271
lines changed

apps/single-app/app/expectedPackages.json

Lines changed: 238 additions & 229 deletions
Large diffs are not rendered by default.

shared/packages/api/src/expectationApi.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ export namespace Expectation {
531531
| ExpectedJSONData
532532
| ExpectedFTPFile
533533
| ExpectedUnspecified
534+
| ExpectedS3Resource
535+
534536
export type Any =
535537
| FileOnDisk
536538
| MediaFileThumbnail
@@ -542,6 +544,8 @@ export namespace Expectation {
542544
| JSONData
543545
| FTPFile
544546
| Unspecified
547+
| S3Resource
548+
545549
export interface Base {
546550
type: Type
547551
}
@@ -559,6 +563,7 @@ export namespace Expectation {
559563
JSON_DATA = 'json_data',
560564
FTP_FILE = 'ftp_file',
561565
UNSPECIFIED = 'unspecified',
566+
S3_RESOURCE = 's3_resource',
562567
}
563568
type ExpectedType<T extends Base> = Partial<T> & Pick<T, 'type'>
564569

@@ -674,5 +679,13 @@ export namespace Expectation {
674679
type: Type.UNSPECIFIED
675680
}
676681
export type ExpectedUnspecified = ExpectedType<Unspecified>
682+
683+
export interface S3Resource extends Base {
684+
type: Type.S3_RESOURCE
685+
fileSize: number
686+
modifiedDate: number
687+
}
688+
689+
export type ExpectedS3Resource = ExpectedType<S3Resource>
677690
}
678691
}

shared/packages/api/src/inputApi.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ export namespace Accessor {
410410
| AtemMediaStore
411411
| FTP
412412
| KairosClip
413+
| S3
413414

414415
export enum AccessType {
415416
LOCAL_FOLDER = 'local_folder',
@@ -421,6 +422,7 @@ export namespace Accessor {
421422
ATEM_MEDIA_STORE = 'atem_media_store',
422423
FTP = 'ftp',
423424
KAIROS_CLIP = 'kairos_clip',
425+
S3 = 's3',
424426
}
425427

426428
/** Generic (used in extends) */
@@ -574,6 +576,33 @@ export namespace Accessor {
574576
/** Name/Id of the network the share exists on. Used to differ between different local networks. Leave empty if globally accessible. */
575577
networkId?: string
576578
}
579+
580+
/** Definition of access to a generic FTP/SFTP endpoint. (Read-access only) */
581+
export interface S3 extends Base {
582+
type: AccessType.S3
583+
584+
/** Identifier of the S3 bucket */
585+
bucketId: string
586+
587+
/** AWS Access key */
588+
accessKey: string
589+
590+
/** AWS Secret access key */
591+
secretAccessKey: string
592+
593+
/** AWS region of the bucket */
594+
region: string
595+
596+
/** Base URL for the S3 bucket */
597+
s3PublicBaseUrl: string
598+
599+
/** S3 endpoint (obligatory for non-AWS S3 deployments). If undefined, AWS S3 is assumed */
600+
endpoint?: string
601+
602+
/** If true, forces path-style URLs (required for some S3-compatible storage solutions that use path-style URLs for buckets)
603+
* i.e. use this is bucket URL is `http://localhost/test` instead of `http://test.localhost` */
604+
forcePathStyle?: boolean
605+
}
577606
}
578607
/**
579608
* AccessorOnPackage contains interfaces for Accessor definitions that are put ON the Package.
@@ -591,6 +620,7 @@ export namespace AccessorOnPackage {
591620
| AtemMediaStore
592621
| FTP
593622
| KairosClip
623+
| S3
594624

595625
export interface LocalFolder extends Partial<Accessor.LocalFolder> {
596626
/** Path to the file (starting from .folderPath). If not set, the filePath of the ExpectedPackage will be used */
@@ -623,9 +653,15 @@ export namespace AccessorOnPackage {
623653
/** path to resource (combined with .basePath gives the full path), for example: /folder/myFile */
624654
path?: string
625655
}
656+
626657
export interface KairosClip extends Partial<Accessor.KairosClip> {
627658
ref?: MediaRamRecRef | MediaStillRef
628659
}
660+
661+
export interface S3 extends Partial<Accessor.S3> {
662+
/** key of resource */
663+
filePath?: string
664+
}
629665
}
630666

631667
export interface PackageContainerOnPackage extends Omit<PackageContainer, 'accessors'> {

shared/packages/worker/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"rimraf": "^5.0.5"
3030
},
3131
"dependencies": {
32+
"@aws-sdk/client-s3": "^3.943.0",
33+
"@aws-sdk/lib-storage": "^3.943.0",
3234
"@parcel/watcher": "^2.3.0",
3335
"@sofie-package-manager/api": "1.53.0-alpha.4",
3436
"abort-controller": "^3.0.0",

shared/packages/worker/src/worker/accessorHandlers/accessor.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { QuantelAccessorHandle } from './quantel'
1010
import { ATEMAccessorHandle } from './atem'
1111
import { FTPAccessorHandle } from './ftp'
1212
import { KairosClipAccessorHandle } from './kairosClip'
13+
import { S3AccessorHandle } from './s3'
1314

1415
export function getAccessorHandle<Metadata>(
1516
worker: BaseWorker,
@@ -56,6 +57,8 @@ export function getAccessorStaticHandle(accessor: AccessorOnPackage.Any) {
5657
return FTPAccessorHandle
5758
} else if (accessor.type === Accessor.AccessType.KAIROS_CLIP) {
5859
return KairosClipAccessorHandle
60+
} else if (accessor.type === Accessor.AccessType.S3) {
61+
return S3AccessorHandle
5962
} else {
6063
assertNever(accessor.type) // Assert so as to not forget to add an if-clause above
6164
throw new Error(`Unsupported Accessor type "${accessor.type}"`)
@@ -108,6 +111,12 @@ export function isKairosClipAccessorHandle<Metadata>(
108111
return accessorHandler.type === KairosClipAccessorHandle.type
109112
}
110113

114+
export function isS3AccessorHandle<Metadata>(
115+
accessorHandler: GenericAccessorHandle<Metadata>
116+
): accessorHandler is S3AccessorHandle<Metadata> {
117+
return accessorHandler.type === S3AccessorHandle.type
118+
}
119+
111120
/** Returns a generic value for how costly it is to use an Accessor type. A higher value means that it is more expensive to access the accessor */
112121
export function getAccessorCost(accessorType: Accessor.AccessType | undefined): number {
113122
switch (accessorType) {
@@ -127,6 +136,7 @@ export function getAccessorCost(accessorType: Accessor.AccessType | undefined):
127136
return 2
128137
case Accessor.AccessType.HTTP_PROXY:
129138
case Accessor.AccessType.HTTP:
139+
case Accessor.AccessType.S3:
130140
return 3
131141

132142
case undefined:

shared/packages/worker/src/worker/accessorHandlers/lib/GenericFileOperations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export class GenericFileOperationsHandler {
103103
for (const file of files) {
104104
const filePath = path.join(dirPath, file.name)
105105
const fullPath = path.join(folderPath, filePath)
106+
106107
if (file.isDirectory) {
107108
await cleanUpDirectory(filePath, true)
108109
} else if (file.lastModified && file.lastModified > 0) {

0 commit comments

Comments
 (0)