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}