Fix/nodebara compatibility (#2)
This commit is contained in:
@@ -244,6 +244,8 @@ class Client {
|
|||||||
this.requestId = 0;
|
this.requestId = 0;
|
||||||
this._buffer = Buffer.alloc(0);
|
this._buffer = Buffer.alloc(0);
|
||||||
this._pendingResolve = null;
|
this._pendingResolve = null;
|
||||||
|
this._requestQueue = [];
|
||||||
|
this._requestLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
@@ -478,70 +480,98 @@ class Client {
|
|||||||
throw new Error(`Unexpected auth response: 0x${header.kind.toString(16)}`);
|
throw new Error(`Unexpected auth response: 0x${header.kind.toString(16)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _processQueue() {
|
||||||
|
if (this._requestLock || this._requestQueue.length === 0) return;
|
||||||
|
this._requestLock = true;
|
||||||
|
const { task, resolve, reject } = this._requestQueue.shift();
|
||||||
|
try {
|
||||||
|
const result = await task();
|
||||||
|
resolve(result);
|
||||||
|
} catch (err) {
|
||||||
|
reject(err);
|
||||||
|
} finally {
|
||||||
|
this._requestLock = false;
|
||||||
|
setImmediate(() => this._processQueue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_enqueue(task) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this._requestQueue.push({ task, resolve, reject });
|
||||||
|
this._processQueue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async ping() {
|
async ping() {
|
||||||
if (!this.connected) throw new Error('Not connected');
|
if (!this.connected) throw new Error('Not connected');
|
||||||
const msg = this._build(MsgKind.PING, Buffer.alloc(0));
|
return this._enqueue(async () => {
|
||||||
this.socket.write(msg);
|
const msg = this._build(MsgKind.PING, Buffer.alloc(0));
|
||||||
|
this.socket.write(msg);
|
||||||
|
|
||||||
const header = await this._readHeader();
|
const header = await this._readHeader();
|
||||||
if (header.kind === MsgKind.PONG) return true;
|
if (header.kind === MsgKind.PONG) return true;
|
||||||
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
||||||
return false;
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async query(sql) {
|
async query(sql) {
|
||||||
if (!this.connected) throw new Error('Not connected');
|
if (!this.connected) throw new Error('Not connected');
|
||||||
const queryBuf = Buffer.from(sql, 'utf-8');
|
return this._enqueue(async () => {
|
||||||
const payload = Buffer.alloc(4 + queryBuf.length + 1);
|
const queryBuf = Buffer.from(sql, 'utf-8');
|
||||||
payload.writeUInt32BE(queryBuf.length, 0);
|
const payload = Buffer.alloc(4 + queryBuf.length + 1);
|
||||||
queryBuf.copy(payload, 4);
|
payload.writeUInt32BE(queryBuf.length, 0);
|
||||||
payload[4 + queryBuf.length] = ResultFormat.BINARY;
|
queryBuf.copy(payload, 4);
|
||||||
|
payload[4 + queryBuf.length] = ResultFormat.BINARY;
|
||||||
|
|
||||||
const msg = this._build(MsgKind.QUERY, payload);
|
const msg = this._build(MsgKind.QUERY, payload);
|
||||||
this.socket.write(msg);
|
this.socket.write(msg);
|
||||||
|
|
||||||
const header = await this._readHeader();
|
const header = await this._readHeader();
|
||||||
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
||||||
if (header.kind === MsgKind.DATA) return await this._readDataResponse(header.length);
|
if (header.kind === MsgKind.DATA) return await this._readDataResponse(header.length);
|
||||||
if (header.kind === MsgKind.COMPLETE) {
|
if (header.kind === MsgKind.COMPLETE) {
|
||||||
const data = await this._recvExact(header.length);
|
const data = await this._recvExact(header.length);
|
||||||
const result = new QueryResult();
|
const result = new QueryResult();
|
||||||
result.affectedRows = data.readUInt32BE(0);
|
result.affectedRows = data.readUInt32BE(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return new QueryResult();
|
return new QueryResult();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryParams(sql, params = []) {
|
async queryParams(sql, params = []) {
|
||||||
if (!this.connected) throw new Error('Not connected');
|
if (!this.connected) throw new Error('Not connected');
|
||||||
const queryBuf = Buffer.from(sql, 'utf-8');
|
return this._enqueue(async () => {
|
||||||
const paramParts = [];
|
const queryBuf = Buffer.from(sql, 'utf-8');
|
||||||
for (const p of params) {
|
const paramParts = [];
|
||||||
paramParts.push(p.serialize());
|
for (const p of params) {
|
||||||
}
|
paramParts.push(p.serialize());
|
||||||
const paramsBuf = Buffer.concat(paramParts);
|
}
|
||||||
|
const paramsBuf = Buffer.concat(paramParts);
|
||||||
|
|
||||||
const payload = Buffer.alloc(4 + queryBuf.length + 1 + 4 + paramsBuf.length);
|
const payload = Buffer.alloc(4 + queryBuf.length + 1 + 4 + paramsBuf.length);
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
payload.writeUInt32BE(queryBuf.length, pos); pos += 4;
|
payload.writeUInt32BE(queryBuf.length, pos); pos += 4;
|
||||||
queryBuf.copy(payload, pos); pos += queryBuf.length;
|
queryBuf.copy(payload, pos); pos += queryBuf.length;
|
||||||
payload[pos] = ResultFormat.BINARY; pos++;
|
payload[pos] = ResultFormat.BINARY; pos++;
|
||||||
payload.writeUInt32BE(params.length, pos); pos += 4;
|
payload.writeUInt32BE(params.length, pos); pos += 4;
|
||||||
paramsBuf.copy(payload, pos);
|
paramsBuf.copy(payload, pos);
|
||||||
|
|
||||||
const msg = this._build(MsgKind.QUERY_PARAMS, payload);
|
const msg = this._build(MsgKind.QUERY_PARAMS, payload);
|
||||||
this.socket.write(msg);
|
this.socket.write(msg);
|
||||||
|
|
||||||
const header = await this._readHeader();
|
const header = await this._readHeader();
|
||||||
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
if (header.kind === MsgKind.ERROR) throw await this._readError(header.length);
|
||||||
if (header.kind === MsgKind.DATA) return await this._readDataResponse(header.length);
|
if (header.kind === MsgKind.DATA) return await this._readDataResponse(header.length);
|
||||||
if (header.kind === MsgKind.COMPLETE) {
|
if (header.kind === MsgKind.COMPLETE) {
|
||||||
const data = await this._recvExact(header.length);
|
const data = await this._recvExact(header.length);
|
||||||
const result = new QueryResult();
|
const result = new QueryResult();
|
||||||
result.affectedRows = data.readUInt32BE(0);
|
result.affectedRows = data.readUInt32BE(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return new QueryResult();
|
return new QueryResult();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(sql) {
|
async execute(sql) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import std/random
|
|||||||
import std/monotimes
|
import std/monotimes
|
||||||
import std/asyncdispatch
|
import std/asyncdispatch
|
||||||
import std/net
|
import std/net
|
||||||
|
import std/asyncnet
|
||||||
import std/strutils
|
import std/strutils
|
||||||
import std/streams
|
import std/streams
|
||||||
import std/os
|
import std/os
|
||||||
@@ -36,7 +37,7 @@ type
|
|||||||
fanout*: int # number of nodes to gossip to per round
|
fanout*: int # number of nodes to gossip to per round
|
||||||
gossipPort*: int
|
gossipPort*: int
|
||||||
running*: bool
|
running*: bool
|
||||||
sock*: Socket
|
sock*: AsyncSocket
|
||||||
onJoin*: proc(node: GossipNode) {.gcsafe.}
|
onJoin*: proc(node: GossipNode) {.gcsafe.}
|
||||||
onLeave*: proc(nodeId: string) {.gcsafe.}
|
onLeave*: proc(nodeId: string) {.gcsafe.}
|
||||||
onSuspect*: proc(nodeId: string) {.gcsafe.}
|
onSuspect*: proc(nodeId: string) {.gcsafe.}
|
||||||
@@ -305,25 +306,21 @@ proc startGossipRound*(gp: GossipProtocol, intervalMs: int = 2000) {.async.} =
|
|||||||
gp.broadcastGossip()
|
gp.broadcastGossip()
|
||||||
|
|
||||||
proc startGossipListener*(gp: GossipProtocol) {.async.} =
|
proc startGossipListener*(gp: GossipProtocol) {.async.} =
|
||||||
gp.sock = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
gp.sock = newAsyncSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
||||||
gp.sock.setSockOpt(OptReuseAddr, true)
|
gp.sock.setSockOpt(OptReuseAddr, true)
|
||||||
gp.sock.bindAddr(Port(gp.gossipPort))
|
gp.sock.bindAddr(Port(gp.gossipPort))
|
||||||
gp.running = true
|
gp.running = true
|
||||||
while gp.running:
|
while gp.running:
|
||||||
try:
|
try:
|
||||||
var data = newString(65535)
|
let (data, senderAddr, senderPort) = await gp.sock.recvFrom(65535)
|
||||||
var senderAddr = ""
|
if data.len > 0:
|
||||||
var senderPort: Port
|
|
||||||
let bytesRead = gp.sock.recvFrom(data, 65535, senderAddr, senderPort)
|
|
||||||
if bytesRead > 0:
|
|
||||||
data.setLen(bytesRead)
|
|
||||||
gp.handleIncomingGossip(data, senderAddr)
|
gp.handleIncomingGossip(data, senderAddr)
|
||||||
except:
|
except:
|
||||||
# Small sleep on error to avoid spin
|
# Small sleep on error to avoid spin
|
||||||
gp.sock.close()
|
gp.sock.close()
|
||||||
# Recreate socket for next iteration
|
# Recreate socket for next iteration
|
||||||
try:
|
try:
|
||||||
gp.sock = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
gp.sock = newAsyncSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
||||||
gp.sock.setSockOpt(OptReuseAddr, true)
|
gp.sock.setSockOpt(OptReuseAddr, true)
|
||||||
gp.sock.bindAddr(Port(gp.gossipPort))
|
gp.sock.bindAddr(Port(gp.gossipPort))
|
||||||
except:
|
except:
|
||||||
|
|||||||
@@ -169,12 +169,14 @@ proc serializeValue*(buf: var seq[byte], val: WireValue) =
|
|||||||
of fkFloat32:
|
of fkFloat32:
|
||||||
var fl = val.float32Val
|
var fl = val.float32Val
|
||||||
var bytes: array[4, byte]
|
var bytes: array[4, byte]
|
||||||
copyMem(addr bytes, unsafeAddr fl, 4)
|
var i32 = cast[int32](fl)
|
||||||
|
bigEndian32(addr bytes, unsafeAddr i32)
|
||||||
buf.add(bytes)
|
buf.add(bytes)
|
||||||
of fkFloat64:
|
of fkFloat64:
|
||||||
var fl = val.float64Val
|
var fl = val.float64Val
|
||||||
var bytes: array[8, byte]
|
var bytes: array[8, byte]
|
||||||
copyMem(addr bytes, unsafeAddr fl, 8)
|
var i64 = cast[int64](fl)
|
||||||
|
bigEndian64(addr bytes, unsafeAddr i64)
|
||||||
buf.add(bytes)
|
buf.add(bytes)
|
||||||
of fkString: buf.writeString(val.strVal)
|
of fkString: buf.writeString(val.strVal)
|
||||||
of fkBytes: buf.writeBytes(val.bytesVal)
|
of fkBytes: buf.writeBytes(val.bytesVal)
|
||||||
@@ -192,7 +194,8 @@ proc serializeValue*(buf: var seq[byte], val: WireValue) =
|
|||||||
for f in val.vecVal:
|
for f in val.vecVal:
|
||||||
var fl = f
|
var fl = f
|
||||||
var bytes: array[4, byte]
|
var bytes: array[4, byte]
|
||||||
copyMem(addr bytes, unsafeAddr fl, 4)
|
var i32 = cast[int32](fl)
|
||||||
|
bigEndian32(addr bytes, unsafeAddr i32)
|
||||||
buf.add(bytes)
|
buf.add(bytes)
|
||||||
of fkJson:
|
of fkJson:
|
||||||
buf.writeString(val.jsonVal)
|
buf.writeString(val.jsonVal)
|
||||||
@@ -227,14 +230,18 @@ proc deserializeValue*(buf: openArray[byte], pos: var int, depth: int = 0): Wire
|
|||||||
var fl: float32
|
var fl: float32
|
||||||
var bytes: array[4, byte]
|
var bytes: array[4, byte]
|
||||||
for i in 0..3: bytes[i] = buf[pos + i]
|
for i in 0..3: bytes[i] = buf[pos + i]
|
||||||
copyMem(addr fl, unsafeAddr bytes, 4)
|
var i32: int32
|
||||||
|
bigEndian32(addr i32, unsafeAddr bytes)
|
||||||
|
fl = cast[float32](i32)
|
||||||
pos += 4
|
pos += 4
|
||||||
result = WireValue(kind: fkFloat32, float32Val: fl)
|
result = WireValue(kind: fkFloat32, float32Val: fl)
|
||||||
of fkFloat64:
|
of fkFloat64:
|
||||||
var fl: float64
|
var fl: float64
|
||||||
var bytes: array[8, byte]
|
var bytes: array[8, byte]
|
||||||
for i in 0..7: bytes[i] = buf[pos + i]
|
for i in 0..7: bytes[i] = buf[pos + i]
|
||||||
copyMem(addr fl, unsafeAddr bytes, 8)
|
var i64: int64
|
||||||
|
bigEndian64(addr i64, unsafeAddr bytes)
|
||||||
|
fl = cast[float64](i64)
|
||||||
pos += 8
|
pos += 8
|
||||||
result = WireValue(kind: fkFloat64, float64Val: fl)
|
result = WireValue(kind: fkFloat64, float64Val: fl)
|
||||||
of fkString:
|
of fkString:
|
||||||
@@ -270,7 +277,9 @@ proc deserializeValue*(buf: openArray[byte], pos: var int, depth: int = 0): Wire
|
|||||||
var fl: float32
|
var fl: float32
|
||||||
var bytes: array[4, byte]
|
var bytes: array[4, byte]
|
||||||
for j in 0..3: bytes[j] = buf[pos + j]
|
for j in 0..3: bytes[j] = buf[pos + j]
|
||||||
copyMem(addr fl, unsafeAddr bytes, 4)
|
var i32: int32
|
||||||
|
bigEndian32(addr i32, unsafeAddr bytes)
|
||||||
|
fl = cast[float32](i32)
|
||||||
pos += 4
|
pos += 4
|
||||||
vec.add(fl)
|
vec.add(fl)
|
||||||
result = WireValue(kind: fkVector, vecVal: vec)
|
result = WireValue(kind: fkVector, vecVal: vec)
|
||||||
|
|||||||
Reference in New Issue
Block a user