protocol-inner is added

This commit is contained in:
병준 박 2019-09-19 14:15:43 +09:00
parent b934474aa3
commit 834c25762c
27 changed files with 435 additions and 126 deletions

View File

@ -1200,9 +1200,7 @@
"projects/ucap-webmessenger-web-socket/tsconfig.lib.json", "projects/ucap-webmessenger-web-socket/tsconfig.lib.json",
"projects/ucap-webmessenger-web-socket/tsconfig.spec.json" "projects/ucap-webmessenger-web-socket/tsconfig.spec.json"
], ],
"exclude": [ "exclude": ["**/node_modules/**"]
"**/node_modules/**"
]
} }
} }
} }
@ -1235,9 +1233,40 @@
"projects/ucap-webmessenger-util/tsconfig.lib.json", "projects/ucap-webmessenger-util/tsconfig.lib.json",
"projects/ucap-webmessenger-util/tsconfig.spec.json" "projects/ucap-webmessenger-util/tsconfig.spec.json"
], ],
"exclude": [ "exclude": ["**/node_modules/**"]
"**/node_modules/**" }
] }
}
},
"ucap-webmessenger-protocol-inner": {
"projectType": "library",
"root": "projects/ucap-webmessenger-protocol-inner",
"sourceRoot": "projects/ucap-webmessenger-protocol-inner/src",
"prefix": "ucap-protocol-inner",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/ucap-webmessenger-protocol-inner/tsconfig.lib.json",
"project": "projects/ucap-webmessenger-protocol-inner/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ucap-webmessenger-protocol-inner/src/test.ts",
"tsConfig": "projects/ucap-webmessenger-protocol-inner/tsconfig.spec.json",
"karmaConfig": "projects/ucap-webmessenger-protocol-inner/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/ucap-webmessenger-protocol-inner/tsconfig.lib.json",
"projects/ucap-webmessenger-protocol-inner/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
} }
} }
} }

6
package-lock.json generated
View File

