summaryrefslogtreecommitdiff
path: root/client/3rd-party
diff options
context:
space:
mode:
Diffstat (limited to 'client/3rd-party')
-rw-r--r--client/3rd-party/client.py69
-rw-r--r--client/3rd-party/client.ts72
2 files changed, 115 insertions, 26 deletions
diff --git a/client/3rd-party/client.py b/client/3rd-party/client.py
index 56a8faa..52675ad 100644
--- a/client/3rd-party/client.py
+++ b/client/3rd-party/client.py
@@ -411,6 +411,17 @@ class MoonpasteFFI:
self.lib.mp_generate_keypair.argtypes = []
self.lib.mp_generate_keypair.restype = KeyPair
+ # mp_query_author_packets
+ self.lib.mp_query_author_packets.argtypes = [
+ ctypes.c_char_p, # ip
+ c_int, # port
+ KeyPair, # author_keys
+ c_uint16, # count
+ c_uint64, # offset
+ POINTER(DataPacketList) # out_list
+ ]
+ self.lib.mp_query_author_packets.restype = c_int
+
class MoonpasteClient:
'''High-level Python client for moonpaste'''
@@ -680,4 +691,60 @@ class MoonpasteClient:
# Push to server
success = self.push_packet(ip, port, packet)
- return packet, success \ No newline at end of file
+ return packet, success
+
+ def query_author_packets(self, ip: str, port: int, author_keys: PyKeyPair, count: int = 10, offset: int = 0) -> PyDataPacketList:
+ '''Query packets for a specific author'''
+ c_keys = author_keys.to_c()
+ packet_list = DataPacketList()
+
+ result = self.ffi.lib.mp_query_author_packets(
+ ip.encode('utf-8'),
+ port,
+ c_keys,
+ count,
+ offset,
+ byref(packet_list)
+ )
+
+ if result != ClientError.SUCCESS:
+ raise MoonpasteClientError(ClientError(result))
+
+ packets = []
+ if packet_list.count > 0 and packet_list.packets:
+ for i in range(packet_list.count):
+ packets.append(PyDataPacket.from_c(packet_list.packets[i]))
+
+ # Free the allocated memory safely
+ try:
+ import ctypes.util
+ libc_name = ctypes.util.find_library('c')
+ if libc_name:
+ libc = ctypes.CDLL(libc_name)
+ libc.free.argtypes = [c_void_p]
+ libc.free(cast(packet_list.packets, c_void_p))
+ else:
+ # Platform-specific fallback
+ try:
+ if sys.platform.startswith('linux'):
+ libc = ctypes.CDLL('libc.so.6')
+ elif sys.platform == 'darwin':
+ libc = ctypes.CDLL('libc.dylib')
+ elif sys.platform == 'win32':
+ libc = ctypes.CDLL('msvcrt.dll')
+ else:
+ libc = None
+
+ if libc:
+ libc.free.argtypes = [c_void_p]
+ libc.free(cast(packet_list.packets, c_void_p))
+ except OSError:
+ pass # Can't free, but better than crash
+ except:
+ pass # Memory will be freed when process exits
+
+ return PyDataPacketList(
+ packets=packets,
+ count=packet_list.count,
+ new_offset=packet_list.new_offset
+ ) \ No newline at end of file
diff --git a/client/3rd-party/client.ts b/client/3rd-party/client.ts
index 44f4634..711dc3b 100644
--- a/client/3rd-party/client.ts
+++ b/client/3rd-party/client.ts
@@ -155,7 +155,11 @@ class MoonpasteFFI {
mp_generate_keypair: {
args: [],
returns: FFIType.ptr
- }
+ },
+ mp_query_author_packets: {
+ args: [FFIType.cstring, FFIType.i32, FFIType.ptr, FFIType.u16, FFIType.u64, FFIType.ptr],
+ returns: FFIType.i32
+ },
})
break
@@ -204,7 +208,7 @@ class MoonpasteFFI {
try {
const ffi = require('ffi-napi') // dependency
const ref = require('ref-napi') // dependency
-
+
this.lib = ffi.Library(libPath, {
mp_get_server_info: ['int', ['string', 'int', 'pointer']],
mp_get_server_neighbors: ['int', ['string', 'int', 'uint8', 'pointer', 'pointer']],
@@ -248,9 +252,9 @@ class MoonpasteFFI {
async getServerInfo(ip: string, port: number): Promise<RelayInfo> {
const infoBuffer = this.allocateBuffer(1024)
const ipBuffer = this.stringToBuffer(ip)
-
+
const result = this.lib.symbols.mp_get_server_info(ipBuffer, port, infoBuffer)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to get server info: ${result}`)
}
@@ -262,9 +266,9 @@ class MoonpasteFFI {
const neighborsPtr = this.allocateBuffer(8) // pointer
const countPtr = this.allocateBuffer(1) // uint8
const ipBuffer = this.stringToBuffer(ip)
-
+
const result = this.lib.symbols.mp_get_server_neighbors(ipBuffer, port, count, neighborsPtr, countPtr)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to get neighbors: ${result}`)
}
@@ -276,9 +280,9 @@ class MoonpasteFFI {
const successPtr = this.allocateBuffer(1)
const ipBuffer = this.stringToBuffer(ip)
const packetBuffer = this.serializePacket(packet)
-
+
const result = this.lib.symbols.mp_push_packet(ipBuffer, port, packetBuffer, successPtr)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to push packet: ${result}`)
}
@@ -289,9 +293,9 @@ class MoonpasteFFI {
async getPacket(ip: string, port: number, hash: Uint8Array): Promise<DataPacket> {
const packetBuffer = this.allocateBuffer(70000) // approximation
const ipBuffer = this.stringToBuffer(ip)
-
+
const result = this.lib.symbols.mp_get_packet(ipBuffer, port, hash, packetBuffer)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to get packet: ${result}`)
}
@@ -302,9 +306,9 @@ class MoonpasteFFI {
async getFirehosePackets(ip: string, port: number, offset: bigint, count: number): Promise<DataPacketList> {
const listBuffer = this.allocateBuffer(1024)
const ipBuffer = this.stringToBuffer(ip)
-
+
const result = this.lib.symbols.mp_get_firehose_packets(ipBuffer, port, offset, count, listBuffer)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to get firehose packets: ${result}`)
}
@@ -312,10 +316,24 @@ class MoonpasteFFI {
return this.parseDataPacketList(listBuffer)
}
+ async queryAuthorPackets(ip: string, port: number, authorKeys: KeyPair, count: number, offset: bigint): Promise<DataPacketList> {
+ const keysBuffer = this.serializeKeyPair(authorKeys)
+ const listBuffer = this.allocateBuffer(1024)
+ const ipBuffer = this.stringToBuffer(ip)
+
+ const result = this.lib.symbols.mp_query_author_packets(ipBuffer, port, keysBuffer, count, offset, listBuffer)
+
+ if (result !== ClientError.Success) {
+ throw new Error(`Failed to query author packets: ${result}`)
+ }
+
+ return this.parseDataPacketList(listBuffer)
+ }
+
createPacketFromBytes(input: Uint8Array, recipientCount: number, recipients: Uint8Array[] | null, authorKeys: KeyPair): DataPacket {
const recipientsBuffer = recipients ? this.serializeRecipients(recipients) : null
const keysBuffer = this.serializeKeyPair(authorKeys)
-
+
const result = this.lib.symbols.mp_create_packet_from_bytes(
input,
input.length,
@@ -323,7 +341,7 @@ class MoonpasteFFI {
recipientsBuffer,
keysBuffer
)
-
+
return this.parseDataPacket(result)
}
@@ -332,7 +350,7 @@ class MoonpasteFFI {
const filenameBuffer = this.stringToBuffer(filename)
const recipientsBuffer = recipients ? this.serializeRecipients(recipients) : null
const keysBuffer = this.serializeKeyPair(authorKeys)
-
+
const result = this.lib.symbols.mp_create_packet_from_file(
filenameBuffer,
recipientCount,
@@ -340,7 +358,7 @@ class MoonpasteFFI {
keysBuffer,
packetBuffer
)
-
+
if (result !== ClientError.Success) {
throw new Error(`Failed to create packet from file: ${result}`)
}
@@ -365,7 +383,7 @@ class MoonpasteFFI {
const majorVersion = view.getUint8(offset++)
const minorVersion = view.getUint8(offset++)
-
+
const motdBytes = new Uint8Array(buffer, offset, 128)
const motd = new TextDecoder().decode(motdBytes).replace(/\0.*$/, '')
offset += 128
@@ -407,11 +425,11 @@ class MoonpasteFFI {
private parseRelayNeighborAt(buffer: any, offset: number): RelayNeighbor {
const view = new DataView(buffer instanceof ArrayBuffer ? buffer : buffer.buffer)
-
+
const active = view.getUint8(offset) !== 0
const hasIpv4 = view.getUint8(offset + 1) !== 0
const hasIpv6 = view.getUint8(offset + 2) !== 0
-
+
const v4Addr = new Uint8Array(buffer, offset + 3, 4)
const v6Addr = new Uint8Array(buffer, offset + 7, 16)
@@ -421,14 +439,14 @@ class MoonpasteFFI {
private parseNeighbors(neighborsPtr: any, countPtr: any): RelayNeighbor[] {
const count = this.readUint8(countPtr)
const neighbors: RelayNeighbor[] = []
-
+
if (count > 0 && neighborsPtr) {
for (let i = 0; i < count; i++) {
const neighborOffset = i * 23 // RELAY_NEIGHBOR_WIRE_LEN
neighbors.push(this.parseRelayNeighborAt(neighborsPtr, neighborOffset))
}
}
-
+
return neighbors
}
@@ -481,12 +499,12 @@ class MoonpasteFFI {
private parseDataPacketList(buffer: any): DataPacketList {
const view = new DataView(buffer instanceof ArrayBuffer ? buffer : buffer.buffer)
-
+
const newOffset = view.getBigUint64(0, true)
const availableBytes = buffer.byteLength - 8
const packetSize = 4 + 32 + (1 + 8 + 32 + 32 + 1 + (32 * 32) + 65536 + 64) // PACKET_SIZE
const packetCount = Math.floor(availableBytes / packetSize)
-
+
const packets: DataPacket[] = []
for (let i = 0; i < packetCount; i++) {
const packetOffset = 8 + (i * packetSize)
@@ -624,14 +642,14 @@ export class MoonpasteClient {
const data = typeof message === 'string' ? new TextEncoder().encode(message) : message
const keys = authorKeys || this.generateKeyPair()
const recipientCount = recipients ? recipients.length : 0
-
+
return this.ffi.createPacketFromBytes(data, recipientCount, recipients || null, keys)
}
async createPacketFromFile(filename: string, recipients?: Uint8Array[], authorKeys?: KeyPair): Promise<DataPacket> {
const keys = authorKeys || this.generateKeyPair()
const recipientCount = recipients ? recipients.length : 0
-
+
return this.ffi.createPacketFromFile(filename, recipientCount, recipients || null, keys)
}
@@ -643,6 +661,10 @@ export class MoonpasteClient {
return this.ffi.generateKeyPair()
}
+ async queryAuthorPackets(ip: string, port: number, authorKeys: KeyPair, count: number = 10, offset: bigint = 0n): Promise<DataPacketList> {
+ return this.ffi.queryAuthorPackets(ip, port, authorKeys, count, offset)
+ }
+
// Utility methods
static hashToHex(hash: Uint8Array): string {
return Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('')