• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const distributedObject = requireInternal('data.distributedDataObject');
17const SESSION_ID = '__sessionId';
18const VERSION = '__version';
19const COMPLEX_TYPE = '[COMPLEX]';
20const STRING_TYPE = '[STRING]';
21const NULL_TYPE = '[NULL]';
22const ASSET_KEYS = ['status', 'name', 'uri', 'path', 'createTime', 'modifyTime', 'size'];
23const STATUS_INDEX = 0;
24const ASSET_KEY_SEPARATOR = '.';
25const JS_ERROR = 1;
26const SDK_VERSION_8 = 8;
27const SDK_VERSION_9 = 9;
28const SESSION_ID_REGEX = /^\w+$/;
29const SESSION_ID_MAX_LENGTH = 128;
30
31class Distributed {
32  constructor(obj) {
33    constructorMethod(this, obj);
34  }
35
36  setSessionId(sessionId) {
37    if (sessionId == null || sessionId === '') {
38      leaveSession(this.__sdkVersion, this.__proxy);
39      return false;
40    }
41    if (this.__proxy[SESSION_ID] === sessionId) {
42      return true;
43    }
44    leaveSession(this.__sdkVersion, this.__proxy);
45    let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId);
46    if (object != null) {
47      this.__proxy = object;
48      return true;
49    }
50    return false;
51  }
52
53  on(type, callback) {
54    onWatch(this.__sdkVersion, type, this.__proxy, callback);
55    distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback);
56  }
57
58  off(type, callback) {
59    offWatch(this.__sdkVersion, type, this.__proxy, callback);
60    if (callback !== undefined || callback != null) {
61      distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback);
62    } else {
63      distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId);
64    }
65  }
66
67  save(deviceId, callback) {
68    if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') {
69      console.info('not join a session, can not do save');
70      return JS_ERROR;
71    }
72    return this.__proxy.save(deviceId, this[VERSION], callback);
73  }
74
75  revokeSave(callback) {
76    if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') {
77      console.info('not join a session, can not do revoke save');
78      return JS_ERROR;
79    }
80    return this.__proxy.revokeSave(callback);
81  }
82
83  __proxy;
84  __objectId;
85  __version;
86  __sdkVersion = SDK_VERSION_8;
87}
88
89function constructorMethod(result, obj) {
90  result.__proxy = obj;
91  Object.keys(obj).forEach(key => {
92    Object.defineProperty(result, key, {
93      enumerable: true,
94      configurable: true,
95      get: function () {
96        return result.__proxy[key];
97      },
98      set: function (newValue) {
99        result[VERSION]++;
100        result.__proxy[key] = newValue;
101      }
102    });
103  });
104  Object.defineProperty(result, SESSION_ID, {
105    enumerable: true,
106    configurable: true,
107    get: function () {
108      return result.__proxy[SESSION_ID];
109    },
110    set: function (newValue) {
111      result.__proxy[SESSION_ID] = newValue;
112    }
113  });
114  result.__objectId = randomNum();
115  result[VERSION] = 0;
116  console.info('constructor success ');
117}
118
119function randomNum() {
120  return distributedObject.sequenceNum();
121}
122
123function newDistributed(obj) {
124  console.info('start newDistributed');
125  if (obj == null) {
126    console.error('object is null');
127    return null;
128  }
129  return new Distributed(obj);
130}
131
132function getObjectValue(object, key) {
133  console.info('start get ' + key);
134  let result = object.get(key);
135  if (typeof result === 'string') {
136    if (result.startsWith(STRING_TYPE)) {
137      result = result.substr(STRING_TYPE.length);
138    } else if (result.startsWith(COMPLEX_TYPE)) {
139      result = JSON.parse(result.substr(COMPLEX_TYPE.length));
140    } else if (result.startsWith(NULL_TYPE)) {
141      result = null;
142    } else {
143      console.error('error type');
144    }
145  }
146  console.info('get success');
147  return result;
148}
149
150function setObjectValue(object, key, newValue) {
151  console.info('start set ' + key);
152  if (typeof newValue === 'object') {
153    let value = COMPLEX_TYPE + JSON.stringify(newValue);
154    object.put(key, value);
155  } else if (typeof newValue === 'string') {
156    let value = STRING_TYPE + newValue;
157    object.put(key, value);
158  } else if (newValue == null) {
159    let value = NULL_TYPE;
160    object.put(key, value);
161  } else {
162    object.put(key, newValue);
163  }
164}
165
166function isAsset(obj) {
167  if (Object.prototype.toString.call(obj) !== '[object Object]') {
168    return false;
169  }
170  let length = Object.prototype.hasOwnProperty.call(obj, ASSET_KEYS[STATUS_INDEX]) ? ASSET_KEYS.length : ASSET_KEYS.length - 1;
171  if (Object.keys(obj).length !== length) {
172    return false;
173  }
174  if (Object.prototype.hasOwnProperty.call(obj, ASSET_KEYS[STATUS_INDEX]) &&
175    typeof obj[ASSET_KEYS[STATUS_INDEX]] !== 'number' && typeof obj[ASSET_KEYS[STATUS_INDEX]] !== 'undefined') {
176    return false;
177  }
178  for (const key of ASSET_KEYS.slice(1)) {
179    if (!Object.prototype.hasOwnProperty.call(obj, key) || typeof obj[key] !== 'string') {
180      return false;
181    }
182  }
183  return true;
184}
185
186function defineAsset(object, key, data) {
187  Object.defineProperty(object, key, {
188    enumerable: true,
189    configurable: true,
190    get: function () {
191      return getAssetValue(object, key);
192    },
193    set: function (newValue) {
194      setAssetValue(object, key, newValue);
195    }
196  });
197  let asset = object[key];
198  Object.keys(data).forEach(subKey => {
199    if (data[subKey] !== '') {
200      asset[subKey] = data[subKey];
201    }
202  });
203}
204
205function getAssetValue(object, key) {
206  let asset = {};
207  ASSET_KEYS.forEach(subKey => {
208    Object.defineProperty(asset, subKey, {
209      enumerable: true,
210      configurable: true,
211      get: function () {
212        return getObjectValue(object, key + ASSET_KEY_SEPARATOR + subKey);
213      },
214      set: function (newValue) {
215        setObjectValue(object, key + ASSET_KEY_SEPARATOR + subKey, newValue);
216      }
217    });
218  });
219  return asset;
220}
221
222function setAssetValue(object, key, newValue) {
223  if (!isAsset(newValue)) {
224    throw {
225      code: 401,
226      message: 'cannot set ' + key + ' by non Asset type data'
227    };
228  }
229  Object.keys(newValue).forEach(subKey => {
230    setObjectValue(object, key + ASSET_KEY_SEPARATOR + subKey, newValue[subKey]);
231  });
232}
233
234function joinSession(version, obj, objectId, sessionId, context) {
235  if (obj == null || sessionId == null || sessionId === '') {
236    console.error('object is null');
237    return null;
238  }
239
240  let object = null;
241  if (context !== undefined || context != null) {
242    object = distributedObject.createObjectSync(version, sessionId, objectId, context);
243  } else {
244    object = distributedObject.createObjectSync(version, sessionId, objectId);
245  }
246
247  if (object == null) {
248    console.error('create fail');
249    return null;
250  }
251  Object.keys(obj).forEach(key => {
252    console.info('start define ' + key);
253    if (isAsset(obj[key])) {
254      defineAsset(object, key, obj[key]);
255    } else {
256      Object.defineProperty(object, key, {
257        enumerable: true,
258        configurable: true,
259        get: function () {
260          return getObjectValue(object, key);
261        },
262        set: function (newValue) {
263          setObjectValue(object, key, newValue);
264        }
265      });
266      if (obj[key] !== undefined) {
267        object[key] = obj[key];
268      }
269    }
270  });
271
272  Object.defineProperty(object, SESSION_ID, {
273    value: sessionId,
274    configurable: true,
275  });
276  return object;
277}
278
279function leaveSession(version, obj) {
280  console.info('start leaveSession');
281  if (obj == null || obj[SESSION_ID] == null || obj[SESSION_ID] === '') {
282    console.warn('object is null');
283    return;
284  }
285  Object.keys(obj).forEach(key => {
286    Object.defineProperty(obj, key, {
287      value: obj[key],
288      configurable: true,
289      writable: true,
290      enumerable: true,
291    });
292    if (isAsset(obj[key])) {
293      Object.keys(obj[key]).forEach(subKey => {
294        Object.defineProperty(obj[key], subKey, {
295          value: obj[key][subKey],
296          configurable: true,
297          writable: true,
298          enumerable: true,
299        });
300      });
301    }
302  });
303  // disconnect,delete object
304  distributedObject.destroyObjectSync(version, obj);
305  delete obj[SESSION_ID];
306}
307
308function onWatch(version, type, obj, callback) {
309  console.info('start on ' + obj[SESSION_ID]);
310  if (obj[SESSION_ID] != null && obj[SESSION_ID] !== undefined && obj[SESSION_ID].length > 0) {
311    distributedObject.on(version, type, obj, callback);
312  }
313}
314
315function offWatch(version, type, obj, callback = undefined) {
316  console.info('start off ' + obj[SESSION_ID] + ' ' + callback);
317  if (obj[SESSION_ID] != null && obj[SESSION_ID] !== undefined && obj[SESSION_ID].length > 0) {
318    if (callback !== undefined || callback != null) {
319      distributedObject.off(version, type, obj, callback);
320    } else {
321      distributedObject.off(version, type, obj);
322    }
323  }
324}
325
326function newDistributedV9(context, obj) {
327  console.info('start newDistributed');
328  let checkparameter = function(parameter, type) {
329    throw {
330      code: 401,
331      message :"Parameter error. The type of '" + parameter + "' must be '" + type + "'."};
332  };
333  if (typeof context !== 'object') {
334    checkparameter('context', 'Context');
335  }
336  if (typeof obj !== 'object') {
337    checkparameter('source', 'object');
338  }
339  if (obj == null) {
340    console.error('object is null');
341    return null;
342  }
343  return new DistributedV9(obj, context);
344}
345
346class DistributedV9 {
347
348  constructor(obj, context) {
349    this.__context = context;
350    constructorMethod(this, obj);
351  }
352
353  setSessionId(sessionId, callback) {
354    if (typeof sessionId === 'function' || sessionId == null || sessionId === '') {
355      leaveSession(this.__sdkVersion, this.__proxy);
356      if (typeof sessionId === 'function') {
357        return sessionId(this.__proxy);
358      } else if (typeof callback === 'function') {
359        return callback(null, this.__proxy);
360      } else {
361        return Promise.resolve(null, this.__proxy);
362      }
363    }
364    if (this.__proxy[SESSION_ID] === sessionId) {
365      if (typeof callback === 'function') {
366        return callback(null, this.__proxy);
367      } else {
368        return Promise.resolve(null, this.__proxy);
369      }
370    }
371    leaveSession(this.__sdkVersion, this.__proxy);
372    if (sessionId.length > SESSION_ID_MAX_LENGTH || !SESSION_ID_REGEX.test(sessionId)) {
373      throw {
374        code: 401,
375        message: 'The sessionId allows only letters, digits, and underscores(_), and cannot exceed 128 in length.'
376      };
377    }
378    let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId, this.__context);
379    if (object != null) {
380      this.__proxy = object;
381      if (typeof callback === 'function') {
382        return callback(null, this.__proxy);
383      } else {
384        return Promise.resolve(null, object);
385      }
386    } else {
387      if (typeof callback === 'function') {
388        return callback(null, null);
389      } else {
390        return Promise.reject(null, null);
391      }
392    }
393  }
394
395  on(type, callback) {
396    onWatch(this.__sdkVersion, type, this.__proxy, callback);
397    distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback);
398  }
399
400  off(type, callback) {
401    offWatch(this.__sdkVersion, type, this.__proxy, callback);
402    if (callback !== undefined || callback != null) {
403      distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback);
404    } else {
405      distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId);
406    }
407  }
408
409  save(deviceId, callback) {
410    if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') {
411      console.info('not join a session, can not do save');
412      return JS_ERROR;
413    }
414    return this.__proxy.save(deviceId, this[VERSION], callback);
415  }
416
417  revokeSave(callback) {
418    if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') {
419      console.info('not join a session, can not do revoke save');
420      return JS_ERROR;
421    }
422    return this.__proxy.revokeSave(callback);
423  }
424
425  bindAssetStore(assetkey, bindInfo, callback) {
426    if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') {
427      console.info('not join a session, can not do bindAssetStore');
428      return JS_ERROR;
429    }
430    return this.__proxy.bindAssetStore(assetkey, bindInfo, callback);
431  }
432
433  __context;
434  __proxy;
435  __objectId;
436  __version;
437  __sdkVersion = SDK_VERSION_9;
438}
439
440export default {
441  createDistributedObject: newDistributed,
442  create: newDistributedV9,
443  genSessionId: randomNum
444};
445