@plasosdk/plaso-electron-sdk 1.3.6 → 1.3.8-beta.1

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/README.md CHANGED
@@ -1,14 +1,29 @@
1
1
  # Plaso SDK for Electron
2
2
 
3
- ## 🖥 环境支持
4
-
5
- - 🌈 支持 MacOS x86-64 和 arm64
6
- - ⚙️ 支持 Windows ia32 和 x64
7
- - [Electron](https://www.electronjs.org/): 14.0.0~22.3.27
8
-
9
- | MacOS | Windows | Electron |
10
- | --- | --- | --- |
11
- | x86 \| arm64 | ia32 \| x64 | 14.0.0~22.3.27
3
+ ## 目录
4
+
5
+ <!-- toc -->
6
+ - [环境支持](#环境支持)
7
+ - [安装](#安装)
8
+ - [electron-builder打包特别说明](#electron-builder打包特别说明)
9
+ - [使用](#使用)
10
+ - [在主进程中使用](#在主进程中使用)
11
+ - [在渲染进程中使用](#在渲染进程中使用)
12
+ - [打开实时课堂](#打开实时课堂)
13
+ - [打开备课课堂](#打开备课课堂)
14
+ - [打开实时课堂/备课课堂通用参数说明](#打开实时课堂备课课堂通用参数说明)
15
+ - [API参考](#api参考)
16
+ - [资料中心](#资料中心)
17
+ - [播放历史课堂](#播放历史课堂)
18
+ - [注意点](#注意点)
19
+ - [Q&A](#qa)
20
+ <!-- tocstop -->
21
+
22
+ ## 环境支持
23
+
24
+ - MacOS:x86-64、arm64
25
+ - Windows:ia32、x64
26
+ - Electron:14.0.0~22.3.27
12
27
 
13
28
  ## 安装
14
29
 
@@ -27,33 +42,63 @@ npm install @plasosdk/plaso-electron-sdk --global-style
27
42
  **<font color=red>注意: 不同平台需要单独安装,尤其是MacOS,请分别在Intel芯片和Apple芯片的电脑上安装</font>**
28
43
 
29
44
  ## electron-builder打包特别说明
30
- 使用electron-builder打包时,需要对工程的node_modules中的agora-electron-sdk-v4进行特殊处理,该包是在安装@plasosdk/plaso-electron-sdk时动态安装的,因此需要通过配置extraResources单独拷贝。配置入如下
45
+
46
+ ### extraResources配置
47
+
48
+ > ⚠️ 注意:该配置在 1.3.7 版本有所调整。如果你正在从 < 1.3.7 升级到 >= 1.3.7,请参照下列说明进行调整。
49
+
50
+ agora-electron-sdk-v4包是在安装plaso-electron-sdk时通过脚本动态安装的,不在dependencies依赖树中,electron-builder打包时不会包含它。为了保留它,需要配置[extraResources](https://www.electron.build/configuration#extraresources)来单独拷贝一份,把它包含进来。
51
+
31
52
  ```json
32
- "extraResources": [
33
- {
34
- "from": "node_modules/agora-electron-sdk-v4",
35
- "to": "app/node_modules/agora-electron-sdk-v4",
36
- "filter": ["**/*"]
37
- },
38
- {
39
- "from": "node_modules/agora-electron-sdk-v4/node_modules",
40
- "to": "app/node_modules/agora-electron-sdk-v4/node_modules",
41
- "filter": ["**/*"]
42
- }
43
- ]
53
+ {
54
+ "extraResources": [
55
+ {
56
+ "from": "node_modules/@plasosdk/plaso-electron-sdk/node_modules/agora-electron-sdk-v4",
57
+ "to": "app/node_modules/@plasosdk/plaso-electron-sdk/node_modules/agora-electron-sdk-v4",
58
+ "filter": [
59
+ "**/*"
60
+ ]
61
+ },
62
+ {
63
+ "from": "node_modules/@plasosdk/plaso-electron-sdk/node_modules/agora-electron-sdk-v4/node_modules",
64
+ "to": "app/node_modules/@plasosdk/plaso-electron-sdk/node_modules/agora-electron-sdk-v4/node_modules",
65
+ "filter": [
66
+ "**/*"
67
+ ]
68
+ }
69
+ ]
70
+ }
44
71
  ```
72
+
45
73
  同时,由于这个包是通过extraResources进行拷贝的,需要在签名脚本中额外配置这个包的路径。
46
74
 
47
- 另外在打包MacOS的包时有几个需要额外进行授权的可执行文件。建议通过额外的脚本来执行。下面的可执行文件是在安装@plasosdk/plaso-electron-sdk时动态下载的,因此授权的脚本需要保证是在文件下载之后。
75
+ ### 关闭asar
76
+
77
+ 需要关闭asar,否则SDK会无法加载到node_modules。关闭方式详见electron-buider[官方文档](https://www.electron.build/configuration#asar)。
78
+
79
+ ```json
80
+ {
81
+ "asar": false, // 关闭asar
82
+ }
83
+ ```
84
+
85
+ ### MacOS赋予文件执行权限
86
+
87
+ 打MacOS的包时有几个需要额外进行授权的可执行文件。建议通过额外的脚本来执行。
88
+
89
+ 下面的可执行文件是在安装@plasosdk/plaso-electron-sdk时动态下载的,因此授权的脚本需要保证是在文件下载之后。
90
+
48
91
  ```shell
49
92
  // 截图会用到
50
- chmod +x node_modules/@plasosdk/plaso-electron-sdk/lib/flameshot
93
+ chmod +x node_modules/@plasosdk/plaso-electron-sdk/lib/flameshot.app
51
94
 
52
95
  // 桌面共享会用到
53
96
  chmod +x node_modules/@plasosdk/plaso-electron-sdk/lib/PlasoALD/PlasoALD.scpt
54
97
  ```
55
98
 
56
- MacOS打包完毕后,建议安装打好的包后自行验证上述的操作时候生效了。
99
+ ### 验证
100
+
101
+ MacOS打包完毕后,建议安装打好的包,验证上述操作是否成功。核对清单:
57
102
  - 检查包内容中node_modules里面的agora-electron-sdk-v4包中是否包含node_modules,包含则说明打包正确。
58
103
  - 上课测试截图功能是否正常,截图正常说明授权正确。
59
104
  - 上课测试桌面共享功能,使用屏幕共享,并在浏览器里面播放一段视频,结束课堂后检查回放中能否听到桌面共享那一段播放的视频的声音,能听到说明授权正确。
@@ -98,7 +143,8 @@ interface CreateClassWindowPamras {
98
143
  callback: (result: boolean) => void,
99
144
  ) => void;
100
145
  onOpenResourceCenterFn?: () => void;
101
- onGetExtFileNameFn?: (...args: any[]) => Promise<string>;
146
+ onGetExtFileNameFn?: (info: any[], ...args: any[]) => Promise<string>;
147
+ onGetPreParseFileNameFn?: (info: any[], option: { suffix: string }) => Promise<string>;
102
148
  }
103
149
  ```
104
150
 
@@ -205,6 +251,7 @@ interface IQueryParams {
205
251
  isNewMT?: number;
206
252
  enableNewClassExam?: number;
207
253
  d_enableReRecording?: number;
254
+ d_restrictAssistantPerm?: number;
208
255
  }
209
256
  ```
210
257
 
@@ -234,6 +281,7 @@ interface IQueryParams {
234
281
  | recordScreen | 否 | string | 传入`screen`表示录制屏幕(当前仅支持录制老师屏幕)|
235
282
  | enableNewClassExam | 否 | number | 是否启用新版随堂测,取值:<ul><li>0: 不启用</li><li>1: 启用选择题</li><li>2: 启用填空题</li><li>3: 启用选择题+填空题</li></ul>默认不启用,建议传3 |
236
283
  | d_enableReRecording | 否 | number | 是否允许老师/助教重新录制,取值:<ul><li>0: 不允许老师和助教重新录制</li><li>1: 仅允许老师重新录制</li><li>2: 仅允许助教重新录制</li><li>3: 允许老师和助教重新录制</li></ul>默认值为3 |
284
+ | d_restrictAssistantPerm | 否 | number | 是否启用限制助教权限,取值:<ul><li>0: 不启用</li><li>1: 启用</li></ul>默认不启用 |
237
285
 
238
286
  **根据 queryParams 对象生成签名字符串**
239
287
  > 注意:为了安全和各端签名统一,建议将签名的计算放在服务端,前端通过接口获取带签名的query
@@ -390,31 +438,208 @@ type onOpenResourceCenterFn = () => void;
390
438
  // 通过 insertObject 插入的文件传入 参数 info 时,怎么从info中获取文件的可访问地址的逻辑在用户那,所以需要函数从外部用户获取外部用户传入的文件地址
391
439
  // 其中info会作为args中的第一个参数回传
392
440
 
393
- type onGetExtFileNameFn = (...args: any[]) => Promise<string>;
441
+ type onGetExtFileNameFn = (info: any, ...args: any[]) => Promise<string>;
442
+ ```
443
+
444
+ ##### onGetPreParseFileNameFn
445
+ ```ts
446
+ // 通过 insertObject 插入的文件传入 参数 info 时,如果该资源是预解析资源,SDK需要访问解析后的文件
447
+ // 其中info会作为args中的第一个参数回传
448
+ // 预解析结果是一个文件夹,要访问文件夹里的哪个文件,会通过suffix指出,如/index.html、/pre1.jpg等
449
+
450
+ type onGetPreParseFileNameFn = (info: any, option: { suffix: string }) => Promise<string>;
394
451
  ```
395
452
 
396
453
  #### API参考
397
454
 
398
455
  ##### PlasoElectronSdk.initLogConfig
399
456
 
400
- **初始化课堂窗口日志位置**,窗口崩溃时会在同级目录下生成 reports 文件夹存储 dump,**在 调用 createLiveClassWindow 前设置**
401
-
402
- **日志默认位置**:
457
+ 该方法用于设置SDK日志位置,SDK崩溃时会在同级目录下生成`reports`文件夹存储 dump,在调用`createLiveClassWindow`前设置,不调用SDK会在默认位置写入日志,默认位置如下:
403
458
 
404
459
  ```js
460
+ // 获取日志路径的代码如下
405
461
  require('path').join(require('electron').app.getPath('userData'), 'P403FileTemp');
406
462
 
407
463
  // Windows:C:\Users\${userName}\AppData\Roaming\${appName}\P403FileTemp
408
464
  // Mac:/Users/${userName}/Application\ Support/${appName}/P403FileTemp
409
465
  ```
410
466
 
411
- 参数示例:
467
+ 参考示例:
412
468
 
413
469
  ```ts
414
470
  // 代码示例
415
471
  const PlasoElectronSdk = window.require('@plasosdk/plaso-electron-sdk');
416
- const logFilePath = 'C:/Users/userName/Desktop/electronDemo/electron12.0.18_x32/resources/app';
417
- PlasoElectronSdk.initLogConfig(logFilePath);
472
+ const logDir = 'C:/Users/userName/Desktop/electronDemo/electron12.0.18_x32/resources/app';
473
+ PlasoElectronSdk.initLogConfig(logDir);
474
+ ```
475
+
476
+ > 重要:用户需要对日志目录做定期清理和及时上传日志到自己的服务器或OSS。推荐在退出SDK后做一次清理和上传,建议清理创建时间超过7天的日志即可。
477
+ 相关代码示例如下:
478
+ ```ts
479
+ import fs from 'fs';
480
+ import path from 'path';
481
+
482
+ /**
483
+ * 清理创建时间超过7天的日志
484
+ * @param logDir 日志目录
485
+ */
486
+ function clearExpireLogs(logDir: string) {
487
+ try {
488
+ const logFile = fs.readdirSync(logDir).filter((fileName) => /\.(log|dmp|ips|diag)/.test(path.extname(fileName)));
489
+ logFile.forEach((fileName) => {
490
+ const fileInfo = fs.statSync(path.join(logDir, fileName));
491
+ const fileDate = new Date(fileInfo.birthtime).setHours(0, 0, 0, 0).valueOf();
492
+ const currentDate = new Date().setHours(0, 0, 0, 0);
493
+ if (currentDate - fileDate > 7 * 24 * 60 * 60 * 1000) {
494
+ fs.unlinkSync(path.join(logDir, fileName));
495
+ }
496
+ });
497
+ } catch (e) {
498
+ console.error('clear expire log error', e);
499
+ }
500
+ }
501
+
502
+ /**
503
+ * 收集崩溃日志
504
+ * @param logDir 日志目录
505
+ * @param pendingUploadDir 待上传目录
506
+ */
507
+ function collectCrashLogs(logDir: string, pendingUploadDir: string) {
508
+ const platform = require('os').platform();
509
+ switch (platform) {
510
+ case 'darwin':
511
+ const newDumpFolder = path.join(logDir, '/new/');
512
+ const pendingDumpFolder = path.join(logDir, '/pending/');
513
+ const completedDumpFolder = path.join(logDir, '/completed/');
514
+ const diagnosticReports = path.normalize('/Library/Logs/DiagnosticReports');
515
+ collectDumpFiles(newDumpFolder);
516
+ collectDumpFiles(pendingDumpFolder);
517
+ collectDumpFiles(completedDumpFolder);
518
+ collectSystemLogs(diagnosticReports);
519
+ break;
520
+ case 'win32':
521
+ const reportsDumpFolder = path.join(logDir, '/reports/');
522
+ collectDumpFiles(reportsDumpFolder);
523
+ break;
524
+ default:
525
+ break;
526
+ }
527
+
528
+ function collectSystemLogs(folder: string) {
529
+ try {
530
+ const files = fs.readdirSync(folder);
531
+ const todayDate = new Date();
532
+ const formatDate = `${todayDate.getFullYear()}-${(todayDate.getMonth() + 1).toString().padStart(2, '0')}-${todayDate
533
+ .getDate()
534
+ .toString()
535
+ .padStart(2, '0')}`;
536
+ files.forEach((name) => {
537
+ const reg = new RegExp(`Electron Helper.*${formatDate}`);
538
+ if (name && name.match(reg)) {
539
+ fs.copyFileSync(path.join(folder, name), path.join(pendingUploadDir, name));
540
+ }
541
+ });
542
+ } catch (e) {
543
+ console.error(e);
544
+ }
545
+ }
546
+
547
+ function collectDumpFiles(folder: string) {
548
+ try {
549
+ const files = fs.readdirSync(folder);
550
+ files.forEach((name) => {
551
+ if (name) {
552
+ fs.copyFileSync(path.join(folder, name), path.join(pendingUploadDir, name));
553
+ fs.unlinkSync(path.join(folder, name));
554
+ }
555
+ });
556
+ } catch (e) {
557
+ console.error(e);
558
+ }
559
+ }
560
+ }
561
+
562
+ /**
563
+ * 收集业务日志
564
+ * @param logDir 日志目录
565
+ * @param pendingUploadDir 待上传目录
566
+ */
567
+ function collectBussinessLogs(logDir: string, pendingUploadDir: string) {
568
+ const logFiles = fs.readdirSync(logDir).filter((fileName) => /\.(log|dmp|ips|diag)/.test(path.extname(fileName)));
569
+ logFiles.forEach((fileName) => {
570
+ fs.copyFileSync(path.join(logDir, fileName), path.join(pendingUploadDir, fileName));
571
+ });
572
+ }
573
+
574
+ /**
575
+ * 收集日志
576
+ * @param logDir 日志目录
577
+ * @param pendingUploadDir 待上传目录
578
+ */
579
+ function collectLogs(logDir: string, pendingUploadDir: string) {
580
+ collectCrashLogs(logDir, pendingUploadDir);
581
+ collectBussinessLogs(logDir, pendingUploadDir);
582
+ }
583
+
584
+ /**
585
+ * 压缩日志
586
+ * @param pendingUploadDir 待上传目录
587
+ */
588
+ function zipLogs(pendingUploadDir: string): Promise<string> {
589
+ return new Promise((resolve) => {
590
+ const zipLogPath = path.join(pendingUploadDir, 'xxx.zip'); // 这边的xxx.zip取名时建议将用户名以及上传时间拼接上去,方便查询
591
+ // TODO: 这边做压缩,压缩完毕后将zip文件路径返回
592
+ resolve(zipLogPath);
593
+ });
594
+ }
595
+
596
+ /**
597
+ * 上传日志到服务器
598
+ * @param filePath zip文件路径
599
+ */
600
+ function uploadToServer(filePath: string): Promise<boolean> {
601
+ return new Promise((resolve) => {
602
+ // TODO: 这边做上传
603
+ resolve(true);
604
+ });
605
+ }
606
+
607
+ /**
608
+ * 上传日志
609
+ * @param logDir 日志目录
610
+ */
611
+ export function uploadLogs(logDir: string): Promise<boolean> {
612
+ return new Promise(async (resolve) => {
613
+ try {
614
+ // 上传前先清理过期的日志,避免垃圾日志太多
615
+ clearExpireLogs(logDir);
616
+
617
+ // 创建待上传目录
618
+ const pendingUploadDir = path.join(logDir, 'pendingUpload');
619
+ if (fs.existsSync(pendingUploadDir)) {
620
+ fs.rmdirSync(pendingUploadDir, { recursive: true });
621
+ }
622
+ fs.mkdirSync(pendingUploadDir);
623
+
624
+ // 将日志复制到待上传目录
625
+ collectLogs(logDir, pendingUploadDir);
626
+
627
+ // 压缩待上传目录
628
+ const zipName = await zipLogs(pendingUploadDir);
629
+
630
+ // 将压缩后的日志上传到服务器
631
+ await uploadToServer(zipName);
632
+
633
+ // 上传完成后删除临时文件
634
+ fs.unlinkSync(zipName);
635
+ fs.rmdirSync(pendingUploadDir, { recursive: true });
636
+
637
+ resolve(true);
638
+ } catch (error) {
639
+ resolve(false);
640
+ }
641
+ });
642
+ }
418
643
  ```
419
644
 
420
645
  ##### PlasoElectronSdk.getVersion
@@ -465,6 +690,8 @@ const enum FILE_TYPE {
465
690
  DOC,
466
691
  /** 这种模式传入真实EXCEL地址 */
467
692
  XLS,
693
+ /** 预解析PPT */
694
+ ISPRINGPPT,
468
695
  /** 备课文件 */
469
696
  PREPARE_LESSONS,
470
697
  };
@@ -483,6 +710,9 @@ interface IFileData {
483
710
  /** 访问权限为公开的全地址,建议使用https协议的全地址,传入`info`时会忽略该属性 */
484
711
  url?: string;
485
712
 
713
+ /** 预解析结果的页数(插入预解析PDF/DOC/XLS时要传入这个属性) */
714
+ totalPages?: number;
715
+
486
716
  /**
487
717
  * 当用户插入的文件有签名时效时需要以info属性插入文件,这种方式需要配合onGetExtFileNameFn回调使用。
488
718
  * `info`的值由SDK用户自行决定,SDK内部会把`info`作为onGetExtFileNameFn回调函数的参数传入,由SDK用户
@@ -553,6 +783,18 @@ const fileDataWithUrl = {
553
783
  };
554
784
  ```
555
785
 
786
+ ###### 插入预解析PPT
787
+
788
+ ```ts
789
+ // 预解析PPT仅支持info插入
790
+
791
+ const fileDataWithInfo = {
792
+ type: PlasoElectronSdk.FILE_TYPE.ISPRINGPPT,
793
+ title: 'xxx',
794
+ info: ['xxx', ...],
795
+ };
796
+ ```
797
+
556
798
  ###### 插入音视频
557
799
 
558
800
  ```ts
@@ -589,6 +831,17 @@ const fileDataWithInfo = {
589
831
  }
590
832
  ```
591
833
 
834
+ ###### 插入预解析PDF
835
+ ```ts
836
+ // 预解析PDF仅支持info接入,且需要传入totalPages总页数
837
+
838
+ const fileDataWithInfo = {
839
+ type: PlasoElectronSdk.FILE_TYPE.PDF,
840
+ title: 'xxx',
841
+ info: ['xxx', ...],
842
+ totalPages: 12,
843
+ }
844
+ ```
592
845
 
593
846
  ###### 插入WORD/EXCEL/DOC/XLS
594
847
 
@@ -602,6 +855,19 @@ const fileDataWithUrl = {
602
855
  }
603
856
  ```
604
857
 
858
+ ###### 插入预解析DOC/XLS
859
+
860
+ ```ts
861
+ // 预解析DOC/XLS仅支持info插入,且需要传入totalPages总页数
862
+
863
+ const fileDataWithInfo = {
864
+ type: PlasoElectronSdk.FILE_TYPE/.DOC/.XLS,
865
+ title: 'xxx',
866
+ info: ['xxx', ...],
867
+ totalPages: 12,
868
+ }
869
+ ```
870
+
605
871
  ## 资料中心
606
872
 
607
873
  step1、进课堂时,对象 **classOptions.supportShowResourceCenter** 需要是 true
@@ -610,7 +876,9 @@ step2、在课堂内点击资料中心后,会触发进课堂时传入的回调
610
876
 
611
877
  step3、选择文件后,通过 **PlasoElectronSdk.insertObject** 方法插入文件,方法入参参考 [insertObject](#insert-object) 说明
612
878
 
613
- step4、insertObject 方法 入参 有 info 时,此时 会触发进课堂时传入的回调函数 **onGetExtFileNameFn** 来获取文件的全地址
879
+ step4.1、insertObject 方法 入参 有 info 时,此时 会触发进课堂时传入的回调函数 **onGetExtFileNameFn** 来获取文件的全地址
880
+
881
+ step4.2、insertObject 方法插入的如果是预解析资源,那么就会触发回调 **onGetPreParseFileNameFn** 来获取解析后资源的全地址
614
882
 
615
883
  ## 播放历史课堂
616
884
 
@@ -618,6 +886,8 @@ step4、insertObject 方法 入参 有 info 时,此时 会触发进课堂时
618
886
 
619
887
  2、当课堂中insertObject使用了`info`属性时,SDK内部需要外部传入`getExtFileName`,因此历史课堂需要使用jssdk的接入方式, 详见:**[Web播放器-jssdk接入](https://open.plaso.cn/doc-6285192#jssdk%E6%8E%A5%E5%85%A5)**
620
888
 
889
+ 3、当课堂中insertObject插入了预解析资源时,SDK内部需要外部传入`getPreParseFileName`,因此历史课堂需要使用jssdk的接入方式,同上。
890
+
621
891
  ## 注意点
622
892
 
623
893
  (1)用户的课堂外主窗口销毁时需要销毁课堂窗口
@@ -625,3 +895,10 @@ step4、insertObject 方法 入参 有 info 时,此时 会触发进课堂时
625
895
  (2)**基于 此包封装新包时**:注意 @electron/remote 这个包的位置需要 和新包处于同级目录,需要把 和该包同级的@electron/remote 移到新包的同级目录处
626
896
 
627
897
  (3)确保 仅最后的 node_moudles 的顶层有 @electron/remote
898
+
899
+ ## Q&A
900
+
901
+ ### 进课堂遇到闪退/崩溃怎么办?
902
+ - 检查应用程序路径中是否存在中文,路径中不应出现中文</br>
903
+ 可通过在主进程中,用`console.log(require.resolve('@plasosdk/plaso-electron-sdk'))`来检查路径
904
+ - 如果是Mac,进课堂会需要麦克风权限。打开系统设置->隐私与安全性->麦克风,查看列表里你的应用程序是否被授权。
package/index.html CHANGED
@@ -137,14 +137,63 @@
137
137
  document.head.appendChild(ele);
138
138
  }
139
139
 
140
+ let hasInit = false;
141
+ function init(appinfo) {
142
+ if (hasInit) {
143
+ return;
144
+ } else {
145
+ hasInit = true;
146
+ }
140
147
 
141
- function init(classObj) {
142
- let query;
143
- if (classObj) {
144
- globalAppInfo = Object.assign({}, classObj)
148
+ // from url
149
+ var query;
150
+ if (window.location.search) {
151
+ query = window.location.search.substring(1).split("&");
152
+ for (var i = 0, l = query.length; i < l; i++) {
153
+ var temp = query[i].split('=');
154
+ if (temp.length == 2) {
155
+ globalAppInfo[temp[0]] = decodeURIComponent(temp[1]);
156
+ } else if (
157
+ typeof globalAppInfo[temp[0]] === 'string' &&
158
+ globalAppInfo[temp[0]].length > 0 &&
159
+ !isNaN(Number(globalAppInfo[temp[0]])) &&
160
+ Number(globalAppInfo[temp[0]]) !== undefined &&
161
+ !globalAppInfo[temp[0]]?.includes?.('.')
162
+ ) {
163
+ globalAppInfo[temp[0]] = Number(globalAppInfo[temp[0]]);
164
+ }
165
+ }
166
+ }
167
+
168
+ // from ipc
169
+ if (appinfo) {
170
+ globalAppInfo = Object.assign({}, globalAppInfo, appinfo)
145
171
  }
146
- globalAppInfo.needFullScreen = false;
147
172
 
173
+ // properties init
174
+ if (globalAppInfo.rhost == undefined && location.protocol.indexOf('http') == 0) {
175
+ globalAppInfo.rhost = './';
176
+ if (!globalAppInfo.dhost) {
177
+ if (globalAppInfo.env) {
178
+ if (globalAppInfo.env === 'local') {
179
+ globalAppInfo.dhost = location.origin;
180
+ } else {
181
+ globalAppInfo.dhost = `${location.protocol}//${globalAppInfo.env}.plaso.cn/`;
182
+ }
183
+ } else if (location.origin.indexOf('plaso.cn') > -1) {
184
+ globalAppInfo.dhost = location.origin.replace('wwwr', 'www');
185
+ globalAppInfo.env = location.host.split('.')[0];
186
+ } else if (location.origin.indexOf('127.0.0.1') > -1 || location.origin.indexOf('192.168') > -1) {
187
+ globalAppInfo.env = 'dev';
188
+ globalAppInfo.dhost = `${location.protocol}//${globalAppInfo.env}.plaso.cn/`;
189
+ } else {
190
+ globalAppInfo.dhost = `${location.protocol}//www.plaso.cn/`;
191
+ }
192
+ }
193
+ }
194
+ if (!globalAppInfo.env) globalAppInfo.env = 'www';
195
+ globalAppInfo.markString = globalAppInfo.markString ?? '';
196
+ globalAppInfo.needFullScreen = false;
148
197
  if (globalAppInfo.rhost && globalAppInfo.rhost.substring(globalAppInfo.rhost.length - 1) != '/') {
149
198
  globalAppInfo.rhost += "/";
150
199
  }
@@ -152,6 +201,7 @@
152
201
  globalAppInfo.dhost += "/";
153
202
  }
154
203
 
204
+ // load all.js
155
205
  path = globalAppInfo.initjs || "js/all.js";
156
206
  include(path);
157
207
  }
@@ -166,14 +216,14 @@
166
216
  if (key === 'openerId') openerId = Number(value);
167
217
  });
168
218
 
169
- ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.INIT_CLASS_OPTIONS, (_, classObj) => {
170
- if (classObj) init(classObj);
219
+ ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.INIT_GLOBAL_APPINFO, (_, appinfo) => {
220
+ if (appinfo) init(appinfo);
171
221
  });
172
222
 
173
223
  if(openerId){
174
224
  const remote = getElectronRemote();
175
225
  const webContents = remote.getCurrentWebContents();
176
- ipcRenderer.sendTo(openerId, CLASS_WINDOW_MESG_TYPE.CLASS_READY, {webContentId: webContents.id});
226
+ ipcRenderer.sendTo(openerId, CLASS_WINDOW_MESG_TYPE.HTML_READY, {webContentId: webContents.id});
177
227
  }
178
228
 
179
229
  }
package/js/macro.js CHANGED
@@ -24,10 +24,10 @@ const CLASS_WINDOW_MESG_TYPE = {
24
24
  LIVE_WINDOW_READY: 'liveWindowReady',
25
25
  /** 课堂结束 */
26
26
  ON_CLASS_FINISHED: 'onClassFinished',
27
- /** 初始化进课堂参数 */
28
- INIT_CLASS_OPTIONS: 'init_class_options',
29
- /** 课堂窗口 html ready */
30
- CLASS_READY: 'class_ready',
27
+ /** 初始化 globalAppInfo */
28
+ INIT_GLOBAL_APPINFO: 'init_global_appinfo',
29
+ /** html ready */
30
+ HTML_READY: 'html_ready',
31
31
  /** 保存白板文件 */
32
32
  SAVE_BOARD: 'save_board',
33
33
  /** 响应保存白板文件 */
@@ -42,6 +42,10 @@ const CLASS_WINDOW_MESG_TYPE = {
42
42
  GET_EXT_FILE_NAME: 'getExtFileName',
43
43
  /** 响应getExtFileName */
44
44
  RESP_GET_EXT_FILE_NAME: 'respGetExtFileName',
45
+ /** 通知外部调用getPreParseFileName */
46
+ GET_PRE_PARSE_FILE_NAME: 'getPreParseFileName',
47
+ /** 响应getPreParseFileName */
48
+ RESP_GET_PRE_PARSE_FILE_NAME: 'respGetPreParseFileName',
45
49
  };
46
50
 
47
51
  const LEVEL = {
@@ -68,6 +72,7 @@ const FILE_TYPE = {
68
72
  VIDEO: 7,
69
73
  DOC: 14,
70
74
  XLS: 15,
75
+ ISPRINGPPT: 21,
71
76
  PREPARE_LESSONS: 22,
72
77
  };
73
78
 
package/js/render.js CHANGED
@@ -46,7 +46,8 @@ let currentWebContentsId = null;
46
46
  * callback: (result: boolean) => void
47
47
  * ) => void} [onSaveBoardFn] 保存板书,具体的保存逻辑由外部实现,取消保存板书时,callback传false, 不然传true
48
48
  * @property {()=>void} [onOpenResourceCenterFn] 通知外部用户打开自己的资料中心,资料中心的具体ui和逻辑由外部用户自己实现
49
- * @property {(...args: any[])=>Promise<string>} [onGetExtFileNameFn] 通过insertObject插入的文件传入 参数 info 时,怎么从info中获取文件的可访问地址的逻辑在用户那,所以需要函数从外部用户获取外部用户传入的文件地址
49
+ * @property {(info: any, option: any)=>Promise<string>} [onGetExtFileNameFn] 通过insertObject插入的文件传入 参数 info 时,怎么从info中获取文件的可访问地址的逻辑在用户那,所以需要函数从外部用户获取外部用户传入的文件地址
50
+ * @property {(info: any, option: { suffix: string })=>Promise<string>} [onGetPreParseFileNameFn] 类似onGetExtFileNameFn,只是获取的文件地址是预解析文件地址,通过suffix得到预解析文件路径
50
51
  *
51
52
  */
52
53
 
@@ -64,10 +65,11 @@ function createClassWindow(classWindowProps) {
64
65
  onSaveBoardFn,
65
66
  onOpenResourceCenterFn,
66
67
  onGetExtFileNameFn,
68
+ onGetPreParseFileNameFn,
67
69
  } = classWindowProps;
68
70
 
69
71
  logger.info(
70
- `课堂窗口创建信息: classOptions is ${JSON.stringify(classOptions)},electronWinOptions is ${JSON.stringify(
72
+ `课堂窗口创建信息: version is ${getVersion()}, classOptions is ${JSON.stringify(classOptions)},electronWinOptions is ${JSON.stringify(
71
73
  electronWinOptions,
72
74
  )}`,
73
75
  );
@@ -108,7 +110,7 @@ function createClassWindow(classWindowProps) {
108
110
  rhost = `https://${env}.plaso.cn/static/yxtelectronsdk/`;
109
111
  dhost = `https://${env}.plaso.cn/`;
110
112
  } else {
111
- rhost = `https://wwwr.plaso.cn/static/sdk/styleupime/${classOptions.version ?? '1.58.307'}/`;
113
+ rhost = `https://wwwr.plaso.cn/static/sdk/styleupime/${classOptions.version ?? '1.59.201'}/`;
112
114
  dhost = 'https://www.plaso.cn/';
113
115
  }
114
116
 
@@ -225,12 +227,12 @@ function createClassWindow(classWindowProps) {
225
227
  logger.info(`课堂已结束,id:${currentWinId}, meetingId is ${meetingId}`);
226
228
  if (onClassFinishedFn && currentWinId) onClassFinishedFn(meetingId);
227
229
  };
228
- const onClassHtmlReady = (event, value) => {
230
+ const onHtmlReady = (event, value) => {
229
231
  currentWebContentsId = value?.webContentId;
230
232
  logger.info(`课堂窗口 html ready,web contents id:${currentWebContentsId}`);
231
233
 
232
234
  if (currentWebContentsId) {
233
- ipcRenderer.sendTo(currentWebContentsId, CLASS_WINDOW_MESG_TYPE.INIT_CLASS_OPTIONS, classOptionsObj);
235
+ ipcRenderer.sendTo(currentWebContentsId, CLASS_WINDOW_MESG_TYPE.INIT_GLOBAL_APPINFO, classOptionsObj);
234
236
  }
235
237
  };
236
238
  const onSaveBoard = (event, value) => {
@@ -258,12 +260,22 @@ function createClassWindow(classWindowProps) {
258
260
  }
259
261
  };
260
262
 
263
+ const onGetPreParseFileName = async (event, requestId, ...args) => {
264
+ if (onGetPreParseFileNameFn && args.length > 0) {
265
+ const url = await onGetPreParseFileNameFn(...args);
266
+ if (url) {
267
+ ipcRenderer.sendTo(currentWebContentsId, CLASS_WINDOW_MESG_TYPE.RESP_GET_PRE_PARSE_FILE_NAME, requestId, url);
268
+ }
269
+ }
270
+ };
271
+
261
272
  ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.LIVE_WINDOW_READY, onClassWindowReady);
262
273
  ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.ON_CLASS_FINISHED, onClassFinished);
263
- ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.CLASS_READY, onClassHtmlReady);
274
+ ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.HTML_READY, onHtmlReady);
264
275
  ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.SAVE_BOARD, onSaveBoard);
265
276
  ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.OPEN_RESOURCE_CENTER, onOpenResourceCenter);
266
277
  ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.GET_EXT_FILE_NAME, onGetExtFileName);
278
+ ipcRenderer.on(CLASS_WINDOW_MESG_TYPE.GET_PRE_PARSE_FILE_NAME, onGetPreParseFileName);
267
279
 
268
280
  const url = require('url');
269
281
  const htmlPath =
@@ -293,10 +305,11 @@ function createClassWindow(classWindowProps) {
293
305
  currentWebContentsId = null;
294
306
  ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.LIVE_WINDOW_READY, onClassWindowReady);
295
307
  ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.ON_CLASS_FINISHED, onClassFinished);
296
- ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.CLASS_READY, onClassHtmlReady);
308
+ ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.HTML_READY, onHtmlReady);
297
309
  ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.SAVE_BOARD, onSaveBoard);
