ws-server.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. //edit webdav config
  2. let config = {
  3. davUrl: 'https://example.com/dav.php',
  4. davUsername: 'username',
  5. davPassword: 'password',
  6. davAddressBook: ''
  7. }
  8. //and delete this line:
  9. config = require('./secrets')
  10. //or create secrets.js:
  11. /*
  12. module.exports = {
  13. davUrl: 'https://example.com/dav.php',
  14. davUsername: 'username',
  15. davPassword: 'password',
  16. davAddressBook: ''
  17. }
  18. */
  19. const WebSocket = require('ws');
  20. var dav = require('dav');
  21. var VCard = require('vcard');
  22. var VCF = require('vcf');
  23. const wss = new WebSocket.Server({
  24. port: 23845,
  25. perMessageDeflate: false
  26. });
  27. var xhr = new dav.transport.Basic(
  28. new dav.Credentials({
  29. username: config.davUsername,
  30. password: config.davPassword
  31. })
  32. );
  33. let davClient = new dav.Client(xhr);
  34. let usedAddressBook = null;
  35. davClient.createAccount({
  36. server: config.davUrl,
  37. accountType: 'carddav'
  38. }).then(function(account) {
  39. let addressBook = null;
  40. account.addressBooks.forEach(function(ab) {
  41. console.log('Found address book name ' + ab.displayName);
  42. addressBook = ab;
  43. if(ab.displayName === config.davAddressBook) return;
  44. });
  45. console.log('Using ' + addressBook.displayName);
  46. usedAddressBook = addressBook;
  47. });
  48. wss.on('connection', function connection(ws) {
  49. console.log('new ws connection');
  50. ws.on('message', function incoming(message) {
  51. const bDays = JSON.parse(message);
  52. console.log('received: ', bDays);
  53. syncDavAddressBook(ws, bDays);
  54. });
  55. });
  56. var oldRemoteBDays = {};
  57. function syncDavAddressBook(ws, bDays) {
  58. if(!usedAddressBook)
  59. return;
  60. davClient.syncAddressBook(usedAddressBook).then(function(x) {
  61. let remoteBDays = {};
  62. let hasUpdates = false;
  63. for(const vcard of x.objects) {
  64. VCF.parse(vcard.addressData, function(card) {
  65. if(!isNaN(card.bday) && card.note && card.note.length > 0) {
  66. const uid = card.note[0]
  67. remoteBDays[uid] = [card.fn, card.bday, card.rev];
  68. if(!bDays[uid] && !oldRemoteBDays[uid]) {
  69. //create local
  70. console.log('new birthday from dav')
  71. bDays[uid] = remoteBDays[uid];
  72. hasUpdates = true;
  73. } else if(bDays[uid].count < 3 || new Date(bDays[uid][2]) < card.rev) {
  74. //pull from dav
  75. console.log('updated birthday from dav')
  76. bDays[uid] = remoteBDays[uid];
  77. hasUpdates = true;
  78. } else if(new Date(bDays[uid][2]) > card.rev && !isNaN(card.rev)) {
  79. //push to dav
  80. console.log('synced birthday to dav')
  81. card.fn = bDays[uid][0];
  82. card.bday = new Date(bDays[uid][1]);
  83. card.rev = new Date(bDays[uid][2]);
  84. card.validate();
  85. vcard.addressData = vCardToString(card);
  86. davClient.updateCard(vcard);
  87. }
  88. }
  89. })
  90. }
  91. for(const uid in bDays) {
  92. if(!oldRemoteBDays[uid] && !remoteBDays[uid] && bDays[uid][1]) {
  93. //create in dav
  94. console.log('created birthday in dav')
  95. const card = new VCard({
  96. fn: bDays[uid][0],
  97. bday: new Date(bDays[uid][1]),
  98. rev: bDays[uid].length > 2 ? new Date(bDays[uid][2]) : new Date(),
  99. note: uid});
  100. card.validate();
  101. davClient.createCard(usedAddressBook, {
  102. data: vCardToString(card),
  103. filename: `${card.uid}.vcf`,
  104. xhr: xhr
  105. });
  106. remoteBDays[uid] = bDays[uid];
  107. } else if(oldRemoteBDays[uid] && !remoteBDays[uid] && bDays[uid][1]) {
  108. // delete local
  109. delete bDays[uid];
  110. hasUpdates = true;
  111. }
  112. }
  113. oldRemoteBDays = remoteBDays;
  114. //send ws
  115. if(hasUpdates) {
  116. console.log('send: ', bDays);
  117. ws.send(JSON.stringify(bDays))
  118. }
  119. })
  120. }
  121. function vCardToString(vCard) {
  122. return `BEGIN:VCARD
  123. VERSION:3.0
  124. UID:${vCard.uid}
  125. N:;${vCard.fn};;;
  126. FN:${vCard.fn}
  127. NOTE:${vCard.note && vCard.note[0] ? vCard.note[0] : ""}
  128. REV:${(vCard.rev instanceof Date ? vCard.rev.toISOString().replace(/[-:]|\.000/g, '') : vCard.rev)}
  129. BDAY;VALUE=date:${vCard.bday.toISOString().substring(0, 10).replace(/-/g, '')}
  130. PRODID:-//birthday-script//EN
  131. END:VCARD
  132. `;
  133. }