2019-11-19 19:34:53 +09:00
|
|
|
import { ipcRenderer, remote, shell } from 'electron';
|
2019-09-18 15:02:21 +09:00
|
|
|
|
2019-10-24 15:37:33 +09:00
|
|
|
import { Observable, Subject } from 'rxjs';
|
2019-09-19 10:40:16 +09:00
|
|
|
|
2019-11-01 11:25:54 +09:00
|
|
|
import {
|
|
|
|
NativeService,
|
|
|
|
WindowState,
|
2019-11-09 17:29:02 +09:00
|
|
|
NotificationRequest,
|
2019-12-12 17:15:09 +09:00
|
|
|
WindowIdle,
|
|
|
|
UpdateInfo,
|
2019-12-24 11:41:50 +09:00
|
|
|
UpdateCheckConfig,
|
|
|
|
NativePathName,
|
|
|
|
NativeType
|
2019-11-01 11:25:54 +09:00
|
|
|
} from '@ucap-webmessenger/native';
|
2019-10-24 15:37:33 +09:00
|
|
|
import { share } from 'rxjs/operators';
|
2019-11-09 17:29:02 +09:00
|
|
|
import {
|
|
|
|
NotificationChannel,
|
|
|
|
UpdaterChannel,
|
|
|
|
FileChannel,
|
|
|
|
WindowStateChannel,
|
2019-11-12 10:38:51 +09:00
|
|
|
IdleStateChannel,
|
2019-11-12 18:54:21 +09:00
|
|
|
ChatChannel,
|
2019-12-17 16:39:02 +09:00
|
|
|
MessengerChannel,
|
|
|
|
MessageChannel
|
2019-11-09 17:29:02 +09:00
|
|
|
} from '../types/channel.type';
|
2019-11-11 15:53:39 +09:00
|
|
|
import { Injectable } from '@angular/core';
|
2019-11-11 18:09:47 +09:00
|
|
|
import { TranslateLoaderService } from '../translate/electron-loader';
|
|
|
|
import { TranslateLoader } from '@ngx-translate/core';
|
2019-11-19 16:44:50 +09:00
|
|
|
import { StatusCode } from '@ucap-webmessenger/core';
|
2019-09-18 15:02:21 +09:00
|
|
|
|
2019-11-11 15:53:39 +09:00
|
|
|
@Injectable({
|
2019-11-19 16:44:50 +09:00
|
|
|
providedIn: 'root'
|
2019-11-11 15:53:39 +09:00
|
|
|
})
|
2019-09-18 15:02:21 +09:00
|
|
|
export class ElectronNativeService implements NativeService {
|
2019-11-12 18:54:21 +09:00
|
|
|
private ipcRenderer: typeof ipcRenderer;
|
|
|
|
private remote: typeof remote;
|
2019-11-19 19:34:53 +09:00
|
|
|
private shell: typeof shell;
|
2019-11-12 18:54:21 +09:00
|
|
|
|
2019-11-19 16:44:50 +09:00
|
|
|
private logoutSubject: Subject<void> | null = null;
|
|
|
|
private logout$: Observable<void> | null = null;
|
|
|
|
|
|
|
|
private changeStatusSubject: Subject<StatusCode> | null = null;
|
|
|
|
private changeStatus$: Observable<StatusCode> | null = null;
|
|
|
|
|
|
|
|
private showSettingSubject: Subject<void> | null = null;
|
|
|
|
private showSetting$: Observable<void> | null = null;
|
|
|
|
|
2019-10-24 15:37:33 +09:00
|
|
|
private windowStateChangedSubject: Subject<WindowState> | null = null;
|
|
|
|
private windowStateChanged$: Observable<WindowState> | null = null;
|
|
|
|
|
2019-11-07 16:56:14 +09:00
|
|
|
private idleStateChangedSubject: Subject<WindowIdle> | null = null;
|
|
|
|
private idleStateChanged$: Observable<WindowIdle> | null = null;
|
|
|
|
|
2019-11-12 10:38:51 +09:00
|
|
|
private chatOpenRoomSubject: Subject<string> | null = null;
|
|
|
|
private chatOpenRoom$: Observable<string> | null = null;
|
|
|
|
|
2019-12-17 16:39:02 +09:00
|
|
|
private msgOpenMessageSubject: Subject<string> | null = null;
|
|
|
|
private msgOpenMessage$: Observable<string> | null = null;
|
|
|
|
|
2019-12-12 17:15:09 +09:00
|
|
|
private backgroundCheckForUpdatesSubject: Subject<UpdateInfo> | null = null;
|
|
|
|
private backgroundCheckForUpdates$: Observable<UpdateInfo> | null = null;
|
|
|
|
|
2019-12-24 11:41:50 +09:00
|
|
|
type(): NativeType {
|
|
|
|
return NativeType.Electron;
|
|
|
|
}
|
|
|
|
|
2019-11-11 18:09:47 +09:00
|
|
|
postAppInit(): void {}
|
|
|
|
|
2019-11-19 16:44:50 +09:00
|
|
|
logout(): Observable<void> {
|
|
|
|
if (!this.logoutSubject) {
|
|
|
|
this.logoutSubject = new Subject<void>();
|
|
|
|
this.logout$ = this.logoutSubject.asObservable().pipe(share());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.ipcRenderer.on(MessengerChannel.Logout, (event: any) => {
|
|
|
|
this.logoutSubject.next();
|
|
|
|
});
|
|
|
|
return this.logout$;
|
|
|
|
}
|
|
|
|
|
2019-12-24 17:31:03 +09:00
|
|
|
getNetworkInfo(): Promise<any> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(this.ipcRenderer.sendSync(MessengerChannel.GetNetworkInfo));
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-19 16:44:50 +09:00
|
|
|
changeStatus(): Observable<StatusCode> {
|
|
|
|
if (!this.changeStatusSubject) {
|
|
|
|
this.changeStatusSubject = new Subject<StatusCode>();
|
|
|
|
this.changeStatus$ = this.changeStatusSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.ipcRenderer.on(
|
|
|
|
MessengerChannel.ChangeStatus,
|
|
|
|
(event: any, statusCode: StatusCode) => {
|
|
|
|
this.changeStatusSubject.next(statusCode);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return this.changeStatus$;
|
|
|
|
}
|
|
|
|
|
|
|
|
showSetting(): Observable<void> {
|
|
|
|
if (!this.showSettingSubject) {
|
|
|
|
this.showSettingSubject = new Subject<void>();
|
|
|
|
this.showSetting$ = this.showSettingSubject.asObservable().pipe(share());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.ipcRenderer.on(MessengerChannel.ShowSetting, (event: any) => {
|
|
|
|
this.showSettingSubject.next();
|
|
|
|
});
|
|
|
|
return this.showSetting$;
|
|
|
|
}
|
|
|
|
|
2019-12-17 17:27:08 +09:00
|
|
|
changeAutoLaunch(autoLaunch: boolean): Promise<boolean> {
|
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(
|
|
|
|
MessengerChannel.ChangeAutoLaunch,
|
|
|
|
autoLaunch
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-18 17:11:58 +09:00
|
|
|
changeStartupHideWindow(startupHideWindow: boolean): Promise<boolean> {
|
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(
|
|
|
|
MessengerChannel.ChangeStartupHideWindow,
|
|
|
|
startupHideWindow
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-01-03 10:29:40 +09:00
|
|
|
changeDownloadPath(downloadPath: string): Promise<string> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(
|
|
|
|
MessengerChannel.ChangeDownloadPath,
|
|
|
|
downloadPath
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-09 17:29:02 +09:00
|
|
|
notify(noti: NotificationRequest): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.send(NotificationChannel.Notify, noti);
|
2019-11-09 17:29:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
closeAllNotify(): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.send(NotificationChannel.CloseAllNotify);
|
2019-09-18 15:02:21 +09:00
|
|
|
}
|
|
|
|
|
2019-12-16 02:33:40 +09:00
|
|
|
checkForUpdates(currentVersion: string): Promise<boolean> {
|
2019-11-13 15:28:33 +09:00
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
2019-09-18 15:02:21 +09:00
|
|
|
try {
|
2019-12-16 02:33:40 +09:00
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(UpdaterChannel.Check, currentVersion)
|
|
|
|
);
|
2019-09-18 15:02:21 +09:00
|
|
|
} catch (error) {
|
2019-11-13 15:28:33 +09:00
|
|
|
reject(error);
|
2019-09-18 15:02:21 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-12 17:15:09 +09:00
|
|
|
checkForInstantUpdates(config: UpdateCheckConfig): Observable<UpdateInfo> {
|
|
|
|
if (!this.backgroundCheckForUpdatesSubject) {
|
|
|
|
this.backgroundCheckForUpdatesSubject = new Subject<UpdateInfo>();
|
|
|
|
this.backgroundCheckForUpdates$ = this.backgroundCheckForUpdatesSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.ipcRenderer.send(UpdaterChannel.StartCheckInstant, config);
|
|
|
|
|
|
|
|
this.ipcRenderer.on(
|
|
|
|
UpdaterChannel.ExistInstant,
|
|
|
|
(event: any, updateInfo: UpdateInfo) => {
|
|
|
|
this.backgroundCheckForUpdatesSubject.next(updateInfo);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return this.backgroundCheckForUpdates$;
|
|
|
|
}
|
|
|
|
|
|
|
|
applyInstantUpdates(): void {
|
|
|
|
this.ipcRenderer.send(UpdaterChannel.ApplyInstant);
|
|
|
|
}
|
|
|
|
|
2019-09-18 15:02:21 +09:00
|
|
|
showImageViewer(): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.send(FileChannel.ShowImageViewer);
|
2019-09-18 15:02:21 +09:00
|
|
|
}
|
|
|
|
|
2019-11-13 15:28:33 +09:00
|
|
|
readFile(path: string): Promise<Buffer> {
|
|
|
|
return new Promise<Buffer>((resolve, reject) => {
|
2019-09-24 09:03:36 +09:00
|
|
|
try {
|
2019-12-18 13:44:26 +09:00
|
|
|
const buffer = this.ipcRenderer.sendSync(FileChannel.ReadFile, path);
|
|
|
|
if (!!buffer) {
|
|
|
|
resolve(buffer);
|
|
|
|
} else {
|
|
|
|
reject(buffer as Error);
|
|
|
|
}
|
2019-09-24 09:03:36 +09:00
|
|
|
} catch (error) {
|
2019-11-13 15:28:33 +09:00
|
|
|
reject(error);
|
2019-09-24 09:03:36 +09:00
|
|
|
}
|
|
|
|
});
|
2019-09-18 15:02:21 +09:00
|
|
|
}
|
2019-09-24 09:03:36 +09:00
|
|
|
|
2019-11-07 11:37:33 +09:00
|
|
|
saveFile(
|
|
|
|
buffer: Buffer,
|
|
|
|
fileName: string,
|
2019-11-13 15:28:33 +09:00
|
|
|
mimeType: string,
|
2019-11-07 11:37:33 +09:00
|
|
|
path?: string
|
2019-11-13 15:28:33 +09:00
|
|
|
): Promise<string> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
2019-09-24 09:03:36 +09:00
|
|
|
try {
|
2019-11-13 15:28:33 +09:00
|
|
|
resolve(
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.sendSync(
|
|
|
|
FileChannel.SaveFile,
|
|
|
|
buffer,
|
|
|
|
fileName,
|
2019-11-13 15:28:33 +09:00
|
|
|
mimeType,
|
2019-11-12 18:54:21 +09:00
|
|
|
path
|
|
|
|
)
|
2019-11-07 11:37:33 +09:00
|
|
|
);
|
2019-09-24 09:03:36 +09:00
|
|
|
} catch (error) {
|
2019-11-13 15:28:33 +09:00
|
|
|
reject(error);
|
2019-09-24 09:03:36 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-04 16:37:19 +09:00
|
|
|
openDefaultDownloadFolder(): Promise<boolean> {
|
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(FileChannel.OpenFolderItem, undefined, true)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
openTargetFolder(folderPath?: string, make?: boolean): Promise<boolean> {
|
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(
|
|
|
|
FileChannel.OpenFolderItem,
|
|
|
|
folderPath,
|
|
|
|
!make ? false : make
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
openTargetItem(filePath?: string): Promise<boolean> {
|
|
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(FileChannel.OpenFolderItem, filePath, false)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-12-24 11:41:50 +09:00
|
|
|
getPath(name: NativePathName): Promise<string> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(this.ipcRenderer.sendSync(FileChannel.GetPath, name));
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-12-04 16:37:19 +09:00
|
|
|
|
2019-12-24 16:16:13 +09:00
|
|
|
selectDirectory(): Promise<string> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(this.ipcRenderer.sendSync(FileChannel.SelectDirectory));
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-01-03 15:52:19 +09:00
|
|
|
selectSaveFilePath(defaultPath?: string): Promise<string> {
|
|
|
|
return new Promise<string>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
resolve(
|
|
|
|
this.ipcRenderer.sendSync(FileChannel.SelectSaveFilePath, defaultPath)
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-10-24 15:37:33 +09:00
|
|
|
windowStateChanged(): Observable<WindowState> {
|
|
|
|
if (!this.windowStateChangedSubject) {
|
|
|
|
this.windowStateChangedSubject = new Subject<WindowState>();
|
|
|
|
this.windowStateChanged$ = this.windowStateChangedSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.on(
|
2019-11-09 17:29:02 +09:00
|
|
|
WindowStateChannel.Changed,
|
2019-11-12 18:54:21 +09:00
|
|
|
(event: any, windowState: WindowState) => {
|
2019-10-24 15:37:33 +09:00
|
|
|
this.windowStateChangedSubject.next(windowState);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return this.windowStateChanged$;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowClose(): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
const currentWindow = this.remote.getCurrentWindow();
|
2019-10-24 15:37:33 +09:00
|
|
|
if (!currentWindow) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentWindow.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
windowMinimize(): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
const currentWindow = this.remote.getCurrentWindow();
|
2019-10-24 15:37:33 +09:00
|
|
|
if (!currentWindow) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentWindow.minimize();
|
|
|
|
}
|
|
|
|
|
|
|
|
windowMaximize(): void {
|
2019-11-12 18:54:21 +09:00
|
|
|
const currentWindow = this.remote.getCurrentWindow();
|
2019-10-24 15:37:33 +09:00
|
|
|
if (!currentWindow) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentWindow.isMaximized()) {
|
|
|
|
currentWindow.unmaximize();
|
|
|
|
} else {
|
|
|
|
currentWindow.maximize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-07 16:56:14 +09:00
|
|
|
idleStateChanged(): Observable<WindowIdle> {
|
|
|
|
if (!this.idleStateChangedSubject) {
|
|
|
|
this.idleStateChangedSubject = new Subject<WindowIdle>();
|
|
|
|
this.idleStateChanged$ = this.idleStateChangedSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.send(IdleStateChannel.StartCheck);
|
2019-11-07 16:56:14 +09:00
|
|
|
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.on(
|
2019-11-09 17:29:02 +09:00
|
|
|
IdleStateChannel.Changed,
|
2019-11-12 18:54:21 +09:00
|
|
|
(event: any, idleState: WindowIdle) => {
|
2019-11-07 16:56:14 +09:00
|
|
|
this.idleStateChangedSubject.next(idleState);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return this.idleStateChanged$;
|
|
|
|
}
|
|
|
|
|
2019-11-12 10:38:51 +09:00
|
|
|
chatOpenRoom(): Observable<string> {
|
|
|
|
if (!this.chatOpenRoomSubject) {
|
|
|
|
this.chatOpenRoomSubject = new Subject<WindowIdle>();
|
|
|
|
this.chatOpenRoom$ = this.chatOpenRoomSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
2019-11-12 18:54:21 +09:00
|
|
|
this.ipcRenderer.on(ChatChannel.OpenRoom, (event: any, roomSeq: string) => {
|
|
|
|
this.chatOpenRoomSubject.next(roomSeq);
|
|
|
|
});
|
2019-11-12 10:38:51 +09:00
|
|
|
return this.chatOpenRoom$;
|
|
|
|
}
|
|
|
|
|
2019-12-17 16:39:02 +09:00
|
|
|
msgOpenMessage(): Observable<string> {
|
|
|
|
if (!this.msgOpenMessageSubject) {
|
|
|
|
this.msgOpenMessageSubject = new Subject<WindowIdle>();
|
|
|
|
this.msgOpenMessage$ = this.msgOpenMessageSubject
|
|
|
|
.asObservable()
|
|
|
|
.pipe(share());
|
|
|
|
}
|
|
|
|
|
|
|
|
this.ipcRenderer.on(
|
|
|
|
MessageChannel.OpenMessage,
|
|
|
|
(event: any, messageSeq: string) => {
|
|
|
|
this.msgOpenMessageSubject.next(messageSeq);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return this.msgOpenMessage$;
|
|
|
|
}
|
|
|
|
|
2019-11-11 18:09:47 +09:00
|
|
|
getTranslateLoader(prefix?: string, suffix?: string): TranslateLoader {
|
|
|
|
return new TranslateLoaderService(this, prefix, suffix);
|
|
|
|
}
|
|
|
|
|
2019-11-19 19:34:53 +09:00
|
|
|
openDefaultBrowser(url: string): void {
|
|
|
|
this.shell.openExternal(url);
|
|
|
|
}
|
|
|
|
|
2019-11-12 18:54:21 +09:00
|
|
|
get isElectron() {
|
|
|
|
return window && (window as any).process && (window as any).process.type;
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
if (this.isElectron) {
|
|
|
|
this.ipcRenderer = (window as any).require('electron').ipcRenderer;
|
|
|
|
this.remote = (window as any).require('electron').remote;
|
2019-11-19 19:34:53 +09:00
|
|
|
this.shell = (window as any).require('electron').shell;
|
2019-11-12 18:54:21 +09:00
|
|
|
}
|
|
|
|
}
|
2019-09-18 15:02:21 +09:00
|
|
|
}
|