Put methods into a class called logjson.File
authorNick Downing <nick@ndcode.org>
Tue, 4 Jan 2022 08:28:58 +0000 (19:28 +1100)
committerNick Downing <nick@ndcode.org>
Tue, 4 Jan 2022 08:29:53 +0000 (19:29 +1100)
a.mjs
b.mjs
logjson.mjs

diff --git a/a.mjs b/a.mjs
index 8cc3797..d84e952 100755 (executable)
--- a/a.mjs
+++ b/a.mjs
@@ -3,7 +3,10 @@
 import logjson from './logjson.mjs'
 import fsPromises from 'fs/promises'
 
-let {log, eof, value} = await logjson.open_log(
-  'a.logjson',
+let file = new logjson.File()
+await file.open(
+  'a.logjson', 
   JSON.parse(await fsPromises.readFile('random.json', 'utf-8'))
 )
+console.log('file.value', file.value)
+await file.close()
diff --git a/b.mjs b/b.mjs
index ef146d2..7e89a37 100755 (executable)
--- a/b.mjs
+++ b/b.mjs
@@ -3,5 +3,7 @@
 import logjson from './logjson.mjs'
 import fsPromises from 'fs/promises'
 
-let {log, eof, value} = await logjson.open_log('a.logjson', {})
-console.log('value', value)
+let file = new logjson.File()
+await file.open('a.logjson', {})
+console.log('file.value', file.value)
+await file.close()
index a2c3934..9c8c296 100644 (file)
@@ -3,131 +3,171 @@ import fsPromises from 'fs/promises'
 
 let open_angle = Buffer.from('\n<', 'utf-8')
 let close_angle = Buffer.from('>\n', 'utf-8')
-let find_root = async (log, eof) => {
-  let ptr = eof & ~0xfff
-  let count = eof & 0xfff
-  let buffer = Buffer.alloc(0x1001)
-  assert((await log.read(buffer, 0, count, ptr)).bytesRead === count)
-  while (true) {
-    let i = count
-    if (i && (i = buffer.lastIndexOf(close_angle, i - 2)) != -1) {
-      let end = i + ptr
-      while (true) {
-        if (i && (i = buffer.lastIndexOf(open_angle, i - 2)) != -1) {
-          let start = i + ptr + 2
-          return {ptr: start, len: end - start}
-        }
+class File {
+  constructor() {
+    this.log = null
+    this.eof = 0
+    this.value = null
+  }
 
-        if (ptr == 0)
-          break
-        ptr -= 0x1000
-        buffer[0x1000] = buffer[0]
-        assert((await log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000)
-        count = 0x1001
-      }
+  async open(path, default_value) {
+    assert(this.log === null)
 
-      // special case for < at start of file
-      if (count && buffer[0] === 0x3c) {
-        let start = 1
-        return {ptr: start, len: end - start}
-      }
+    try {
+      this.log = await fsPromises.open(path, 'r+')
+    }
+    catch (error) {
+      if (error.code !== 'ENOENT')
+        throw error
 
-      throw new Error('can\'t find logjson start marker') 
+      this.log = await fsPromises.open(path, 'w+')
+      this.eof = 0
+
+      await this.write(default_value, true)
+      this.value = default_value
+      return
     }
 
-    if (ptr == 0)
-      break
-    ptr -= 0x1000
-    buffer[0x1000] = buffer[0]
-    assert((await log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000)
-    count = 0x1001
-  } while (ptr >= 0)
-  throw new Error('can\'t find logjson end marker') 
-}
+    this.eof = (await this.log.stat()).size
+    let {ptr, len} = await this.find_root()
+    this.value = await this.read(ptr, len)
 
-let open_log = async (path, default_value) => {
-  let log
-  try {
-    log = await fsPromises.open(path, 'r+')
+    this.eof = ptr + len + 2
+    await this.log.truncate(this.eof)
   }
-  catch (error) {
-    if (error.code !== 'ENOENT')
-      throw error
-    log = await fsPromises.open(path, 'w+')
-    let {eof} = await write_log(log, 0, default_value, true)
-    return {log, eof, value: default_value}
+
+  async close() {
+    assert(this.log !== null)
+
+    await this.log.close()
+    this.log = null
   }
 
-  let eof = (await log.stat()).size
-  let {ptr, len} = await find_root(log, eof)
-  let value = await read_log(log, ptr, len)
+  async find_root() {
+    let ptr = this.eof & ~0xfff
+    let count = this.eof & 0xfff
+    let buffer = Buffer.alloc(0x1001)
+    assert(
+      (await this.log.read(buffer, 0, count, ptr)).bytesRead === count
+    )
+    while (true) {
+      let i = count
+      if (i && (i = buffer.lastIndexOf(close_angle, i - 2)) != -1) {
+        let end = i + ptr
+        while (true) {
+          if (i && (i = buffer.lastIndexOf(open_angle, i - 2)) != -1) {
+            let start = i + ptr + 2
+            return {ptr: start, len: end - start}
+          }
 
-  eof = ptr + len + 2
-  await log.truncate(eof)
+          if (ptr == 0)
+            break
+          ptr -= 0x1000
+          if (count) {
+            buffer[0x1000] = buffer[0]
+            count = 0x1001
+          }
+          else
+            count = 0x1000
+          assert(
+            (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
+          )
+        }
 
-  return {log, eof, value}
-}
+        // special case for < at start of file
+        if (count && buffer[0] === 0x3c) {
+          let start = 1
+          return {ptr: start, len: end - start}
+        }
 
-let read_log = async (log, ptr, len) => {
-  let buffer = Buffer.alloc(len)
-  assert((await log.read(buffer, 0, len, ptr)).bytesRead === len)
-  let value = JSON.parse(buffer.toString('utf-8'))
-  if (typeof value === 'object' && value !== null)
-    if (value instanceof Array) {
-      for (let i = 0; i < value.length; ++i) {
-        let item = value[i]
-        if (item instanceof Array)
-          value[i] = await read_log(log, item[0], item[1])
+        throw new Error('can\'t find logjson start marker')
       }
+
+      if (ptr == 0)
+        break
+      ptr -= 0x1000
+      if (count) {
+        buffer[0x1000] = buffer[0]
+        count = 0x1001
+      }
+      else
+        count = 0x1000
+      assert(
+        (await this.log.read(buffer, 0, 0x1000, ptr)).bytesRead === 0x1000
+      )
     }
-    else
-      for (let i in value) {
-        let item = value[i]
-        if (item instanceof Array)
-          value[i] = await read_log(log, item[0], item[1])
+
+    throw new Error('can\'t find logjson end marker')
+  }
+
+  async read(ptr, len) {
+    let buffer = Buffer.alloc(len)
+    assert((await this.log.read(buffer, 0, len, ptr)).bytesRead === len)
+    let value = JSON.parse(buffer.toString('utf-8'))
+    if (typeof value === 'object' && value !== null)
+      if (value instanceof Array) {
+        for (let i = 0; i < value.length; ++i) {
+          let item = value[i]
+          if (item instanceof Array)
+            value[i] = await this.read(item[0], item[1])
+        }
       }
-  return value
-}
+      else
+        for (let i in value) {
+          let item = value[i]
+          if (item instanceof Array)
+            value[i] = await this.read(item[0], item[1])
+        }
+    return value
+  }
 
-let write_log = async (log, eof, value, is_root) => {
-  if (typeof value === 'object' && value !== null)
-    if (value instanceof Array) {
-      let value1 = []
-      for (let i = 0; i < value.length; ++i) {
-        let item = value[i]
-        if (typeof item === 'object' && item !== null) {
-          let {ptr, len, eof: eof1} = await write_log(log, eof, item, false)
-          item = [ptr, len]
-          eof = eof1
+  async write(value, is_root) {
+    if (typeof value === 'object' && value !== null)
+      if (value instanceof Array) {
+        let value1 = []
+        for (let i = 0; i < value.length; ++i) {
+          let item = value[i]
+          if (typeof item === 'object' && item !== null) {
+            let {ptr, len} = await this.write(item, false)
+            item = [ptr, len]
+          }
+          value1.push(item)
         }
-        value1.push(item)
+        value = value1
       }
-      value = value1
-    }
-    else {
-      let value1 = {}
-      for (let i in value) {
-        let item = value[i]
-        if (typeof item === 'object' && item !== null) {
-          let {ptr, len, eof: eof1} = await write_log(log, eof, item, false)
-          item = [ptr, len]
-          eof = eof1
+      else {
+        let value1 = {}
+        for (let i in value) {
+          let item = value[i]
+          if (typeof item === 'object' && item !== null) {
+            let {ptr, len} = await this.write(item, false)
+            item = [ptr, len]
+          }
+          value1[i] = item
         }
-        value1[i] = item
+        value = value1
       }
-      value = value1
+
+    let data = JSON.stringify(value, null, 2)
+    if (is_root) {
+      let buffer = Buffer.from(`<${data}>\n`)
+      let len = buffer.length
+      assert(
+        (await this.log.write(buffer, 0, len, this.eof)).bytesWritten === len
+      )
+      let ptr = this.eof + 1
+      this.eof += len
+      return {ptr, len: len - 2}
     }
-  let data = JSON.stringify(value, null, 2)
-  if (is_root) {
-    let buffer = Buffer.from(`<${data}>\n`)
+    let buffer = Buffer.from(`${data}\n`)
     let len = buffer.length
-    assert((await log.write(buffer, 0, len, eof)).bytesWritten === len)
-    return {ptr: eof + 1, len: len - 2, eof: eof + len}
+    assert(
+      (await this.log.write(buffer, 0, len, this.eof)).bytesWritten === len
+    )
+    let ptr = this.eof
+    this.eof += len
+    return {ptr, len: len - 1}
   }
-  let buffer = Buffer.from(`${data}\n`)
-  let len = buffer.length
-  assert((await log.write(buffer, 0, len, eof)).bytesWritten === len)
-  return {ptr: eof, len: len - 1, eof: eof + len}
 }
 
-export default {open_log, read_log, write_log}
+export default {File}