Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //?addrs=<$addr,>&msg=<$msg> // send message to addresses
- //output: {msgId,addrs:[$addr,],msg,date:$ms}
- //?addrs=<$addr,>&msgAfter=<$msgId> // get messages for addresses after msgId
- //output: [{msgId,addrs:[$addr,],msg,date:$ms},]
- const PORT = 4697
- const http = require( 'http' )
- const url = require( 'url' )
- const fs = require( 'fs' )
- let msgId = 0
- let subId = 0
- let msgs = {} // {$msgId:{addrs:[$addr,],msg,date:$ms},}
- let subs = {} // {$subId:{addrs:[$addr,],msgAfter,date:$ms,res},}
- let addr_subs = {} // {$addr:{$subId:$msgAfter,},}
- let addr_msgs = {} // {$addr:{$msgId:$date,},,lastMsgId}
- let mylog = s => console.log( new Date().toLocaleString( 'sv' ) + " " + s )
- let logFile = {}
- let webserver = http.createServer( function( req, res ){
- res.writeHead( 200, { "Content-Type" : "text/html" } )
- let q = url.parse( req.url, true ).query
- if ( ! q.addrs || ! /^[a-z0-9_\-]{1,12}(,[a-z0-9_\-]{1,12})*$/.test( q.addrs ) )
- q.addrs = ""
- if ( q.msg )
- q.msg = q.msg.replace( /[^!-~\s\t\r\n]/g, "" )
- if ( q.msgAfter )
- q.msgAfter = q.msgAfter | 0
- mylog( `Query param: ${ JSON.stringify( q ) }.` )
- let date = Date.now()
- let addrs = q.addrs.split( ',' )
- if ( q.addrs && q.msg ){
- msgId++
- msgs[ msgId ] = { addrs: addrs, msg: q.msg, date: date }
- mylog( `New message ${msgId} saved.` )
- let out = { msgId: msgId, addrs: addrs, msg: q.msg, date: date }
- addrs.forEach( ( addr ) => {
- if ( addr_subs[addr] ){
- for ( const [ subId, msgAfter ] of Object.entries( addr_subs[addr] ) ){
- if ( msgAfter < msgId ){
- mylog( `Serve message ${msgId} to subscriber ${subId}.` )
- let sub = subs[subId]
- let out = [ { msgId: msgId, addrs: addrs, msg: q.msg, date: date } ]
- sub.res.write( JSON.stringify( out ) )
- sub.res.end()
- mylog( `Subscriber ${subId} unsubscribe.` )
- sub.addrs.forEach( ( addr )=>{
- delete addr_subs[addr][subId]
- } )
- delete subs[subId]
- }
- }
- }
- addr_msgs[addr] = addr_msgs[addr] || {}
- addr_msgs[addr][ msgId ] = date
- addr_msgs[addr].lastMsgId = msgId
- } )
- res.write( JSON.stringify( out ) )
- res.end()
- let ymd = new Date( date ).toLocaleString( 'sv' ).slice( 0, 10 )
- if ( logFile.ymd != ymd ){
- if ( logFile.stream )
- logFile.stream.end()
- logFile.stream = fs.createWriteStream( `${ymd}.txt`, { flags: 'a' } )
- }
- logFile.stream.write( JSON.stringify( { msgId: msgId, addrs: addrs, msg: q.msg, date: date } ) + "\n" )
- } else if ( q.addrs && q.msgAfter ){
- let out = []
- mylog( `New client` )
- addrs.forEach( ( addr ) => {
- if ( addr_msgs[addr] && addr_msgs[addr].lastMsgId > + q.msgAfter ){
- for ( let msgId in addr_msgs[addr] ){
- if ( + msgId > + q.msgAfter ){
- mylog( `Serve message ${msgId} to client.` )
- let msg = msgs[ msgId ]
- out.push( { msgId: msgId, addrs:msg.addrs, msg: msg.msg, date: msg.date } )
- }
- }
- }
- } )
- if ( out.length ){
- res.write( JSON.stringify( out ) )
- res.end()
- } else {
- subId++
- subs[ subId ] = { addrs: addrs, msgAfter: + q.msgAfter, date:date, res: res }
- mylog( `Saved as new subscriber ${subId}.` )
- addrs.forEach( ( addr ) => {
- addr_subs[addr] = addr_subs[addr] || {}
- addr_subs[addr][subId] = + q.msgAfter
- } )
- }
- } else {
- res.write( JSON.stringify( { error: "wtf are you doing?" } ) )
- res.end()
- }
- } ).listen( PORT, 'localhost' ).on( 'connection', function( socket ){
- socket.setTimeout( 600_000 );
- } )
- let cleanups = () => {
- let oldest = Date.now() + 240_000 // 4 = 5 - 1 minutes in ms = 240_000
- mylog( `Iteration tick` )
- let old = Date.now() - 2_629_746_000 // 1 month in ms = 2_629_746_000
- let found = false
- for ( const [ msgId, msg ] of Object.entries( msgs ) ){ // Remove old mesages
- if ( msg.date < old ){
- found = true
- mylog( `Cleanup: Remove message ${msgId}.` )
- delete msgs[ msgId ]
- } else {
- oldest = Math.min( oldest, msg.date + 2_629_746_000 )
- break
- }
- }
- if ( found ) for ( const [ addr, msg ] of Object.entries( addr_msgs ) ){ // Remove old mesages
- for ( const [ msgId, date ] of Object.entries( msg ) ){
- if ( + msgId && date < old ){
- mylog( `Cleanup: Remove message ${msgId} address ${addr}.` )
- delete addr_msgs[addr][msgId]
- } else if ( + msgId )
- oldest = Math.min( oldest, date + 2_629_746_000 )
- }
- }
- old = Date.now() - 300_000 // 5 minutes in ms = 300_000
- for ( const [ subId, sub ] of Object.entries( subs ) ){ // Serve old subscribers closing them
- if ( sub.date < old ){
- mylog( `Cleanup: Close subscriber ${subId}.` )
- sub.res.write( "[]" )
- sub.res.end()
- sub.addrs.forEach( ( addr ) => {
- delete addr_subs[addr][subId]
- } )
- delete subs[ subId ]
- } else {
- oldest = Math.min( oldest, sub.date + 300_000 )
- break
- }
- }
- oldest = Math.max( oldest - Date.now(), 60_000 ) // 1 minute in ms = 60_000
- mylog( `Cleanup: Sleep ${oldest} ms.` )
- setTimeout( cleanups, oldest )
- }
- cleanups()
Add Comment
Please, Sign In to add comment