@speckle/objectsender 1.0.0 → 1.0.2

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.
@@ -1,49 +1,70 @@
1
1
  import { ITransport } from './ITransport'
2
2
  import { IDisposable } from '../utils/IDisposable'
3
+ import { retry, timeoutAt } from '@speckle/shared'
4
+
3
5
  /**
4
6
  * Basic object sender to a speckle server
5
7
  */
6
8
  export class ServerTransport implements ITransport, IDisposable {
7
- buffer: string[]
8
- maxSize: number
9
- currSize: number
10
- serverUrl: string
11
- projectId: string
12
- authToken: string
9
+ #buffer: string[]
10
+ #maxSize: number
11
+ #currSize: number
12
+ #serverUrl: string
13
+ #projectId: string
14
+ #authToken: string
15
+ #flushRetryCount: number
16
+ #flushTimeout: number
13
17
 
14
18
  constructor(
15
19
  serverUrl: string,
16
20
  projectId: string,
17
21
  authToken: string,
18
- maxSize: number = 200_000
22
+ options?: Partial<{
23
+ maxSize: number
24
+ flushRetryCount: number
25
+ flushTimeout: number
26
+ }>
19
27
  ) {
20
- this.maxSize = maxSize
21
- this.currSize = 0
22
- this.serverUrl = serverUrl
23
- this.projectId = projectId
24
- this.authToken = authToken
25
- this.buffer = []
28
+ this.#maxSize = options?.maxSize || 200_000
29
+ this.#flushRetryCount = options?.flushRetryCount || 3
30
+ this.#flushTimeout = options?.flushTimeout || 2 * 60 * 1000
31
+
32
+ this.#currSize = 0
33
+ this.#serverUrl = serverUrl
34
+ this.#projectId = projectId
35
+ this.#authToken = authToken
36
+ this.#buffer = []
26
37
  }
27
38
 
28
39
  async write(serialisedObject: string, size: number) {
29
- this.buffer.push(serialisedObject)
30
- this.currSize += size
31
- if (this.currSize < this.maxSize) return // return fast
40
+ this.#buffer.push(serialisedObject)
41
+ this.#currSize += size
42
+ if (this.#currSize < this.#maxSize) return // return fast
32
43
  await this.flush() // block until we send objects
33
44
  }
34
45
 
35
46
  async flush() {
36
- if (this.buffer.length === 0) return
47
+ if (this.#buffer.length === 0) return
37
48
 
38
49
  const formData = new FormData()
39
- const concat = '[' + this.buffer.join(',') + ']'
50
+ const concat = '[' + this.#buffer.join(',') + ']'
40
51
  formData.append('object-batch', new Blob([concat], { type: 'application/json' }))
41
- const url = new URL(`/objects/${this.projectId}`, this.serverUrl)
42
- const res = await fetch(url, {
43
- method: 'POST',
44
- headers: { Authorization: `Bearer ${this.authToken}` },
45
- body: formData
46
- })
52
+ const url = new URL(`/objects/${this.#projectId}`, this.#serverUrl)
53
+ const res = await retry(
54
+ async () =>
55
+ await Promise.race([
56
+ fetch(url, {
57
+ method: 'POST',
58
+ headers: { Authorization: `Bearer ${this.#authToken}` },
59
+ body: formData
60
+ }),
61
+ timeoutAt(this.#flushTimeout, 'Object sender flush timed out')
62
+ ]),
63
+ this.#flushRetryCount,
64
+ (i) => {
65
+ return i * 1000
66
+ }
67
+ )
47
68
 
48
69
  if (res.status !== 201) {
49
70
  throw new Error(
@@ -51,11 +72,11 @@ export class ServerTransport implements ITransport, IDisposable {
51
72
  )
52
73
  }
53
74
 
54
- this.buffer = []
55
- this.currSize = 0
75
+ this.#buffer = []
76
+ this.#currSize = 0
56
77
  }
57
78
 
58
79
  dispose() {
59
- this.buffer = []
80
+ this.#buffer = []
60
81
  }
61
82
  }
@@ -0,0 +1,15 @@
1
+ import { expect, describe, it } from 'vitest'
2
+ import { SHA1 } from './Sha1'
3
+
4
+ describe('SHA1 encryption', () => {
5
+ it.each([
6
+ ['le speckle', '67413ddfa55bab1b735d4d90bf5be7f5fafbcdfb'],
7
+ [
8
+ 'the quick brown fox jumped over the lazy dog? i think',
9
+ 'b724fbdc205bae3b1d7511304ec4b576af563f93'
10
+ ],
11
+ ['1', '356a192b7913b04c54574d18c28d46e6395428ab']
12
+ ])('SHA1(%s) should return %s', (input, expected) => {
13
+ expect(SHA1(input)).toBe(expected)
14
+ })
15
+ })
package/src/utils/Sha1.ts CHANGED
@@ -134,5 +134,5 @@ export function SHA1(msg: string) {
134
134
  H4 = (H4 + E) & 0x0ffffffff
135
135
  }
136
136
  const h = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4)
137
- return h.toLowerCase().substring(0, 32)
137
+ return h.toLowerCase().substring(0, 40)
138
138
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["node_modules", "dist", "coverage"],
4
+ "include": ["src", "vite.config.ts", "vitest.config.ts"]
5
+ }
@@ -1,11 +1,13 @@
1
+ /// <reference types="vitest" />
1
2
  import pkg from './package.json'
2
3
  import { defineConfig } from 'vite'
3
4
  import { resolve } from 'path'
5
+ import dts from 'vite-plugin-dts'
4
6
 
5
7
  export default defineConfig({
6
8
  build: {
7
9
  lib: {
8
- entry: resolve(import.meta.dirname, './src/index.ts'),
10
+ entry: resolve(__dirname, './src/index.ts'),
9
11
  name: 'objectsender',
10
12
  fileName: 'objectsender',
11
13
  formats: ['es', 'cjs']
@@ -14,5 +16,6 @@ export default defineConfig({
14
16
  rollupOptions: {
15
17
  external: Object.keys(pkg.dependencies || {})
16
18
  }
17
- }
19
+ },
20
+ plugins: [dts()]
18
21
  })
@@ -0,0 +1,9 @@
1
+ import { coverageConfigDefaults, defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ coverage: {
6
+ exclude: ['**/src/examples/**', ...coverageConfigDefaults.exclude]
7
+ }
8
+ }
9
+ })