298
310
  ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.OPEN_RESOURCE_CENTER, onOpenResourceCenter);
299
311
  ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.GET_EXT_FILE_NAME, onGetExtFileName);
312
+ ipcRenderer.removeListener(CLASS_WINDOW_MESG_TYPE.GET_PRE_PARSE_FILE_NAME, onGetPreParseFileName);
300
313
  });
301
314
  },
302
315
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasosdk/plaso-electron-sdk",
3
- "version": "1.3.6",
3
+ "version": "1.3.8-beta.1",
4
4
  "description": "伯索课堂Electron SDK",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -14,6 +14,9 @@
14
14
  "electron",
15
15
  "classroom"
16
16
  ],
17
+ "peerDependencies": {
18
+ "@electron/remote": "^2.1.2"
19
+ },
17
20
  "dependencies": {
18
21
  "@plasosdk/screenshot": "^1.3.4",
19
22
  "@plasosdk/winproxy": "^1.1.5",
@@ -94,10 +94,10 @@ const npmInstall = () => {
94
94
  installCb(agora_electron_sdk_v4, installAgora, error, stdout, stderr);
95
95
  if (!error?.message) {
96
96
  const oldAgoraV4Path = path.join(__dirname, '../node_modules', 'agora-electron-sdk');
97
- const newAgoraV4Path = path.join(__dirname, '../../../', 'agora-electron-sdk-v4');
97
+ const newAgoraV4Path = path.join(__dirname, '../node_modules', 'agora-electron-sdk-v4');
98
98
  fs.move(oldAgoraV4Path, newAgoraV4Path, { overwrite: true }, (err) => {
99
99
  if (!err) {
100
- logger.info('更新agora_electron_sdk_v4成功');
100
+ logger.info('命名agora_electron_sdk_v4成功');
101
101
  }
102
102
  });
103
103
  }