pastehub 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,287 @@
1
+ #
2
+ # clientsync.rb - PasteHub's client sync library
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'net/http'
35
+ require 'uri'
36
+ require 'open-uri'
37
+ require 'fileutils'
38
+
39
+ module PasteHub
40
+
41
+ class ClientSync
42
+
43
+ def initialize( alive_entries, localdb_path, polling_interval )
44
+ @alive_entries = alive_entries
45
+ @localdb_path = localdb_path
46
+ @polling_interval = polling_interval
47
+ end
48
+
49
+
50
+ def syncDb( auth, password )
51
+ notifyFlag = false
52
+
53
+ STDERR.puts "synchronizing..."
54
+ client = PasteHub::Client.new( auth, password )
55
+ util = PasteHub::Util.new
56
+ # open local db
57
+ localdb = PasteHub::LocalDB.new( @localdb_path )
58
+ localdb.open( auth.username, true )
59
+
60
+ masterList = localdb.getServerList()
61
+ #pp [ "masterList.size", masterList.size ]
62
+
63
+ # calc difference between master and local.
64
+ localList = localdb.getList()
65
+ #pp [ "localList.size(1)", localList.size ]
66
+
67
+ # pickup first ALIVE_ENTRIES from localList
68
+ #_half0 = util.takeList( localList, @alive_entries )
69
+ _half1 = util.dropList( masterList, @alive_entries )
70
+ localList = localList + _half1
71
+ #pp [ "localList.size(2)", localList.size ]
72
+
73
+ downList = util.diffList( masterList, localList )
74
+ #pp [ "downList.size", downList.size ]
75
+
76
+ upList = util.diffList( localList, masterList )
77
+ #pp [ "upList.size", upList.size ]
78
+
79
+ # push first element to clipboard.
80
+ if 0 < downList.size
81
+ key = downList.first
82
+ value = client.getValue( key )
83
+ if @prevData == value
84
+ #p [ @prevData , value ]
85
+ STDERR.puts "Info: did not push to OS's clipboard because prevData == donwloaded-firstEntry."
86
+ else
87
+ STDERR.printf( "Info: push to OS's clipboard (size=%d).\n", value.size )
88
+ PasteHub::AbstractClipboard.push( value.dup )
89
+ notifyFlag = true
90
+ @prevData = value
91
+ end
92
+ end
93
+
94
+ # donwload
95
+ downList.each {|key|
96
+ value = client.getValue( key )
97
+ localdb_w = PasteHub::LocalDB.new( @localdb_path )
98
+ localdb_w.open( auth.username )
99
+ localdb_w.insertValue( key.dup, value.dup )
100
+ localdb_w.close
101
+ sleep( 0.2 )
102
+ }
103
+ # upload
104
+ upList.each {|key|
105
+ value = localdb.getValue( key )
106
+ client.putValue( key.dup, value.dup )
107
+ }
108
+
109
+ STDERR.puts "Info: download #{downList.size} records."
110
+ downList.each { |x|
111
+ #STDERR.puts " key=#{x}"
112
+ }
113
+ STDERR.puts "Info: upload #{upList.size} records."
114
+ upList.each { |x|
115
+ #STDERR.puts " key=#{x}"
116
+ }
117
+ localdb.close()
118
+
119
+ if 0 < downList.size or 0 < upList.size
120
+ STDERR.puts "Info: send signal to Emacs."
121
+ system( "killall -SIGUSR1 Emacs emacs" )
122
+ end
123
+
124
+ return notifyFlag
125
+ end
126
+
127
+
128
+ def gcLocalDb( auth )
129
+ STDERR.puts "GCing..."
130
+
131
+ # open local db
132
+ localdb_w = PasteHub::LocalDB.new( @localdb_path )
133
+ localdb_w.open( auth.username )
134
+ localList = localdb_w.getList()
135
+ deleteList = localList[@alive_entries..(localList.size)]
136
+ if deleteList and 0 < deleteList.size
137
+ STDERR.puts "Info: delete #{deleteList.size} records."
138
+ deleteList.each { |key|
139
+ localdb_w.deleteValue( key.dup )
140
+ }
141
+ end
142
+ localdb_w.close
143
+ end
144
+
145
+
146
+ def fetchServerList( latestKey, auth )
147
+ client = PasteHub::Client.new( auth )
148
+ if latestKey.is_a? String
149
+ STDERR.puts "Info: fetch one entry"
150
+ list = [ latestKey.clone() ]
151
+ else
152
+ STDERR.puts "Info: fetch ALL entries"
153
+ list = client.getList()
154
+ end
155
+ client.setServerFlags( list )
156
+ end
157
+
158
+ def addNoitfyCallback( countUpNotifyFunc, connectNotifyFunc, disconnectNotifyFunc )
159
+ @countUpNotifyFunc = countUpNotifyFunc
160
+ @connectNotifyFunc = connectNotifyFunc
161
+ @disconnectNotifyFunc = disconnectNotifyFunc
162
+ end
163
+
164
+ def notifyCountUp()
165
+ @countUpNotifyFunc.call() if @countUpNotifyFunc
166
+ end
167
+
168
+ def notifyConnect()
169
+ @connectNotifyFunc.call() if @connectNotifyFunc
170
+ end
171
+
172
+ def notifyDisconnect()
173
+ @disconnectNotifyFunc.call() if @disconnectNotifyFunc
174
+ end
175
+
176
+
177
+ def syncMain( username, secretKey, password )
178
+ freeCounter = 0
179
+
180
+ auth = PasteHub::AuthForClient.new( username, secretKey )
181
+ client = PasteHub::Client.new( auth )
182
+ client.setOnlineState( false )
183
+ client.setOnlineState( true ) # create Trigger token ___-___
184
+ client.setOnlineState( false )
185
+ result = :start
186
+
187
+ while true
188
+ begin
189
+ freeCounter += 1
190
+
191
+ if client.getTrigger() or (0 == (freeCounter % 60))
192
+ STDERR.puts "Info: force sync."
193
+ result = :sync
194
+ gcLocalDb( auth )
195
+ else
196
+ auth = PasteHub::AuthForClient.new( username, secretKey )
197
+ result = client.wait_notify( auth )
198
+ end
199
+
200
+ case result
201
+ when :timeout
202
+ STDERR.puts "waiting..."
203
+ client.setOnlineState( true )
204
+ notifyConnect()
205
+ when :retry
206
+ STDERR.puts "retrying...."
207
+ client.setOnlineState( false )
208
+ notifyDisconnect()
209
+ sleep 60
210
+ else
211
+ if not client.online?()
212
+ notifyConnect()
213
+ end
214
+ client.setOnlineState( true )
215
+ fetchServerList( result, auth )
216
+ if syncDb( auth, password )
217
+ notifyCountUp()
218
+ end
219
+ end
220
+ rescue Errno::EAGAIN => e
221
+ STDERR.puts "retrying... DB is locked"
222
+ notifyDisconnect()
223
+ sleep 2
224
+ rescue Errno::ECONNREFUSED => e
225
+ STDERR.puts "retrying... pastehub server is down(1)"
226
+ notifyDisconnect()
227
+ sleep 60
228
+ rescue Errno::ETIMEDOUT => e
229
+ STDERR.puts "retrying... network is offline(1)"
230
+ notifyDisconnect()
231
+ sleep 60
232
+ rescue SocketError => e
233
+ STDERR.puts "retrying... network is offline(2)"
234
+ notifyDisconnect()
235
+ sleep 60
236
+ rescue Timeout::Error => e
237
+ # ONLINE, but server is not helthy
238
+ notifyDisconnect()
239
+ STDERR.puts "retrying... pastehub server is down(2)"
240
+ sleep 60
241
+ end
242
+ end
243
+ end
244
+
245
+
246
+ def clipboardCheck( username, secretKey, password )
247
+ STDERR.puts "Info: clipboardCheck thread start"
248
+ @prevData = ""
249
+ while true
250
+ sleep @polling_interval
251
+ data = PasteHub::AbstractClipboard.hasNew?( username )
252
+ if data
253
+ if @prevData != data
254
+ #p [ @prevData, data ]
255
+ auth = PasteHub::AuthForClient.new( username, secretKey )
256
+ client = PasteHub::Client.new( auth, password )
257
+ if client.online?( )
258
+ STDERR.puts( "Info: posted data from OS." )
259
+ begin
260
+ client.putValue( "_", data )
261
+ rescue Errno::ECONNREFUSED => e
262
+ # if postData was fail, save to local.
263
+ client.setOnlineState( false )
264
+ client.localSaveValue( data )
265
+ sleep 60
266
+ end
267
+ else
268
+ client.localSaveValue( data )
269
+ end
270
+ @prevData = data
271
+ end
272
+ end
273
+ end
274
+ end
275
+
276
+
277
+ def syncNow( username, secretKey, password )
278
+ STDERR.puts( "Info: caught signal." )
279
+ store = PasteHub::LocalStore.new( username, true )
280
+ pair = store.top()
281
+ auth = PasteHub::AuthForClient.new( username, secretKey )
282
+ client = PasteHub::Client.new( auth, password )
283
+ client.putValue( pair[0], pair[1] )
284
+ end
285
+
286
+ end
287
+ end
@@ -0,0 +1,56 @@
1
+ #
2
+ # clipboard.rb - PasteHub's platform independent clipboard library.
3
+ #
4
+ # Copyright (c) 2013-2013 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'clipboard'
35
+
36
+ module PasteHub
37
+
38
+ class AbstractClipboard
39
+
40
+ def self.push( data )
41
+ Encoding.default_external = "UTF-8"
42
+ Clipboard.copy( data.force_encoding("UTF-8") )
43
+ nil
44
+ end
45
+
46
+ def self.hasNew?( username )
47
+ Encoding.default_external = "UTF-8"
48
+ str = Clipboard.paste( )
49
+ str = str.force_encoding("UTF-8")
50
+ if 0 == str.size
51
+ return nil
52
+ end
53
+ return str
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,166 @@
1
+ #
2
+ # config.rb - PasteHub's config file loader and config object.
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'singleton'
35
+ require 'json'
36
+
37
+ module PasteHub
38
+ class Config
39
+ include Singleton
40
+
41
+ def self.instance
42
+ @@instance ||= new
43
+ end
44
+
45
+ def initialize( )
46
+ self.setupServer( {} )
47
+ self.setupClient( {} )
48
+ @listItems = 10
49
+ end
50
+
51
+ def setupServer( hash )
52
+ @aws = if hash[ :aws ]
53
+ hash[ :aws ]
54
+ else
55
+ false
56
+ end
57
+ @awsWarn = if hash[ :awsWarn ]
58
+ hash[ :awsWarn ]
59
+ else
60
+ false
61
+ end
62
+ @dynamoEp = if hash[ :dynamoEp ]
63
+ hash[ :dynamoEp ]
64
+ else
65
+ dynamoEp = 'dynamodb.ap-northeast-1.amazonaws.com' # Default DynamoDB's endpoint is Tokyo Region
66
+ end
67
+ @dynamoAccessKey = if hash[ :dynamoAccessKey ]
68
+ hash[ :dynamoAccessKey ]
69
+ else
70
+ "xxxx"
71
+ end
72
+ @dynamoSecretKey = if hash[ :dynamoSecretKey ]
73
+ hash[ :dynamoSecretKey ]
74
+ else
75
+ "xxxx"
76
+ end
77
+ @memcacheEp = if hash[ :memcacheEp ]
78
+ hash[ :memcacheEp ]
79
+ else
80
+ "localhost:11211"
81
+ end
82
+ @keyCacheTime = if hash[ :keyCacheTime ]
83
+ hash[ :keyCacheTime ]
84
+ else
85
+ 24 * 3600
86
+ end
87
+ @domain = if hash[ :domain ]
88
+ hash[ :domain ]
89
+ else
90
+ "localhost"
91
+ end
92
+ @keystore = if hash[ :keystore ]
93
+ hash[ :keystore ]
94
+ else
95
+ nil
96
+ end
97
+ @keystorePassword = if hash[ :keystorePassword ]
98
+ hash[ :keystorePassword ]
99
+ else
100
+ "password"
101
+ end
102
+ end
103
+
104
+ def appendSlash( uri )
105
+ if uri.match( /\/$/ )
106
+ uri
107
+ else
108
+ uri + "/"
109
+ end
110
+ end
111
+
112
+ def setupClient( hash )
113
+ @targetApiURL = if hash[ :targetApiURL ]
114
+ appendSlash( hash[ :targetApiURL ] )
115
+ else
116
+ "https://pastehub.net/api/"
117
+ end
118
+ @targetNotifierURL = if hash[ :targetNotifierURL ]
119
+ appendSlash( hash[ :targetNotifierURL ] )
120
+ else
121
+ "https://pastehub.net:8001/"
122
+ end
123
+ @localDbPath = if hash[ :localDbPath ]
124
+ hash[ :localDbPath ]
125
+ else
126
+ File.expand_path( "~/.pastehub/" ) + "/"
127
+ end
128
+ end
129
+
130
+ def loadServer()
131
+ name = "/etc/pastehub.conf"
132
+ if File.exist?( name )
133
+ open( name ) { |f|
134
+ json = JSON.parse( f.read )
135
+ self.setupServer( { :aws => json[ 'aws' ],
136
+ :awsWarn => json[ 'awsWarn' ],
137
+ :dynamoEp => json[ 'dynamoEp' ],
138
+ :dynamoAccessKey => json[ 'dynamoAccessKey' ],
139
+ :dynamoSecretKey => json[ 'dynamoSecretKey' ],
140
+ :memcacheEp => json[ 'memcacheEp' ],
141
+ :keyCacheTime => json[ 'keyCacheTime' ],
142
+ :domain => json[ 'domain' ],
143
+ :keystore => json[ 'keystore' ],
144
+ :keystorePassword => json[ 'keystorePassword' ] } )
145
+ }
146
+ end
147
+ end
148
+
149
+ def loadClient()
150
+ name = File.expand_path( "~/.pastehub.conf" )
151
+ if File.exist?( name )
152
+ open( name ) { |f|
153
+ json = JSON.parse( f.read )
154
+ self.setupClient( { :targetApiURL => json[ 'targetApiURL' ],
155
+ :targetNotifierURL => json[ 'targetNotifierURL' ],
156
+ :localDbPath => json[ 'localDbPath' ] } )
157
+
158
+ }
159
+ end
160
+ end
161
+
162
+ attr_reader :aws, :dynamoEp, :dynamoAccessKey, :dynamoSecretKey, :memcacheEp, :keyCacheTime, :domain, :keystore, :keystorePassword
163
+ attr_reader :targetApiURL, :targetNotifierURL, :localDbPath, :listItems
164
+ attr_accessor :awsWarn
165
+ end
166
+ end