"""每资源版本检测票据和局部发布;拒绝较早检测的迟到结果。""" from owned_thread import run_owned_thread import uuid from github_archive import commit_sha, source_signature from github_source import select_github_token from proxy_access import read_proxy_item def _entry(versions, item_id): if not isinstance(versions, dict): raise ValueError('invalid version source') entry = versions.get(item_id) if entry is None: return {} if isinstance(entry, str): return {'hash': entry} if not isinstance(entry, dict): raise ValueError('invalid version record') return dict(entry) def _without_cache(entry): return {key: value for key, value in entry.items() if key not in ('cached_at', 'zip_size') and not key.startswith('archive_')} def begin_probe(store, item_id): item = read_proxy_item(store, item_id) token = select_github_token(item) source = source_signature(item, token) ticket = uuid.uuid4().hex def update(versions): entry = _entry(versions, item_id) entry['_probe_ticket'] = ticket entry['_probe_source'] = source versions[item_id] = entry store.atomic_update('versions.json', update, default_data={}) return dict(item=item, token=token, source=source, ticket=ticket) def finish_probe(store, operation, sha): sha = commit_sha(sha) item_id = operation['item']['id'] current = read_proxy_item(store, item_id) if source_signature(current, select_github_token(current)) != operation['source']: return None def update(versions): entry = _entry(versions, item_id) if entry.get('_probe_ticket') != operation['ticket'] or entry.get('_probe_source') != operation['source']: return None changed = entry.get('hash') != sha[:7] if (changed or entry.get('version_source') not in (None, operation['source']) or entry.get('version_commit') not in (None, sha) or entry.get('archive_commit') not in (None, sha)): entry = _without_cache(entry) entry.update(hash=sha[:7], version_commit=sha, version_source=operation['source']) entry.pop('_probe_ticket', None); entry.pop('_probe_source', None) versions[item_id] = entry return dict(item=current, token=operation['token'], commit=sha, changed=changed) return store.atomic_update('versions.json', update, default_data={}) def invalidate_source(store, item_id): """旧编辑回调也读取最新资源;已属于最新来源的确认记录保持。""" current = read_proxy_item(store, item_id) try: source = source_signature(current, select_github_token(current)) except ValueError: source = None def update(versions): entry = _entry(versions, item_id) if source is not None and entry.get('version_source') == source: return False entry = _without_cache(entry) for key in ('version_commit', '_probe_ticket', '_probe_source'): entry.pop(key, None) entry.update(hash='', version_source=source) versions[item_id] = entry return True return store.atomic_update('versions.json', update, default_data={}) async def refresh_resource_version(store, item_id): from 云端_定时版本检测引擎 import fetch_github_commit operation = await run_owned_thread(begin_probe, store, item_id) sha = await fetch_github_commit(operation['item']['link'], operation['token']) if not sha: return None return await run_owned_thread(finish_probe, store, operation, sha)