boned 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +5 -0
- data/LICENSE.txt +19 -0
- data/README.md +32 -0
- data/Rakefile +55 -0
- data/bin/boned +72 -0
- data/boned.gemspec +45 -0
- data/config/redis-default.yml +14 -0
- data/config/redis-server-default.conf +171 -0
- data/config/stella/api-set.rb +32 -0
- data/config/stella/api.rb +51 -0
- data/lib/boned/api/debug.rb +21 -0
- data/lib/boned/api/redis.rb +44 -0
- data/lib/boned/api/service.rb +86 -0
- data/lib/boned/api.rb +98 -0
- data/lib/boned/cli.rb +58 -0
- data/lib/boned/models/bone.rb +113 -0
- data/lib/boned/models.rb +34 -0
- data/lib/boned/server.rb +67 -0
- data/lib/boned.rb +139 -0
- data/public/index.html +4 -0
- data/try/10_bone_model.rb +21 -0
- data/views/redisviewer/keys.erb +12 -0
- metadata +82 -0
data/CHANGES.txt
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Solutious Inc, Delano Mandelbaum
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
## Bone - 0.2 ##
|
2
|
+
|
3
|
+
**Bones it!**
|
4
|
+
|
5
|
+
|
6
|
+
== Running
|
7
|
+
|
8
|
+
$ redis-server config/redis-server.conf
|
9
|
+
$ boned start
|
10
|
+
|
11
|
+
|
12
|
+
== Installation
|
13
|
+
|
14
|
+
$ sudo gem install boned
|
15
|
+
|
16
|
+
|
17
|
+
== More Information
|
18
|
+
|
19
|
+
|
20
|
+
== Credits
|
21
|
+
|
22
|
+
* Delano Mandelbaum (http://solutious.com)
|
23
|
+
|
24
|
+
|
25
|
+
== Thanks
|
26
|
+
|
27
|
+
* Kalin Harvey for the early feedback.
|
28
|
+
|
29
|
+
|
30
|
+
== License
|
31
|
+
|
32
|
+
See LICENSE.txt
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'hanna/rdoctask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'shoulda/tasks'
|
7
|
+
require 'rake/runtest'
|
8
|
+
require 'fileutils'
|
9
|
+
include FileUtils
|
10
|
+
|
11
|
+
task :default => :test
|
12
|
+
|
13
|
+
|
14
|
+
# PACKAGE =============================================================
|
15
|
+
|
16
|
+
name = "boned"
|
17
|
+
load "#{name}.gemspec"
|
18
|
+
|
19
|
+
version = @spec.version
|
20
|
+
|
21
|
+
Rake::GemPackageTask.new(@spec) do |p|
|
22
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
23
|
+
end
|
24
|
+
|
25
|
+
task :test do
|
26
|
+
puts "Success!"
|
27
|
+
end
|
28
|
+
|
29
|
+
task :install => [ :rdoc, :package ] do
|
30
|
+
sh %{sudo gem install pkg/#{name}-#{version}.gem}
|
31
|
+
end
|
32
|
+
|
33
|
+
task :uninstall => [ :clean ] do
|
34
|
+
sh %{sudo gem uninstall #{name}}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
Rake::RDocTask.new do |t|
|
40
|
+
t.rdoc_dir = 'doc'
|
41
|
+
t.title = @spec.summary
|
42
|
+
t.options << '--line-numbers' << '-A cattr_accessor=object'
|
43
|
+
t.options << '--charset' << 'utf-8'
|
44
|
+
t.rdoc_files.include('LICENSE.txt')
|
45
|
+
t.rdoc_files.include('README.md')
|
46
|
+
t.rdoc_files.include('CHANGES.txt')
|
47
|
+
#t.rdoc_files.include('Rudyfile') # why is the formatting f'd?
|
48
|
+
t.rdoc_files.include('bin/*')
|
49
|
+
t.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
51
|
+
|
52
|
+
CLEAN.include [ 'pkg', '*.gem', '.config', 'doc', 'coverage*' ]
|
53
|
+
|
54
|
+
|
55
|
+
|
data/bin/boned
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# = Boned
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# $ boned -h
|
9
|
+
# $ boned [-d] start-master
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
|
13
|
+
# Put our local lib in first place
|
14
|
+
BASE_PATH = File.expand_path File.join(File.dirname(__FILE__), '..')
|
15
|
+
lib_dir = File.join(BASE_PATH, 'lib')
|
16
|
+
$:.unshift lib_dir
|
17
|
+
#$:.unshift '/Users/delano/Projects/opensource/drydock/lib'
|
18
|
+
|
19
|
+
require 'drydock'
|
20
|
+
require 'boned'
|
21
|
+
require 'boned/cli'
|
22
|
+
|
23
|
+
# Command-line interface for bin/stella
|
24
|
+
class Boned::CLI::Definition
|
25
|
+
extend Drydock
|
26
|
+
|
27
|
+
debug :off
|
28
|
+
|
29
|
+
default :info
|
30
|
+
|
31
|
+
global :V, :version, "Display version" do
|
32
|
+
puts "Boned: #{Boned::VERSION} (api: #{Boned::APIVERSION})"
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
global :R, :rackup, String, "Specify a rackup file"
|
37
|
+
global :e, :environment, String, "Rack environment"
|
38
|
+
global :v, :verbose, "Increase output" do; 1 end
|
39
|
+
global :d, :daemon, "Run as a daemon"
|
40
|
+
global :p, :port, Integer, "Port to run on"
|
41
|
+
global :D, :debug do
|
42
|
+
Drydock.debug true
|
43
|
+
Boned.enable_debug
|
44
|
+
end
|
45
|
+
|
46
|
+
command :start => Boned::CLI
|
47
|
+
command :stop => Boned::CLI
|
48
|
+
command :info => Boned::CLI
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
begin
|
54
|
+
Drydock.run!(ARGV, STDIN) if Drydock.run? && !Drydock.has_run?
|
55
|
+
rescue Boned::Problem => ex
|
56
|
+
STDERR.puts ex.message
|
57
|
+
STDERR.puts ex.backtrace if Drydock.debug?
|
58
|
+
exit 1
|
59
|
+
rescue Drydock::ArgError, Drydock::OptError => ex
|
60
|
+
STDERR.puts ex.message
|
61
|
+
STDERR.puts ex.usage
|
62
|
+
rescue Drydock::InvalidArgument => ex
|
63
|
+
STDERR.puts ex.message
|
64
|
+
rescue Drydock::UnknownCommand => ex
|
65
|
+
STDERR.puts "Unknown command: %s" % ex.name
|
66
|
+
rescue Interrupt
|
67
|
+
puts $/, "Exiting... "
|
68
|
+
exit 1
|
69
|
+
rescue => ex
|
70
|
+
STDERR.puts "ERROR (#{ex.class.to_s}): #{ex.message}"
|
71
|
+
STDERR.puts ex.backtrace if Drydock.debug?
|
72
|
+
end
|
data/boned.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
@spec = Gem::Specification.new do |s|
|
2
|
+
s.name = "boned"
|
3
|
+
s.rubyforge_project = 'boned'
|
4
|
+
s.version = "0.2.0"
|
5
|
+
s.summary = "Get Bones"
|
6
|
+
s.description = s.summary
|
7
|
+
s.author = "Delano Mandelbaum"
|
8
|
+
s.email = "delano@solutious.com"
|
9
|
+
s.homepage = ""
|
10
|
+
|
11
|
+
s.extra_rdoc_files = %w[README.md LICENSE.txt CHANGES.txt]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
|
14
|
+
s.require_paths = %w[lib]
|
15
|
+
|
16
|
+
s.executables = %w[boned]
|
17
|
+
|
18
|
+
# = MANIFEST =
|
19
|
+
# git ls-files
|
20
|
+
s.files = %w(
|
21
|
+
LICENSE.txt
|
22
|
+
README.md
|
23
|
+
Rakefile
|
24
|
+
bin/boned
|
25
|
+
boned.gemspec
|
26
|
+
config/redis-default.yml
|
27
|
+
config/redis-server-default.conf
|
28
|
+
config/stella/api-set.rb
|
29
|
+
config/stella/api.rb
|
30
|
+
lib/boned.rb
|
31
|
+
lib/boned/api.rb
|
32
|
+
lib/boned/api/debug.rb
|
33
|
+
lib/boned/api/redis.rb
|
34
|
+
lib/boned/api/service.rb
|
35
|
+
lib/boned/cli.rb
|
36
|
+
lib/boned/models.rb
|
37
|
+
lib/boned/models/bone.rb
|
38
|
+
lib/boned/server.rb
|
39
|
+
public/index.html
|
40
|
+
try/10_bone_model.rb
|
41
|
+
views/redisviewer/keys.erb
|
42
|
+
)
|
43
|
+
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
:development:
|
2
|
+
# :password: e89da64b29cf622e7c0fa545b537d7
|
3
|
+
:host: localhost
|
4
|
+
:port: "6379"
|
5
|
+
:db: 1
|
6
|
+
:timeout: 5
|
7
|
+
:thread_safe: true
|
8
|
+
:production:
|
9
|
+
# :password: e89da64b29cf622e7c0fa545b537d7
|
10
|
+
:host: localhost
|
11
|
+
:port: "6379"
|
12
|
+
:db: 0
|
13
|
+
:timeout: 5
|
14
|
+
:thread_safe: true
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# Redis configuration file example
|
2
|
+
|
3
|
+
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
4
|
+
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
5
|
+
daemonize no
|
6
|
+
|
7
|
+
# When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
|
8
|
+
# You can specify a custom pid file location here.
|
9
|
+
pidfile /var/run/redis.pid
|
10
|
+
|
11
|
+
# Accept connections on the specified port, default is 6379
|
12
|
+
port 6379
|
13
|
+
|
14
|
+
# If you want you can bind a single interface, if the bind option is not
|
15
|
+
# specified all the interfaces will listen for connections.
|
16
|
+
#
|
17
|
+
# bind 127.0.0.1
|
18
|
+
|
19
|
+
# Close the connection after a client is idle for N seconds (0 to disable)
|
20
|
+
timeout 300
|
21
|
+
|
22
|
+
# Save the DB on disk:
|
23
|
+
#
|
24
|
+
# save <seconds> <changes>
|
25
|
+
#
|
26
|
+
# Will save the DB if both the given number of seconds and the given
|
27
|
+
# number of write operations against the DB occurred.
|
28
|
+
#
|
29
|
+
# In the example below the behaviour will be to save:
|
30
|
+
# after 900 sec (15 min) if at least 1 key changed
|
31
|
+
# after 300 sec (5 min) if at least 10 keys changed
|
32
|
+
# after 60 sec if at least 10000 keys changed
|
33
|
+
save 900 1
|
34
|
+
save 300 10
|
35
|
+
save 60 10000
|
36
|
+
|
37
|
+
# The filename where to dump the DB
|
38
|
+
dbfilename dump.rdb
|
39
|
+
|
40
|
+
# For default save/load DB in/from the working directory
|
41
|
+
# Note that you must specify a directory not a file name.
|
42
|
+
dir ./
|
43
|
+
|
44
|
+
# Set server verbosity to 'debug'
|
45
|
+
# it can be one of:
|
46
|
+
# debug (a lot of information, useful for development/testing)
|
47
|
+
# notice (moderately verbose, what you want in production probably)
|
48
|
+
# warning (only very important / critical messages are logged)
|
49
|
+
loglevel debug
|
50
|
+
|
51
|
+
# Specify the log file name. Also 'stdout' can be used to force
|
52
|
+
# the demon to log on the standard output. Note that if you use standard
|
53
|
+
# output for logging but daemonize, logs will be sent to /dev/null
|
54
|
+
logfile stdout
|
55
|
+
|
56
|
+
# Set the number of databases. The default database is DB 0, you can select
|
57
|
+
# a different one on a per-connection basis using SELECT <dbid> where
|
58
|
+
# dbid is a number between 0 and 'databases'-1
|
59
|
+
databases 16
|
60
|
+
|
61
|
+
################################# REPLICATION #################################
|
62
|
+
|
63
|
+
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
|
64
|
+
# another Redis server. Note that the configuration is local to the slave
|
65
|
+
# so for example it is possible to configure the slave to save the DB with a
|
66
|
+
# different interval, or to listen to another port, and so on.
|
67
|
+
|
68
|
+
# slaveof <masterip> <masterport>
|
69
|
+
|
70
|
+
################################## SECURITY ###################################
|
71
|
+
|
72
|
+
# Require clients to issue AUTH <PASSWORD> before processing any other
|
73
|
+
# commands. This might be useful in environments in which you do not trust
|
74
|
+
# others with access to the host running redis-server.
|
75
|
+
#
|
76
|
+
# This should stay commented out for backward compatibility and because most
|
77
|
+
# people do not need auth (e.g. they run their own servers).
|
78
|
+
|
79
|
+
# requirepass foobared
|
80
|
+
|
81
|
+
################################### LIMITS ####################################
|
82
|
+
|
83
|
+
# Set the max number of connected clients at the same time. By default there
|
84
|
+
# is no limit, and it's up to the number of file descriptors the Redis process
|
85
|
+
# is able to open. The special value '0' means no limts.
|
86
|
+
# Once the limit is reached Redis will close all the new connections sending
|
87
|
+
# an error 'max number of clients reached'.
|
88
|
+
|
89
|
+
# maxclients 128
|
90
|
+
|
91
|
+
# Don't use more memory than the specified amount of bytes.
|
92
|
+
# When the memory limit is reached Redis will try to remove keys with an
|
93
|
+
# EXPIRE set. It will try to start freeing keys that are going to expire
|
94
|
+
# in little time and preserve keys with a longer time to live.
|
95
|
+
# Redis will also try to remove objects from free lists if possible.
|
96
|
+
#
|
97
|
+
# If all this fails, Redis will start to reply with errors to commands
|
98
|
+
# that will use more memory, like SET, LPUSH, and so on, and will continue
|
99
|
+
# to reply to most read-only commands like GET.
|
100
|
+
#
|
101
|
+
# WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
|
102
|
+
# 'state' server or cache, not as a real DB. When Redis is used as a real
|
103
|
+
# database the memory usage will grow over the weeks, it will be obvious if
|
104
|
+
# it is going to use too much memory in the long run, and you'll have the time
|
105
|
+
# to upgrade. With maxmemory after the limit is reached you'll start to get
|
106
|
+
# errors for write operations, and this may even lead to DB inconsistency.
|
107
|
+
|
108
|
+
# maxmemory <bytes>
|
109
|
+
|
110
|
+
############################## APPEND ONLY MODE ###############################
|
111
|
+
|
112
|
+
# By default Redis asynchronously dumps the dataset on disk. If you can live
|
113
|
+
# with the idea that the latest records will be lost if something like a crash
|
114
|
+
# happens this is the preferred way to run Redis. If instead you care a lot
|
115
|
+
# about your data and don't want to that a single record can get lost you should
|
116
|
+
# enable the append only mode: when this mode is enabled Redis will append
|
117
|
+
# every write operation received in the file appendonly.log. This file will
|
118
|
+
# be read on startup in order to rebuild the full dataset in memory.
|
119
|
+
#
|
120
|
+
# Note that you can have both the async dumps and the append only file if you
|
121
|
+
# like (you have to comment the "save" statements above to disable the dumps).
|
122
|
+
# Still if append only mode is enabled Redis will load the data from the
|
123
|
+
# log file at startup ignoring the dump.rdb file.
|
124
|
+
#
|
125
|
+
# The name of the append only file is "appendonly.log"
|
126
|
+
|
127
|
+
appendonly no
|
128
|
+
|
129
|
+
# The fsync() call tells the Operating System to actually write data on disk
|
130
|
+
# instead to wait for more data in the output buffer. Some OS will really flush
|
131
|
+
# data on disk, some other OS will just try to do it ASAP.
|
132
|
+
#
|
133
|
+
# Redis supports three different modes:
|
134
|
+
#
|
135
|
+
# no: don't fsync, just let the OS flush the data when it wants. Faster.
|
136
|
+
# always: fsync after every write to the append only log . Slow, Safest.
|
137
|
+
# everysec: fsync only if one second passed since the last fsync. Compromise.
|
138
|
+
#
|
139
|
+
# The default is "always" that's the safer of the options. It's up to you to
|
140
|
+
# understand if you can relax this to "everysec" that will fsync every second
|
141
|
+
# or to "no" that will let the operating system flush the output buffer when
|
142
|
+
# it want, for better performances (but if you can live with the idea of
|
143
|
+
# some data loss consider the default persistence mode that's snapshotting).
|
144
|
+
|
145
|
+
appendfsync always
|
146
|
+
# appendfsync everysec
|
147
|
+
# appendfsync no
|
148
|
+
|
149
|
+
############################### ADVANCED CONFIG ###############################
|
150
|
+
|
151
|
+
# Glue small output buffers together in order to send small replies in a
|
152
|
+
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
153
|
+
# in terms of number of queries per second. Use 'yes' if unsure.
|
154
|
+
glueoutputbuf yes
|
155
|
+
|
156
|
+
# Use object sharing. Can save a lot of memory if you have many common
|
157
|
+
# string in your dataset, but performs lookups against the shared objects
|
158
|
+
# pool so it uses more CPU and can be a bit slower. Usually it's a good
|
159
|
+
# idea.
|
160
|
+
#
|
161
|
+
# When object sharing is enabled (shareobjects yes) you can use
|
162
|
+
# shareobjectspoolsize to control the size of the pool used in order to try
|
163
|
+
# object sharing. A bigger pool size will lead to better sharing capabilities.
|
164
|
+
# In general you want this value to be at least the double of the number of
|
165
|
+
# very common strings you have in your dataset.
|
166
|
+
#
|
167
|
+
# WARNING: object sharing is experimental, don't enable this feature
|
168
|
+
# in production before of Redis 1.0-stable. Still please try this feature in
|
169
|
+
# your development environment so that we can test it better.
|
170
|
+
shareobjects no
|
171
|
+
shareobjectspoolsize 1024
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
usecase "Set" do
|
4
|
+
set :key => :simple
|
5
|
+
set :token => '1901484c41b8752d61863e323c743abe2c6e90f8841bbdfa789e1d70bc6f4899'
|
6
|
+
|
7
|
+
get "/v1/set/:key" do
|
8
|
+
set :value => (rand*100000).to_i
|
9
|
+
param :token => resource(:token)
|
10
|
+
param :value => resource(:value)
|
11
|
+
end
|
12
|
+
|
13
|
+
get "/v1/get/:key" do
|
14
|
+
param :token => resource(:token)
|
15
|
+
response 200 do
|
16
|
+
p [resource(:value), body.to_i]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
get "/v1/set/:key" do
|
21
|
+
param :key => rand(1000).to_i
|
22
|
+
set :value => (rand*100000).to_i
|
23
|
+
param :token => resource(:token)
|
24
|
+
param :value => resource(:value)
|
25
|
+
end
|
26
|
+
|
27
|
+
xpost "/v1/set/:key" do
|
28
|
+
param :key => :file
|
29
|
+
body file('/tmp/file')
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
usecase do
|
4
|
+
set :token => '1901484c41b8752d61863e323c743abe2c6e90f8841bbdfa789e1d70bc6f4899'
|
5
|
+
set :key => :simple
|
6
|
+
|
7
|
+
post "/v1/set/:key" do
|
8
|
+
set :value => (rand*100000).to_i
|
9
|
+
param :token => resource(:token)
|
10
|
+
param :value => resource(:value)
|
11
|
+
end
|
12
|
+
|
13
|
+
get "/v1/get/:key" do
|
14
|
+
param :token => resource(:token)
|
15
|
+
response 200 do
|
16
|
+
p [resource(:value), body.to_i]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
post "/v1/set/:key" do
|
21
|
+
param :key => 'rand(1000).to_i'
|
22
|
+
set :value => (rand*100000).to_i
|
23
|
+
param :token => resource(:token)
|
24
|
+
param :value => resource(:value)
|
25
|
+
end
|
26
|
+
|
27
|
+
xpost "/v1/set/:key" do
|
28
|
+
param :key => :file
|
29
|
+
body file('/tmp/file')
|
30
|
+
end
|
31
|
+
|
32
|
+
get "/v1/keys/:key" do
|
33
|
+
param :token => resource(:token)
|
34
|
+
end
|
35
|
+
|
36
|
+
get "/v1/keys" do
|
37
|
+
param :token => resource(:token)
|
38
|
+
end
|
39
|
+
|
40
|
+
delete "/v1/del/:key" do
|
41
|
+
header :'X-BONE-TOKEN' => resource(:token)
|
42
|
+
end
|
43
|
+
|
44
|
+
get "/v1/get/:key" do
|
45
|
+
param :token => resource(:token)
|
46
|
+
response 404 do
|
47
|
+
# This is the correct response so don't fail
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
class Boned::API::Debug < Boned::API
|
3
|
+
set :public => 'public/debug/'
|
4
|
+
set :views => 'views/debug/'
|
5
|
+
|
6
|
+
not_found do
|
7
|
+
'not found'
|
8
|
+
end
|
9
|
+
|
10
|
+
get '/env/?' do
|
11
|
+
content_type 'text/plain'
|
12
|
+
env.to_yaml
|
13
|
+
end
|
14
|
+
|
15
|
+
get '/slideshow' do
|
16
|
+
content_type 'text/html'
|
17
|
+
erb :slideshow
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Boned::API::RedisViewer < Boned::API
|
4
|
+
|
5
|
+
set :public => 'public/'
|
6
|
+
set :views => 'views/redisviewer/'
|
7
|
+
|
8
|
+
before do
|
9
|
+
content_type 'text/html'
|
10
|
+
end
|
11
|
+
|
12
|
+
get '/list/:name' do
|
13
|
+
Boned.redis.lrange(params[:name], 0, -1).to_yaml
|
14
|
+
end
|
15
|
+
|
16
|
+
get '/smembers/:name' do
|
17
|
+
Boned.redis.smembers(params[:name]).to_yaml
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/opts' do
|
21
|
+
Boned.redis_opts.to_yaml
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/get/:name' do
|
25
|
+
'%s=%s' % [params[:name], Boned.redis.get(params[:name])]
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/:key' do
|
29
|
+
@keys = Boned.redis.keys("*#{params[:key]}*")
|
30
|
+
erb :keys
|
31
|
+
end
|
32
|
+
|
33
|
+
get '/?' do
|
34
|
+
@keys = Boned.redis.keys("*")
|
35
|
+
erb :keys
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
helpers do
|
40
|
+
def key_kind(key)
|
41
|
+
Boned.redis.type key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
# /get/bashrc?path=/Users/delano/&env=development&role=fe&token=1901484c41b8752d61863e323c743abe2c6e90f8841bbdfa789e1d70bc6f4899
|
4
|
+
# /set/bashrc?value=1000&path=/Users/delano/&env=development&role=fe&token=1901484c41b8752d61863e323c743abe2c6e90f8841bbdfa789e1d70bc6f4899
|
5
|
+
#
|
6
|
+
class Boned::API::Service < Boned::API
|
7
|
+
set :public => 'public/'
|
8
|
+
set :views => 'views/'
|
9
|
+
|
10
|
+
error do
|
11
|
+
"Bad bone rising"
|
12
|
+
end
|
13
|
+
|
14
|
+
get '/' do
|
15
|
+
'Throw me a fricken bone'
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/rev/?' do
|
19
|
+
Boned::VERSION.inspect
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/get/:key/?' do
|
23
|
+
carefully do
|
24
|
+
assert_params :key
|
25
|
+
assert_exists current_token, "No token"
|
26
|
+
assert_sha256 current_token
|
27
|
+
bone = Bone.get current_token, params[:key], params
|
28
|
+
bone.value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
post '/set/:key/?' do
|
33
|
+
carefully do
|
34
|
+
assert_params :key, :value
|
35
|
+
assert_exists current_token, "No token"
|
36
|
+
assert_sha256 current_token
|
37
|
+
bone = Bone.new current_token, params[:key], params[:value], params
|
38
|
+
bone.save
|
39
|
+
end
|
40
|
+
params[:value]
|
41
|
+
end
|
42
|
+
|
43
|
+
delete "/del/:key/?" do
|
44
|
+
carefully do
|
45
|
+
assert_params :key
|
46
|
+
assert_exists current_token, "No token"
|
47
|
+
assert_sha256 current_token
|
48
|
+
bone = Bone.del current_token, params[:key], params
|
49
|
+
bone.value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
get '/keys/:key' do
|
54
|
+
carefully do
|
55
|
+
assert_params :key
|
56
|
+
assert_exists current_token, "No token"
|
57
|
+
assert_sha256 current_token
|
58
|
+
keys = Bone.keys current_token, params[:key]
|
59
|
+
keys.join($/)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
get '/keys/?' do
|
64
|
+
carefully do
|
65
|
+
assert_exists current_token, "No token"
|
66
|
+
assert_sha256 current_token
|
67
|
+
keys = Bone.keys current_token, '*'
|
68
|
+
keys.join($/)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#post '/set/:key/?' do
|
73
|
+
# carefully do
|
74
|
+
# assert_params :key
|
75
|
+
# assert_sha256 current_token
|
76
|
+
# #assert_exists current_token
|
77
|
+
# #key, filter, path = params.values_at :key, :filter, :path
|
78
|
+
# #Boned::Object.set current_token, key
|
79
|
+
# pp request
|
80
|
+
# pp env['rack.input'].read
|
81
|
+
# end
|
82
|
+
#end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
data/lib/boned/api.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
require 'boned'
|
3
|
+
|
4
|
+
|
5
|
+
class Boned::API < Sinatra::Base
|
6
|
+
|
7
|
+
set :public => 'public/'
|
8
|
+
set :views => 'views/'
|
9
|
+
set :static => true
|
10
|
+
|
11
|
+
before do
|
12
|
+
puts ENV['RACK_ENV']
|
13
|
+
end
|
14
|
+
|
15
|
+
configure :development do
|
16
|
+
before do
|
17
|
+
Boned.enable_debug
|
18
|
+
Boned.ld ' --> ' << env['REQUEST_URI']
|
19
|
+
content_type 'text/plain'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
configure :production do
|
24
|
+
Boned.disable_debug
|
25
|
+
before do
|
26
|
+
content_type 'application/json'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
helpers do
|
31
|
+
def carefully(ret='', &blk)
|
32
|
+
begin
|
33
|
+
ret = blk.call
|
34
|
+
rescue Boned::BadBone => ex
|
35
|
+
return error(404, ex.message)
|
36
|
+
rescue => ex
|
37
|
+
Boned.ld "#{current_token}:#{params[:key]}", ex.message
|
38
|
+
Boned.ld ex.backtrace
|
39
|
+
return error(400, "Bad bone rising")
|
40
|
+
end
|
41
|
+
ret
|
42
|
+
end
|
43
|
+
|
44
|
+
def current_token() @env['HTTP_X_BONE_TOKEN'] || params[:token] end
|
45
|
+
def current_sig() @env['HTTP_X_BONE_SIGNATURE'] || params[:sig] end
|
46
|
+
|
47
|
+
def uri(*path)
|
48
|
+
[root_path, path].flatten.join('/')
|
49
|
+
end
|
50
|
+
def root_path
|
51
|
+
env['SCRIPT_NAME']
|
52
|
+
end
|
53
|
+
|
54
|
+
# +names+ One or more a required parameter names (Symbol)
|
55
|
+
def assert_params(*names)
|
56
|
+
names.each do |n|
|
57
|
+
if params[n].nil? || params[n].empty?
|
58
|
+
return error(400, "Missing param: %s" % n)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
alias_method :assert_param, :assert_params
|
63
|
+
|
64
|
+
def assert_exists(val, msg)
|
65
|
+
return error(400, msg) if val.nil? ||
|
66
|
+
(val.respond_to?(:empty?) && val.empty?)
|
67
|
+
end
|
68
|
+
|
69
|
+
def assert_true(val, msg)
|
70
|
+
return error(400, msg) if val == true
|
71
|
+
end
|
72
|
+
|
73
|
+
def assert_sha1(val)
|
74
|
+
return error(400, "#{val} is not a sha1 digest") unless is_sha1?(val)
|
75
|
+
end
|
76
|
+
|
77
|
+
def assert_sha256(val)
|
78
|
+
return error(400, "#{val} is not a sha256 digest") unless is_sha256?(val)
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_sha1?(val)
|
82
|
+
val.match(/\A[0-9a-f]{40}\z/)
|
83
|
+
end
|
84
|
+
def is_sha256?(val)
|
85
|
+
val.match(/\A[0-9a-f]{64}\z/)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Boned::API::Stub < Boned::API
|
92
|
+
get '/' do
|
93
|
+
content_type 'text/plain'
|
94
|
+
"Do you want to get bones?"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
require 'boned/api/service'
|
data/lib/boned/cli.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'boned/server'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class Boned::CLI < Drydock::Command
|
5
|
+
attr_accessor :exit_code
|
6
|
+
|
7
|
+
def init
|
8
|
+
Boned.load_config Dir.pwd, :development
|
9
|
+
Boned.connect
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
if Boned.service_available?('127.0.0.1', server_opts[:port])
|
14
|
+
raise Boned::Server::ServerRunning, server_opts[:port]
|
15
|
+
end
|
16
|
+
Boned::Controllers::Controller.new(server_opts).start
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
if not Boned.service_available?('127.0.0.1', server_opts[:port])
|
21
|
+
raise Boned::Server::ServerNotRunning, server_opts[:port]
|
22
|
+
end
|
23
|
+
Boned::Controllers::Controller.new(server_opts).stop
|
24
|
+
end
|
25
|
+
|
26
|
+
def info
|
27
|
+
require 'yaml'
|
28
|
+
if Boned.service_available?('127.0.0.1', server_opts[:port])
|
29
|
+
puts "boned is running on port #{server_opts[:port]}"
|
30
|
+
else
|
31
|
+
puts "No boned"
|
32
|
+
end
|
33
|
+
puts "Options:", server_opts.to_yaml if @global.verbose > 0
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def server_opts
|
39
|
+
port = @global.port || Boned::Server::DEFAULT_PORT
|
40
|
+
config = @global.rackup || File.join(Dir.pwd, "config.ru")
|
41
|
+
@server_opts ||= {
|
42
|
+
:chdir => Dir.pwd,
|
43
|
+
:environment => @global.environment || 'development',
|
44
|
+
:address => '0.0.0.0',
|
45
|
+
:port => port,
|
46
|
+
:timeout => 30,
|
47
|
+
:log => "log/boned-#{port}.log",
|
48
|
+
:pid => "tmp/pids/boned-#{port}.pid",
|
49
|
+
:max_conns => Thin::Server::DEFAULT_MAXIMUM_CONNECTIONS,
|
50
|
+
:max_persistent_conns => Thin::Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS,
|
51
|
+
:require => [],
|
52
|
+
:wait => Thin::Controllers::Cluster::DEFAULT_WAIT_TIME,
|
53
|
+
:backend => "Boned::Server",
|
54
|
+
:rackup => config,
|
55
|
+
:daemonize => @global.daemon || false
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
# Bone:a462b9ebda71f16cb1567ba8704695ae8dba9999:simple
|
3
|
+
# Bone:a462b9ebda71f16cb1567ba8704695ae8dba9999:us-east-1a-dev-fe:simple
|
4
|
+
# Bone:a462b9ebda71f16cb1567ba8704695ae8dba9999:dev-fe:simple
|
5
|
+
# Bone:a462b9ebda71f16cb1567ba8704695ae8dba9999:us-east-1a:simple
|
6
|
+
|
7
|
+
class Bone < Boned::Model
|
8
|
+
|
9
|
+
primarykey :boneid
|
10
|
+
|
11
|
+
field :token
|
12
|
+
field :name
|
13
|
+
field :value
|
14
|
+
field :prop
|
15
|
+
|
16
|
+
def initialize(token, name, value, prop={})
|
17
|
+
@prop ||= {}
|
18
|
+
prop ||= {}
|
19
|
+
prop.each_pair { |n,v| @prop[n.to_sym] ||= v }
|
20
|
+
@token, @name = token, name
|
21
|
+
@new = refresh!.nil?
|
22
|
+
@value = value unless value.nil? # use the new value if provided
|
23
|
+
@prop[:created] = Time.now.utc.to_i if new? || @prop[:created].nil?
|
24
|
+
# resolve string/symbol ambiguity for properties
|
25
|
+
def @prop.[](k) super(k.to_s.to_sym) || super(k.to_s) end
|
26
|
+
def @prop.[]=(k,v) super(k.to_s.to_sym,v) end
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](k)
|
30
|
+
self.respond_to?(k) ? self.send : self.prop[k]
|
31
|
+
end
|
32
|
+
|
33
|
+
def new?() @new == true end
|
34
|
+
|
35
|
+
def file?
|
36
|
+
!prop[:file].nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def region() prop[:region] end
|
40
|
+
def env() prop[:env] end
|
41
|
+
def role() prop[:role] end
|
42
|
+
def num() prop[:num] end
|
43
|
+
def path() prop[:path] end
|
44
|
+
|
45
|
+
def boneid
|
46
|
+
loc = [region, env, role, num].compact.join('-')
|
47
|
+
parts = loc.empty? ? [token] : [token, loc]
|
48
|
+
parts << path.gsub(/\A\//, '').tr('/', '-') unless path.nil? # TODO: support windows
|
49
|
+
parts << name
|
50
|
+
parts.collect { |p| p.to_s.tr(':', '-') }.join(':')
|
51
|
+
end
|
52
|
+
|
53
|
+
def key(*parts)
|
54
|
+
parts.unshift boneid
|
55
|
+
self.class.key *parts
|
56
|
+
end
|
57
|
+
|
58
|
+
def save
|
59
|
+
redis.set(key, value)
|
60
|
+
prop[:modified] = Time.now.utc.to_i
|
61
|
+
redis.set(key(:prop), prop.to_json)
|
62
|
+
end
|
63
|
+
|
64
|
+
def refresh!
|
65
|
+
Boned.ld "REFRESH: #{key}"
|
66
|
+
@value = redis.get key
|
67
|
+
prop = redis.get key(:prop)
|
68
|
+
prop &&= JSON.parse(prop) rescue {}
|
69
|
+
# Merge the stored props with the current ones. Enforce symbols!
|
70
|
+
prop.each_pair { |n,v| @prop[n.to_sym] ||= v }
|
71
|
+
Boned.ld " -> #{@value} #{@prop.inspect}"
|
72
|
+
self
|
73
|
+
rescue
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def destroy!
|
78
|
+
Boned.ld "DESTROY: #{key}"
|
79
|
+
redis.del key
|
80
|
+
redis.del key(:prop)
|
81
|
+
end
|
82
|
+
|
83
|
+
class << self
|
84
|
+
|
85
|
+
def del(token, name, opts={})
|
86
|
+
bone = get(token, name, opts)
|
87
|
+
bone.destroy!
|
88
|
+
bone
|
89
|
+
end
|
90
|
+
|
91
|
+
def get(token, name, opts={})
|
92
|
+
bone = Bone.new token, name, nil, opts
|
93
|
+
raise Boned::BadBone, bone.name if bone.value.nil?
|
94
|
+
bone
|
95
|
+
end
|
96
|
+
|
97
|
+
def keys(token, k=nil, opts={})
|
98
|
+
search = key(token) << '*'
|
99
|
+
search << k unless k.nil?
|
100
|
+
Boned.ld "SEARCHING: #{search}"
|
101
|
+
dirty = redis.keys search # contains :prop when no keyname specified
|
102
|
+
clean = []
|
103
|
+
dirty.each { |k|
|
104
|
+
next if k.match(/prop\z/);
|
105
|
+
p k
|
106
|
+
clean << k.split(':')[4..-1].join(':')
|
107
|
+
}
|
108
|
+
clean
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
data/lib/boned/models.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Boned
|
4
|
+
class Model < Storable
|
5
|
+
def self.key(*el)
|
6
|
+
raise "#{self}: nil keypart: #{el.inspect}" if el.size != el.compact.size
|
7
|
+
a = "v1::#{self}"
|
8
|
+
a << ':' << el.join(':') unless el.empty?
|
9
|
+
a
|
10
|
+
end
|
11
|
+
def self.redis
|
12
|
+
Boned.redis
|
13
|
+
end
|
14
|
+
def self.primarykey(v=nil)
|
15
|
+
unless v.nil?
|
16
|
+
@primarykey = v
|
17
|
+
class_eval do
|
18
|
+
def primarykey() send(self.class.primarykey) end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@primarykey
|
22
|
+
end
|
23
|
+
def redis
|
24
|
+
self.class.redis
|
25
|
+
end
|
26
|
+
def save
|
27
|
+
redis.sadd(self.class.key(kind, :all), self.primarykey) &&
|
28
|
+
redis.set(key(:created), self.time.to_i) &&
|
29
|
+
redis.set(key(:object), to_json)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Boned.require_glob 'boned', 'models', '*.rb'
|
data/lib/boned/server.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'thin'
|
2
|
+
require 'logging'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Boned
|
6
|
+
class Server < Thin::Backends::Base
|
7
|
+
DEFAULT_PORT = 6043.freeze
|
8
|
+
|
9
|
+
class ServerRunning < Boned::Problem
|
10
|
+
def message() "Server already running on port: #{super}" end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ServerNotRunning < Boned::Problem
|
14
|
+
def message() "Server not running on port: #{super}" end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
end
|
19
|
+
|
20
|
+
# Address and port on which the server is listening for connections.
|
21
|
+
attr_accessor :host, :port
|
22
|
+
|
23
|
+
def initialize(host, port, options)
|
24
|
+
@host = host
|
25
|
+
@port = port
|
26
|
+
super()
|
27
|
+
end
|
28
|
+
|
29
|
+
# Connect the server
|
30
|
+
def connect
|
31
|
+
@signature = EventMachine.start_server(@host, @port, Thin::Connection, &method(:initialize_connection))
|
32
|
+
rescue => ex
|
33
|
+
puts ex.message
|
34
|
+
puts ex.backtrace if Boned.debug
|
35
|
+
stop!
|
36
|
+
end
|
37
|
+
|
38
|
+
# Stops the server
|
39
|
+
def disconnect
|
40
|
+
EventMachine.stop_server(@signature)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"#{@host}:#{@port}"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
module Controllers
|
49
|
+
class Controller < Thin::Controllers::Controller
|
50
|
+
end
|
51
|
+
class Service < Thin::Controllers::Service
|
52
|
+
end
|
53
|
+
class Cluster < Thin::Controllers::Cluster
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
#controller = case
|
62
|
+
#when cluster? then Thin::Controllers::Cluster.new(options)
|
63
|
+
#when service? then Thin::Controllers::Service.new(options)
|
64
|
+
#else Thin::Controllers::Controller.new(options)
|
65
|
+
#end
|
66
|
+
|
67
|
+
|
data/lib/boned.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'rack/auth/digest/md5'
|
2
|
+
|
3
|
+
require 'redis'
|
4
|
+
require 'redis/namespace'
|
5
|
+
require 'storable'
|
6
|
+
require 'attic'
|
7
|
+
require 'gibbler/aliases'
|
8
|
+
require 'sysinfo'
|
9
|
+
require 'socket'
|
10
|
+
|
11
|
+
unless defined?(BONED_HOME)
|
12
|
+
BONED_HOME = File.expand_path(File.join(File.dirname(__FILE__), '..') )
|
13
|
+
end
|
14
|
+
|
15
|
+
module Boned
|
16
|
+
APIVERSION = 'v1'.freeze unless defined?(APIVERSION)
|
17
|
+
module VERSION
|
18
|
+
MAJOR = 0
|
19
|
+
MINOR = 2
|
20
|
+
TINY = 0
|
21
|
+
PATCH = '001'
|
22
|
+
def self.inspect; [to_s, PATCH].join('.'); end
|
23
|
+
def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
|
24
|
+
def self.to_f; self.to_s.to_f; end
|
25
|
+
def self.patch; PATCH; end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Problem < RuntimeError; end
|
29
|
+
class BadBone < Problem
|
30
|
+
def message() "No such bone: #{super}" end
|
31
|
+
end
|
32
|
+
|
33
|
+
@debug = false
|
34
|
+
@conf = nil
|
35
|
+
@redis = nil
|
36
|
+
@sysinfo = nil
|
37
|
+
class << self
|
38
|
+
attr_accessor :debug
|
39
|
+
attr_reader :conf
|
40
|
+
attr_accessor :redis
|
41
|
+
def debug?() @debug == true end
|
42
|
+
def enable_debug() @debug = true end
|
43
|
+
def disable_debug() @debug = false end
|
44
|
+
def sysinfo
|
45
|
+
@sysinfo = SysInfo.new.freeze if @sysinfo.nil?
|
46
|
+
@sysinfo
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Connect to Redis and Mongo.
|
51
|
+
def self.connect(conf=@conf)
|
52
|
+
@redis = Redis.new conf[:redis]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Loads the yaml config files from config/
|
56
|
+
# * +base+ path where config dir lives
|
57
|
+
# * +env one of: :development, :production
|
58
|
+
# Returns a Hash: conf[:mongo][:host], ...
|
59
|
+
def self.load_config(base=Dir.pwd, env=:development)
|
60
|
+
@conf = {}
|
61
|
+
[:redis].each do |n|
|
62
|
+
Boned.ld "LOADING CONFIG: #{n}"
|
63
|
+
tmp = YAML.load_file(File.join(base, "config", "#{n}.yml"))
|
64
|
+
@conf[n] = tmp[ env.to_sym ]
|
65
|
+
end
|
66
|
+
@conf
|
67
|
+
end
|
68
|
+
|
69
|
+
# <tt>require</tt> a library from the vendor directory.
|
70
|
+
# The vendor directory should be organized such
|
71
|
+
# that +name+ and +version+ can be used to create
|
72
|
+
# the path to the library.
|
73
|
+
#
|
74
|
+
# e.g.
|
75
|
+
#
|
76
|
+
# vendor/httpclient-2.1.5.2/httpclient
|
77
|
+
#
|
78
|
+
def self.require_vendor(name, version)
|
79
|
+
path = File.join(BONED_HOME, 'vendor', "#{name}-#{version}", 'lib')
|
80
|
+
$:.unshift path
|
81
|
+
Boned.ld "REQUIRE VENDOR: ", path
|
82
|
+
require name
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.require_glob(*path)
|
86
|
+
path = [BONED_HOME, 'lib', path].flatten
|
87
|
+
libs = Dir.glob(File.join(*path))
|
88
|
+
Boned.ld "REQUIRE GLOB: ", libs
|
89
|
+
libs.each do |lib|
|
90
|
+
next if lib == __FILE__
|
91
|
+
require lib if File.file? lib
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Checks whether something is listening to a socket.
|
96
|
+
# * +host+ A hostname
|
97
|
+
# * +port+ The port to check
|
98
|
+
# * +wait+ The number of seconds to wait for before timing out.
|
99
|
+
#
|
100
|
+
# Returns true if +host+ allows a socket connection on +port+.
|
101
|
+
# Returns false if one of the following exceptions is raised:
|
102
|
+
# Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error
|
103
|
+
#
|
104
|
+
def self.service_available?(host, port, wait=3)
|
105
|
+
if Boned.sysinfo.vm == :java
|
106
|
+
begin
|
107
|
+
iadd = Java::InetSocketAddress.new host, port
|
108
|
+
socket = Java::Socket.new
|
109
|
+
socket.connect iadd, wait * 1000 # milliseconds
|
110
|
+
success = !socket.isClosed && socket.isConnected
|
111
|
+
rescue NativeException => ex
|
112
|
+
puts ex.message, ex.backtrace if Boned.debug?
|
113
|
+
false
|
114
|
+
end
|
115
|
+
else
|
116
|
+
begin
|
117
|
+
status = Timeout::timeout(wait) do
|
118
|
+
socket = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
119
|
+
sockaddr = Socket.pack_sockaddr_in( port, host )
|
120
|
+
socket.connect( sockaddr )
|
121
|
+
end
|
122
|
+
true
|
123
|
+
rescue Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error => ex
|
124
|
+
puts ex.class, ex.message, ex.backtrace if Boned.debug?
|
125
|
+
false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def self.ld(*msg)
|
132
|
+
return unless Boned.debug
|
133
|
+
prefix = "D(#{Thread.current.object_id}): "
|
134
|
+
puts "#{prefix}" << msg.join("#{$/}#{prefix}")
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
require 'boned/models'
|
data/public/index.html
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# ruby -rubygems -Ilib try/10_bone_model.rb
|
2
|
+
require 'boned'
|
3
|
+
Boned.load_config
|
4
|
+
Boned.connect
|
5
|
+
Boned.enable_debug
|
6
|
+
|
7
|
+
token = Digest::SHA256.hexdigest('1901484c41b8752d61863e323c743')
|
8
|
+
key = 'simple'
|
9
|
+
|
10
|
+
puts Bone.keys(token)
|
11
|
+
|
12
|
+
__END__
|
13
|
+
opts = { :env => 'dev', :region => 'us-east-1a', :num => '01', :role => 'fe', :path => Dir.pwd }
|
14
|
+
bone = Bone.new token, key, rand(100000).to_i, opts
|
15
|
+
#puts "BONE: " << bone.inspect, $/
|
16
|
+
bone.save
|
17
|
+
#puts "KEYS: " << Bone.keys( token, key).inspect, $/
|
18
|
+
|
19
|
+
bone = Bone.get( token, key, opts)
|
20
|
+
puts "GET: " << bone.inspect, $/
|
21
|
+
puts bone.to_json
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% @keys.each do |key| %>
|
2
|
+
<div class="key">
|
3
|
+
<% kind = key_kind(key) %>
|
4
|
+
<% if kind == 'string' %>
|
5
|
+
<a href="<%= root_path %>/get/<%= key %>"><%= key %></a> <%= (kind) %>
|
6
|
+
<% elsif kind == 'set' %>
|
7
|
+
<a href="<%= root_path %>/smembers/<%= key %>"><%= key %></a> <%= (kind) %>
|
8
|
+
<% elsif kind == 'list' %>
|
9
|
+
<a href="<%= root_path %>/list/<%= key %>"><%= key %></a> <%= (kind) %>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: boned
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Delano Mandelbaum
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-13 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Get Bones
|
17
|
+
email: delano@solutious.com
|
18
|
+
executables:
|
19
|
+
- boned
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.md
|
24
|
+
- LICENSE.txt
|
25
|
+
- CHANGES.txt
|
26
|
+
files:
|
27
|
+
- LICENSE.txt
|
28
|
+
- README.md
|
29
|
+
- Rakefile
|
30
|
+
- bin/boned
|
31
|
+
- boned.gemspec
|
32
|
+
- config/redis-default.yml
|
33
|
+
- config/redis-server-default.conf
|
34
|
+
- config/stella/api-set.rb
|
35
|
+
- config/stella/api.rb
|
36
|
+
- lib/boned.rb
|
37
|
+
- lib/boned/api.rb
|
38
|
+
- lib/boned/api/debug.rb
|
39
|
+
- lib/boned/api/redis.rb
|
40
|
+
- lib/boned/api/service.rb
|
41
|
+
- lib/boned/cli.rb
|
42
|
+
- lib/boned/models.rb
|
43
|
+
- lib/boned/models/bone.rb
|
44
|
+
- lib/boned/server.rb
|
45
|
+
- public/index.html
|
46
|
+
- try/10_bone_model.rb
|
47
|
+
- views/redisviewer/keys.erb
|
48
|
+
- CHANGES.txt
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: ""
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --line-numbers
|
56
|
+
- --title
|
57
|
+
- Get Bones
|
58
|
+
- --main
|
59
|
+
- README.rdoc
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
version:
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project: boned
|
77
|
+
rubygems_version: 1.3.5
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Get Bones
|
81
|
+
test_files: []
|
82
|
+
|