@talex-touch/utils 1.0.3 → 1.0.6

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.
package/channel/index.ts CHANGED
@@ -15,7 +15,7 @@ export interface ITouchChannel {
15
15
  * Register a channel
16
16
  * @description Register a channel, and return a function to cancel the registration
17
17
  * @param type {@link ChannelType} The type of channel
18
- * @param eventName {string} The name of event, must be unique in the channel {@link ChannelType
18
+ * @param eventName {string} The name of event, must be unique in the channel {@link ChannelType}
19
19
  * @param callback {Function} The callback function
20
20
  */
21
21
  regChannel(type: ChannelType, eventName: string, callback: (data: StandardChannelData) => any): () => void
package/eventbus/index.ts CHANGED
@@ -40,7 +40,7 @@ export interface ITouchEventBus<E> {
40
40
  * @param handler Event handler (extends from EventHandler)
41
41
  * @returns true if the event was added, otherwise false
42
42
  */
43
- on(event: E, handler: EventHandler): boolean;
43
+ on(event: E, handler: EventHandler): boolean | void;
44
44
 
45
45
  /**
46
46
  * Subscribe touch-app events (any kind of events extends from TouchEvent)
@@ -48,7 +48,7 @@ export interface ITouchEventBus<E> {
48
48
  * @param handler Event handler (extends from EventHandler)
49
49
  * @returns true if the event was added, otherwise false
50
50
  */
51
- once(event: E, handler: EventHandler): boolean;
51
+ once(event: E, handler: EventHandler): boolean | void;
52
52
 
53
53
  /**
54
54
  * UnSubscribe touch-app events (any kind of events extends from TouchEvent)
package/package.json CHANGED
@@ -1,29 +1,29 @@
1
- {
2
- "main": "./index.ts",
3
- "name": "@talex-touch/utils",
4
- "author": "TalexDreamSoul",
5
- "module": "./index.ts",
6
- "license": "MPL-2.0",
7
- "private": false,
8
- "version": "1.0.3",
9
- "scripts": {
10
- "publish": "npm publish --access public"
11
- },
12
- "keywords": [
13
- "vue",
14
- "electron",
15
- "talex-touch"
16
- ],
17
- "repository": {
18
- "url": "https://github.com/talex-touch/talex-touch.git",
19
- "type": "git"
20
- },
21
- "description": "TalexTouch series utils",
22
- "dependencies": {
23
- "vue": "^3.2.47"
24
- },
25
- "peerDependencies": {
26
- "vue": "^3.2.47",
27
- "electron": "^24.4.0"
28
- }
29
- }
1
+ {
2
+ "main": "./index.ts",
3
+ "name": "@talex-touch/utils",
4
+ "author": "TalexDreamSoul",
5
+ "module": "./index.ts",
6
+ "license": "MPL-2.0",
7
+ "private": false,
8
+ "version": "1.0.6",
9
+ "scripts": {
10
+ "publish": "npm publish --access public"
11
+ },
12
+ "keywords": [
13
+ "vue",
14
+ "electron",
15
+ "talex-touch"
16
+ ],
17
+ "repository": {
18
+ "url": "https://github.com/talex-touch/talex-touch.git",
19
+ "type": "git"
20
+ },
21
+ "description": "TalexTouch series utils",
22
+ "dependencies": {
23
+ "vue": "^3.3.4"
24
+ },
25
+ "peerDependencies": {
26
+ "vue": "^3.2.47",
27
+ "electron": "^24.4.0"
28
+ }
29
+ }
@@ -0,0 +1,49 @@
1
+ export interface Permission {
2
+ /**
3
+ * permission id
4
+ */
5
+ id: symbol;
6
+
7
+ /**
8
+ * permission name
9
+ */
10
+ name: string;
11
+
12
+ /**
13
+ * permission description
14
+ */
15
+ description: string;
16
+ }
17
+
18
+ export interface IPermissionCenter {
19
+ /**
20
+ * add a permission
21
+ * @param pluginScope plugin name
22
+ * @param permission permission
23
+ * @throws if permission already exists
24
+ */
25
+ addPermission(pluginScope: string, permission: Permission): void;
26
+
27
+ /**
28
+ * remove a permission
29
+ * @param pluginScope plugin name
30
+ * @param permission permission
31
+ * @throws if permission not exists
32
+ */
33
+ delPermission(pluginScope: string, permission: Permission): void;
34
+
35
+ /**
36
+ * if pluginScope has permission
37
+ * @param pluginScope plugin name
38
+ * @param permission permission
39
+ */
40
+ hasPermission(pluginScope: string, permission: Permission): boolean;
41
+
42
+ /**
43
+ * get permission
44
+ * @param pluginScope plugin name
45
+ * @param permission permission id
46
+ * @returns permission
47
+ */
48
+ getPermission(pluginScope: string, permission: symbol): Permission;
49
+ }
package/plugin/channel.ts CHANGED
@@ -18,13 +18,13 @@ class TouchChannel implements ITouchClientChannel {
18
18
  constructor(pluginName: string) {
19
19
  this.plugin = pluginName;
20
20
 
21
- ipcRenderer.on("@main-process-message", this.__handle_main.bind(this));
21
+ ipcRenderer.on("@plugin-process-message", this.__handle_main.bind(this));
22
22
  }
23
23
 
24
- __parse_raw_data(e, arg): RawStandardChannelData | null {
25
- // console.log("Raw data: ", arg, e);
24
+ __parse_raw_data(e: typeof IpcMainEvent, arg: any): RawStandardChannelData | null {
25
+ console.log("Raw data: ", arg, e);
26
26
  if (arg) {
27
- const { name, header, code, plugin, data, sync } = arg;
27
+ const { name, header, code, data, sync } = arg;
28
28
 
29
29
  if (header) {
30
30
  return {
@@ -36,7 +36,6 @@ class TouchChannel implements ITouchClientChannel {
36
36
  sync,
37
37
  code,
38
38
  data,
39
- plugin,
40
39
  name: name as string,
41
40
  };
42
41
  }
@@ -47,7 +46,8 @@ class TouchChannel implements ITouchClientChannel {
47
46
  // throw new Error("Invalid message!");
48
47
  }
49
48
 
50
- __handle_main(e: typeof IpcMainEvent, arg: any): any {
49
+ __handle_main(e: typeof IpcMainEvent, _arg: any): any {
50
+ const arg = JSON.parse(_arg)
51
51
  const rawData = this.__parse_raw_data(e, arg);
52
52
  if ( !rawData ) return
53
53
 
@@ -57,13 +57,13 @@ class TouchChannel implements ITouchClientChannel {
57
57
  return this.pendingMap.get(id)?.(rawData);
58
58
  }
59
59
 
60
- if ( rawData.plugin !== this.plugin ) return
60
+ // if ( rawData.plugin !== this.plugin ) return
61
61
 
62
62
  this.channelMap.get(rawData.name)?.forEach((func) => {
63
63
  const handInData: StandardChannelData = {
64
- reply: (code: DataCode, data: any, options: any) => {
64
+ reply: (code: DataCode, data: any) => {
65
65
  e.sender.send(
66
- "@main-process-message",
66
+ "@plugin-process-message",
67
67
  this.__parse_sender(code, rawData, data, rawData.sync)
68
68
  );
69
69
  },
@@ -148,9 +148,9 @@ class TouchChannel implements ITouchClientChannel {
148
148
 
149
149
  return new Promise((resolve) => {
150
150
 
151
- ipcRenderer.send("@main-process-message", data);
151
+ ipcRenderer.send("@plugin-process-message", data);
152
152
 
153
- this.pendingMap.set(uniqueId, (res) => {
153
+ this.pendingMap.set(uniqueId, (res: any) => {
154
154
  this.pendingMap.delete(uniqueId);
155
155
 
156
156
  resolve(res.data);
@@ -170,7 +170,7 @@ class TouchChannel implements ITouchClientChannel {
170
170
  },
171
171
  } as RawStandardChannelData;
172
172
 
173
- const res = this.__parse_raw_data(null, ipcRenderer.sendSync("@main-process-message", data))!
173
+ const res = this.__parse_raw_data(null, ipcRenderer.sendSync("@plugin-process-message", data))!
174
174
 
175
175
  if ( res.header.status === 'reply' ) return res.data;
176
176
 
@@ -179,4 +179,13 @@ class TouchChannel implements ITouchClientChannel {
179
179
  }
180
180
  }
181
181
 
182
- export const touchChannel: ITouchClientChannel = window['$channel'] = new TouchChannel(window.$plugin.name);
182
+ let touchChannel: ITouchClientChannel
183
+
184
+ export function genChannel() {
185
+ if (!touchChannel) {
186
+ // @ts-ignore
187
+ touchChannel = window.$channel = new TouchChannel(window.$plugin.name)
188
+ }
189
+
190
+ return touchChannel
191
+ }
package/plugin/index.ts CHANGED
@@ -68,3 +68,30 @@ export interface IPluginManager {
68
68
  loadPlugin(pluginName: string): Promise<boolean>
69
69
  unloadPlugin(pluginName: string): Promise<boolean>
70
70
  }
71
+
72
+ export interface IManifest {
73
+ name: string
74
+ version: string
75
+ description: string
76
+ plugin?: {
77
+ dev: {
78
+ enable: boolean
79
+ address: string
80
+ }
81
+ }
82
+ build?: {
83
+ files: string[]
84
+ secret: {
85
+ pos: string
86
+ addon: string[]
87
+ }
88
+ verify?: {
89
+ enable: boolean
90
+ online: 'custom' | 'always' | 'once'
91
+ }
92
+ version?: {
93
+ update: 'auto' | 'ask' | 'readable'
94
+ downgrade: boolean
95
+ }
96
+ }
97
+ }
package/plugin/preload.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { touchChannel } from './channel'
1
+ import { genChannel } from './channel'
2
+ import './sdk/index'
2
3
 
3
4
  // window type
4
5
  declare global {
@@ -30,7 +31,9 @@ export function init(window: Window) {
30
31
  }
31
32
 
32
33
  export function initBridge(window: Window) {
33
- window.$send = touchChannel.send
34
- window.$sendSync = touchChannel.sendSync
35
- window.$regChannel = touchChannel.regChannel
34
+ const touchChannel = genChannel()
35
+
36
+ window.$send = touchChannel.send.bind(touchChannel)
37
+ window.$sendSync = touchChannel.sendSync.bind(touchChannel)
38
+ window.$regChannel = touchChannel.regChannel.bind(touchChannel)
36
39
  }
@@ -0,0 +1,30 @@
1
+ import { genChannel } from '../channel';
2
+ import {
3
+ BrowserWindowConstructorOptions
4
+ } from "electron";
5
+
6
+ export function regShortcut(key: string, func: Function) {
7
+ const channel = genChannel()
8
+
9
+ const res = channel.sendSync('shortcon:reg', { key })
10
+ if ( res instanceof String ) throw new Error(res)
11
+ if ( res === false ) return false;
12
+
13
+ channel.regChannel('shortcon:trigger', ({ data }) => key === data.key && func())
14
+
15
+ return true;
16
+ }
17
+
18
+ export function createWindow(options: BrowserWindowConstructorOptions & { file?: string } & { url?: string }): number {
19
+ const res = genChannel().sendSync('window:new', options)
20
+ if ( res.error ) throw new Error(res.error)
21
+
22
+ return res.id
23
+ }
24
+
25
+ export function toggleWinVisible(id: number, visible?: boolean): boolean {
26
+ const res = genChannel().sendSync('window:visible', visible !== undefined ? { id, visible } : { id })
27
+ if ( res.error ) throw new Error(res.error)
28
+
29
+ return res.visible
30
+ }
@@ -0,0 +1 @@
1
+ export * as LifeCycle from './life-cycle'
@@ -0,0 +1,96 @@
1
+ import { genChannel } from './../../channel';
2
+
3
+ export enum LifecycleHooks {
4
+ ENABLE = 'en',
5
+ DISABLE = 'di',
6
+ ACTIVE = 'ac',
7
+ INACTIVE = 'in',
8
+ // FORE_PAUSED = 'fp',
9
+ CRASH = 'cr'
10
+ }
11
+
12
+ // @ts-ignore
13
+ export function injectHook(type: LifecycleHooks, hook: Function, processFunc = ({ data, reply }) => {
14
+ // @ts-ignore
15
+ const hooks: Array<Function> = window.$touchSDK.__hooks[type]
16
+ if (hooks) {
17
+ hooks.forEach(hook => hook(data))
18
+ }
19
+ reply(true)
20
+ }) {
21
+ // @ts-ignore
22
+ const __hooks = window.$touchSDK.__hooks
23
+ // @ts-ignore
24
+ const hooks: Array<Function> = __hooks[type] || (__hooks[type] = [])
25
+
26
+ if (hooks.length === 0) {
27
+
28
+ genChannel().regChannel("@lifecycle:" + type, (obj: any) => {
29
+
30
+ processFunc(obj)
31
+
32
+ // @ts-ignore
33
+ delete window.$touchSDK.__hooks[type]
34
+ })
35
+
36
+ }
37
+
38
+ const wrappedHook = (data: any) => {
39
+
40
+ try {
41
+
42
+ hook(data)
43
+
44
+ } catch (e) {
45
+ console.error(`[TouchSDK] ${type} hook error: `, e)
46
+ }
47
+
48
+ }
49
+
50
+ hooks.push(wrappedHook)
51
+
52
+ return wrappedHook
53
+ }
54
+
55
+ export const createHook = <T extends Function = (data: any) => any>(type: LifecycleHooks) => (hook: T) => injectHook(type, hook)
56
+
57
+ /**
58
+ * The plugin is enabled
59
+ * When the plugin is enabled, the plugin can be used
60
+ * @returns void
61
+ */
62
+ export const onPluginEnable = createHook(LifecycleHooks.ENABLE)
63
+
64
+ /**
65
+ * The plugin is disabled
66
+ * When the plugin is disabled, the plugin can not be used
67
+ * @returns void
68
+ */
69
+ export const onPluginDisable = createHook(LifecycleHooks.DISABLE)
70
+
71
+ /**
72
+ * The plugin is activated
73
+ * @returns boolean If return false, the plugin will not be activated (User can force to activate the plugin)
74
+ */
75
+ export const onPluginActive = createHook(LifecycleHooks.ACTIVE)
76
+
77
+ /**
78
+ * The plugin is inactivated
79
+ * @returns boolean If return false, the plugin will not be inactivated (User can force to inactivate the plugin)
80
+ */
81
+ export const onPluginInactive = createHook(LifecycleHooks.INACTIVE)
82
+
83
+ /**
84
+ * When plugin is in foreground (e.g. plugin is using media, camera, microphone, etc.) But paused by user
85
+ * For a detail example: User force to stop music playing
86
+ * @returns void
87
+ */
88
+ // export const onForePaused = createHook(LifecycleHooks.FORE_PAUSED)
89
+
90
+ /**
91
+ * When plugin is crashed
92
+ * data.message Crash message
93
+ * data.extraData Crash data
94
+ * @returns void
95
+ */
96
+ export const onCrash = createHook(LifecycleHooks.CRASH)
@@ -0,0 +1,13 @@
1
+ import * as HOOKS from './hooks/index'
2
+
3
+ export interface ITouchSDK {
4
+ hooks: typeof HOOKS
5
+ __hooks: {}
6
+ }
7
+
8
+ // window type
9
+ declare global {
10
+ export interface Window {
11
+ $touchSDK: ITouchSDK
12
+ }
13
+ }
@@ -0,0 +1,30 @@
1
+ import { genChannel } from '../../channel';
2
+ import { IService } from "../../../service";
3
+
4
+ export function regService(service: IService, handler: Function): boolean {
5
+ const res = !!genChannel().sendSync('service:reg', { service: service.name })
6
+
7
+ if (res)
8
+ onHandleService(service, handler)
9
+
10
+ return res
11
+ }
12
+
13
+ export function unRegService(service: IService): boolean {
14
+ return !!genChannel().sendSync('service:unreg', { service: service.name })
15
+ }
16
+
17
+ export function onHandleService(service: IService, handler: Function) {
18
+ // @ts-ignore
19
+ genChannel().regChannel('service:handle', ({ data: _data }) => {
20
+ const { data } = _data
21
+
22
+ // console.log('service:handle', data, service)
23
+
24
+ if (data.service === service.name) {
25
+ return handler(data)
26
+ }
27
+
28
+ return false
29
+ })
30
+ }
@@ -0,0 +1,68 @@
1
+ export interface IService {
2
+ /**
3
+ * service id
4
+ */
5
+ id: Symbol;
6
+
7
+ /**
8
+ * service name
9
+ */
10
+ name: string;
11
+
12
+ /**
13
+ * service description
14
+ */
15
+ description: string;
16
+ }
17
+
18
+ export interface IServiceEvent {
19
+
20
+ service: IService;
21
+
22
+ setCancelled(cancelled: boolean): void;
23
+
24
+ isCancelled(): boolean;
25
+ }
26
+
27
+ export interface IServiceHandler {
28
+ /**
29
+ * The plugin scope of the service handler
30
+ * @description
31
+ * When service registered, the service center will use the plugin scope to find the service handler.
32
+ * If plugin is disabled, the app will automatically enable plugin and hand on the service to the plugin.
33
+ * When plugin enabled, you must immediately register service handler to the service center, app will waiting for the service handler, until the service handler handled.
34
+ */
35
+ pluginScope: string
36
+
37
+ /**
38
+ * Handle the service data
39
+ * @param data service data
40
+ */
41
+ handle(event: IServiceEvent, data: object): any;
42
+ }
43
+
44
+ export interface IServiceCenter {
45
+ /**
46
+ * The service center will register the service
47
+ * @param service will be registered service
48
+ * @param handler service handler
49
+ * @returns register result (true: success, false: fail)
50
+ */
51
+ regService(service: IService, handler: IServiceHandler): boolean;
52
+
53
+ /**
54
+ * The service center will unregister the service
55
+ * @param service will be unregistered service
56
+ * @returns unregister result (true: success, false: fail)
57
+ */
58
+ unRegService(service: IService): boolean;
59
+
60
+ /**
61
+ * Get the service by service id
62
+ * @param id service id
63
+ * @returns service
64
+ */
65
+ // getService(id: symbol): IService;
66
+
67
+ useService(service: IService, data: object): Promise<boolean> | boolean;
68
+ }
@@ -0,0 +1,78 @@
1
+ import { IService } from './../index';
2
+
3
+ export abstract class ProtocolService<T extends string> implements IService {
4
+ id: symbol;
5
+ name: string;
6
+ description: string;
7
+
8
+ protocol: string[]
9
+
10
+ type: T
11
+
12
+ constructor(id: symbol, protocol: string[]) {
13
+ this.id = id;
14
+ this.name = id.description!;
15
+ this.description = `${this.name} Protocol Service`;
16
+ this.protocol = protocol
17
+
18
+ this.type = id.description as T
19
+ }
20
+ }
21
+
22
+ export const IMAGE_SUFFIX = [
23
+ 'jpg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico', 'tiff', 'tif', 'jpeg', 'avif'
24
+ ]
25
+
26
+ export class ImageProtocolService extends ProtocolService<'image'> {
27
+ constructor() {
28
+ super(Symbol('Image'), IMAGE_SUFFIX)
29
+ }
30
+ }
31
+
32
+ export const AUDIO_SUFFIX = [
33
+ 'mp3', 'wav', 'ogg', 'aac', 'flac', 'wma', 'ape', 'm4a', 'm4r', 'm4b', 'm4p', 'm4v', 'mp4', '3gp', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'rmvb', 'rm', 'asf', 'dat', 'mpg', 'mpeg', 'vob', 'f4v', 'm3u8', 'webm', 'ts', 'mts', 'm2ts', 'mts', 'dv', 'divx', 'xvid', 'mpe', 'mod', 'sdp', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts'
34
+ ]
35
+
36
+ export class AudioProtocolService extends ProtocolService<'audio'> {
37
+ constructor() {
38
+ super(Symbol('Audio'), AUDIO_SUFFIX)
39
+ }
40
+ }
41
+
42
+ export const VIDEO_SUFFIX = [
43
+ 'mp4', '3gp', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'rmvb', 'rm', 'asf', 'dat', 'mpg', 'mpeg', 'vob', 'f4v', 'm3u8', 'webm', 'ts', 'mts', 'm2ts', 'mts', 'dv', 'divx', 'xvid', 'mpe', 'mod', 'sdp', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts', 'm2v', 'm2p', 'm2t', 'm2ts'
44
+ ]
45
+
46
+ export class VideoProtocolService extends ProtocolService<'video'> {
47
+ constructor() {
48
+ super(Symbol('Video'), VIDEO_SUFFIX)
49
+ }
50
+ }
51
+
52
+ export const TEXT_SUFFIX = [
53
+ 'txt', 'md', 'markdown', 'json', 'js', 'ts', 'html', 'css', 'scss', 'sass', 'less', 'xml', 'yaml', 'yml', 'ini', 'log', 'bat', 'sh', 'cmd', 'c', 'cpp', 'h', 'hpp', 'java', 'py', 'go', 'php', 'sql', 'swift', 'vb', 'vbs', 'lua', 'rb', 'r', 'cs', 'm', 'mm', 'pl', 'perl', 'asm', 'asmx', 'inc', 'coffee', 'ts', 'tsx', 'jsx', 'vue', 'php', 'php3', 'php4', 'php5', 'php7', 'phps', 'phtml', 'pht', 'phar', 'phpt', 'php-cgi', 'php-cs-fixer', 'phpunit', 'phpunit.xml', 'phpunit.xml.dist', 'phpunit.phar', 'phpunit.phar.dist', 'phpunit-4.8.36.phar', 'phpunit-4.8.36.phar.dist', 'phpunit-5.7.27.phar', 'phpunit-5.7.27.phar.dist', 'phpunit-6.5.14.phar', 'phpunit-6.5.14.phar.dist', 'phpunit-7.5.20.phar', 'phpunit-7.5.20.phar.dist', 'phpunit-8.5.8.phar', 'phpunit-8.5.8.phar.dist', 'phpunit-9.3.10.phar', 'phpunit-9.3.10.phar.dist', 'phpunit-9.4.3.phar', 'phpunit-9.4.3.phar.dist', 'phpunit-9.5.0.phar', 'phpunit-9.5.0.phar.dist', 'phpunit-9.5.1.phar', 'phpunit-9.5.1.phar.dist', 'phpunit-9.5.2.phar', 'phpunit-9.5.2.phar.dist', 'phpunit-9.5.4.phar', 'phpunit-9.5.4.phar.dist', 'php'
54
+ ]
55
+
56
+ export class TextProtocolService extends ProtocolService<'text'> {
57
+ constructor() {
58
+ super(Symbol('Text'), TEXT_SUFFIX)
59
+ }
60
+ }
61
+
62
+ export const serviceSuffixMap = new Map<ProtocolService<string>, string[]>
63
+
64
+ serviceSuffixMap.set(new ImageProtocolService(), IMAGE_SUFFIX)
65
+ serviceSuffixMap.set(new AudioProtocolService(), AUDIO_SUFFIX)
66
+ serviceSuffixMap.set(new VideoProtocolService(), VIDEO_SUFFIX)
67
+ serviceSuffixMap.set(new TextProtocolService(), TEXT_SUFFIX)
68
+
69
+ export function suffix2Service(suffix: string): ProtocolService<string> | null {
70
+
71
+ for (const [type, suffixes] of serviceSuffixMap.entries()) {
72
+ if (suffixes.includes(suffix)) {
73
+ return type
74
+ }
75
+ }
76
+
77
+ return null
78
+ }