pastehub 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/README.md +32 -0
- data/Rakefile +146 -0
- data/VERSION.yml +4 -0
- data/bin/PastehubSync +107 -0
- data/bin/pastehubDump +114 -0
- data/bin/pastehubPost +63 -0
- data/lib/pastehub.rb +43 -0
- data/lib/pastehub/auth.rb +171 -0
- data/lib/pastehub/client.rb +453 -0
- data/lib/pastehub/clientsync.rb +287 -0
- data/lib/pastehub/clipboard.rb +56 -0
- data/lib/pastehub/config.rb +166 -0
- data/lib/pastehub/crypt.rb +70 -0
- data/lib/pastehub/localdb.rb +187 -0
- data/lib/pastehub/log.rb +95 -0
- data/lib/pastehub/macosx.rb +66 -0
- data/lib/pastehub/masterdb.rb +213 -0
- data/lib/pastehub/store.rb +83 -0
- data/lib/pastehub/util.rb +153 -0
- data/server/masterdb.rb +141 -0
- data/server/notifier.rb +89 -0
- metadata +235 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
#
|
2
|
+
# crypt.rb - PasteHub's encrypt/decrypt 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 'openssl'
|
35
|
+
require 'base64'
|
36
|
+
|
37
|
+
module PasteHub
|
38
|
+
class Crypt
|
39
|
+
def initialize( password )
|
40
|
+
@password = password
|
41
|
+
@des3 = OpenSSL::Cipher.new('des3')
|
42
|
+
end
|
43
|
+
|
44
|
+
def en( str )
|
45
|
+
if 0 == str.size
|
46
|
+
""
|
47
|
+
else
|
48
|
+
@des3.encrypt
|
49
|
+
@des3.pkcs5_keyivgen( @password )
|
50
|
+
Base64.encode64( @des3.update( str ) + @des3.final )
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def de( str )
|
55
|
+
if 0 == str.size
|
56
|
+
""
|
57
|
+
else
|
58
|
+
begin
|
59
|
+
@des3.decrypt
|
60
|
+
@des3.pkcs5_keyivgen( @password )
|
61
|
+
ret = @des3.update( Base64.decode64( str ))
|
62
|
+
ret += @des3.final
|
63
|
+
rescue OpenSSL::Cipher::CipherError => e
|
64
|
+
ret = nil
|
65
|
+
end
|
66
|
+
ret
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
#
|
2
|
+
# localdb.rb - PasteHub's localdb manager
|
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 'gdbm'
|
35
|
+
|
36
|
+
module PasteHub
|
37
|
+
class MutexSingleton
|
38
|
+
include Singleton
|
39
|
+
|
40
|
+
attr_reader :mutex
|
41
|
+
|
42
|
+
def self.instance
|
43
|
+
@@instance ||= new
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize( )
|
47
|
+
@mutex = Mutex.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
ONLINE_STATE_KEY='__ONLINE_STATE'
|
52
|
+
LOCAL_DATE_KEY ='__LOCAL_DATE'
|
53
|
+
SERVER_DATE_KEY ='__SERVER_DATE'
|
54
|
+
|
55
|
+
LOCAL_PREFIX = "local::"
|
56
|
+
SERVER_PREFIX = "server::"
|
57
|
+
|
58
|
+
class LocalDB
|
59
|
+
def initialize( basepath = "/tmp/")
|
60
|
+
@mutex = MutexSingleton.instance.mutex
|
61
|
+
@basepath = basepath
|
62
|
+
end
|
63
|
+
|
64
|
+
def open( username, reader = false )
|
65
|
+
closed = false
|
66
|
+
(60*2).times { |n|
|
67
|
+
@mutex.synchronize {
|
68
|
+
if reader
|
69
|
+
@db = GDBM.new( @basepath + username + ".db", nil, GDBM::READER | GDBM::NOLOCK )
|
70
|
+
else
|
71
|
+
@db = GDBM.new( @basepath + username + ".db", nil, GDBM::WRCREAT )
|
72
|
+
end
|
73
|
+
closed = @db.closed?
|
74
|
+
}
|
75
|
+
break unless closed
|
76
|
+
#STDERR.puts "#Warning: DB open fail(locked) retry..."
|
77
|
+
sleep 0.5
|
78
|
+
}
|
79
|
+
@mutex.synchronize {
|
80
|
+
closed = @db.closed?
|
81
|
+
}
|
82
|
+
if closed
|
83
|
+
raise RuntimeError, sprintf( "DBM.new open error: file=%s", username + ".db" )
|
84
|
+
end
|
85
|
+
@username = username
|
86
|
+
end
|
87
|
+
|
88
|
+
def getList( limit = nil )
|
89
|
+
arr = self._getList().reject{|x| x.match( /^_/ )}
|
90
|
+
if limit
|
91
|
+
arr.take( limit )
|
92
|
+
else
|
93
|
+
arr
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def _getList( )
|
98
|
+
forward_match_keys( LOCAL_PREFIX ).sort {|a,b| -(a <=> b) }.map {|x|
|
99
|
+
x[(LOCAL_PREFIX.size)...(x.size)]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def getServerList( )
|
104
|
+
self._getServerList().reject{|x| x.match( /^_/ )}
|
105
|
+
end
|
106
|
+
|
107
|
+
def _getServerList( )
|
108
|
+
forward_match_keys( SERVER_PREFIX ).sort {|a,b| -(a <=> b) }.map {|x|
|
109
|
+
x[(SERVER_PREFIX.size)...(x.size)]
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def getValue( key, fallback = false )
|
114
|
+
val = nil
|
115
|
+
@mutex.synchronize {
|
116
|
+
val = @db[ LOCAL_PREFIX + key ]
|
117
|
+
}
|
118
|
+
if val
|
119
|
+
val.force_encoding("UTF-8")
|
120
|
+
else
|
121
|
+
fallback
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def insertValue( key, value )
|
126
|
+
@mutex.synchronize {
|
127
|
+
@db[ LOCAL_PREFIX + key.force_encoding("ASCII-8BIT") ] = value.force_encoding("ASCII-8BIT")
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def deleteValue( key )
|
132
|
+
ret = false
|
133
|
+
@mutex.synchronize {
|
134
|
+
val = @db[ LOCAL_PREFIX + key ]
|
135
|
+
if val
|
136
|
+
@db.delete( LOCAL_PREFIX + key )
|
137
|
+
ret = true
|
138
|
+
else
|
139
|
+
ret = false
|
140
|
+
end
|
141
|
+
}
|
142
|
+
ret
|
143
|
+
end
|
144
|
+
|
145
|
+
def setServerFlag( key )
|
146
|
+
@mutex.synchronize {
|
147
|
+
@db[ SERVER_PREFIX + key ] = '1'
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def onServer?( key )
|
152
|
+
ret = false
|
153
|
+
@mutex.synchronize {
|
154
|
+
if @db[ SERVER_PREFIX + key ]
|
155
|
+
ret = true
|
156
|
+
else
|
157
|
+
ret = false
|
158
|
+
end
|
159
|
+
}
|
160
|
+
ret
|
161
|
+
end
|
162
|
+
|
163
|
+
def forward_match_keys( prefix )
|
164
|
+
keys = []
|
165
|
+
@mutex.synchronize {
|
166
|
+
keys = @db.keys( ).select {|key|
|
167
|
+
key.match( "^" + prefix )
|
168
|
+
}
|
169
|
+
}
|
170
|
+
keys
|
171
|
+
end
|
172
|
+
|
173
|
+
def clear
|
174
|
+
@mutex.synchronize {
|
175
|
+
@db.clear
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def close
|
180
|
+
ret = nil
|
181
|
+
@mutex.synchronize {
|
182
|
+
ret = @db.close
|
183
|
+
}
|
184
|
+
ret
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
data/lib/pastehub/log.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#
|
2
|
+
# log.rb - PasteHub's log manager
|
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
|
+
class LogBase
|
37
|
+
def initialize( hash )
|
38
|
+
@user = nil
|
39
|
+
if hash.is_a? Hash
|
40
|
+
if hash.has_key?( :user )
|
41
|
+
@user = hash[ :user ]
|
42
|
+
else
|
43
|
+
@user = 'UNSPECIFIED'
|
44
|
+
end
|
45
|
+
if hash.has_key?( :api )
|
46
|
+
@api = hash[ :api ]
|
47
|
+
else
|
48
|
+
raise ArgumentError if not @api
|
49
|
+
end
|
50
|
+
else
|
51
|
+
raise ArgumentError
|
52
|
+
end
|
53
|
+
|
54
|
+
@uri = URI.parse( "http://localhost:9880/pastehub.webapi" )
|
55
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
56
|
+
#Fluent::Logger::FluentLogger.open(nil, :host=>'localhost', :port=>24224)
|
57
|
+
end
|
58
|
+
|
59
|
+
def write( hashData )
|
60
|
+
begin
|
61
|
+
jsonStr = hashData.to_json
|
62
|
+
resp = @http.post( @uri.request_uri, "json=" + jsonStr )
|
63
|
+
if "200" != resp.code
|
64
|
+
STDERR.print "Error: can't post to fluentd(http)[1].\n"
|
65
|
+
end
|
66
|
+
rescue
|
67
|
+
STDERR.print "Error: can't post to fluentd(http)[2].\n"
|
68
|
+
end
|
69
|
+
#Fluent::Logger.post("pastehub.webapi", hashData)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Log < LogBase
|
75
|
+
# info without error
|
76
|
+
def info( message, moreHash = {} )
|
77
|
+
hashData = {
|
78
|
+
"user"=>"#{@user}",
|
79
|
+
"api"=>"#{@api}",
|
80
|
+
"message"=>"#{message}",
|
81
|
+
"error" => false}
|
82
|
+
write( hashData.merge( moreHash ) )
|
83
|
+
end
|
84
|
+
|
85
|
+
# errors
|
86
|
+
def error( message, moreHash = {} )
|
87
|
+
hashData = {
|
88
|
+
"user"=>"#{@user}",
|
89
|
+
"api"=>"#{@api}",
|
90
|
+
"message"=>"#{message}",
|
91
|
+
"error" => true}
|
92
|
+
write( hashData.merge( moreHash ) )
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# macosx.rb - PasteHub's clipboard sync thread for MacOS X
|
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 MacOSX
|
38
|
+
|
39
|
+
def self.push( data )
|
40
|
+
pbcopy = "/usr/bin/pbcopy"
|
41
|
+
if File.exist?( pbcopy )
|
42
|
+
begin
|
43
|
+
IO.popen(pbcopy, "r+") {|io|
|
44
|
+
io.write data
|
45
|
+
io.close
|
46
|
+
}
|
47
|
+
STDERR.puts "Info: push to MacOS X clipboard."
|
48
|
+
rescue IOError => e
|
49
|
+
STDERR.puts( "Error: program #{pbcopy} not found." )
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.hasNew?( username )
|
56
|
+
osxPaste = open( "|/usr/bin/pbpaste" ) { |f|
|
57
|
+
f.read
|
58
|
+
}
|
59
|
+
if 0 < osxPaste.size
|
60
|
+
osxPaste
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
#
|
2
|
+
# masterdb.rb - PasteHub's master database manager
|
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 'dynamoid'
|
35
|
+
require 'date'
|
36
|
+
|
37
|
+
module PasteHub
|
38
|
+
|
39
|
+
# fake DynamoDB on localhost
|
40
|
+
Dynamoid.configure do |conf|
|
41
|
+
config = PasteHub::Config.instance
|
42
|
+
conf.adapter = 'aws_sdk'
|
43
|
+
conf.namespace = config.domain # To namespace tables created by Dynamoid from other tables you might have.
|
44
|
+
conf.warn_on_scan = config.awsWarn # Output a warning to the logger when you perform a scan rather than a query on a table.
|
45
|
+
conf.partitioning = false # Spread writes randomly across the database. See "partitioning" below for more.
|
46
|
+
conf.partition_size = 1 # Determine the key space size that writes are randomly spread across.
|
47
|
+
conf.read_capacity = 1 # Read capacity for your tables
|
48
|
+
conf.write_capacity = 1 # Write capacity for your tables
|
49
|
+
conf.access_key = config.dynamoAccessKey # If connecting to DynamoDB, your access key is required.
|
50
|
+
conf.secret_key = config.dynamoSecretKey # So is your secret key.
|
51
|
+
conf.endpoint = config.dynamoEp # Set the regional endpoint
|
52
|
+
conf.port = '443' # Use real dynamo
|
53
|
+
if not config.aws
|
54
|
+
conf.endpoint = 'localhost' # Set the regional endpoint
|
55
|
+
conf.use_ssl = false # Don't use SSL
|
56
|
+
conf.port = '4567' # Use fake_dynamo
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class User
|
61
|
+
include Dynamoid::Document
|
62
|
+
|
63
|
+
table :name => :users, :key => :username
|
64
|
+
|
65
|
+
field :username
|
66
|
+
field :secretKey
|
67
|
+
field :created_datetime, :datetime
|
68
|
+
field :touched_datetime, :datetime
|
69
|
+
#field :friends, :set
|
70
|
+
|
71
|
+
# index :username
|
72
|
+
|
73
|
+
validates_presence_of :username
|
74
|
+
validates_presence_of :secretKey
|
75
|
+
end
|
76
|
+
|
77
|
+
class Entry
|
78
|
+
include Dynamoid::Document
|
79
|
+
|
80
|
+
table :name => :entries, :key => :userkey
|
81
|
+
|
82
|
+
field :userkey
|
83
|
+
field :username
|
84
|
+
# field :comment
|
85
|
+
# field :from
|
86
|
+
# field :to
|
87
|
+
# field :cc
|
88
|
+
# field :type
|
89
|
+
field :data
|
90
|
+
|
91
|
+
index [:username]
|
92
|
+
|
93
|
+
validates_presence_of :userkey
|
94
|
+
# validates_presence_of :data
|
95
|
+
|
96
|
+
def id
|
97
|
+
userkey
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
class Users
|
103
|
+
def addUser( username, secretKey )
|
104
|
+
user = User.new( :username => username, :secretKey => secretKey, :created_datetime => DateTime.new())
|
105
|
+
user.save
|
106
|
+
end
|
107
|
+
|
108
|
+
def updateSecretKey( username, secretKey )
|
109
|
+
arr = User.where( :username => username ).all
|
110
|
+
if 0 < arr.size
|
111
|
+
arr.first.secretKey = secretKey
|
112
|
+
arr.first.save
|
113
|
+
true
|
114
|
+
else
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def getSecretKey( username )
|
120
|
+
arr = User.where( :username => username ).all
|
121
|
+
if 0 < arr.size
|
122
|
+
arr.first.secretKey
|
123
|
+
else
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def touch( username )
|
129
|
+
arr = User.where( :username => username ).all
|
130
|
+
if 0 < arr.size
|
131
|
+
arr.first.touched_datetime = DateTime.new()
|
132
|
+
arr.first.save
|
133
|
+
true
|
134
|
+
else
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def getList()
|
140
|
+
arr = User.all
|
141
|
+
arr.map { |x| x.username }.sort
|
142
|
+
end
|
143
|
+
|
144
|
+
def __deleteUser( username )
|
145
|
+
user = User.find( username )
|
146
|
+
if user
|
147
|
+
user.delete
|
148
|
+
true
|
149
|
+
else
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
class Entries
|
158
|
+
def initialize( username )
|
159
|
+
@holdUsername = username
|
160
|
+
end
|
161
|
+
|
162
|
+
def getList( limit = nil )
|
163
|
+
arr = Entry.where( :username => @holdUsername ).map {|x|
|
164
|
+
# remove username from `userkey'
|
165
|
+
field = x.userkey.split( /::/ )
|
166
|
+
field[1]
|
167
|
+
}.sort {|a,b| -(a <=> b) }
|
168
|
+
if limit
|
169
|
+
arr.take( limit )
|
170
|
+
else
|
171
|
+
arr
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def getValue( key, fallback = false )
|
176
|
+
p "username=#{@holdUsername}"
|
177
|
+
p "key=#{key}"
|
178
|
+
entry = Entry.find( @holdUsername + "::" + key, :consistent_read => true )
|
179
|
+
if entry
|
180
|
+
if entry.data
|
181
|
+
entry.data.force_encoding("UTF-8")
|
182
|
+
end
|
183
|
+
else
|
184
|
+
fallback
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def insertValue( key, value )
|
189
|
+
entry = Entry.new( :username => @holdUsername,
|
190
|
+
:userkey => @holdUsername + "::" + key,
|
191
|
+
:data => value.force_encoding("UTF-8") )
|
192
|
+
entry.save
|
193
|
+
end
|
194
|
+
|
195
|
+
def deleteLast( )
|
196
|
+
arr = getList( )
|
197
|
+
if 0 < arr.size
|
198
|
+
deleteValue( arr[arr.size-1] )
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def deleteValue( key )
|
203
|
+
# caution: This method is non consistent read.
|
204
|
+
entry = Entry.find( @holdUsername + "::" + key )
|
205
|
+
if entry
|
206
|
+
entry.delete
|
207
|
+
true
|
208
|
+
else
|
209
|
+
false
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|