Skip to content

Commit

Permalink
feat: example proxying to multiple pglite dbs with persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
gregnr committed Jul 25, 2024
1 parent 8695b81 commit 80b196f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 2 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
node_modules/
dist/
dbs/
*.pem
*.srl
98 changes: 98 additions & 0 deletions examples/pglite-multiple/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { PGlite, PGliteInterface } from '@electric-sql/pglite';
import { mkdir, readFile } from 'node:fs/promises';
import net from 'node:net';
import {
PostgresConnection,
TlsOptionsCallback,
hashMd5Password,
} from '../../src';

const tls: TlsOptionsCallback = async ({ sniServerName }) => {
// Optionally serve different certs based on `sniServerName`
// In this example we'll use a single wildcard cert for all servers (ie. *.db.example.com)
return {
key: await readFile('server-key.pem'),
cert: await readFile('server-cert.pem'),
ca: await readFile('ca-cert.pem'),
};
};

function getIdFromServerName(serverName: string) {
// In this example the left-most subdomain contains the ID
// ie. 12345.db.example.com -> 12345
const [id] = serverName.split('.');
return id;
}

const server = net.createServer((socket) => {
let db: PGliteInterface;

const connection = new PostgresConnection(socket, {
serverVersion: '16.3 (PGlite 0.2.0)',
authMode: 'md5Password',
tls,
async validateCredentials(credentials) {
if (credentials.authMode === 'md5Password') {
const { hash, salt } = credentials;
const expectedHash = await hashMd5Password(
'postgres',
'postgres',
salt
);
return hash === expectedHash;
}
return false;
},
onTlsUpgrade({ tlsInfo }) {
if (!tlsInfo) {
connection.sendError({
severity: 'FATAL',
code: '08000',
message: `ssl connection required`,
});
connection.socket.end();
return;
}

if (!tlsInfo.sniServerName) {
connection.sendError({
severity: 'FATAL',
code: '08000',
message: `ssl sni extension required`,
});
connection.socket.end();
return;
}

const databaseId = getIdFromServerName(tlsInfo.sniServerName);

db = new PGlite(`./dbs/${databaseId}`);
},
async onMessage(data, { isAuthenticated }) {
// Only forward messages to PGlite after authentication
if (!isAuthenticated) {
return false;
}

// Forward raw message to PGlite
try {
const [[_, responseData]] = await db.execProtocol(data);
connection.sendData(responseData);
} catch (err) {
connection.sendError(err);
connection.sendReadyForQuery();
}
return true;
},
});

socket.on('end', () => {
console.log('Client disconnected');
});
});

server.listen(5432, async () => {
console.log('Server listening on port 5432');

await mkdir('./dbs', { recursive: true });
});

0 comments on commit 80b196f

Please sign in to comment.