Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added tilecache server, not yet fully functional
- Loading branch information
Deepwinter
committed
Mar 15, 2012
1 parent
335d17f
commit cc503b0
Showing
74 changed files
with
6,745 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors | ||
import os, sys, time | ||
from warnings import warn | ||
|
||
class Cache (object): | ||
def __init__ (self, timeout = 30.0, stale_interval = 300.0, readonly = False, expire = False, sendfile = False, **kwargs): | ||
self.stale = float(stale_interval) | ||
self.timeout = float(timeout) | ||
self.readonly = readonly | ||
self.expire = expire | ||
self.sendfile = sendfile and sendfile.lower() in ["yes", "y", "t", "true"] | ||
if expire != False: | ||
self.expire = long(expire) | ||
|
||
def lock (self, tile, blocking = True): | ||
start_time = time.time() | ||
result = self.attemptLock(tile) | ||
if result: | ||
return True | ||
elif not blocking: | ||
return False | ||
while result is not True: | ||
if time.time() - start_time > self.timeout: | ||
raise Exception("You appear to have a stuck lock. You may wish to remove the lock named:\n%s" % self.getLockName(tile)) | ||
time.sleep(0.25) | ||
result = self.attemptLock(tile) | ||
return True | ||
|
||
def getLockName (self, tile): | ||
return self.getKey(tile) + ".lck" | ||
|
||
def getKey (self, tile): | ||
raise NotImplementedError() | ||
|
||
def attemptLock (self, tile): | ||
raise NotImplementedError() | ||
|
||
def unlock (self, tile): | ||
raise NotImplementedError() | ||
|
||
def get (self, tile): | ||
raise NotImplementedError() | ||
|
||
def set (self, tile, data): | ||
raise NotImplementedError() | ||
|
||
def delete(self, tile): | ||
raise NotImplementedError() |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors | ||
from TileCache.Cache import Cache | ||
import time | ||
|
||
class AWSS3(Cache): | ||
import_error = "Problem importing S3 support library. You must have either boto or the Amazon S3 library.\nErrors:\n * %s" | ||
def __init__ (self, access_key, secret_access_key, use_tms_paths = "False", **kwargs): | ||
self.module = None | ||
try: | ||
import boto.s3 | ||
self.s3 = boto.s3 | ||
self.module = "boto" | ||
except ImportError, E: | ||
exceptions = [str(E)] | ||
try: | ||
import S3 | ||
self.s3 = S3 | ||
self.module = "amazon" | ||
except Exception, E: | ||
exceptions.append(str(E)) | ||
raise Exception(self.import_error % ('\n * '.join(exceptions))) | ||
Cache.__init__(self, **kwargs) | ||
self.bucket_name = "%s-tilecache" % access_key.lower() | ||
if use_tms_paths.lower() in ("true", "yes", "1"): | ||
use_tms_paths = True | ||
elif use_tms_paths.lower() == "flipped": | ||
use_tms_paths = "google" | ||
self.use_tms_paths = use_tms_paths | ||
if self.module == "amazon": | ||
self.cache = self.s3.AWSAuthConnection(access_key, secret_access_key) | ||
self.cache.create_bucket(self.bucket_name) | ||
else: | ||
self.cache = self.s3.connection.S3Connection(access_key, secret_access_key) | ||
self.bucket = self.cache.create_bucket(self.bucket_name) | ||
|
||
def getBotoKey(self, key): | ||
boto_key = self.s3.key.Key(self.bucket) | ||
boto_key.key = key | ||
return boto_key | ||
|
||
def getKey(self, tile): | ||
if self.use_tms_paths == True or self.use_tms_paths == "flipped": | ||
grid = tile.layer.grid(tile.z) | ||
y = tile.y | ||
if self.use_tms_paths == "flipped": | ||
y = int(grid[1] - 1 - tile.y) | ||
version = "1.0.0" | ||
path = "/".join(map(str, [version, tile.layer.name, tile.z, tile.x, y])) | ||
path = ".".join(map(str, [path, tile.layer.extension])) | ||
else: | ||
path = "-".join(map(str, [tile.layer.name, tile.z , tile.x, tile.y])) | ||
return path | ||
|
||
def get(self, tile): | ||
key = self.getKey(tile) | ||
tile.data = self.getObject(key) | ||
return tile.data | ||
|
||
def getObject(self, key): | ||
data = None | ||
if self.module == "amazon": | ||
response = self.cache.get(self.bucket_name, key) | ||
if not response.object.data.startswith("<?xml"): | ||
data = response.object.data | ||
else: | ||
try: | ||
data = self.getBotoKey(key).get_contents_as_string() | ||
except: | ||
pass | ||
self.bucket.connection.connection.close() | ||
return data | ||
|
||
def set(self, tile, data): | ||
if self.readonly: return data | ||
key = self.getKey(tile) | ||
self.setObject(key, data) | ||
return data | ||
|
||
def setObject(self, key, data): | ||
if self.module == "amazon": | ||
self.cache.put(self.bucket_name, key, self.s3.S3Object(data)) | ||
else: | ||
self.getBotoKey(key).set_contents_from_string(data) | ||
self.bucket.connection.connection.close() | ||
|
||
def delete(self, tile): | ||
key = self.getKey(tile) | ||
self.deleteObject(key) | ||
|
||
def deleteObject(self, key): | ||
if self.module == "amazon": | ||
self.cache.delete(self.bucket_name, key) | ||
else: | ||
self.getBotoKey(key).delete() | ||
|
||
def getLockName (self, tile): | ||
return "lock-%s" % self.getKey(tile) | ||
|
||
def attemptLock (self, tile): | ||
data = self.getObject(self.getLockName(tile)) | ||
if not data: | ||
self.setObject(self.getLockName(tile), str(time.time() + self.timeout)) | ||
return True | ||
|
||
def unlock (self, tile): | ||
self.deleteObject( self.getLockName(tile) ) | ||
|
||
def keys (self, options = {}): | ||
if self.module == "amazon": | ||
return map(lambda x: x.key, | ||
self.cache.list_bucket(self.bucket_name, options).entries) | ||
else: | ||
prefix = "" | ||
if options.has_key('prefix'): | ||
prefix = options['prefix'] | ||
response = self.bucket.list(prefix=prefix) | ||
keys = [] | ||
for key in response: | ||
keys.append(key.key) | ||
return keys | ||
|
||
|
||
if __name__ == "__main__": | ||
import sys | ||
from optparse import OptionParser | ||
parser = OptionParser(usage="""%prog [options] action | ||
action is one of: | ||
list_locks | ||
count_tiles | ||
show_tiles | ||
delete <object_key> or <list>,<of>,<keys> | ||
delete_tiles""") | ||
parser.add_option('-z', dest='zoom', help='zoom level for count_tiles (requires layer name)') | ||
parser.add_option('-l', dest='layer', help='layer name for count_tiles') | ||
parser.add_option('-k', dest='key', help='access key for S3') | ||
parser.add_option('-s', dest='secret', help='secret access key for S3') | ||
|
||
(options, args) = parser.parse_args() | ||
if not options.key or not options.secret or not args: | ||
parser.print_help() | ||
sys.exit() | ||
|
||
def create_prefix(options): | ||
prefix = "" | ||
if options.layer: | ||
prefix = "%s-" % options.layer | ||
if options.zoom: | ||
prefix = "%s%s-" % (prefix, options.zoom) | ||
return prefix | ||
|
||
# Debug mode. | ||
a = AWSS3(options.key, | ||
options.secret) | ||
if args[0] == "list_locks": | ||
print ','.join(a.keys({'prefix':'lock-'})) | ||
elif args[0] == "list_keys": | ||
print ','.join(a.keys()) | ||
elif args[0] == "count_tiles" or args[0] == "show_tiles": | ||
opts = { | ||
'prefix': create_prefix(options) | ||
} | ||
if args[0] == "show_tiles": | ||
print ",".join(a.keys(opts)) | ||
else: | ||
print len(a.keys(opts)) | ||
elif args[0] == "delete": | ||
for key in args[1].split(","): | ||
a.deleteObject(key) | ||
elif args[0] == "delete_tiles": | ||
opts = { | ||
'prefix': create_prefix(options) | ||
} | ||
keys = a.keys(opts) | ||
val = raw_input("Are you sure you want to delete %s tiles? (y/n) " % len(keys)) | ||
if val.lower() in ['y', 'yes']: | ||
for key in keys: | ||
a.deleteObject(key) | ||
|
||
else: | ||
parser.print_help() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# BSD Licensed, Copyright (c) 2006-2010 TileCache Contributors | ||
|
||
from TileCache.Cache import Cache | ||
import sys, os, time, warnings | ||
|
||
class Disk (Cache): | ||
def __init__ (self, base = None, umask = '002', **kwargs): | ||
Cache.__init__(self, **kwargs) | ||
self.basedir = base | ||
self.umask = int(umask, 0) | ||
if sys.platform.startswith("java"): | ||
from java.io import File | ||
self.file_module = File | ||
self.platform = "jython" | ||
else: | ||
self.platform = "cpython" | ||
|
||
if not self.access(base, 'read'): | ||
self.makedirs(base) | ||
|
||
def makedirs(self, path, hide_dir_exists=True): | ||
if hasattr(os, "umask"): | ||
old_umask = os.umask(self.umask) | ||
try: | ||
os.makedirs(path) | ||
except OSError, E: | ||
# os.makedirs can suffer a race condition because it doesn't check | ||
# that the directory doesn't exist at each step, nor does it | ||
# catch errors. This lets 'directory exists' errors pass through, | ||
# since they mean that as far as we're concerned, os.makedirs | ||
# has 'worked' | ||
if E.errno != 17 or not hide_dir_exists: | ||
raise E | ||
if hasattr(os, "umask"): | ||
os.umask(old_umask) | ||
|
||
def access(self, path, type='read'): | ||
if self.platform == "jython": | ||
if type == "read": | ||
return self.file_module(path).canRead() | ||
else: | ||
return self.file_module(path).canWrite() | ||
else: | ||
if type =="read": | ||
return os.access(path, os.R_OK) | ||
else: | ||
return os.access(path, os.W_OK) | ||
|
||
def getKey (self, tile): | ||
components = ( self.basedir, | ||
tile.layer.name, | ||
"%02d" % tile.z, | ||
"%03d" % int(tile.x / 1000000), | ||
"%03d" % (int(tile.x / 1000) % 1000), | ||
"%03d" % (int(tile.x) % 1000), | ||
"%03d" % int(tile.y / 1000000), | ||
"%03d" % (int(tile.y / 1000) % 1000), | ||
"%03d.%s" % (int(tile.y) % 1000, tile.layer.extension) | ||
) | ||
filename = os.path.join( *components ) | ||
return filename | ||
|
||
def get (self, tile): | ||
filename = self.getKey(tile) | ||
if self.access(filename, 'read'): | ||
if self.sendfile: | ||
return filename | ||
else: | ||
tile.data = file(filename, "rb").read() | ||
return tile.data | ||
else: | ||
return None | ||
|
||
def set (self, tile, data): | ||
if self.readonly: return data | ||
filename = self.getKey(tile) | ||
dirname = os.path.dirname(filename) | ||
if not self.access(dirname, 'write'): | ||
self.makedirs(dirname) | ||
tmpfile = filename + ".%d.tmp" % os.getpid() | ||
if hasattr(os, "umask"): | ||
old_umask = os.umask(self.umask) | ||
output = file(tmpfile, "wb") | ||
output.write(data) | ||
output.close() | ||
if hasattr(os, "umask"): | ||
os.umask( old_umask ); | ||
try: | ||
os.rename(tmpfile, filename) | ||
except OSError: | ||
os.unlink(filename) | ||
os.rename(tmpfile, filename) | ||
tile.data = data | ||
return data | ||
|
||
def delete (self, tile): | ||
filename = self.getKey(tile) | ||
if self.access(filename, 'read'): | ||
os.unlink(filename) | ||
|
||
def attemptLock (self, tile): | ||
name = self.getLockName(tile) | ||
try: | ||
self.makedirs(name, hide_dir_exists=False) | ||
return True | ||
except OSError: | ||
pass | ||
try: | ||
st = os.stat(name) | ||
if st.st_ctime + self.stale < time.time(): | ||
warnings.warn("removing stale lock %s" % name) | ||
# remove stale lock | ||
self.unlock(tile) | ||
self.makedirs(name) | ||
return True | ||
except OSError: | ||
pass | ||
return False | ||
|
||
def unlock (self, tile): | ||
name = self.getLockName(tile) | ||
try: | ||
os.rmdir(name) | ||
except OSError, E: | ||
print >>sys.stderr, "unlock %s failed: %s" % (name, str(E)) |
Binary file not shown.
Oops, something went wrong.