const koffi = require('koffi');
const fs = require('fs');
const path = require('path');
const os = require('os');
function libraryFilename() {
switch (os.platform()) {
case 'win32': return 'thaiidcard.dll';
case 'darwin': return 'libthaiidcard.dylib';
default: return 'libthaiidcard.so';
}
}
function findLibrary() {
const name = libraryFilename();
const projectRoot = path.resolve(__dirname, '..');
const candidates = [
path.join(projectRoot, 'target', 'debug', name),
path.join(projectRoot, 'target', 'release', name),
];
switch (os.platform()) {
case 'darwin':
candidates.push(
'/usr/local/lib/' + name,
'/opt/homebrew/lib/' + name
);
break;
case 'win32':
const sysRoot = process.env.SYSTEMROOT || 'C:\\Windows';
const pf = process.env.PROGRAMFILES || 'C:\\Program Files';
candidates.push(
path.join(sysRoot, 'System32', name),
path.join(pf, 'thaiidcard', 'bin', name)
);
break;
default: candidates.push(
'/usr/local/lib/' + name,
'/usr/lib/' + name,
'/usr/lib/x86_64-linux-gnu/' + name,
'/usr/lib/aarch64-linux-gnu/' + name
);
break;
}
for (const p of candidates) {
if (fs.existsSync(p)) return p;
}
return name;
}
const libPath = findLibrary();
const lib = koffi.load(libPath);
const thaiid_read = lib.func('thaiid_read', 'void *', ['string', 'int', 'int', 'int']);
const thaiid_free = lib.func('thaiid_free', 'void', ['void *']);
const thaiid_get_last_error = lib.func('thaiid_get_last_error', 'string', []);
const GETTERS = {
cid: lib.func('thaiid_get_cid', 'string', ['void *']),
name_thai: lib.func('thaiid_get_name_thai', 'string', ['void *']),
name_en: lib.func('thaiid_get_name_en', 'string', ['void *']),
dob: lib.func('thaiid_get_dob', 'string', ['void *']),
gender: lib.func('thaiid_get_gender', 'string', ['void *']),
card_issuer: lib.func('thaiid_get_card_issuer', 'string', ['void *']),
issue_date: lib.func('thaiid_get_issue_date', 'string', ['void *']),
expire_date: lib.func('thaiid_get_expire_date', 'string', ['void *']),
address: lib.func('thaiid_get_address', 'string', ['void *']),
face_image: lib.func('thaiid_get_face_image', 'string', ['void *']),
laser_id: lib.func('thaiid_get_laser_id', 'string', ['void *']),
main_inscl: lib.func('thaiid_get_main_inscl', 'string', ['void *']),
sub_inscl: lib.func('thaiid_get_sub_inscl', 'string', ['void *']),
main_hospital: lib.func('thaiid_get_main_hospital', 'string', ['void *']),
sub_hospital: lib.func('thaiid_get_sub_hospital', 'string', ['void *']),
paid_type: lib.func('thaiid_get_paid_type', 'string', ['void *']),
nhso_issue_date: lib.func('thaiid_get_nhso_issue_date', 'string', ['void *']),
nhso_expire_date: lib.func('thaiid_get_nhso_expire_date', 'string', ['void *']),
nhso_update_date: lib.func('thaiid_get_nhso_update_date', 'string', ['void *']),
change_hospital_amount: lib.func('thaiid_get_change_hospital_amount', 'string', ['void *']),
};
function readCard(readerName, showFace = true, showNhso = true, showLaser = false) {
const handle = thaiid_read(readerName || null, +showFace, +showNhso, +showLaser);
if (!handle) {
const err = thaiid_get_last_error();
throw new Error(err || 'Unknown error');
}
try {
const data = {};
for (const [key, fn] of Object.entries(GETTERS)) {
data[key] = fn(handle) || '';
}
return data;
} finally {
thaiid_free(handle);
}
}
function printCard(data) {
const field = (label, val) => console.log(` ${label.padEnd(20)} ${val}`);
console.log('\n=== Personal Information ===');
field('CID:', data.cid);
field('Name (TH):', data.name_thai);
field('Name (EN):', data.name_en);
field('DOB:', data.dob);
field('Gender:', data.gender);
field('Card Issuer:', data.card_issuer);
field('Issue Date:', data.issue_date);
field('Expire Date:', data.expire_date);
field('Address:', data.address);
if (data.face_image) {
console.log(` ${'Face Image:'.padEnd(20)} [${Buffer.byteLength(data.face_image, 'utf8')} bytes base64]`);
}
if (data.laser_id) {
console.log('\n=== Card Info ===');
field('Laser ID:', data.laser_id);
}
if (data.main_inscl) {
console.log('\n=== NHSO Information ===');
field('Main Inscl:', data.main_inscl);
field('Sub Inscl:', data.sub_inscl);
field('Main Hosp:', data.main_hospital);
field('Sub Hosp:', data.sub_hospital);
field('Paid Type:', data.paid_type);
field('NHSO Issue:', data.nhso_issue_date);
field('NHSO Expire:', data.nhso_expire_date);
field('NHSO Update:', data.nhso_update_date);
field('Change Hosp:', data.change_hospital_amount);
}
}
const reader = process.argv[2] || null;
console.log(`Using library: ${libPath}`);
console.log(`Reader: ${reader || '(auto-detect)'}`);
console.log('Waiting for card...');
try {
const data = readCard(reader);
printCard(data);
console.log('\nDone.');
} catch (err) {
console.error('Error:', err.message);
process.exit(1);
}