ucap-doc/documents/업무/6월/1째주/backup/chat/effects.ts

534 lines
14 KiB
TypeScript
Raw Normal View History

2020-06-05 09:45:18 +00:00
import { of } from 'rxjs';
import {
tap,
switchMap,
map,
catchError,
exhaustMap,
concatMap,
withLatestFrom,
debounceTime,
mergeMap
} from 'rxjs/operators';
import { Injectable, Inject } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Dictionary } from '@ngrx/entity';
import { EventProtocolService } from '@ucap/ng-protocol-event';
import {
RoomType,
OpenResponse as CreateResponse,
Open3Response as CreateTimerResponse,
ExitResponse as DeleteResponse,
ExitAllResponse as DeleteMultiResponse
} from '@ucap/protocol-room';
import { RoomProtocolService } from '@ucap/ng-protocol-room';
import { FileProtocolService } from '@ucap/ng-protocol-file';
import * as RoomActions from '../room/actions';
import {
events,
eventsFailure,
eventsSuccess,
read,
readFailure,
readSuccess,
fileInfos,
fileInfosFailure,
fileInfosSuccess,
send,
sendSuccess,
sendFailure,
addEvent,
addEventSuccess,
del,
delNotification,
delFailure,
delEventList,
moreEvents,
forward,
forwardFailure,
forwardAfterRoomOpen,
roomOpenAfterForward,
cancel,
cancelFailure,
cancelNotification,
updateEventList
} from './actions';
import {
InfoRequest,
ReadResponse,
FileType,
EventType,
DelResponse,
SendResponse,
CancelResponse
} from '@ucap/protocol-event';
import { ModuleConfig } from '../../config/module-config';
import { _MODULE_CONFIG } from '../../config/token';
import { Chatting } from './state';
import { ChattingSelector, RoomSelector } from '../state';
import { Router } from '@angular/router';
import { LocaleCode } from '@ucap/core';
import { LoginSelector } from '@ucap/ng-store-authentication';
import { I18nService } from '@ucap/ng-i18n';
@Injectable()
export class Effects {
events$ = createEffect(
() => {
return this.actions$.pipe(
ofType(events),
map((action) => action.req),
switchMap((req) => {
return this.eventProtocolService.info(req).pipe(
map((res) => {
if (!!res && !!res.res) {
const infoList = res.infoList;
this.store.dispatch(
eventsSuccess({
eventInfoList: infoList,
res: res.res,
remainEvent:
infoList.length === req.requestCount ? true : false
})
);
if (req.baseSeq === 0) {
// 최초 이벤트 목록 조회.
// SSVC_TYPE_EVENT_READ_REQ 수행.
const maxSeq = Math.max.apply(
Math,
infoList.map((v) => v.seq)
);
this.store.dispatch(
read({
roomId: req.roomId,
lastReadSeq: Number(maxSeq)
})
);
// File 정보 수집.
this.store.dispatch(
fileInfos({
req: {
roomId: res.res.roomId,
// { 파일타입 } cf) I : 이미지 V: 동영상 F: 파일 "" 빈값이면 모든 타입을 내려줌
type: FileType.All
}
})
);
} else {
}
}
}),
catchError((error) =>
of(eventsFailure({ roomId: req.roomId, error }))
)
);
})
);
},
{ dispatch: false }
);
moreEvents$ = createEffect(
() => {
return this.actions$.pipe(
ofType(moreEvents),
mergeMap(
(action) =>
of(action).pipe(
withLatestFrom(
this.store.pipe(
select(ChattingSelector.eventList, action.roomId)
)
)
),
(action, latestStoreData) => latestStoreData
),
tap(([req, eventList]) => {
if (!!eventList && eventList.length > 0) {
this.store.dispatch(
events({
req: {
roomId: req.roomId,
baseSeq: eventList.sort((a, b) => a.seq - b.seq)[0].seq,
requestCount:
this.moduleConfig?.eventRequestDefaultCount || 50
} as InfoRequest
})
);
}
})
);
},
{ dispatch: false }
);
read$ = createEffect(
() => {
return this.actions$.pipe(
ofType(read),
exhaustMap((req) =>
this.eventProtocolService.read(req).pipe(
map((res: ReadResponse) => {
// room user lastReadEventSeq reset.
this.store.dispatch(readSuccess(res));
// room noReadCount reset.
this.store.dispatch(
RoomActions.updateUnreadCount({
roomId: res.roomId
})
);
}),
catchError((error) => of(readFailure({ error })))
)
)
);
},
{ dispatch: false }
);
fileInfos$ = createEffect(
() => {
return this.actions$.pipe(
ofType(fileInfos),
switchMap((action) => {
return this.fileProtocolService.info(action.req).pipe(
map((res) => {
this.store.dispatch(
fileInfosSuccess({
fileInfoList: res.fileInfos,
fileInfoCheckList: res.fileInfoChecks,
res: res.res
})
);
}),
catchError((error) =>
of(fileInfosFailure({ roomId: action.req.roomId, error }))
)
);
})
);
},
{ dispatch: false }
);
addEvent$ = createEffect(
() => {
return this.actions$.pipe(
ofType(addEvent),
withLatestFrom(
this.store.pipe(
select(
(state: any) =>
state.chat.chatting.chattings.entities as Dictionary<Chatting>
)
),
this.store.pipe(
select((state: any) => state.chat.chatting.activeRoomId)
)
),
tap(([action, chattings, activeRoomId]) => {
// Room in chattings state >> event add
if (!!chattings && !!chattings[action.roomId]) {
if (action.info.type === EventType.File) {
// Retrieve event of FileType in rooms
this.store.dispatch(
fileInfos({
req: {
roomId: action.roomId,
type: FileType.All
}
})
);
}
}
// room > rooms :: finalEvent-Infos refresh
this.store.dispatch(
addEventSuccess({
roomId: action.roomId,
info: action.info
})
);
})
);
},
{ dispatch: false }
);
send$ = createEffect(() =>
this.actions$.pipe(
ofType(send),
concatMap((action) =>
this.eventProtocolService.send(action.req).pipe(
map((res) => {
return sendSuccess({
senderSeq: action.senderSeq,
res
});
}),
catchError((error) => of(sendFailure({ error })))
)
)
)
);
sendSuccess$ = createEffect(
() => {
return this.actions$.pipe(
ofType(sendSuccess),
tap((action) => {
const res = action.res;
this.store.dispatch(
addEvent({
roomId: res.roomId,
info: res.info,
SVC_TYPE: res.SVC_TYPE,
SSVC_TYPE: res.SSVC_TYPE
})
);
})
);
},
{ dispatch: false }
);
/*******************************************************************
* [Room Action watching.]
*******************************************************************/
selectedRoomSuccess$ = createEffect(
() => {
return this.actions$.pipe(
ofType(RoomActions.selectedRoomSuccess),
debounceTime(300),
tap((action) => {
const requestCount = this.moduleConfig?.eventRequestInitCount || 50;
const req: InfoRequest = {
roomId: action.roomId,
baseSeq: 0,
requestCount
};
this.store.dispatch(events({ req }));
})
);
},
{ dispatch: false }
);
del$ = createEffect(() =>
this.actions$.pipe(
ofType(del),
exhaustMap((req) =>
this.eventProtocolService.del(req).pipe(
map((res: DelResponse) => {
return delNotification({ noti: res });
}),
catchError((error) => of(delFailure({ error })))
)
)
)
);
delNotification$ = createEffect(
() => {
return this.actions$.pipe(
ofType(delNotification),
map((action) => action.noti),
withLatestFrom(this.store.pipe(select(ChattingSelector.activeRoomId))),
tap(([noti, activeRoomId]) => {
// 현재 방이 오픈되어 있으면 방내용 갱신
const roomId = noti.roomId;
if (!!activeRoomId && activeRoomId === roomId) {
this.store.dispatch(
delEventList({ roomId, eventSeqs: [noti.eventSeq] })
);
}
// 대화 > 리스트의 항목 갱신
this.store.dispatch(
RoomActions.room({
req: {
roomId: noti.roomId,
isDetail: false,
localeCode: this.i18nService.currentLng.toUpperCase() as LocaleCode
}
})
);
})
);
},
{ dispatch: false }
);
forward$ = createEffect(
() => {
return this.actions$.pipe(
ofType(forward),
tap((action) => {
if (!!action.trgtRoomSeq) {
// 대화전달 후 방오픈. Exist roomSeq.
if (action.req.eventType === EventType.File) {
// file share request action
} else {
this.store.dispatch(roomOpenAfterForward(action));
}
} else if (!!action.trgtUserSeqs && action.trgtUserSeqs.length > 0) {
// 방오픈 후 대화전달.
this.store.dispatch(forwardAfterRoomOpen(action));
}
})
);
},
{ dispatch: false }
);
forwardAfterRoomOpen$ = createEffect(
() => {
let createRes: CreateResponse;
return this.actions$.pipe(
ofType(forwardAfterRoomOpen),
exhaustMap((actionReq) => {
return this.roomProtocolService
.open({ divCd: 'forwardOpen', userSeqs: actionReq.trgtUserSeqs })
.pipe(
map((res: CreateResponse) => {
createRes = res;
this.store.dispatch(RoomActions.createSuccess({ res }));
}),
map(() => {
if (actionReq.req.eventType === EventType.File) {
// file share request action
} else {
this.store.dispatch(
send({
senderSeq: actionReq.senderSeq,
req: {
roomId: createRes.roomId,
eventType: actionReq.req.eventType,
sentMessage: actionReq.req.sentMessage
}
})
);
}
}),
catchError((error) => of(RoomActions.createFailure({ error })))
);
})
);
},
{ dispatch: false }
);
roomOpenAfterForward$ = createEffect(
() => {
return this.actions$.pipe(
ofType(roomOpenAfterForward),
exhaustMap((action) => {
return this.eventProtocolService
.send({
roomId: action.trgtRoomSeq,
eventType: action.req.eventType,
sentMessage: action.req.sentMessage
})
.pipe(
map((res: SendResponse) => {
this.store.dispatch(
addEvent({
roomId: res.roomId,
info: res.info,
SVC_TYPE: res.SVC_TYPE,
SSVC_TYPE: res.SSVC_TYPE
})
);
this.store.dispatch(
RoomActions.selectedRoom({
roomId: res.roomId,
localeCode: this.i18nService.currentLng.toUpperCase() as LocaleCode
})
);
}),
catchError((error) => of(RoomActions.createFailure({ error })))
);
})
);
},
{ dispatch: false }
);
cancel$ = createEffect(() =>
this.actions$.pipe(
ofType(cancel),
exhaustMap((req) =>
this.eventProtocolService.cancel(req).pipe(
map((res: CancelResponse) => {
return delNotification({ noti: res });
}),
catchError((error) => of(delFailure({ error })))
)
)
)
);
cancelNotification$ = createEffect(
() => {
return this.actions$.pipe(
ofType(cancelNotification),
withLatestFrom(this.store.pipe(select(ChattingSelector.activeRoomId))),
tap(([action, activeRoomId]) => {
// 현재 방이 오픈되어 있으면 방내용 갱신
if (
!!activeRoomId &&
activeRoomId.localeCompare(action.noti.roomId) === 0
) {
this.store.dispatch(
updateEventList({
roomId: action.noti.roomId,
eventSeq: action.noti.eventSeq,
sentMessage: this.i18nService.t('event.recalled')
})
);
}
// 대화 > 리스트의 항목 갱신
this.store.dispatch(
RoomActions.room({
req: {
roomId: action.noti.roomId,
isDetail: false,
localeCode: this.i18nService.currentLng.toUpperCase() as LocaleCode
}
})
);
})
);
},
{ dispatch: false }
);
constructor(
private actions$: Actions,
private store: Store<any>,
private router: Router,
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
private roomProtocolService: RoomProtocolService,
private eventProtocolService: EventProtocolService,
private fileProtocolService: FileProtocolService,
private i18nService: I18nService
) {
this.i18nService.setDefaultNamespace('chat');
}
}