iclientpy.rest.api.updatetileset 源代码

import re
import time
import uuid
import os
from typing import List
import progressbar
from iclientpy.rest.api.model import Rectangle2D, Point2D, ServiceType, TileSize, OutputFormat, PostWorkspaceParameter, \
    PostTileJobsItem, BuildState, PostTilesetUpdateJobs, SMTilesTileSourceInfo, TilesetExportJobRunState, TileType, \
    TileSourceInfo
from iclientpy.rest.api.management import Management
from iclientpy.rest.api.model import PostFileUploadTasksParam, FileUploadState
from iclientpy.rest.apifactory import APIFactory
from .cacheutils import provider_setting_to_tile_source_info
from iclientpy.dtojson import to_json_str
import zipfile
from io import BufferedIOBase


[文档]def output(tip: str): print(tip)
field_and_desc = { 'address': '地址', 'username': '用户名', 'password': '密码', 'token': 'token', 'component_name': '待更新缓存服务名称', 'w_loc': '工作空间路径', 'map_name': '切图地图名称', 'original_point': '切图原点', 'cache_bounds': '缓存范围', 'scale': '缓存比例尺分母', 'w_servicetype': '工作空间服务类型', 'tile_size': '切片大小', 'tile_type': '切片类型', 'format': '切片输出格式', 'epsg_code': '投影', 'remote_workspace': '远程工作空间', 'source_component_name': '缓存更新数据来源服务', 'update': '更新服务缓存' }
[文档]def confirm(**d): output('执行参数如下:') for field in field_and_desc.keys(): if field in d: val = '' if d[field] is None: val = '' elif isinstance(d[field], tuple): val = ','.join(map(str, d[field])) elif isinstance(d[field], bool): val = str(d[field]) elif not isinstance(d[field], str): val = to_json_str(d[field]) else: val = d[field] output(field_and_desc[field] + ": " + val) print('是否继续?(Y/N)', end=' ') return input('')
[文档]def recache_tileset(address: str, username: str, password: str, component_name: str, map_name: str, storageid: str = None, tileset_name: str = None, token: str = None): api = APIFactory(address, username, password, token) mng = api.management() storage_info = mng.get_datastore(storageid) tilesetinfos = [info for info in storage_info.tilesetInfos if info.metaData.mapName == map_name] if len(tilesetinfos) != 1 and tileset_name is None: raise Exception("存在多个地图名称相同的缓存") tilesetinfo = None if len(tilesetinfos) == 1: tilesetinfo = tilesetinfos[0] else: for info in tilesetinfos: if info.name == tileset_name: tilesetinfo = info storage_config = storage_info.tileSourceInfo post_tile_jobs_param = PostTileJobsItem() post_tile_jobs_param.dataConnectionString = component_name post_tile_jobs_param.mapName = map_name post_tile_jobs_param.scaleDenominators = tilesetinfo.metaData.scaleDenominators if tilesetinfo.metaData.tileHeight == 512: post_tile_jobs_param.tileSize = TileSize.SIZE_512 elif tilesetinfo.metaData.tileHeight == 1024: post_tile_jobs_param.tileSize = TileSize.SIZE_1024 else: post_tile_jobs_param.tileSize = TileSize.SIZE_256 post_tile_jobs_param.tileType = tilesetinfo.metaData.tileType post_tile_jobs_param.format = tilesetinfo.metaData.tileFormat post_tile_jobs_param.epsgCode = tilesetinfo.metaData.prjCoordSys.epsgCode post_tile_jobs_param.storeConfig = storage_config post_tile_jobs_param.originalPoint = tilesetinfo.metaData.originalPoint post_tile_jobs_param.cacheBounds = tilesetinfo.metaData.bounds post_tile_jobs_param.tileVersionDescription = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) post_tile_jobs_param.createNewTileVersion = True ptjr = mng.post_tilejobs(post_tile_jobs_param) jobstate = mng.get_tilejob(ptjr.newResourceID).state bar = _process_bar('切图', _PercentageCounter(), jobstate.total) while (jobstate.runState is BuildState.BUILDING): time.sleep(5) jobstate = mng.get_tilejob(ptjr.newResourceID).state bar.update(jobstate.completed) gjr = mng.get_tilejob(ptjr.newResourceID) if (gjr.state.runState is not BuildState.COMPLETED): raise Exception('切图失败')
[文档]def update_smtilestileset(address: str, username: str, password: str, component_name: str, w_loc: str, map_name: str, original_point: tuple, cache_bounds: tuple, scale: List[float] = None, w_servicetypes: List[ServiceType] = [ServiceType.RESTMAP], tile_size: TileSize = TileSize.SIZE_256, tile_type: TileType = TileType.Image, format: OutputFormat = OutputFormat.PNG, epsgcode: int = -1, storageid: str = None, storageconfig: TileSourceInfo = None, remote_workspace: bool = False, quiet: bool = False, source_component_name: str = '', update: bool = False, tile_version: str = None, token: str = None): if len(original_point) is not 2: raise Exception("切图原点坐标长度错误") tem_original_point = Point2D() tem_original_point.x = original_point[0] tem_original_point.y = original_point[1] if len(cache_bounds) is not 4: raise Exception("切图范围长度错误") tem_cache_Bounds = Rectangle2D() tem_cache_Bounds.leftBottom = Point2D() tem_cache_Bounds.leftBottom.x = cache_bounds[0] tem_cache_Bounds.leftBottom.y = cache_bounds[1] tem_cache_Bounds.rightTop = Point2D() tem_cache_Bounds.rightTop.x = cache_bounds[2] tem_cache_Bounds.rightTop.y = cache_bounds[3] api = APIFactory(address, username, password, token) mng = api.management() if scale is None: map_service = api.map_service(component_name + '/rest') mr = map_service.get_map(map_name) scale = [1 / x for x in mr.visibleScales] if scale is None or len(scale) is 0: raise Exception('无法获取目标地图比例尺且未指定比例尺') if storageid is not None: storage_info = mng.get_datastore(storageid) for info in storage_info.tilesetInfos: if info.metaData.mapName == map_name: storageconfig = storage_info.tileSourceInfo if storageconfig is None: storageconfig = SMTilesTileSourceInfo() storageconfig.type = 'SMTiles' storageconfig.outputPath = '../webapps/iserver/output/sqlite_' + uuid.uuid1().__str__() if not quiet: confirmResult = confirm(address=address, username=username, password=password, component_name=component_name, w_loc=w_loc, map_name=map_name, original_point=original_point, cache_bounds=cache_bounds, scale=scale, w_servicetype=w_servicetypes, tile_size=tile_size, tile_type=tile_type, format=format, epsg_code=epsgcode, storageid=storageid, remote_workspace=remote_workspace, source_component_name=source_component_name, update=update, token=token) if confirmResult.lower() == 'n': return wkn = source_component_name if not update: param = PostFileUploadTasksParam() if remote_workspace: remote_workspace_file_full_path = w_loc else: pfutsr = mng.post_fileuploadtasks(param) remote_workspace_file_full_path = _upload_workspace_file(mng, w_loc, pfutsr.newResourceID) gfutr = mng.get_fileuploadtask(pfutsr.newResourceID) if gfutr.state is not FileUploadState.COMPLETED: raise Exception('文件上传失败') post_param = PostWorkspaceParameter() post_param.workspaceConnectionInfo = remote_workspace_file_full_path post_param.servicesTypes = w_servicetypes pwr = mng.post_workspaces(post_param) wkn = re.findall('services/[^/]*', pwr[0].serviceAddress)[0].lstrip('services/') post_tile_jobs_param = PostTileJobsItem() post_tile_jobs_param.dataConnectionString = wkn post_tile_jobs_param.mapName = map_name post_tile_jobs_param.scaleDenominators = scale post_tile_jobs_param.tileSize = tile_size post_tile_jobs_param.tileType = tile_type post_tile_jobs_param.format = format post_tile_jobs_param.epsgCode = epsgcode post_tile_jobs_param.storeConfig = storageconfig post_tile_jobs_param.originalPoint = tem_original_point post_tile_jobs_param.cacheBounds = tem_cache_Bounds post_tile_jobs_param.tileVersionDescription = tile_version ptjr = mng.post_tilejobs(post_tile_jobs_param) jobstate = mng.get_tilejob(ptjr.newResourceID).state bar = _process_bar('切图', _PercentageCounter(), jobstate.total) while (jobstate.runState is BuildState.BUILDING): time.sleep(5) jobstate = mng.get_tilejob(ptjr.newResourceID).state bar.update(jobstate.completed) gjr = mng.get_tilejob(ptjr.newResourceID) if (gjr.state.runState is not BuildState.COMPLETED): raise Exception('切图失败') if isinstance(storageconfig, SMTilesTileSourceInfo): post_tile_update_param = PostTilesetUpdateJobs() post_tile_update_param.scaleDenominators = scale post_tile_update_param.bounds = tem_cache_Bounds post_tile_update_param.targetTilesetIdentifier = None post_tile_update_param.targetTileSourceInfo = _get_tile_source_info_from_service(mng, component_name) post_tile_update_param.sourceTilesetIdentifier = gjr.targetTilesetInfo.filePath post_tile_update_param.sourceTileSourceInfo = SMTilesTileSourceInfo() post_tile_update_param.sourceTileSourceInfo.type = 'SMTiles' post_tile_update_param.sourceTileSourceInfo.outputPath = post_tile_jobs_param.storeConfig.outputPath ptur = mng.post_tilesetupdatejobs(post_tile_update_param) gtur = mng.get_tilesetupdatejob(ptur.newResourceID) bar = _process_bar('更新', _PercentageCounter(), gtur.state.total) while (not hasattr(gtur.state, 'runState') or gtur.state.runState is TilesetExportJobRunState.RUNNING): time.sleep(5) gtur = mng.get_tilesetupdatejob(ptur.newResourceID) bar.update(gtur.state.actualCompleted) if (gtur.state.runState is not TilesetExportJobRunState.COMPLETED): raise Exception('更新切片失败') if not update: mng.delete_mapcomponent(name=wkn)
def _get_tile_source_info_from_service(mng: Management, name: str) -> TileSourceInfo: service_info = mng.get_service(name) return provider_setting_to_tile_source_info(service_info.providers[0].spSetting.config) def _custom_len(value): total = 0 for c in value: if c >= u'\u4e00' and c <= u'\u9fa5': # 中文字符宽度为2 total += 2 else: total += 1 return total def _process_bar(name: str, counter: progressbar.Counter, max_value: int) -> progressbar.ProgressBar: return progressbar.ProgressBar( widgets=[ name + '进度: ', progressbar.Bar(), ' ', counter, ], len_func=_custom_len, max_value=max_value ) class _PercentageCounter(progressbar.Counter): def __call__(self, progress, data, format=None): # processbar似乎计算宽度有问题导致换行,给多加几个空格让希望显示的内容不换行。 return '{0:5}% '.format(round(data['value'] / data['max_value'] * 100, 2)) class _DisableSeekAndTellIOWrapper(BufferedIOBase): """ zipfile压缩文件的时候会通过seek和tell来定位写入zip文件头信息。 但是管道流不能正常的seek和tell,故通过这个wrapper来禁用seek和tell,从而强迫zipfile使用流式压缩 """ def __init__(self, towrap): self._wrapped = towrap def seek(self, *args, **kwargs): raise AttributeError() def tell(self, *args, **kwargs): raise AttributeError() def seekable(self, *args, **kwargs): return False def __getattribute__(self, item): if item in ('_wrapped', 'seek', 'seekable', 'tell'): return object.__getattribute__(self, item) return self._wrapped.__getattribute__(item) def __enter__(self): self._wrapped.__enter__() return self def __exit__(self, *args, **kwargs): self._wrapped.__exit__(*args, **kwargs) def _zip_files_in_workspace_directory(w_loc: str) -> BufferedIOBase: rfd, wfd = os.pipe() def zip_in_thread(wfd): dirname = os.path.dirname(w_loc) with os.fdopen(wfd, 'wb') as outputfile: with zipfile.ZipFile(_DisableSeekAndTellIOWrapper(outputfile), 'w') as zfile: for root, dirs, files in os.walk(dirname): for name in files: fullpath = os.path.join(root, name) arcname = os.path.relpath(fullpath, dirname) zfile.write(fullpath, arcname=arcname) import threading threading.Thread(target=zip_in_thread, args=(wfd,), name='zip ' + w_loc).start() return os.fdopen(rfd, 'rb') def _upload_workspace_file(mng: Management, w_loc: str, upload_task_id: str) -> str: r_post = None # type PostFileUploadTaskResult if w_loc.lower().endswith('.zip'): with zipfile.ZipFile(w_loc) as zipf: zipfns = zipf.namelist() workspace_file_name = [item for item in zipfns if item.endswith('.sxwu')][0] with open(w_loc, 'rb') as wf: r_post = mng.post_fileuploadtask(upload_task_id, wf, './' + os.path.basename(w_loc), overwrite=True, unzip=True) else: workspace_file_name = os.path.basename(w_loc) with _zip_files_in_workspace_directory(w_loc) as wf: r_post = mng.post_fileuploadtask(upload_task_id, wf, './' + workspace_file_name.split('.')[0] + '.zip', overwrite=True, unzip=True) return r_post.filePath + './' + workspace_file_name