@3dsource/angular-unreal-module 0.0.172 → 0.0.173

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4870,6 +4870,121 @@ const deepEqual = (a, b) => {
4870
4870
  return false;
4871
4871
  };
4872
4872
 
4873
+ class FileReceiverService extends SubService {
4874
+ constructor() {
4875
+ super();
4876
+ this.fileComplete$ = new Subject();
4877
+ this.valid = false;
4878
+ this.chunks = 0;
4879
+ this.mimetype = '';
4880
+ this.receiving = false;
4881
+ this.extension = '';
4882
+ this.data = [];
4883
+ this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
4884
+ this.init();
4885
+ }
4886
+ init() {
4887
+ if (this.unrealConfig?.playwright) {
4888
+ return;
4889
+ }
4890
+ this.store
4891
+ .select(unrealFeature.selectViewportReady)
4892
+ .pipe(filter(Truthy), takeUntil(this.destroy$))
4893
+ .subscribe(() => this.reset());
4894
+ }
4895
+ reset() {
4896
+ this.mimetype = '';
4897
+ this.extension = '';
4898
+ this.receiving = false;
4899
+ this.valid = false;
4900
+ this.chunks = 0;
4901
+ this.data = [];
4902
+ }
4903
+ resetOnStart() {
4904
+ this.reset();
4905
+ this.receiving = true;
4906
+ }
4907
+ /**
4908
+ * Processes a file extension when received over data channel
4909
+ * @param view - the file extension data
4910
+ */
4911
+ setExtensionFromBytes(view) {
4912
+ // Reset this if we got a file message and we are not "receiving" it yet
4913
+ if (!this.receiving) {
4914
+ this.resetOnStart();
4915
+ }
4916
+ //Logger.info(extensionAsString);
4917
+ this.extension = decodeData(view.slice(1).buffer);
4918
+ }
4919
+ /**
4920
+ * Processes a file mime type when received over data channel
4921
+ * @param view - the file mime type data
4922
+ */
4923
+ setMimeTypeFromBytes(view) {
4924
+ // Reset this if we got a file message and we are not "receiving" it yet
4925
+ if (!this.receiving) {
4926
+ this.resetOnStart();
4927
+ }
4928
+ const mimeAsString = decodeData(view.slice(1).buffer);
4929
+ // Logger.info(mimeAsString);
4930
+ this.mimetype = mimeAsString;
4931
+ }
4932
+ /*-------------------------------------------------------------------------------------------*/
4933
+ setContentsFromBytes(view) {
4934
+ // If we haven't received the initial setup instructions, return
4935
+ if (!this.receiving)
4936
+ return;
4937
+ const typeSize = 1;
4938
+ const intSize = 4;
4939
+ const maxMessageSize = 16 * 1024;
4940
+ const headerSize = typeSize + intSize;
4941
+ const maxPayloadSize = maxMessageSize - headerSize;
4942
+ // Calculate the total number of chunks from the total this size
4943
+ this.chunks = Math.ceil(new DataView(view.slice(typeSize, headerSize).buffer).getInt32(0, true) /
4944
+ maxPayloadSize);
4945
+ // Get the file part of the payload
4946
+ const thisBytes = view.slice(headerSize);
4947
+ // Append to existing data that holds this
4948
+ this.data.push(thisBytes);
4949
+ // Uncomment for debug
4950
+ // Logger.info(`Received this chunk: ${this.data.length}/${this.chunks}`);
4951
+ if (this.data.length === this.chunks) {
4952
+ this.receiving = false;
4953
+ this.valid = true;
4954
+ /*Logger.info('Received complete file');
4955
+ const transferDuration = new Date().getTime() - this.timestampStart;
4956
+ const transferBitrate = Math.round(
4957
+ (this.chunks * maxMessageSize) / transferDuration,
4958
+ );
4959
+ Logger.info(
4960
+ `Average transfer bitrate: ${transferBitrate}kb/s over ${transferDuration / 1000} seconds`,
4961
+ );*/
4962
+ /**
4963
+ * Reconstruct the file
4964
+ * This code reconstructs the received data into the original this based on the mime type and extension provided
4965
+ */
4966
+ const blob = new Blob([...this.data], { type: this.mimetype });
4967
+ this.fileComplete$.next({
4968
+ blob,
4969
+ mimetype: this.mimetype,
4970
+ extension: this.extension,
4971
+ valid: this.valid,
4972
+ });
4973
+ this.reset();
4974
+ }
4975
+ else if (this.data.length > this.chunks) {
4976
+ Logger.error(`Received bigger this than advertised: ${this.data.length}/${this.chunks}`);
4977
+ this.reset();
4978
+ }
4979
+ }
4980
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4981
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, providedIn: 'root' }); }
4982
+ }
4983
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, decorators: [{
4984
+ type: Injectable,
4985
+ args: [{ providedIn: 'root' }]
4986
+ }], ctorParameters: () => [] });
4987
+
4873
4988
  const filteredLogs = [
4874
4989
  {
4875
4990
  command: 'onChangeSequence',
@@ -4882,6 +4997,7 @@ class AggregatorService extends SubService {
4882
4997
  this.videoService = inject(VideoService);
4883
4998
  this.webrtcPlayer = inject(WebRtcPlayerService);
4884
4999
  this.freezeFrame = inject(FreezeFrameService);
5000
+ this.fileReceiver = inject(FileReceiverService);
4885
5001
  this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
4886
5002
  this.responseEventListeners = new Map();
4887
5003
  this.init();
@@ -4996,12 +5112,17 @@ class AggregatorService extends SubService {
4996
5112
  }
4997
5113
  break;
4998
5114
  }
4999
- // DataChannel file transfer is recognized but deliberately ignored:
5000
- // nothing on the client consumes the reassembled file.
5001
5115
  case ToClientMessage.FileExtension:
5116
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileExtension');
5117
+ this.fileReceiver.setExtensionFromBytes(view);
5118
+ break;
5002
5119
  case ToClientMessage.FileMimeType:
5120
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileMimeType');
5121
+ this.fileReceiver.setMimeTypeFromBytes(view);
5122
+ break;
5003
5123
  case ToClientMessage.FileContents:
5004
- Logger.colored(...COLOR_CODES.FROM_UNREAL, 'File message ignored');
5124
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileContents');
5125
+ this.fileReceiver.setContentsFromBytes(view);
5005
5126
  break;
5006
5127
  case ToClientMessage.FreezeFrame:
5007
5128
  Logger.colored(...COLOR_CODES.FROM_UNREAL, 'Freeze frame');
@@ -6938,6 +7059,48 @@ function resolveOverlays(recipes, times, phaseStartMs, phaseEndMs) {
6938
7059
  return out;
6939
7060
  }
6940
7061
 
7062
+ const ReceivedMimeTypes = {
7063
+ ApplicationJson: 'application/json',
7064
+ };
7065
+
7066
+ class FileHandlerService {
7067
+ constructor() {
7068
+ this.fileService = inject(FileReceiverService);
7069
+ this.fileHandlers = {
7070
+ [ReceivedMimeTypes.ApplicationJson]: this.handleJsonFile.bind(this),
7071
+ };
7072
+ }
7073
+ handleJsonFile(data, correlationId) {
7074
+ const { blob } = data;
7075
+ return from(blob.text()).pipe(map((text) => JSON.parse(text)), filter(({ commandCallback }) => {
7076
+ return commandCallback.correlationId === correlationId;
7077
+ }));
7078
+ }
7079
+ observeFileResponse(mimetype, data, sender, timeOut = 60000) {
7080
+ const correlationId = generateUuid();
7081
+ const out = { ...data, correlationId };
7082
+ return defer(() => {
7083
+ const observable = this.fileService.fileComplete$.pipe(switchMap((data) => {
7084
+ if (data.valid && this.fileHandlers[mimetype]) {
7085
+ return this.fileHandlers[mimetype](data, correlationId).pipe(filter(Truthy));
7086
+ }
7087
+ return of(null);
7088
+ }), timeout$1(timeOut), catchError((e) => {
7089
+ Logger.error(e);
7090
+ return of(null);
7091
+ }), take(1));
7092
+ setTimeout(() => sender(out), 0);
7093
+ return observable;
7094
+ });
7095
+ }
7096
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7097
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, providedIn: 'root' }); }
7098
+ }
7099
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, decorators: [{
7100
+ type: Injectable,
7101
+ args: [{ providedIn: 'root' }]
7102
+ }] });
7103
+
6941
7104
  class AnalyticsService extends SubService {
6942
7105
  #stopMouse$ = new Subject();
6943
7106
  constructor() {
@@ -8249,5 +8412,5 @@ function provideUnrealModule() {
8249
8412
  * Generated bundle index. Do not edit.
8250
8413
  */
8251
8414
 
8252
- export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
8415
+ export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
8253
8416
  //# sourceMappingURL=3dsource-angular-unreal-module.mjs.map