sohotcall

notif.n.js

Feb 14th, 2022 (edited)
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //?addrs=<$addr,>&msg=<$msg> // send message to addresses
  2. //output: {msgId,addrs:[$addr,],msg,date:$ms}
  3. //?addrs=<$addr,>&msgAfter=<$msgId> // get messages for addresses after msgId
  4. //output: [{msgId,addrs:[$addr,],msg,date:$ms},]
  5.  
  6. const PORT = 4697
  7. const http = require( 'http' )
  8. const url = require( 'url' )
  9. const fs = require( 'fs' )
  10.  
  11. let msgId = 0
  12. let subId = 0
  13. let msgs = {} // {$msgId:{addrs:[$addr,],msg,date:$ms},}
  14. let subs = {} // {$subId:{addrs:[$addr,],msgAfter,date:$ms,res},}
  15. let addr_subs = {} // {$addr:{$subId:$msgAfter,},}
  16. let addr_msgs = {} // {$addr:{$msgId:$date,},,lastMsgId}
  17. let mylog = s => console.log( new Date().toLocaleString( 'sv' ) + " " + s )
  18.  
  19. let logFile = {}
  20. let webserver = http.createServer( function( req, res ){
  21.     res.writeHead( 200, { "Content-Type" : "text/html" } )
  22.     let q = url.parse( req.url, true ).query
  23.     if ( ! q.addrs || ! /^[a-z0-9_\-]{1,12}(,[a-z0-9_\-]{1,12})*$/.test( q.addrs ) )
  24.         q.addrs = ""
  25.     if ( q.msg )
  26.         q.msg = q.msg.replace( /[^!-~\s\t\r\n]/g, "" )
  27.     if ( q.msgAfter )
  28.         q.msgAfter = q.msgAfter | 0
  29.     mylog( `Query param: ${ JSON.stringify( q ) }.` )
  30.     let date = Date.now()
  31.     let addrs = q.addrs.split( ',' )
  32.     if ( q.addrs && q.msg ){
  33.         msgId++
  34.         msgs[ msgId ] = { addrs: addrs, msg: q.msg, date: date }
  35.         mylog( `New message ${msgId} saved.` )
  36.         let out = { msgId: msgId, addrs: addrs, msg: q.msg, date: date }
  37.         addrs.forEach( ( addr ) => {
  38.             if ( addr_subs[addr] ){
  39.                 for ( const [ subId, msgAfter ] of Object.entries( addr_subs[addr] ) ){
  40.                     if ( msgAfter < msgId ){
  41.                         mylog( `Serve message ${msgId} to subscriber ${subId}.` )
  42.                         let sub = subs[subId]
  43.                         let out = [ { msgId: msgId, addrs: addrs, msg: q.msg, date: date } ]
  44.                         sub.res.write( JSON.stringify( out ) )
  45.                         sub.res.end()
  46.                         mylog( `Subscriber ${subId} unsubscribe.` )
  47.                         sub.addrs.forEach( ( addr )=>{
  48.                             delete addr_subs[addr][subId]
  49.                         } )
  50.                         delete subs[subId]
  51.                     }
  52.                 }
  53.             }
  54.             addr_msgs[addr] = addr_msgs[addr] || {}
  55.             addr_msgs[addr][ msgId ] = date
  56.             addr_msgs[addr].lastMsgId = msgId
  57.         } )
  58.         res.write( JSON.stringify( out ) )
  59.         res.end()
  60.        
  61.         let ymd = new Date( date ).toLocaleString( 'sv' ).slice( 0, 10 )
  62.         if ( logFile.ymd != ymd ){
  63.             if ( logFile.stream )
  64.                 logFile.stream.end()
  65.             logFile.stream = fs.createWriteStream( `${ymd}.txt`, { flags: 'a' } )
  66.         }
  67.         logFile.stream.write( JSON.stringify( { msgId: msgId, addrs: addrs, msg: q.msg, date: date } ) + "\n" )
  68.     } else if ( q.addrs && q.msgAfter ){
  69.         let out = []
  70.         mylog( `New client` )
  71.         addrs.forEach( ( addr ) => {
  72.             if ( addr_msgs[addr] && addr_msgs[addr].lastMsgId > + q.msgAfter ){
  73.                 for ( let msgId in addr_msgs[addr] ){
  74.                     if ( + msgId > + q.msgAfter ){
  75.                         mylog( `Serve message ${msgId} to client.` )
  76.                         let msg = msgs[ msgId ]
  77.                         out.push( { msgId: msgId, addrs:msg.addrs, msg: msg.msg, date: msg.date } )
  78.                     }
  79.                 }
  80.             }
  81.         } )
  82.         if ( out.length ){
  83.             res.write( JSON.stringify( out ) )
  84.             res.end()
  85.         } else {
  86.             subId++
  87.             subs[ subId ] = { addrs: addrs, msgAfter: + q.msgAfter, date:date, res: res }
  88.             mylog( `Saved as new subscriber ${subId}.` )
  89.             addrs.forEach( ( addr ) => {
  90.                 addr_subs[addr] = addr_subs[addr] || {}
  91.                 addr_subs[addr][subId] = + q.msgAfter
  92.             } )
  93.         }
  94.     } else {
  95.         res.write( JSON.stringify( { error: "wtf are you doing?" } ) )
  96.         res.end()
  97.     }
  98. } ).listen( PORT, 'localhost' ).on( 'connection', function( socket ){
  99.     socket.setTimeout( 600_000 );
  100. } )
  101.  
  102. let cleanups = () => {
  103.     let oldest = Date.now() + 240_000 // 4 = 5 - 1 minutes in ms = 240_000
  104.     mylog( `Iteration tick` )
  105.     let old = Date.now() - 2_629_746_000 // 1 month in ms = 2_629_746_000
  106.     let found = false
  107.     for ( const [ msgId, msg ] of Object.entries( msgs ) ){ // Remove old mesages
  108.         if ( msg.date < old ){
  109.             found = true
  110.             mylog( `Cleanup: Remove message ${msgId}.` )
  111.             delete msgs[ msgId ]
  112.         } else {
  113.             oldest = Math.min( oldest, msg.date + 2_629_746_000 )
  114.             break
  115.         }
  116.     }
  117.     if ( found ) for ( const [ addr, msg ] of Object.entries( addr_msgs ) ){ // Remove old mesages
  118.         for ( const [ msgId, date ] of Object.entries( msg ) ){
  119.             if ( + msgId && date < old ){
  120.                 mylog( `Cleanup: Remove message ${msgId} address ${addr}.` )
  121.                 delete addr_msgs[addr][msgId]
  122.             } else if ( + msgId )
  123.                 oldest = Math.min( oldest, date + 2_629_746_000 )
  124.         }
  125.     }
  126.     old = Date.now() - 300_000 // 5 minutes in ms = 300_000
  127.     for ( const [ subId, sub ] of Object.entries( subs ) ){ // Serve old subscribers closing them
  128.         if ( sub.date < old ){
  129.             mylog( `Cleanup: Close subscriber ${subId}.` )
  130.             sub.res.write( "[]" )
  131.             sub.res.end()
  132.             sub.addrs.forEach( ( addr ) => {
  133.                 delete addr_subs[addr][subId]
  134.             } )
  135.             delete subs[ subId ]
  136.         } else {
  137.             oldest = Math.min( oldest, sub.date + 300_000 )
  138.             break
  139.         }
  140.     }
  141.     oldest = Math.max( oldest - Date.now(), 60_000 ) // 1 minute in ms = 60_000
  142.     mylog( `Cleanup: Sleep ${oldest} ms.` )
  143.     setTimeout( cleanups, oldest )
  144. }
  145. cleanups()
  146.  
Add Comment
Please, Sign In to add comment