parameter of api call is modified

This commit is contained in:
병준 박 2019-09-19 10:40:16 +09:00
parent 9464e3b6bd
commit d918b9a4db
43 changed files with 17178 additions and 87 deletions

View File

@ -1206,6 +1206,41 @@
}
}
}
},
"ucap-webmessenger-util": {
"projectType": "library",
"root": "projects/ucap-webmessenger-util",
"sourceRoot": "projects/ucap-webmessenger-util/src",
"prefix": "ucap-util",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/ucap-webmessenger-util/tsconfig.lib.json",
"project": "projects/ucap-webmessenger-util/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ucap-webmessenger-util/src/test.ts",
"tsConfig": "projects/ucap-webmessenger-util/tsconfig.spec.json",
"karmaConfig": "projects/ucap-webmessenger-util/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/ucap-webmessenger-util/tsconfig.lib.json",
"projects/ucap-webmessenger-util/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "ucap-webmessenger-app"

16353
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
import { DeviceType } from '@ucap-webmessenger/core';
import { APIRequest, APIResponse } from '@ucap-webmessenger/api';
import { SyncMode } from '../types/sync-mode.type';
export interface VersionInfoRequest extends APIRequest {
userSeq?: string;
export interface VersionInfo2Request extends APIRequest {
userSeq?: number;
deviceType: DeviceType;
token?: string;
companyGroupType: string;
@ -10,20 +11,19 @@ export interface VersionInfoRequest extends APIRequest {
loginId: string;
}
export interface VersionInfoResponse extends APIResponse {
protocolCode?: string;
syncMode?: string;
export interface VersionInfo2Response extends APIResponse {
protocolCode?: number;
syncMode?: SyncMode;
appVersion?: string;
installUrl?: string;
serverIp?: string;
serverPort?: string;
uploadUrl?: string;
downloadUrl?: string;
profileUploadUrl?: string;
profileRoot?: string;
fileTerm?: string;
fileAllowSize?: string;
authIp?: string;
fileTerm?: number;
fileAllowSize?: number;
authIp?: boolean;
launcherAppVersion?: string;
launcherInstallUrl?: string;
}

View File

@ -6,11 +6,26 @@ import { map } from 'rxjs/operators';
import { _MODULE_CONFIG } from '../types/token';
import {
VersionInfoRequest,
VersionInfoResponse
} from '../models/version-info';
VersionInfo2Request,
VersionInfo2Response
} from '../models/version-info2';
import { UpdateInfoRequest, UpdateInfoResponse } from '../models/update-info';
import { ModuleConfig } from '../types/module-config';
import { ParameterUtil } from '@ucap-webmessenger/api';
import { SyncMode } from '../types/sync-mode.type';
const versionInfo2Parameters = {
userSeq: 'p_user_seq',
deviceType: 'p_device_type',
token: 'p_token',
companyGroupType: 'p_comp_group_type',
companyCode: 'p_comp_code',
loginId: 'p_login_id'
};
const updateInfoParameters = {
deviceType: 'p_device_type'
};
@Injectable({
providedIn: 'root'
@ -21,43 +36,37 @@ export class PublicApiService {
private httpClient: HttpClient
) {}
public versionInfo(req: VersionInfoRequest): Observable<VersionInfoResponse> {
public versionInfo2(
req: VersionInfo2Request
): Observable<VersionInfo2Response> {
return this.httpClient
.post<any>(
this.moduleConfig.urls.versionInfo,
this.moduleConfig.urls.versionInfo2,
{},
{
params: {
p_user_seq: req.userSeq,
p_device_type: req.deviceType,
p_token: req.token,
p_comp_group_type: req.companyGroupType,
p_comp_code: req.companyCode,
p_login_id: req.loginId
}
params: ParameterUtil.make(versionInfo2Parameters, req)
}
)
.pipe(
map(res => {
map((res: any) => {
return {
statusCode: res.StatusCode,
errorMessage: res.ErrorMessage,
protocolCode: res.ProtocolCD,
syncMode: res.SyncMode,
appVersion: res.AppVer,
installUrl: res.InstallURL,
serverIp: res.ServerIP,
serverPort: res.ServerPort,
uploadUrl: res.UploadURL,
authIp: res.AuthIP === 'Y' ? true : false,
downloadUrl: res.DownloadURL,
profileUploadUrl: res.ProfileUploadURL,
profileRoot: res.ProfileRoot,
fileTerm: res.FileTerm,
fileAllowSize: res.FileAllowSize,
authIp: res.AuthIP,
fileAllowSize: Number(res.FileAllowSize),
fileTerm: Number(res.FileTerm),
installUrl: res.InstallURL,
launcherAppVersion: res.LauncherAppVer,
launcherInstallUrl: res.LauncherInstallURL
} as VersionInfoResponse;
launcherInstallUrl: res.LauncherInstallURL,
profileRoot: res.ProfileRoot,
profileUploadUrl: res.ProfileUploadURL,
protocolCode: Number(res.ProtocolCD),
serverIp: res.ServerIP,
syncMode: res.SyncMode as SyncMode,
uploadUrl: res.UploadURL
} as VersionInfo2Response;
})
);
}
@ -68,9 +77,7 @@ export class PublicApiService {
this.moduleConfig.urls.updateInfo,
{},
{
params: {
p_device_type: req.deviceType
}
params: ParameterUtil.make(updateInfoParameters, req)
}
)
.pipe(

View File

@ -1,6 +1,6 @@
export interface ModuleConfig {
urls: {
versionInfo: string;
versionInfo2: string;
updateInfo: string;
};
}

View File

@ -0,0 +1,4 @@
export enum SyncMode {
BC = 'BC',
SC = 'SC'
}

View File

@ -2,11 +2,12 @@
* Public API Surface of ucap-webmessenger-api-public
*/
export * from './lib/types/module-config';
export * from './lib/models/update-info';
export * from './lib/models/version-info';
export * from './lib/models/version-info2';
export * from './lib/services/public-api.service';
export * from './lib/types/module-config';
export * from './lib/types/sync-mode.type';
export * from './lib/ucap-public-api.module';

View File

@ -1,9 +1,11 @@
import { StatusCode } from '../types/status-code.type';
export interface APIRequest {
_id?: string;
}
export interface APIResponse {
_id?: string;
statusCode: string;
statusCode: StatusCode;
errorMessage: string;
}

View File

@ -0,0 +1,20 @@
export type Parameter = {
[param: string]: string | string[];
} | null;
export class ParameterUtil {
public static make(parameterMap: {}, param: {}): Parameter {
const parameter: Parameter = {};
Object.keys(parameterMap).map(key => {
if (!param.hasOwnProperty(key)) {
return;
}
if (!!param[key]) {
parameter[parameterMap[key]] = param[key];
}
});
return 0 === Object.keys(parameter).length ? null : parameter;
}
}

View File

@ -5,3 +5,5 @@
export * from './lib/models/api';
export * from './lib/types/status-code.type';
export * from './lib/utils/parameter.util';

View File

@ -1,14 +1,28 @@
import { NgModule } from '@angular/core';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { SERVICES } from './services';
import { UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { ElectronNativeService } from '@ucap-webmessenger/native-electron';
import { SERVICES } from './services';
import { AppService } from './services/app.service';
export function initializeApp(appService: AppService) {
return (): Promise<any> => {
return appService.postInit();
};
}
@NgModule({
imports: [],
exports: [],
providers: [
...SERVICES,
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
deps: [AppService],
multi: true
},
{ provide: UCAP_NATIVE_SERVICE, useClass: ElectronNativeService }
]
})

View File

@ -11,11 +11,16 @@ import { UCapPublicApiModule } from '@ucap-webmessenger/api-public';
import { UCapPiModule } from '@ucap-webmessenger/pi';
import { UCapProtocolModule } from '@ucap-webmessenger/protocol';
import { UCapAuthenticationProtocolModule } from '@ucap-webmessenger/protocol-authentication';
import { UCapUiModule } from '@ucap-webmessenger/ui';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
import { UCapWebStorageModule } from '@ucap-webmessenger/web-storage';
import { UCapUtilModule } from '@ucap-webmessenger/util';
import { environment } from '../environments/environment';
import { AppProviderModule } from './app-provider.module';
@ -49,11 +54,20 @@ import { GUARDS } from './guards';
urls: environment.urls.pi
}),
UCapProtocolModule.forRoot({
urls: environment.urls.protocol,
reconnect: environment.protocol.reconnect,
requestId: environment.protocol.requestId
}),
UCapAuthenticationProtocolModule.forRoot(),
UCapUiModule.forRoot(),
UCapUiAccountModule.forRoot(),
UCapWebStorageModule.forRoot(),
UCapUtilModule.forRoot(),
AppProviderModule,
AppRoutingModule,
AppStoreModule,

View File

@ -0,0 +1,12 @@
import { Injectable } from '@angular/core';
@Injectable()
export class AppService {
constructor() {}
public postInit(): Promise<void> {
return new Promise<void>((resolve, reject) => {
resolve();
});
}
}

View File

@ -7,6 +7,8 @@ import {
LocalStorageService
} from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '../types';
import { EnviromentUtilService } from '@ucap-webmessenger/util';
import { DeviceType } from '@ucap-webmessenger/core';
@Injectable({
providedIn: 'root'
@ -16,7 +18,8 @@ export class AuthenticationService {
constructor(
private sessionStorageService: SessionStorageService,
private localStorageService: LocalStorageService
private localStorageService: LocalStorageService,
private enviromentUtilService: EnviromentUtilService
) {}
authenticated(): boolean {
@ -25,9 +28,22 @@ export class AuthenticationService {
}
login(loginInfo: LoginInfo, rememberMe: boolean) {
let deviceType: DeviceType;
if (this.enviromentUtilService.nodeWebkit()) {
deviceType = DeviceType.PC;
} else if (this.enviromentUtilService.android()) {
deviceType = DeviceType.Android;
} else if (this.enviromentUtilService.ios()) {
deviceType = DeviceType.iOS;
} else {
deviceType = DeviceType.Web;
}
this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, {
...loginInfo,
loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw))
loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw)),
deviceType
});
if (rememberMe) {

View File

@ -1,4 +1,5 @@
import { AppService } from './app.service';
import { AuthenticationService } from './authentication.service';
import { LoaderService } from './loader.service';
export const SERVICES = [AuthenticationService, LoaderService];
export const SERVICES = [AppService, AuthenticationService, LoaderService];

View File

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

View File

@ -4,7 +4,7 @@ import { Router } from '@angular/router';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, exhaustMap, map, tap } from 'rxjs/operators';
import { catchError, exhaustMap, map, tap, switchMap } from 'rxjs/operators';
import {
PiService,
@ -17,7 +17,8 @@ import {
loginSuccess,
loginFailure,
loginRedirect,
logout
logout,
postLoginSuccess
} from './actions';
import { LoginInfo } from '../../../types';
import { AuthenticationService } from '../../../services/authentication.service';
@ -55,24 +56,32 @@ export class Effects {
)
);
loginSuccess$ = createEffect(
() =>
loginSuccess$ = createEffect(() =>
this.actions$.pipe(
ofType(loginSuccess),
tap(params => {
this.nativeService
.checkForUpdates()
.then(update => {
map(action => action),
exhaustMap(
(params: {
loginInfo: LoginInfo;
rememberMe: boolean;
login2Response: Login2Response;
}) =>
this.nativeService.checkForUpdates().pipe(
map((update: boolean) => {
if (!update) {
this.authentication.login(params.loginInfo, params.rememberMe);
this.router.navigate(['/messenger']);
return;
return postLoginSuccess({
loginInfo: params.loginInfo,
rememberMe: params.rememberMe,
login2Response: params.login2Response
});
}
})
.catch(reson => {});
})
),
{ dispatch: false }
}),
catchError(error => of(error))
)
)
)
);
loginRedirect$ = createEffect(

View File

@ -12,10 +12,12 @@ import { storeFreeze } from 'ngrx-store-freeze';
import { environment } from '../../environments/environment';
import * as AccountStore from './account';
import * as SettingStore from './setting';
export interface State {
router: fromRouter.RouterReducerState<any>;
account: AccountStore.State;
setting: SettingStore.State;
}
/**
@ -28,11 +30,15 @@ export const ROOT_REDUCERS = new InjectionToken<
>('Root reducers token', {
factory: () => ({
router: fromRouter.routerReducer,
account: AccountStore.reducers
account: AccountStore.reducers,
setting: SettingStore.reducers
})
});
export const effects: Type<any>[] = [...AccountStore.effects];
export const effects: Type<any>[] = [
...AccountStore.effects,
...SettingStore.effects
];
export function logger(reducer: ActionReducer<State>): ActionReducer<State> {
return (state, action) => {
@ -54,3 +60,7 @@ export const metaReducers: MetaReducer<State>[] = !environment.production
export const AccountSelector = AccountStore.selectors(
(state: State) => state.account
);
export const SettingSelector = SettingStore.selectors(
(state: State) => state.setting
);

View File

@ -0,0 +1,27 @@
import { Type } from '@angular/core';
import { Action, combineReducers, Selector, createSelector } from '@ngrx/store';
import * as VersionInfoStore from './version-info';
export interface State {
versionInfo: VersionInfoStore.State;
}
export const effects: Type<any>[] = [VersionInfoStore.Effects];
export function reducers(state: State | undefined, action: Action) {
return combineReducers({
versionInfo: VersionInfoStore.reducers
})(state, action);
}
export function selectors<S>(selector: Selector<any, State>) {
return {
VersionInfoSelector: VersionInfoStore.selectors(
createSelector(
selector,
(state: State) => state.versionInfo
)
)
};
}

View File

@ -1,18 +1,18 @@
import { createAction, props } from '@ngrx/store';
import {
VersionInfoRequest,
VersionInfoResponse
VersionInfo2Request,
VersionInfo2Response
} from '@ucap-webmessenger/api-public';
export const fetch = createAction(
'[Setting::VersionInfo] Fetch',
props<VersionInfoRequest>()
props<VersionInfo2Request>()
);
export const fetchSuccess = createAction(
'[Setting::VersionInfo] Fetch Success',
props<VersionInfoResponse>()
props<VersionInfo2Response>()
);
export const fetchFailure = createAction(

View File

@ -6,20 +6,44 @@ import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, exhaustMap, map, tap } from 'rxjs/operators';
import { fetch, fetchSuccess, fetchFailure } from './actions';
import { PublicApiService } from '@ucap-webmessenger/api-public';
import { StatusCode } from '@ucap-webmessenger/api';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { postLoginSuccess } from '../../account/authentication';
import { fetch, fetchSuccess, fetchFailure } from './actions';
import { LoginInfo, KEY_LOGIN_INFO } from '../../../types';
@Injectable()
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(() =>
this.actions$.pipe(
ofType(fetch),
map(action => action),
exhaustMap(req =>
this.publicApiService.versionInfo(req).pipe(
this.publicApiService.versionInfo2(req).pipe(
map(res => {
if (res.statusCode === StatusCode.Success) {
console.log('fetchSuccess', res);
return fetchSuccess(res);
} else {
return fetchFailure({ error: 'Failed' });
@ -43,6 +67,7 @@ export class Effects {
constructor(
private actions$: Actions,
private publicApiService: PublicApiService,
private sessionStorageService: SessionStorageService,
private router: Router
) {}
}

View File

@ -1,9 +1,12 @@
import { DeviceType } from '@ucap-webmessenger/core';
export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO';
export interface LoginInfo {
loginId?: string;
loginPw?: string;
companyCode?: string;
deviceType?: DeviceType;
lang?: string;
encData?: string;
}

View File

@ -4,11 +4,18 @@ export abstract class UrlConfig {
constructor(
protected useSsl: boolean,
protected domain: string,
protected port: number
protected port: number,
protected webSocket: boolean = false
) {}
protected getProtocol(): string {
return this.useSsl ? 'https:' : 'http:';
return this.webSocket
? this.useSsl
? 'wss:'
: 'ws:'
: this.useSsl
? 'https:'
: 'http:';
}
protected getUrl(extra: url.UrlObject): string {
@ -26,7 +33,7 @@ export class ApiPublicUrlConfig extends UrlConfig {
super(useSsl, domain, port);
}
public get versionInfo(): string {
public get versionInfo2(): string {
return this.getUrl({
pathname: '/Pub/verinfo2.aspx'
});
@ -243,6 +250,18 @@ export class PiUrlConfig extends UrlConfig {
}
}
export class ProtocolUrlConfig extends UrlConfig {
constructor(useSsl: boolean, domain: string, port: number) {
super(useSsl, domain, port, true);
}
public get base(): string {
return this.getUrl({
pathname: '/'
});
}
}
export class VideoConfrenceUrlConfig extends UrlConfig {
constructor(useSsl: boolean, domain: string, port: number) {
super(useSsl, domain, port);
@ -290,9 +309,19 @@ export interface Environment {
apiCommon: ApiCommonUrlConfig;
apiExternal: ApiExternalUrlConfig;
pi: PiUrlConfig;
protocol: ProtocolUrlConfig;
videoConfrence: VideoConfrenceUrlConfig;
clickToCall: ClickToCallUrlConfig;
};
protocol: {
reconnect: {
delay: number;
};
requestId: {
min: number;
max: number;
};
};
}
export function build(production: boolean): Environment {
@ -314,6 +343,7 @@ export function build(production: boolean): Environment {
apiPublic: new ApiPublicUrlConfig(useSsl, webDomain, webPort),
apiExternal: new ApiExternalUrlConfig(useSsl, webDomain, webPort),
pi: new PiUrlConfig(useSsl, webDomain, devServer ? 9097 : 9097),
protocol: new ProtocolUrlConfig(useSsl, webDomain, useSsl ? 9443 : 8080),
videoConfrence: new VideoConfrenceUrlConfig(
useSsl,
devServer ? '101.55.17.24' : '101.55.17.24',
@ -324,6 +354,15 @@ export function build(production: boolean): Environment {
devServer ? '169.56.82.147' : '169.56.82.147',
devServer ? 9095 : 9095
)
},
protocol: {
reconnect: {
delay: 1000
},
requestId: {
min: 1,
max: 59999
}
}
};
}

View File

@ -2,6 +2,8 @@ import { Injectable } from '@angular/core';
import { ipcRenderer } from 'electron';
import { Observable } from 'rxjs';
import { NativeService } from '@ucap-webmessenger/native';
import { Channel } from '../types/channel.type';
@ -23,12 +25,14 @@ export class ElectronNativeService implements NativeService {
);
}
checkForUpdates(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
checkForUpdates(): Observable<boolean> {
return new Observable<boolean>(subscriber => {
try {
resolve(ipcRenderer.sendSync(Channel.checkForUpdates));
subscriber.next(ipcRenderer.sendSync(Channel.checkForUpdates));
} catch (error) {
reject(error);
subscriber.error(error);
} finally {
subscriber.complete();
}
});
}

View File

@ -1,3 +1,5 @@
import { Observable } from 'rxjs';
export interface NativeService {
showNotify(
roomSeq: number,
@ -7,7 +9,7 @@ export interface NativeService {
useSound: boolean
): void;
checkForUpdates(): Promise<boolean>;
checkForUpdates(): Observable<boolean>;
showImageViewer(): void;

View File

@ -2,6 +2,13 @@
* Public API Surface of ucap-webmessenger-protocol-authentication
*/
export * from './lib/models/fmc';
export * from './lib/models/login';
export * from './lib/services/authentication-protocol.service';
export * from './lib/types/role-code';
export * from './lib/types/service';
export * from './lib/types/sso-mode';
export * from './lib/ucap-authentication-protocol.module';

View File

@ -19,6 +19,7 @@ import {
PacketBodyDivider
} from '../types/packet-body-divider';
import { PacketBodyValue } from '../types/packet-body-value.type';
import { SSVC_TYPE_ERROR_RES, ServerErrorCode } from '../types/service';
interface RequestState {
subject: Subject<ServerResponse>;
@ -45,6 +46,7 @@ export class ProtocolService {
private readonly pendingRequests: Map<number, RequestState>;
private readonly input$: QueueingSubject<string>;
private socket$: Observable<GetWebSocketResponses<any>>;
private messages$: Observable<any>;
private messagesSubscription: Subscription | null = null;
constructor(@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig) {
@ -52,9 +54,11 @@ export class ProtocolService {
this.input$ = new QueueingSubject<string>();
}
public connect(): void {
this.socket$ = makeWebSocketObservable(this.moduleConfig.url);
const messages$ = this.socket$.pipe(
public connect(serverIp: string | null = null): void {
this.socket$ = makeWebSocketObservable(
this.moduleConfig.urls.base + serverIp ? serverIp : ''
);
this.messages$ = this.socket$.pipe(
switchMap(getResponses => getResponses(this.input$)),
retryWhen(errors =>
errors.pipe(delay(this.moduleConfig.reconnect.delay))
@ -62,7 +66,7 @@ export class ProtocolService {
share()
);
this.messagesSubscription = messages$.subscribe(
this.messagesSubscription = this.messages$.subscribe(
(message: string) => {
const arg = message.split(PacketBodyDivider);
if (2 > arg.length) {
@ -71,6 +75,26 @@ export class ProtocolService {
}
const res = this.decodePacket(arg);
let requestState: RequestState | null = null;
if (res.requestId) {
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) {
requestState.subject.next(res.response);
}
},
(error: Error) => {
const { message } = error;
@ -160,11 +184,15 @@ export class ProtocolService {
return null;
}
const serviceType = Number(cmdArg[0]);
const subServiceType = Number(cmdArg[1]);
const seqArg = arg[1].split(PacketBodyValueDivider);
if (2 > seqArg.length) {
// OnError(3);
return null;
}
const senderSeq = Number(seqArg[0]);
const bodyList: any[] | null = null;
let requestId: number | null = null;
@ -187,7 +215,7 @@ export class ProtocolService {
bodyList.push(value);
break;
case PacketBodyValue.Integer:
bodyList.push(parseInt(value, 10));
bodyList.push(Number(value));
break;
case PacketBodyValue.String:
bodyList.push(value);
@ -211,6 +239,16 @@ export class ProtocolService {
break;
}
}
return {
requestId,
response: {
serviceType,
subServiceType,
senderSeq,
bodyList
}
};
}
private encodePacket(

View File

@ -1,5 +1,7 @@
export interface ModuleConfig {
url: string;
urls: {
base: string;
};
reconnect: {
delay: number;
};

View File

@ -0,0 +1,26 @@
export const SSVC_TYPE_ERROR_RES = 1000;
export enum ServerErrorCode {
ERRCD_FORCE_CLOSE = 10,
ERRCD_PROTOCOL = 11,
ERRCD_VERSION = 12,
ERRCD_DID = 13,
ERRCD_IDPW = 14,
ERRCD_DUPLICATE = 15,
ERRCD_TOKEN = 16,
ERRCD_SETUP_MAIN = 17,
ERRCD_FORCE_INIT = 18,
ERRCD_SSO_AUTH = 19,
ERRCD_SSO_VALI = 20,
ERRCD_DEV_NOT_SUPPORTED = 21,
ERRCD_NO_MOBILE_PID = 22,
ERRCD_SVC_EXPIRE = 99,
ERRCD_FAILED = 100,
ERRCD_DATABASE = 101,
ERRCD_EXCESS = 102,
ERRCD_NEED_AUTH = 103,
ERRCD_USERINFO = 104, // ucap 은 없음.
ERRCD_AUTH_DENY = 1000,
ERRCD_ENCRYPT = 1001, // 패킷 암호화 오류
ERRCD_RECON = 1002 // 다른 IP로 접속 요청
}

View File

@ -10,5 +10,6 @@ export * from './lib/services/protocol.service';
export * from './lib/types/module-config';
export * from './lib/types/packet-body-divider';
export * from './lib/types/packet-body-value.type';
export * from './lib/types/service';
export * from './lib/ucap-protocol.module';

View File

@ -0,0 +1,24 @@
# UcapWebmessengerUtil
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-util` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-util`.
> Note: Don't forget to add `--project ucap-webmessenger-util` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build ucap-webmessenger-util` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build ucap-webmessenger-util`, go to the dist folder `cd dist/ucap-webmessenger-util` and run `npm publish`.
## Running unit tests
Run `ng test ucap-webmessenger-util` 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,32 @@
// 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-util'),
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-util",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

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

View File

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

View File

@ -0,0 +1,215 @@
import { Injectable } from '@angular/core';
import { detect, BrowserInfo, BotInfo, NodeInfo } from 'detect-browser';
const deviceTypeList = ['mobile', 'tablet', 'desktop'];
const osTypeList = [
'ios',
'iphone',
'ipad',
'ipod',
'android',
'blackberry',
'macos',
'windows',
'fxos',
'meego',
'television'
];
const televisionTypeList = [
'googletv',
'viera',
'smarttv',
'internet.tv',
'netcast',
'nettv',
'appletv',
'boxee',
'kylo',
'roku',
'dlnadoc',
'pov_tv',
'hbbtv',
'ce-html'
];
const orientationTypeList = ['portrait', 'landscape'];
@Injectable({
providedIn: 'root'
})
export class EnviromentUtilService {
private readonly userAgent: string;
constructor() {
this.userAgent = window.navigator.userAgent.toLowerCase();
}
public macos(): boolean {
return this.find('mac');
}
public ios(): boolean {
return this.iphone() || this.ipod() || this.ipad();
}
public iphone(): boolean {
return !this.windows() && this.find('iphone');
}
public ipod(): boolean {
return this.find('ipod');
}
public ipad(): boolean {
return this.find('ipad');
}
public android(): boolean {
return !this.windows() && this.find('android');
}
public androidPhone(): boolean {
return this.android() && this.find('mobile');
}
public androidTablet(): boolean {
return this.android() && !this.find('mobile');
}
public blackberry(): boolean {
return this.find('blackberry') || this.find('bb10') || this.find('rim');
}
public blackberryPhone(): boolean {
return this.blackberry() && !this.find('tablet');
}
public blackberryTablet(): boolean {
return this.blackberry() && this.find('tablet');
}
public windows(): boolean {
return this.find('windows');
}
public windowsPhone(): boolean {
return this.windows() && this.find('phone');
}
public windowsTablet(): boolean {
return this.windows() && (this.find('touch') && !this.windowsPhone());
}
public fxos(): boolean {
return (this.find('(mobile') || this.find('(tablet')) && this.find(' rv:');
}
public fxosPhone(): boolean {
return this.fxos() && this.find('mobile');
}
public fxosTablet(): boolean {
return this.fxos() && this.find('tablet');
}
public meego(): boolean {
return this.find('meego');
}
public cordova(): boolean {
return (window as any).cordova && location.protocol === 'file:';
}
public nodeWebkit(): boolean {
return typeof (window as any).process === 'object';
}
public mobile(): boolean {
return (
this.androidPhone() ||
this.iphone() ||
this.ipod() ||
this.windowsPhone() ||
this.blackberryPhone() ||
this.fxosPhone() ||
this.meego()
);
}
public tablet(): boolean {
return (
this.ipad() ||
this.androidTablet() ||
this.blackberryTablet() ||
this.windowsTablet() ||
this.fxosTablet()
);
}
public desktop(): boolean {
return !this.tablet() && !this.mobile();
}
public television(): boolean {
let i = 0;
while (i < televisionTypeList.length) {
if (this.find(televisionTypeList[i])) {
return true;
}
i++;
}
return false;
}
public portrait(): boolean {
if (
screen.orientation &&
Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
) {
return this.includes(screen.orientation.type, 'portrait');
}
return window.innerHeight / window.innerWidth > 1;
}
public landscape(): boolean {
if (
screen.orientation &&
Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
) {
return this.includes(screen.orientation.type, 'landscape');
}
return window.innerHeight / window.innerWidth < 1;
}
public type(): string {
return this.findMatch(deviceTypeList);
}
public os(): string {
return this.findMatch(osTypeList);
}
public browser(): BrowserInfo | BotInfo | NodeInfo {
return detect();
}
private includes(haystack: string, needle: string): boolean {
return haystack.indexOf(needle) !== -1;
}
private find(needle: string): boolean {
return this.includes(this.userAgent, needle);
}
private findMatch(arr: string[]): string {
for (const item of arr) {
if (this[item]()) {
return item;
}
}
return 'unknown';
}
}

View File

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

View File

@ -0,0 +1,7 @@
/*
* Public API Surface of ucap-webmessenger-util
*/
export * from './lib/services/enviroment-util.service';
export * from './lib/ucap-util.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,17 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"ucapUtil",
"camelCase"
],
"component-selector": [
true,
"element",
"ucap-util",
"kebab-case"
]
}
}

View File

@ -106,6 +106,9 @@
],
"@ucap-webmessenger/web-storage": [
"projects/ucap-webmessenger-web-storage/src/public-api"
],
"@ucap-webmessenger/util": [
"projects/ucap-webmessenger-util/src/public-api"
]
}
},