@ -4832,12 +4832,6 @@
"integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=",
"dev": true "dev": true
}, },
"current-device": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/current-device/-/current-device-0.8.2.tgz",
"integrity": "sha512-DB/lozoIa5jZpyNQq7C6zlWNJ00V/qKeYhXRyI1sckTmlQhS9sfeflK72Tsx7HyUYmDLywb3lhfzrHt/9Tx7Gg==",
"dev": true
},
"currently-unhandled": { "currently-unhandled": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",

View File

@ -3,6 +3,7 @@ import { NgModule, APP_INITIALIZER } from '@angular/core';
import { UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native'; import { UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { ElectronNativeService } from '@ucap-webmessenger/native-electron'; import { ElectronNativeService } from '@ucap-webmessenger/native-electron';
import { RESOLVERS } from './resolvers';
import { SERVICES } from './services'; import { SERVICES } from './services';
import { AppService } from './services/app.service'; import { AppService } from './services/app.service';
@ -17,6 +18,7 @@ export function initializeApp(appService: AppService) {
exports: [], exports: [],
providers: [ providers: [
...SERVICES, ...SERVICES,
...RESOLVERS,
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: initializeApp, useFactory: initializeApp,

View File

@ -1,13 +1,17 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from './guards/auth.guard'; import { AuthGuard } from './guards/auth.guard';
import { MessengerResolver } from './resolvers/messenger.resolver';
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: '/messenger', pathMatch: 'full' }, { path: '', redirectTo: '/messenger', pathMatch: 'full' },
{ {
path: 'messenger', path: 'messenger',
loadChildren: './pages/messenger/messenger.page.module#MessengerPageModule', loadChildren: './pages/messenger/messenger.page.module#MessengerPageModule',
canActivate: [AuthGuard] canActivate: [AuthGuard],
resolve: {
protocol: MessengerResolver
}
}, },
{ {
path: 'account', path: 'account',

View File

@ -13,6 +13,7 @@ import { UCapPiModule } from '@ucap-webmessenger/pi';
import { UCapProtocolModule } from '@ucap-webmessenger/protocol'; import { UCapProtocolModule } from '@ucap-webmessenger/protocol';
import { UCapAuthenticationProtocolModule } from '@ucap-webmessenger/protocol-authentication'; import { UCapAuthenticationProtocolModule } from '@ucap-webmessenger/protocol-authentication';
import { UCapInnerProtocolModule } from '@ucap-webmessenger/protocol-inner';
import { UCapUiModule } from '@ucap-webmessenger/ui'; import { UCapUiModule } from '@ucap-webmessenger/ui';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account'; import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
@ -60,6 +61,7 @@ import { GUARDS } from './guards';
requestId: environment.protocol.requestId requestId: environment.protocol.requestId
}), }),
UCapAuthenticationProtocolModule.forRoot(), UCapAuthenticationProtocolModule.forRoot(),
UCapInnerProtocolModule.forRoot(),
UCapUiModule.forRoot(), UCapUiModule.forRoot(),
UCapUiAccountModule.forRoot(), UCapUiAccountModule.forRoot(),

View File

@ -1,10 +1,17 @@
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { AuthenticationProtocolService } from '@ucap-webmessenger/protocol-authentication';
@Component({ @Component({
selector: 'app-page-messenger-main', selector: 'app-page-messenger-main',
templateUrl: './main.page.component.html', templateUrl: './main.page.component.html',
styleUrls: ['./main.page.component.scss'] styleUrls: ['./main.page.component.scss']
}) })
export class MainPageComponent { export class MainPageComponent implements OnInit {
title = 'ucap-webmessenger-app'; constructor(
private authenticationProtocolService: AuthenticationProtocolService
) {}
ngOnInit(): void {
// this.authenticationProtocolService.login({});
}
} }

View File

@ -0,0 +1,3 @@
import { MessengerResolver } from './messenger.resolver';
export const RESOLVERS = [MessengerResolver];

View File

@ -0,0 +1,65 @@
import { Injectable } from '@angular/core';
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from '@angular/router';
import { Observable } from 'rxjs';
import { take, map } from 'rxjs/operators';
import { Store, select } from '@ngrx/store';
import { ProtocolService } from '@ucap-webmessenger/protocol';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { PublicApiService } from '@ucap-webmessenger/api-public';
import * as AppStore from '../store';
import * as VersionInfoStore from '../store/setting/version-info';
import { LoginInfo, KEY_LOGIN_INFO } from '../types';
import { InnerProtocolService } from '@ucap-webmessenger/protocol-inner';
@Injectable()
export class MessengerResolver implements Resolve<void> {
constructor(
private store: Store<any>,
private sessionStorageService: SessionStorageService,
private publicApiService: PublicApiService,
private protocolService: ProtocolService,
private innerProtocolService: InnerProtocolService
) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): void | Observable<void> | Promise<void> {
const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
return this.publicApiService
.versionInfo2({
deviceType: loginInfo.deviceType,
companyGroupType: 'C',
companyCode: loginInfo.companyCode,
loginId: loginInfo.loginId
})
.pipe(
take(1),
map(res => {
this.store.dispatch(VersionInfoStore.fetchSuccess(res));
this.protocolService
.connect(res.serverIp)
.then(() => {
this.innerProtocolService
.conn({})
.pipe(
take(1),
map(() => {
console.log('innerProtocolService.conn');
})
)
.subscribe();
})
.catch(reason => {});
})
);
}
}

View File

@ -21,15 +21,6 @@ export const loginSuccess = createAction(
}>() }>()
); );
export const postLoginSuccess = createAction(
'[Account::Authentication] Post Login Success',
props<{
loginInfo: LoginInfo;
rememberMe: boolean;
login2Response: Login2Response;
}>()
);
export const loginFailure = createAction( export const loginFailure = createAction(
'[Account::Authentication] Login Failure', '[Account::Authentication] Login Failure',
props<{ error: any }>() props<{ error: any }>()

View File

@ -4,7 +4,14 @@ import { Router } from '@angular/router';
import { Actions, ofType, createEffect } from '@ngrx/effects'; import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { catchError, exhaustMap, map, tap, switchMap } from 'rxjs/operators'; import {
catchError,
exhaustMap,
map,
tap,
switchMap,
take
} from 'rxjs/operators';
import { import {
PiService, PiService,
@ -17,8 +24,7 @@ import {
loginSuccess, loginSuccess,
loginFailure, loginFailure,
loginRedirect, loginRedirect,
logout, logout
postLoginSuccess
} from './actions'; } from './actions';
import { LoginInfo } from '../../../types'; import { LoginInfo } from '../../../types';
import { AuthenticationService } from '../../../services/authentication.service'; import { AuthenticationService } from '../../../services/authentication.service';
@ -39,7 +45,6 @@ export class Effects {
}) })
.pipe( .pipe(
map((res: Login2Response) => { map((res: Login2Response) => {
console.log(res);
if (res.status === ResponseStatus.Fail) { if (res.status === ResponseStatus.Fail) {
return loginFailure({ error: 'Failed' }); return loginFailure({ error: 'Failed' });
} else { } else {
@ -56,32 +61,30 @@ export class Effects {
) )
); );
loginSuccess$ = createEffect(() => loginSuccess$ = createEffect(
this.actions$.pipe( () =>
ofType(loginSuccess), this.actions$.pipe(
map(action => action), ofType(loginSuccess),
exhaustMap( tap(params => {
(params: { this.nativeService
loginInfo: LoginInfo; .checkForUpdates()
rememberMe: boolean; .pipe(
login2Response: Login2Response; take(1),
}) => map((update: boolean) => {
this.nativeService.checkForUpdates().pipe( if (!update) {
map((update: boolean) => { this.authentication.login(
if (!update) { params.loginInfo,
this.authentication.login(params.loginInfo, params.rememberMe); params.rememberMe
this.router.navigate(['/messenger']); );
return postLoginSuccess({ this.router.navigate(['/messenger']);
loginInfo: params.loginInfo, }
rememberMe: params.rememberMe, }),
login2Response: params.login2Response catchError(error => of(error))
}); )
} .subscribe();
}), })
catchError(error => of(error)) ),
) { dispatch: false }
)
)
); );
loginRedirect$ = createEffect( loginRedirect$ = createEffect(

View File

@ -10,31 +10,10 @@ import { PublicApiService } from '@ucap-webmessenger/api-public';
import { StatusCode } from '@ucap-webmessenger/api'; import { StatusCode } from '@ucap-webmessenger/api';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { postLoginSuccess } from '../../account/authentication';
import { fetch, fetchSuccess, fetchFailure } from './actions'; import { fetch, fetchSuccess, fetchFailure } from './actions';
import { LoginInfo, KEY_LOGIN_INFO } from '../../../types';
@Injectable() @Injectable()
export class Effects { export class Effects {
init$ = createEffect(() =>
this.actions$.pipe(
ofType(postLoginSuccess),
map(action => {
const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO
);
return fetch({
deviceType: loginInfo.deviceType,
companyGroupType: 'C',
companyCode: loginInfo.companyCode,
loginId: loginInfo.loginId
});
})
)
);
fetch$ = createEffect(() => fetch$ = createEffect(() =>
this.actions$.pipe( this.actions$.pipe(
ofType(fetch), ofType(fetch),

View File

@ -0,0 +1,25 @@
# UcapWebmessengerProtocolInner
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.5.
## Code scaffolding
Run `ng generate component component-name --project ucap-webmessenger-protocol-inner` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-protocol-inner`.
> Note: Don't forget to add `--project ucap-webmessenger-protocol-inner` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build ucap-webmessenger-protocol-inner` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build ucap-webmessenger-protocol-inner`, go to the dist folder `cd dist/ucap-webmessenger-protocol-inner` and run `npm publish`.
## Running unit tests
Run `ng test ucap-webmessenger-protocol-inner` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -0,0 +1,35 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(
__dirname,
'../../coverage/ucap-webmessenger-protocol-inner'
),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

View File

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ucap-webmessenger-protocol-inner",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -0,0 +1,8 @@
{
"name": "@ucap-webmessenger/protocol-inner",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^8.2.5",
"@angular/core": "^8.2.5"
}
}

View File

@ -0,0 +1,8 @@
import { DeviceType, LocaleCode } from '@ucap-webmessenger/core';
import { ProtocolRequest, ProtocolResponse } from '@ucap-webmessenger/protocol';
// tslint:disable-next-line: no-empty-interface
export interface ConnRequest extends ProtocolRequest {}
// tslint:disable-next-line: no-empty-interface
export interface ConnResponse extends ProtocolResponse {}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { InnerProtocolService } from './inner-protocol.service';
describe('InnerProtocolService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: InnerProtocolService = TestBed.get(InnerProtocolService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ProtocolService } from '@ucap-webmessenger/protocol';
import { ConnResponse, ConnRequest } from '../models/conn';
import { SVC_TYPE_INNER, SSVC_TYPE_CONN_REQ } from '../types/service';
@Injectable({
providedIn: 'root'
})
export class InnerProtocolService {
constructor(private protocolService: ProtocolService) {}
public conn(req: ConnRequest): Observable<ConnResponse> {
return this.protocolService.call(SVC_TYPE_INNER, SSVC_TYPE_CONN_REQ).pipe(
map(res => {
return {} as ConnResponse;
})
);
}
}

View File

@ -0,0 +1,4 @@
export const SVC_TYPE_INNER = 1000;
export const SSVC_TYPE_CONN_REQ = 1; // (클라이언트 접속 시)
export const SSVC_TYPE_CONN_RES = 2; // (클라이언트 접속 시)

View File

@ -0,0 +1,19 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { InnerProtocolService } from './services/inner-protocol.service';
const SERVICES = [InnerProtocolService];
@NgModule({
declarations: [],
imports: [],
exports: []
})
export class UCapInnerProtocolModule {
public static forRoot(): ModuleWithProviders<UCapInnerProtocolModule> {
return {
ngModule: UCapInnerProtocolModule,
providers: [...SERVICES]
};
}
}

View File

@ -0,0 +1,7 @@
/*
* Public API Surface of ucap-webmessenger-protocol-inner
*/
export * from './lib/services/inner-protocol.service';
export * from './lib/ucap-inner-protocol.module';

View File

@ -0,0 +1,21 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -0,0 +1,26 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [true, "attribute", "ucapProtocolInner", "camelCase"],
"component-selector": [true, "element", "ucap-protocol-inner", "kebab-case"]
}
}

View File

@ -54,63 +54,70 @@ export class ProtocolService {
this.input$ = new QueueingSubject<string>(); this.input$ = new QueueingSubject<string>();
} }
public connect(serverIp: string | null = null): void { public connect(serverIp: string | null = null): Promise<void> {
this.socket$ = makeWebSocketObservable( return new Promise<void>((resolve, reject) => {
this.moduleConfig.urls.base + serverIp ? serverIp : '' this.socket$ = makeWebSocketObservable(
); `${this.moduleConfig.urls.base}${serverIp ? serverIp : ''}`
this.messages$ = this.socket$.pipe( );
switchMap(getResponses => getResponses(this.input$)), this.messages$ = this.socket$.pipe(
retryWhen(errors => switchMap(getResponses => {
errors.pipe(delay(this.moduleConfig.reconnect.delay)) resolve();
), return getResponses(this.input$);
share() }),
); retryWhen(errors =>
errors.pipe(delay(this.moduleConfig.reconnect.delay))
),
share()
);
this.messagesSubscription = this.messages$.subscribe( this.messagesSubscription = this.messages$.subscribe(
(message: string) => { (message: string) => {
const arg = message.split(PacketBodyDivider); console.log(`message`, message);
if (2 > arg.length) {
// OnError(3);
return;
}
const res = this.decodePacket(arg); const arg = message.split(PacketBodyDivider);
if (2 > arg.length) {
// OnError(3);
return;
}
let requestState: RequestState | null = null; const res = this.decodePacket(arg);
if (res.requestId) {
requestState = this.pendingRequests.get(res.requestId);
this.pendingRequests.delete(res.requestId);
}
if (SSVC_TYPE_ERROR_RES === res.response.subServiceType) { let requestState: RequestState | null = null;
const errorCode: ServerErrorCode = res.response if (res.requestId) {
.bodyList[0] as ServerErrorCode; requestState = this.pendingRequests.get(res.requestId);
this.pendingRequests.delete(res.requestId);
}
if (SSVC_TYPE_ERROR_RES === res.response.subServiceType) {
const errorCode: ServerErrorCode = res.response
.bodyList[0] as ServerErrorCode;
if (requestState) {
requestState.subject.error(errorCode);
}
return;
}
if (requestState) { if (requestState) {
requestState.subject.error(errorCode); requestState.subject.next(res.response);
} }
return; },
(error: Error) => {
const { message } = error;
if (message === NormalClosureMessage) {
console.log('server closed the websocket connection normally');
} else {
console.log('socket was disconnected due to error:', message);
}
},
() => {
// The clean termination only happens in response to the last
// subscription to the observable being unsubscribed, any
// other closure is considered an error.
console.log('the connection was closed in response to the user');
} }
);
if (requestState) { });
requestState.subject.next(res.response);
}
},
(error: Error) => {
const { message } = error;
if (message === NormalClosureMessage) {
console.log('server closed the websocket connection normally');
} else {
console.log('socket was disconnected due to error:', message);
}
},
() => {
// The clean termination only happens in response to the last
// subscription to the observable being unsubscribed, any
// other closure is considered an error.
console.log('the connection was closed in response to the user');
}
);
} }
public disconnect(): void { public disconnect(): void {
@ -194,7 +201,7 @@ export class ProtocolService {
} }
const senderSeq = Number(seqArg[0]); const senderSeq = Number(seqArg[0]);
const bodyList: any[] | null = null; const bodyList: any[] = [];
let requestId: number | null = null; let requestId: number | null = null;
for (let i = 2; i < arg.length; i++) { for (let i = 2; i < arg.length; i++) {

View File

@ -68,6 +68,9 @@
"@ucap-webmessenger/protocol-info": [ "@ucap-webmessenger/protocol-info": [
"projects/ucap-webmessenger-protocol-info/src/public-api" "projects/ucap-webmessenger-protocol-info/src/public-api"
], ],
"@ucap-webmessenger/protocol-inner": [
"projects/ucap-webmessenger-protocol-inner/src/public-api"
],
"@ucap-webmessenger/protocol-option": [ "@ucap-webmessenger/protocol-option": [
"projects/ucap-webmessenger-protocol-option/src/public-api" "projects/ucap-webmessenger-protocol-option/src/public-api"
], ],