HEX
Server: Apache/2.4.63 (Unix)
System: Linux Synopilou92 4.4.302+ #72806 SMP Mon Jul 21 23:16:00 CST 2025 x86_64
User: pilou92 (1026)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /volume1/@appstore/Spreadsheet/server/common/collab/Instance.js
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"default",{enumerable:true,get:function(){return l}});const t=c(require("./Instance2"));const e=require("./error");const s=c(require("./Constants"));const n=require("../helper");const i=c(require("../../task-daemon/client"));const a=require("@synology-office/logger");const o=require("../../common/webapi/error");const r=require("perf_hooks");function c(t){return t&&t.__esModule?t:{default:t}}class l extends t.default{constructor(t,e,s){super(t,e,s);this.uniqueId=(0,n.randomString)(8,"hex");this.doc=null;this.snapshotting=null;this.snapshotLastError=null;this.snapshotScheduler=null}getMigrator(){return this.getApp().getMigrator()}getSnapshotter(){return this.getApp().getSnapshotter()}getCollabObject(t=false){const e=this.doc;if(t&&!e){throw new Error(`Collab object is not initialized. ${this.objectId}`)}return e}getUniqueId(){return this.uniqueId}getDataVersionCache(){return this.getCollabObject(true).getVersionCache()}async flushCommands(){await(this.getCollabObject()?.drain())}async fetchComments(t){return await this.getCollabObject(true).fetchComments(t)}createReplyData(t,e){if(e.length){return{version:t+e.length,wait:true,steps:e,clientIDs:e.map((t=>String(t.clientID??""))),selections:this.listClients().reduce(((e,s)=>{const n=s.getSelectionAfterVersion(t);if(n){e.push({connectionId:s.id,selection:n})}return e}),[])}}else{return{version:t,wait:true}}}async fetchReplyData(t){if(t===this.getDataVersionCache()){return null}const e=await this.getCollabObject(true).fetchCommands(t,false);if(!e){return null}return this.createReplyData(t,e.commands)}async fetchData(){const{version:t,doc:e,comments:s}=await this.getCollabObject(true).fetchJson();return{doc:{version:t,data:e,comment_store:s}}}async destroy(t){this.clearTimer();await(this.getCollabObject()?.destroy());await this.postDestroy()}clearTimer(){super.clearTimer();this.unscheduleSnapshot()}getSnapshotting(){return this.snapshotting}setSnapshotting(t,e){this.snapshotting={mode:t,promise:e}}clearSnapshotting(){this.snapshotting=null}isSnapshotting(){return!!this.getSnapshotting()}async waitSnapshottingAndFlushCommand(){const t=this.getSnapshotting();if(t){await t.promise.catch((()=>{}))}await this.flushCommands().catch((()=>{}))}setSnapshotFailure(t){this.snapshotLastError={time:Date.now(),code:t}}setSnapshotSuccess(t){this.getCollabObject(true).cut(t);this.snapshotLastError=null}isSnapshotable(){if(this.isDestroying()){return false}const t=this.snapshotLastError;if(!t){return true}const{time:e,code:n}=t;if(57344+62===n){return true}if(s.default.SNAPSHOT_ERROR_INTERVAL>Math.abs(Date.now()-e)){return false}switch(n){case o.WEBAPI_ERR.SYNOFFICE_ERR_CLUSTER_LOCK:return false;case o.WEBAPI_ERR.SYNOFFICE_ERR_ENCRYPT_NO_PASS:case o.WEBAPI_ERR.SYNOFFICE_ERR_ENCRYPT_STATUS_ERR:case o.WEBAPI_ERR.SYNOFFICE_ERR_ENCRYPT_OP_FAILED:return this.getClientCount()!==0}return true}async snapshot(t=Object.create(null)){const e=this.getCollabObject();if(!e){return{success:false}}const s=t.mode||"save";if(s==="save"){if(!this.isSnapshotable()){return{success:false,code:this.snapshotLastError?.code}}}else if(s==="publish"&&(0,n.isTemplate)(this.objectId)){const e=this.getSnapshotting();if(e){if(e.mode==="publish"||e.waitingPublish){return{success:false,code:57344+57}}else{e.waitingPublish=true;e.waitingPublishOption=t}}}const i=this.getSnapshotting();if(i){return i.promise}const a=this.getApp().requestSnapshot((async()=>{let e=await this.doSnapshot(t);const s=this.getSnapshotting();if(s?.waitingPublish){s.mode="publish";s.waitingPublish=undefined;e=await this.doSnapshot(s.waitingPublishOption);s.waitingPublishOption=undefined}this.clearSnapshotting();this.unscheduleSnapshot();this.delayDestroy();return e}));this.setSnapshotting(s,a);return a}async doSnapshot(t=Object.create(null)){const e=r.performance.now();const o=this.getApp();const c=this.objectId;let l;const h=s.default.QUEUE_SNAPSHOT_DIR+c+"_"+Date.now();try{l=(await this.getCollabObject(true).snapshot(h)).count}catch(t){const e=57344;this.setSnapshotFailure(e);a.logger.error("fs.writeFile failed",c,t);return{success:false,code:e}}if(l===0){return{success:true,snapshot_version:this.snapshot_version}}try{const s=this.getSnapshotEventName();const a=await(0,i.default)(s,{objectId:c,password:this.getPassword(),path:h,do_git_pack:"boolean"===typeof t.do_git_pack?t.do_git_pack:true,file_path:this.getPath()});o.sendMetric("node_elapsed_time_seconds",s,(r.performance.now()-e)/1e3);this.setSnapshotSuccess(l);this.updateSnapshotVersion(a.snapshot_version);await(0,n.generateOFileAsync)(c,a.editors,this.getPassword());return{success:true,snapshot_version:a.snapshot_version}}catch(t){const e=(typeof t==="object"&&t?t.code:undefined)||57344;if(57344+7===e){this.setSnapshotSuccess(l)}else{this.setSnapshotFailure(e)}a.logger.error("call snapshot webapi failed",c,t);return{success:false,code:e}}}scheduleSnapshot(){if(this.snapshotScheduler!==null){return}this.snapshotScheduler=setTimeout((()=>{this.snapshotScheduler=null;this.snapshot()}),s.default.SNAPSHOT_SCHEDULE_INTERVAL)}unscheduleSnapshot(){if(this.snapshotScheduler!==null){clearTimeout(this.snapshotScheduler);this.snapshotScheduler=null}}listAndResetWaitingClients(){const t=[];for(const e of this.listClients(true)){const s=e.getWaitingVersion();if(s===undefined){continue}e.stopWaiting();t.push({id:e.id,waitingVersion:s})}return t}async broadcastClientChanges(){const t=this.listAndResetWaitingClients();if(t.length===0){return}let e;try{const s=t.reduce(((t,{waitingVersion:e})=>Math.min(t,e)),t[0].waitingVersion);e=await this.getCollabObject(true).fetchCommands(s,true)}catch(t){a.logger.error(t);e=null}const s=this.getClientsReplyDataMap(t,e);for(const{clients:t,replyData:e}of s.values()){this.broadcastReplyData(t,e)}}getClientsReplyDataMap(t,n){const i=new Map;for(const{id:a,waitingVersion:o}of t){const t=this.getClient(a);if(!t||t.isWaiting()){continue}let r=i.get(o);if(!r){let t;if(n){const{commands:i,fromVersion:a}=n;if(o<a){const n=s.default.ERR_HISTORY_NOT_AVAIL;const r=`${this.getCollabObject(true).getObjectId()}: ${(0,e.getVersionErrorMessage)(n,o,a+i.length)}`;t=new e.OfficeError(r,n)}else{t=this.createReplyData(o,i.slice(o-a))}}else{t={version:o,wait:true}}r={clients:[],replyData:t};i.set(o,r)}r.clients.push(t)}return i}broadcastReplyData(t,e){if("status"in e){a.logger.error(e);this.broadcastByClients(t,"reply",{status:e.status})}else{if(e.wait){const s=e.version;for(const e of t){e.setWaitingVersion(s)}}if(e.steps&&e.steps.length>0){this.broadcastByClients(t,"reply",null,e)}}}async stat(){const t=Promise.all(this.listClients(false).map((t=>t.stat())));const e=this.getCollabObject()?.stat()||Promise.resolve(null);return{objectId:this.objectId,clients:await t,object:await e}}isSnapshotScheduled(){return!!this.snapshotScheduler}}