1+ //history
2+ //external modules
3+ var async = require ( 'async' ) ;
4+ var moment = require ( 'moment' ) ;
5+
6+ //core
7+ var config = require ( "./config.js" ) ;
8+ var logger = require ( "./logger.js" ) ;
9+ var response = require ( "./response.js" ) ;
10+ var models = require ( "./models" ) ;
11+
12+ //public
13+ var History = {
14+ historyGet : historyGet ,
15+ historyPost : historyPost ,
16+ historyDelete : historyDelete ,
17+ isReady : isReady ,
18+ updateHistory : updateHistory
19+ } ;
20+
21+ var caches = { } ;
22+ //update when the history is dirty
23+ var updater = setInterval ( function ( ) {
24+ var deleted = [ ] ;
25+ async . each ( Object . keys ( caches ) , function ( key , callback ) {
26+ var cache = caches [ key ] ;
27+ if ( cache . isDirty ) {
28+ if ( config . debug ) logger . info ( "history updater found dirty history: " + key ) ;
29+ var history = parseHistoryToArray ( cache . history ) ;
30+ finishUpdateHistory ( key , history , function ( err , count ) {
31+ if ( err ) return callback ( err , null ) ;
32+ if ( ! count ) return callback ( null , null ) ;
33+ cache . isDirty = false ;
34+ cache . updateAt = Date . now ( ) ;
35+ return callback ( null , null ) ;
36+ } ) ;
37+ } else {
38+ if ( moment ( ) . isAfter ( moment ( cache . updateAt ) . add ( 5 , 'minutes' ) ) ) {
39+ deleted . push ( key ) ;
40+ }
41+ return callback ( null , null ) ;
42+ }
43+ } , function ( err ) {
44+ if ( err ) return logger . error ( 'history updater error' , err ) ;
45+ } ) ;
46+ // delete specified caches
47+ for ( var i = 0 , l = deleted . length ; i < l ; i ++ ) {
48+ caches [ deleted [ i ] ] . history = { } ;
49+ delete caches [ deleted [ i ] ] ;
50+ }
51+ } , 1000 ) ;
52+
53+ function finishUpdateHistory ( userid , history , callback ) {
54+ models . User . update ( {
55+ history : JSON . stringify ( history )
56+ } , {
57+ where : {
58+ id : userid
59+ }
60+ } ) . then ( function ( count ) {
61+ return callback ( null , count ) ;
62+ } ) . catch ( function ( err ) {
63+ return callback ( err , null ) ;
64+ } ) ;
65+ }
66+
67+ function isReady ( ) {
68+ var dirtyCount = 0 ;
69+ async . each ( Object . keys ( caches ) , function ( key , callback ) {
70+ if ( caches [ key ] . isDirty ) dirtyCount ++ ;
71+ return callback ( null , null ) ;
72+ } , function ( err ) {
73+ if ( err ) return logger . error ( 'history ready check error' , err ) ;
74+ } ) ;
75+ return dirtyCount > 0 ? false : true ;
76+ }
77+
78+ function getHistory ( userid , callback ) {
79+ if ( caches [ userid ] ) {
80+ return callback ( null , caches [ userid ] . history ) ;
81+ } else {
82+ models . User . findOne ( {
83+ where : {
84+ id : userid
85+ }
86+ } ) . then ( function ( user ) {
87+ if ( ! user )
88+ return callback ( null , null ) ;
89+ var history = [ ] ;
90+ if ( user . history )
91+ history = JSON . parse ( user . history ) ;
92+ if ( config . debug )
93+ logger . info ( 'read history success: ' + user . id ) ;
94+ setHistory ( userid , history ) ;
95+ return callback ( null , history ) ;
96+ } ) . catch ( function ( err ) {
97+ logger . error ( 'read history failed: ' + err ) ;
98+ return callback ( err , null ) ;
99+ } ) ;
100+ }
101+ }
102+
103+ function setHistory ( userid , history ) {
104+ if ( Array . isArray ( history ) ) history = parseHistoryToObject ( history ) ;
105+ if ( ! caches [ userid ] ) {
106+ caches [ userid ] = {
107+ history : { } ,
108+ isDirty : false ,
109+ updateAt : Date . now ( )
110+ } ;
111+ }
112+ caches [ userid ] . history = history ;
113+ }
114+
115+ function updateHistory ( userid , noteId , document ) {
116+ var t0 = new Date ( ) . getTime ( ) ;
117+ if ( userid && noteId && document ) {
118+ getHistory ( userid , function ( err , history ) {
119+ if ( err || ! history ) return ;
120+ if ( ! caches [ userid ] . history [ noteId ] ) {
121+ caches [ userid ] . history [ noteId ] = { } ;
122+ }
123+ var noteHistory = caches [ userid ] . history [ noteId ] ;
124+ var noteInfo = models . Note . parseNoteInfo ( document ) ;
125+ noteHistory . id = noteId ;
126+ noteHistory . text = noteInfo . title ;
127+ noteHistory . time = moment ( ) . format ( 'MMMM Do YYYY, h:mm:ss a' ) ;
128+ noteHistory . tags = noteInfo . tags ;
129+ caches [ userid ] . isDirty = true ;
130+ var t1 = new Date ( ) . getTime ( ) ;
131+ console . warn ( t1 - t0 ) ;
132+ } ) ;
133+ }
134+ }
135+
136+ function parseHistoryToArray ( history ) {
137+ var _history = [ ] ;
138+ Object . keys ( history ) . forEach ( function ( key ) {
139+ var item = history [ key ] ;
140+ _history . push ( item ) ;
141+ } ) ;
142+ return _history ;
143+ }
144+
145+ function parseHistoryToObject ( history ) {
146+ var _history = { } ;
147+ for ( var i = 0 , l = history . length ; i < l ; i ++ ) {
148+ var item = history [ i ] ;
149+ _history [ item . id ] = item ;
150+ }
151+ return _history ;
152+ }
153+
154+ function historyGet ( req , res ) {
155+ if ( req . isAuthenticated ( ) ) {
156+ getHistory ( req . user . id , function ( err , history ) {
157+ if ( err ) return response . errorInternalError ( res ) ;
158+ if ( ! history ) return response . errorNotFound ( res ) ;
159+ res . send ( {
160+ history : parseHistoryToArray ( history )
161+ } ) ;
162+ } ) ;
163+ } else {
164+ return response . errorForbidden ( res ) ;
165+ }
166+ }
167+
168+ function historyPost ( req , res ) {
169+ if ( req . isAuthenticated ( ) ) {
170+ var noteId = req . params . noteId ;
171+ if ( ! noteId ) {
172+ if ( typeof req . body [ 'history' ] === 'undefined' ) return response . errorBadRequest ( res ) ;
173+ if ( config . debug )
174+ logger . info ( 'SERVER received history from [' + req . user . id + ']: ' + req . body . history ) ;
175+ try {
176+ var history = JSON . parse ( req . body . history ) ;
177+ } catch ( err ) {
178+ return response . errorBadRequest ( res ) ;
179+ }
180+ if ( Array . isArray ( history ) ) {
181+ setHistory ( req . user . id , history ) ;
182+ caches [ req . user . id ] . isDirty = true ;
183+ res . end ( ) ;
184+ } else {
185+ return response . errorBadRequest ( res ) ;
186+ }
187+ } else {
188+ if ( typeof req . body [ 'pinned' ] === 'undefined' ) return response . errorBadRequest ( res ) ;
189+ getHistory ( req . user . id , function ( err , history ) {
190+ if ( err ) return response . errorInternalError ( res ) ;
191+ if ( ! history ) return response . errorNotFound ( res ) ;
192+ if ( ! caches [ req . user . id ] . history [ noteId ] ) return response . errorNotFound ( res ) ;
193+ if ( req . body . pinned === 'true' || req . body . pinned === 'false' ) {
194+ caches [ req . user . id ] . history [ noteId ] . pinned = ( req . body . pinned === 'true' ) ;
195+ caches [ req . user . id ] . isDirty = true ;
196+ res . end ( ) ;
197+ } else {
198+ return response . errorBadRequest ( res ) ;
199+ }
200+ } ) ;
201+ }
202+ } else {
203+ return response . errorForbidden ( res ) ;
204+ }
205+ }
206+
207+ function historyDelete ( req , res ) {
208+ if ( req . isAuthenticated ( ) ) {
209+ var noteId = req . params . noteId ;
210+ if ( ! noteId ) {
211+ setHistory ( req . user . id , [ ] ) ;
212+ caches [ req . user . id ] . isDirty = true ;
213+ res . end ( ) ;
214+ } else {
215+ getHistory ( req . user . id , function ( err , history ) {
216+ if ( err ) return response . errorInternalError ( res ) ;
217+ if ( ! history ) return response . errorNotFound ( res ) ;
218+ delete caches [ req . user . id ] . history [ noteId ] ;
219+ caches [ req . user . id ] . isDirty = true ;
220+ res . end ( ) ;
221+ } ) ;
222+ }
223+ } else {
224+ return response . errorForbidden ( res ) ;
225+ }
226+ }
227+
228+ module . exports = History ;
0 commit comments