Update CI references to 0.0.122
[ldk-java] / node-net / net.mts
1 import * as ldk from "lightningdevkit";
2 import * as net from "net";
3
4 /**
5  * Handles TCP connections using Node.JS's 'net' module given an `ldk.PeerManager`.
6  */
7 export class NodeLDKNet {
8         private ping_timer;
9         private servers: net.Server[];
10         public constructor(public peer_manager: ldk.PeerManager) {
11                 // @ts-ignore
12                 if (peer_manager._node_ldk_net_singleton_check != undefined) {
13                         throw "Only one NdoeLDKNet should exist per PeerManager";
14                 }
15                 // @ts-ignore
16                 peer_manager._node_ldk_net_singleton_check = this;
17                 this.ping_timer = setInterval(function() {
18                         peer_manager.timer_tick_occurred();
19                         peer_manager.process_events();
20                 }, 10_000);
21                 this.servers = [];
22         }
23
24         /**
25          * Disconnects all connections and releases all resources for this net handler.
26          */
27         public stop() {
28                 clearInterval(this.ping_timer);
29                 for (const server of this.servers) {
30                         server.close();
31                 }
32                 this.peer_manager.disconnect_all_peers();
33                 // @ts-ignore
34                 delete this.peer_manager._node_ldk_net_singleton_check;
35         }
36
37         /**
38          * Processes any pending events for the PeerManager, sending queued messages.
39          * You should call this (or peer_manager.process_events()) any time you take an action which
40          * is likely to generate messages to send (eg send a payment, processing payment forwards,
41          * etc).
42          */
43         public process_events() { this.peer_manager.process_events(); }
44
45         private descriptor_count = BigInt(0);
46         private get_descriptor(socket: net.Socket): ldk.SocketDescriptor {
47                 const this_index = this.descriptor_count;
48                 this.descriptor_count += BigInt(1);
49
50                 socket.setNoDelay(true);
51
52                 const this_pm = this.peer_manager;
53                 var sock_write_waiting = false;
54
55                 let descriptor = ldk.SocketDescriptor.new_impl ({
56                         send_data(data: Uint8Array, resume_read: boolean): number {
57                                 if (resume_read) socket.resume();
58
59                                 if (sock_write_waiting) return 0;
60                                 const written = socket.write(data);
61                                 if (!written) sock_write_waiting = true;
62                                 return data.length;
63                         },
64                         disconnect_socket(): void {
65                                 socket.destroy();
66                         },
67                         eq(other: ldk.SocketDescriptor): boolean {
68                                 return other.hash() == this.hash();
69                         },
70                         hash(): bigint {
71                                 return this_index;
72                         }
73                 } as ldk.SocketDescriptorInterface);
74
75                 socket.on("drain", function() {
76                         if (sock_write_waiting) {
77                                 if (!this_pm.write_buffer_space_avail(descriptor).is_ok()) {
78                                         descriptor.disconnect_socket();
79                                 }
80                         }
81                 });
82
83                 socket.on("data", function(data) {
84                         const res = this_pm.read_event(descriptor, data);
85                         if (!res.is_ok()) descriptor.disconnect_socket();
86                         else if ((res as ldk.Result_boolPeerHandleErrorZ_OK).res) socket.pause();
87                         this_pm.process_events();
88                 });
89
90                 socket.on("close", function() {
91                         this_pm.socket_disconnected(descriptor);
92                 });
93                 socket.on("error", function() {
94                         this_pm.socket_disconnected(descriptor);
95                 });
96
97                 return descriptor;
98         }
99
100         private static v4_addr_from_ip(ip: string, port: number): ldk.SocketAddress {
101                 const sockaddr = ip.split(".").map(parseFloat);
102                 return ldk.SocketAddress.constructor_tcp_ip_v4(new Uint8Array(sockaddr), port);
103         }
104         private static v6_addr_from_ip(ip: string, port: number): ldk.SocketAddress {
105                 const sockaddr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
106                 const halves = ip.split("::"); // either one or two elements
107                 const first_half = halves[0].split(":");
108                 for (var idx = 0; idx < first_half.length; idx++) {
109                         const v = parseInt(first_half[idx], 16);
110                         sockaddr[idx*2] = v >> 8;
111                         sockaddr[idx*2 + 1] = v & 0xff;
112                 }
113                 if (halves.length == 2) {
114                         const second_half = halves[1].split(":");
115                         for (var idx = 0; idx < second_half.length; idx++) {
116                                 const v = parseInt(second_half[second_half.length - idx - 1], 16);
117                                 sockaddr[14 - idx*2] = v >> 8;
118                                 sockaddr[15 - idx*2] = v & 0xff;
119                         }
120                 }
121                 return ldk.SocketAddress.constructor_tcp_ip_v6(new Uint8Array(sockaddr), port);
122         }
123
124         private static get_addr_from_socket(socket: net.Socket): ldk.Option_SocketAddressZ {
125                 const addr = socket.remoteAddress;
126                 if (addr === undefined)
127                         return ldk.Option_SocketAddressZ.constructor_none();
128                 if (net.isIPv4(addr)) {
129                         return ldk.Option_SocketAddressZ.constructor_some(NodeLDKNet.v4_addr_from_ip(addr, socket.remotePort));
130                 }
131                 if (net.isIPv6(addr)) {
132                         return ldk.Option_SocketAddressZ.constructor_some(NodeLDKNet.v6_addr_from_ip(addr, socket.remotePort));
133                 }
134                 return ldk.Option_SocketAddressZ.constructor_none();
135         }
136
137         /**
138          * Binds a listener on the given host and port, accepting incoming connections.
139          */
140         public async bind_listener(host: string, port: number) {
141                 const this_handler = this;
142                 const server = net.createServer(function(incoming_sock: net.Socket) {
143                         const descriptor = this_handler.get_descriptor(incoming_sock);
144                         const res = this_handler.peer_manager
145                                 .new_inbound_connection(descriptor, NodeLDKNet.get_addr_from_socket(incoming_sock));
146                         if (!res.is_ok()) descriptor.disconnect_socket();
147                 });
148                 const servers_list = this.servers;
149                 return new Promise<void>((resolve, reject) => {
150                         server.on("error", function() {
151                                 reject();
152                                 server.close();
153                         });
154                         server.on("listening", function() {
155                                 servers_list.push(server);
156                                 resolve();
157                         });
158                         server.listen(port, host);
159                 });
160         }
161
162         /**
163          * Establishes an outgoing connection to the given peer at the given host and port.
164          *
165          * Note that the peer will not appear in the PeerManager peers list until the socket has
166          * connected and the initial handshake completes.
167          */
168         public async connect_peer(host: string, port: number, peer_node_id: Uint8Array) {
169                 const this_handler = this;
170                 const sock = new net.Socket();
171                 const res = new Promise<void>((resolve, reject) => {
172                         sock.on("connect", function() { resolve(); });
173                         sock.on("error", function() { reject(); });
174                 });
175                 sock.connect(port, host, function() {
176                         const descriptor = this_handler.get_descriptor(sock);
177                         const res = this_handler.peer_manager
178                                 .new_outbound_connection(peer_node_id, descriptor, NodeLDKNet.get_addr_from_socket(sock));
179                         if (!res.is_ok()) descriptor.disconnect_socket();
180                         else {
181                                 const bytes = (res as ldk.Result_CVec_u8ZPeerHandleErrorZ_OK).res;
182                                 const send_res = descriptor.send_data(bytes, true);
183                                 console.assert(send_res == bytes.length);
184                         }
185                 });
186                 return res;
187         }
188 }