pastehub 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ #
2
+ # store.rb - PasteHub's storage 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
+
35
+ module PasteHub
36
+
37
+ class LocalStore
38
+ def initialize( username, reader = false )
39
+ @db = PasteHub::LocalDB.new( PasteHub::Config.instance.localDbPath )
40
+ @db.open( username, reader )
41
+ end
42
+
43
+ def getList
44
+ @db.getList()
45
+ end
46
+
47
+ def getServerList
48
+ @db.getServerList()
49
+ end
50
+
51
+ def top
52
+ lst = @db.getList( 1 )
53
+ if 0 < lst.size
54
+ [ lst.first, @db.getValue( lst.first ) ]
55
+ else
56
+ [ nil, nil ]
57
+ end
58
+ end
59
+
60
+ def getValue( key )
61
+ @db.getValue( key.dup )
62
+ end
63
+
64
+ def latest
65
+ [ @db.getValue( PasteHub::SERVER_DATE_KEY ).to_s,
66
+ @db.getValue( PasteHub::LOCAL_DATE_KEY ).to_s ]
67
+ end
68
+
69
+ def insertValue( key, value )
70
+ @db.insertValue( key, value )
71
+ end
72
+
73
+ def close
74
+ @db.close
75
+ end
76
+
77
+ def clear
78
+ @db.clear
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,153 @@
1
+ require 'digest'
2
+ require 'date'
3
+ require 'set'
4
+
5
+ module PasteHub
6
+ require 'rubygems'
7
+ begin
8
+ require 'highline'
9
+ USE_HIGHLINE = true
10
+ rescue LoadError
11
+ USE_HIGHLINE = false
12
+ end
13
+
14
+ class Util
15
+ def initialize()
16
+ end
17
+
18
+ # return message digest for str.
19
+ def digest( str )
20
+ Digest::SHA1.hexdigest( str )
21
+ end
22
+
23
+ # return the currentTime in Unixtime
24
+ def currentTime( )
25
+ dt = Time.new.gmtime.to_datetime()
26
+ currentDate = dt.strftime( "%s" ) + "=" + dt.strftime( "%F.%H:%M:%S" )
27
+ currentDate
28
+ end
29
+
30
+ def currentSeconds( )
31
+ self.key_seconds( self.currentTime() )
32
+ end
33
+
34
+ def _splitKey( key )
35
+ key.split( /[=]/ )
36
+ end
37
+
38
+ def key_seconds( key )
39
+ arr = _splitKey( key )
40
+ if 1 < arr.size
41
+ arr[0].to_i
42
+ else
43
+ nil
44
+ end
45
+ end
46
+
47
+ def key_timestamp( key )
48
+ arr = _splitKey( key )
49
+ if 1 < arr.size
50
+ arr[1]
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ def key_digest( key )
57
+ arr = _splitKey( key )
58
+ if 2 < arr.size
59
+ arr[2]
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ def diffList( list1, list2 )
66
+ set1 = Set.new
67
+ set2 = Set.new
68
+ list1.each { |e| set1.add(e) }
69
+ list2.each { |e| set2.add(e) }
70
+ set1.difference( set2 ).to_a
71
+ end
72
+
73
+ # Same as Gauche's take* function
74
+ def takeList( list1, num )
75
+ if ( num < 0 )
76
+ list1
77
+ elsif num <= list1.size
78
+ list1[ 0 ... num ]
79
+ else
80
+ list1
81
+ end
82
+ end
83
+
84
+ # Same as Gauche's drop* function
85
+ def dropList( list1, num )
86
+ if num < 0
87
+ list1
88
+ elsif num <= list1.size
89
+ list1[ num .. list1.size ]
90
+ else
91
+ []
92
+ end
93
+ end
94
+
95
+ def say( message )
96
+ if USE_HIGHLINE
97
+ HighLine.new.say( message ) {|q|
98
+ q.readline = true
99
+ }
100
+ else
101
+ puts "#{message}"
102
+ end
103
+ end
104
+
105
+ def inputText( label )
106
+ if USE_HIGHLINE
107
+ HighLine.new.ask( label ) {|q|
108
+ q.readline = true
109
+ }
110
+ else
111
+ print "#{label}"
112
+ return gets.chomp
113
+ end
114
+ end
115
+
116
+ def inputPassword( label )
117
+ if USE_HIGHLINE
118
+ HighLine.new.ask( label ) {|q|
119
+ q.readline = true
120
+ q.echo = '*'
121
+ }
122
+ else
123
+ print "#{label}"
124
+ return gets.chomp
125
+ end
126
+ end
127
+
128
+ # input utility
129
+ def inputPasswordTwice( message, firstLabel, secondLabel )
130
+ required_password_chars = 6
131
+
132
+ STDERR.puts( message )
133
+ 3.times { |n|
134
+ firstStr = nil
135
+ while not firstStr
136
+ firstStr = inputPassword(firstLabel)
137
+ if required_password_chars > firstStr.size()
138
+ STDERR.puts( "you must input #{required_password_chars} or more characters." )
139
+ firstStr = nil
140
+ elsif firstStr.match( /[ \t]/i )
141
+ STDERR.puts( "you must not use white space characters." )
142
+ firstStr = nil
143
+ end
144
+ end
145
+ secondStr = inputPassword(secondLabel)
146
+ if firstStr == secondStr
147
+ return firstStr
148
+ end
149
+ }
150
+ return nil
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,141 @@
1
+ require 'vertx'
2
+ require 'json/pure'
3
+ require 'cgi'
4
+ require 'date'
5
+ require 'memcache'
6
+
7
+ $LOAD_PATH.push( File.dirname(__FILE__) + "/../lib" )
8
+ require 'pastehub'
9
+ require 'pastehub/log'
10
+ PasteHub::Config.instance.loadServer
11
+
12
+ # display config info
13
+ ins = PasteHub::Config.instance
14
+ printf( "Use AWS: %s\n", ins.aws )
15
+ printf( "Domain: %s\n", ins.domain )
16
+ printf( "Dynamo Endpoint: %s\n", ins.dynamoEp )
17
+ printf( "Memcache Endpoint: %s\n", ins.memcacheEp )
18
+
19
+ # initialize master database
20
+ require 'pastehub/masterdb'
21
+
22
+
23
+ # setup user table for Fake DynamoDB
24
+ users = PasteHub::Users.new( )
25
+ if not ins.aws
26
+ open( "/var/pastehub/users.tsv", "r" ) {|f|
27
+ f.readlines.each { |line|
28
+ pair = line.chomp.split( /[\t ]+/ )
29
+ printf( "Added local user table: %s\n", pair[0] )
30
+ users.addUser( pair[0], pair[1] )
31
+ }
32
+ }
33
+ end
34
+
35
+
36
+ notifyHash = Memcache.new( :server => PasteHub::Config.instance.memcacheEp )
37
+
38
+ masterdb_server = Vertx::HttpServer.new
39
+ masterdb_server.request_handler do |req|
40
+
41
+ req.body_handler do |body|
42
+ util = PasteHub::Util.new
43
+ auth = PasteHub::AuthForServer.new( users )
44
+ ret = auth.invoke( req.headers, util.currentSeconds() )
45
+ username = ret[1]
46
+
47
+ log = PasteHub::Log.new( :api => req.path, :user => username )
48
+ if ret[0]
49
+ log.info( "connected" )
50
+ else
51
+ log.error( 'Auth failure:' + ret[2].to_s, { :reason => ret[2].to_s } )
52
+ req.response.status_code = 403
53
+ req.response.status_message = "Authorization failure."
54
+ req.response.end
55
+ return
56
+ end
57
+
58
+ entries = PasteHub::Entries.new( username )
59
+ users = PasteHub::Users.new( )
60
+
61
+ case req.path
62
+ when "/authTest"
63
+ req.response.end
64
+
65
+ when "/putValue"
66
+ data = body.to_s.dup
67
+ digest = util.digest( data )
68
+
69
+ # update db
70
+ key = req.headers[ 'X-Pastehub-Key' ].dup
71
+ puts "[#{username}]:putValue: key=[#{key}] "
72
+
73
+ # client have no specified key
74
+ if "_" == key
75
+ key = util.currentTime( ) + "=" + digest
76
+ end
77
+
78
+ # data duplicate check
79
+ insertFlag = true
80
+ prevKey = notifyHash.get( username )
81
+ if prevKey
82
+ if util.key_digest( prevKey ) == digest
83
+ log.info( "canceled because data is duplicate. ", { :key => key } )
84
+ insertFlag = false
85
+ key = prevKey
86
+ end
87
+ end
88
+
89
+ if insertFlag
90
+ Vertx.set_timer(1000) do
91
+ log.info( "START: delayed job." )
92
+ # update db
93
+ log.info( "insert", { :key => key } )
94
+ entries.insertValue( key, data )
95
+ users.touch( username )
96
+ # notify to client
97
+ notifyHash.set( username, key, PasteHub::Config.instance.keyCacheTime )
98
+
99
+ # remove Last entry
100
+ arr = entries.getList( )
101
+ if PasteHub::Config.instance.listItems < arr.size
102
+ entries.deleteValue( arr[arr.size-1] )
103
+ end
104
+ log.info( "END: delayed job", { :entries => arr.size } )
105
+ end
106
+ end
107
+ req.response.end( key )
108
+
109
+
110
+ when "/getList"
111
+ limit = req.headers[ 'X-Pastehub-Limit' ]
112
+ if limit
113
+ str = entries.getList( ).take( limit.to_i ).join( "\n" )
114
+ else
115
+ str = entries.getList( ).join( "\n" )
116
+ end
117
+ log.info( "getList", { :limit => limit, :entries => entries.getList( ).size } )
118
+ puts str
119
+ req.response.end( str )
120
+
121
+ when "/getValue"
122
+ k = body.to_s.chomp
123
+ if 0 < k.size
124
+ str = entries.getValue( k.dup )
125
+ else
126
+ str = ""
127
+ end
128
+ log.info( "getValue", { :key => k } )
129
+ puts "[#{username}]:getValue:" + k
130
+ req.response.end( str )
131
+
132
+ else
133
+ mes = "Error: Unknown API #{req.path}"
134
+ log.error( mes )
135
+ req.response.status_code = 400
136
+ req.response.status_message = mes
137
+ req.response.end
138
+
139
+ end
140
+ end
141
+ end.listen(8000)
@@ -0,0 +1,89 @@
1
+ require 'vertx'
2
+ require 'cgi'
3
+ require 'memcache'
4
+ require 'pp'
5
+ $LOAD_PATH.push( File.dirname(__FILE__) + "/../lib" )
6
+ require 'pastehub'
7
+ require 'pastehub/log'
8
+ PasteHub::Config.instance.loadServer
9
+
10
+ # display config info
11
+ ins = PasteHub::Config.instance
12
+ printf( "Use AWS: %s\n", ins.aws )
13
+ printf( "Domain: %s\n", ins.domain )
14
+ printf( "Dynamo Endpoint: %s\n", ins.dynamoEp )
15
+ printf( "Memcache Endpoint: %s\n", ins.memcacheEp )
16
+ printf( "ssl keystore file: %s\n", ins.keystore )
17
+
18
+ # initialize master database
19
+ require 'pastehub/masterdb'
20
+
21
+ # setup user table for Fake DynamoDB
22
+ users = PasteHub::Users.new( )
23
+ if not ins.aws
24
+ open( "/var/pastehub/users.tsv", "r" ) {|f|
25
+ f.readlines.each { |line|
26
+ pair = line.chomp.split( /[\t ]+/ )
27
+ printf( "Added local user table: %s\n", pair[0] )
28
+ users.addUser( pair[0], pair[1] )
29
+ }
30
+ }
31
+ end
32
+
33
+
34
+ INTERVAL = 0.5
35
+ POLLING_SEC = 60
36
+
37
+ notifyHash = Memcache.new( :server => PasteHub::Config.instance.memcacheEp )
38
+
39
+ def notify( res, str )
40
+ res.write_str( "#{str}\n" )
41
+ end
42
+
43
+ notifier = Vertx::HttpServer.new
44
+ if ins.keystore
45
+ notifier.ssl = true
46
+ notifier.key_store_path = ins.keystore
47
+ notifier.key_store_password = ins.keystorePassword
48
+ end
49
+
50
+ notifier.request_handler do |req|
51
+ util = PasteHub::Util.new
52
+ auth = PasteHub::AuthForServer.new( users )
53
+
54
+ ret = auth.invoke( req.headers, util.currentSeconds() )
55
+ username = ret[1]
56
+ # Now send back a response
57
+ req.response.chunked = true
58
+
59
+ log = PasteHub::Log.new( :api => 'notifier', :user => username )
60
+ if ret[0]
61
+ log.info( "connected" )
62
+ else
63
+ log.error( 'Auth failure:' + ret[2].to_s, { :reason => ret[2].to_s } )
64
+ req.response.status_code = 403
65
+ req.response.status_message = "Authorization failure."
66
+ req.response.end
67
+ return
68
+ end
69
+
70
+ got = nil
71
+ timer_count = 0
72
+
73
+ Vertx::set_periodic (1000 * INTERVAL) { |timer_id|
74
+ timer_count += INTERVAL
75
+ if notifyHash[ username ]
76
+ if got != notifyHash[ username ]
77
+ got = notifyHash[ username ]
78
+ log.info( 'notify', { :notify => got } )
79
+ notify( req.response, got )
80
+ end
81
+ end
82
+
83
+ if ( POLLING_SEC < timer_count )
84
+ log.info( 'timeout', { :notify => nil } )
85
+ req.response.end
86
+ Vertx::cancel_timer(timer_id)
87
+ end
88
+ }
89
+ end.listen(8001)