Skip to content

Commit

Permalink
Merge branch 'master' into dev/dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
SilianZ authored Mar 30, 2024
2 parents 5f1be9f + e7c1498 commit 3323a21
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 132 deletions.
24 changes: 20 additions & 4 deletions .github/workflows/build_and_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
tag_name: ${{github.ref}}
release_name: Release ${{github.ref}}
draft: false
prerelease: false
build:
Expand Down Expand Up @@ -50,5 +50,21 @@ jobs:
registry.cn-hangzhou.aliyuncs.com/silianz/python-openbmclapi:latest
registry.cn-hangzhou.aliyuncs.com/silianz/python-openbmclapi:${{env.RELEASE_VERSION}}
platforms: linux/amd64, linux/arm64

update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: master
- name: Write version
run: echo "${GITHUB_REF#refs/*/}" > VERSION
- name: Commit and push
run: |
git add VERSION
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -a -m ":sparkles: 更新 VERSION"
git push


1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ WORKDIR /opt/python-openbmclapi
ADD . .

RUN pip install -r requirements.txt --no-deps
VOLUME /opt/python-openbmclapi/bmclapi
ENV port=80
EXPOSE $port
CMD ["python", "./main.py"]
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

## 从源码运行

建议 Python 版本:3.12+。

1. 克隆仓库或从 [Releases](https://github.com/TTB-Network/python-openbmclapi/releases) 中下载代码:

```sh
Expand Down Expand Up @@ -130,6 +132,11 @@ cluster:
download:
# 最高下载线程
threads: 64
dashboard:
# 仪表盘密码
password: ''
# 仪表盘用户名
username: admin
web:
# 要监听的本地端口, 同 CLUSTER_PORT
port: 80
Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v1.9.8-2adf22a
3 changes: 3 additions & 0 deletions config/config.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ cluster:
secret: ''
download:
threads: 64
dashboard:
password: ''
username: admin
web:
port: 8080
server_name: TTB-Network
Expand Down
5 changes: 4 additions & 1 deletion core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,15 @@ async def main():
os.environ["ASYNCIO_STARTUP"] = str(0)
os.kill(os.getpid(), signal.SIGINT)


def init():
asyncio.run(main())


async def close():
await web.close()


def kill(_, __):
if int(os.environ["ASYNCIO_STARTUP"]) and server:
server.close()
Expand All @@ -256,4 +259,4 @@ def kill(_, __):


for sig in (signal.SIGINT, signal.SIGTERM):
signal.signal(sig, kill)
signal.signal(sig, kill)
2 changes: 1 addition & 1 deletion core/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def load_text(cert: str, key: str):
c.write(cert)
k.write(key)
if load_cert(cert_file, key_file):
logger.info("Loaded certificate from local files!")
logger.success("Loaded certificate from local files!")
core.restart = True
if core.server:
core.server.close()
Expand Down
57 changes: 47 additions & 10 deletions core/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@
get_hash,
)

VERSION = "1.10.1"
VERSION = ""
version_path = Path("VERSION")
if version_path.exists():
with open(Path("VERSION"), "r", encoding="utf-8") as f:
VERSION = f.read().split('\n')[0]
f.close()
else:
VERSION = ""
API_VERSION = "1.10.1"
USER_AGENT = f"openbmclapi-cluster/{API_VERSION} python-openbmclapi/{VERSION}"
BASE_URL = "https://openbmclapi.bangbang93.com/"
Expand Down Expand Up @@ -647,7 +654,7 @@ async def message(self, type, data: list[Any]):
if err:
logger.error(f"Unable to request cert. {ack}.")
return
logger.info("Requested cert!")
logger.success("Requested cert!")
certificate.load_text(ack["cert"], ack["key"])
elif type == "enable":
err, ack = data
Expand All @@ -657,24 +664,26 @@ async def message(self, type, data: list[Any]):
await self.reconnect()
return
self.connected = True
logger.info(f"Connected to the main server! Starting service...")
logger.success(f"Connected to the main server! Starting service...")
logger.info(
f"Hosting on {CLUSTER_ID}.openbmclapi.933.moe:{PUBLIC_PORT or PORT}."
)
if self._enable_timer != None:
self._enable_timer.block()
self._enable_timer = None
await self.start_keepalive()
await dashboard.set_status("正常工作" + ("" if self.trusted else "(节点信任度过低)"))
await dashboard.set_status(
"正常工作" + ("" if self.trusted else "(节点信任度过低)")
)
elif type == "keep-alive":
if err:
logger.error(f"Unable to keep alive! Reconnecting...")
await self.reconnect()
return
if self.cur_storage:
storage = self.cur_storage
logger.info(
f"Successfully keep alive, served {unit.format_number(storage.sync_hits)}({unit.format_bytes(storage.sync_bytes)})."
logger.success(
f"Successfully keep alive, serving {unit.format_number(storage.sync_hits)}({unit.format_bytes(storage.sync_bytes)})."
)
storage.object.add_last_hits(storage.sync_hits)
storage.object.add_last_bytes(storage.sync_bytes)
Expand Down Expand Up @@ -762,8 +771,26 @@ async def get_cache_stats(self) -> StatsCache:
cluster: Optional[Cluster] = None
last_status: str = "-"
storages = StorageManager()
github_api = "https://api.github.com"


async def check_update():
async with aiohttp.ClientSession(base_url=github_api) as session:
logger.info("Checking update...")
try:
async with session.get("/repos/TTB-Network/python-openbmclapi/releases/latest") as req:
req.raise_for_status()
fetched_version: str = (await req.json())["tag_name"]
if fetched_version != VERSION:
logger.success(f"New version found: {fetched_version}!")
else:
logger.info(f"Already up to date.")
except aiohttp.ClientError as e:
logger.error(f"An error occured whilst checking update: {e}.")


async def init():
await check_update()
global cluster
cluster = Cluster()
system.init()
Expand Down Expand Up @@ -806,8 +833,10 @@ async def _(request: web.Request, hash: str):
if not await storages.exists(hash):
return web.Response(status_code=404)
start_bytes = 0
range_str = await request.get_headers('range', '')
range_match = re.search(r'bytes=(\d+)-(\d+)', range_str, re.S) or re.search(r'bytes=(\d+)-', range_str, re.S)
range_str = await request.get_headers("range", "")
range_match = re.search(r"bytes=(\d+)-(\d+)", range_str, re.S) or re.search(
r"bytes=(\d+)-", range_str, re.S
)
if range_match:
start_bytes = int(range_match.group(1)) if range_match else 0
data = await storages.get(hash, start_bytes)
Expand Down Expand Up @@ -836,15 +865,23 @@ async def _(request: web.Request, ws: web.WebSocket):
input = utils.DataInputStream(raw_data)
type = input.readString()
data = dashboard.deserialize(input)
await ws.send(dashboard.to_bytes(type, await dashboard.process(type, data)).io.getbuffer())
await ws.send(
dashboard.to_bytes(
type, await dashboard.process(type, data)
).io.getbuffer()
)

@router.get("/auth")
async def _(request: web.Request):
auth = (await request.get_headers("Authorization")).split(" ", 1)[1]
try:
info = json.loads(base64.b64decode(auth))
except:
return web.Response(status_code=401)
if info["username"] != DASHBOARD_USERNAME or info["password"] != DASHBOARD_PASSWORD:
if (
info["username"] != DASHBOARD_USERNAME
or info["password"] != DASHBOARD_PASSWORD
):
return web.Response(status_code=401)
token = dashboard.generate_token(request)
return web.Response(DASHBOARD_USERNAME, cookies=[web.Cookie("auth", token.value, expires=int(time.time() + 86400))])
Expand Down
4 changes: 3 additions & 1 deletion core/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Optional
from typing import Any
import yaml
import os
from core.logger import logger
Expand All @@ -21,6 +21,8 @@
"advanced.request_buffer": 8192,
"advanced.io_buffer": 16777216,
"advanced.header_bytes": 4096,
"dashboard.username": "admin",
"dashboard.password": "",
}


Expand Down
42 changes: 36 additions & 6 deletions core/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
from core.config import Config
from core.timer import Task, Timer


@dataclass
class Token:
value: str
create_at: float


BASE_URL = "https://openbmclapi.bangbang93.com/"
CLUSTER_ID: str = Config.get("cluster.id")
CLUSTER_SECERT: str = Config.get("cluster.secret")
Expand All @@ -30,6 +32,8 @@ class Token:
cur_tqdm_text = None
task_tqdm: Optional[Task] = None
tokens: list[Token] = []


def deserialize(data: utils.DataInputStream):
match (data.readVarInt()):
case 0:
Expand All @@ -43,9 +47,13 @@ def deserialize(data: utils.DataInputStream):
case 4:
return [deserialize(data) for _ in range(data.readVarInt())]
case 5:
return {deserialize(data): deserialize(data) for _ in range(data.readVarInt())}
return {
deserialize(data): deserialize(data) for _ in range(data.readVarInt())
}
case 6:
return None


def serialize(data: Any):
buf = utils.DataOutputStream()
if isinstance(data, str):
Expand All @@ -63,7 +71,7 @@ def serialize(data: Any):
elif isinstance(data, list):
buf.writeVarInt(4)
buf.writeVarInt(len(data))
buf.write(b''.join((serialize(v).io.getvalue() for v in data)))
buf.write(b"".join((serialize(v).io.getvalue() for v in data)))
elif isinstance(data, dict):
buf.writeVarInt(5)
buf.writeVarInt(len(data.keys()))
Expand Down Expand Up @@ -104,7 +112,11 @@ async def process(type: str, data: Any):
"memory": system.get_used_memory(),
"connections": system.get_connections(),
"cpu": system.get_cpus(),
"cache": asdict(await cluster.cluster.get_cache_stats()) if cluster.cluster else StatsCache()
"cache": (
asdict(await cluster.cluster.get_cache_stats())
if cluster.cluster
else StatsCache()
),
}
if type == "storage":
return stats.get_storage_stats()
Expand Down Expand Up @@ -156,14 +168,32 @@ def to_bytes(type: str, data: Any):
output.write(serialize(data).io.getvalue())
return output

def generate_token(request: 'web.Request') -> Token:

def generate_token(request: "web.Request") -> Token:
global tokens
token = Token(hashlib.sha256(zlib.compress(hashlib.sha512((request.get_ip() + request.get_user_agent() + request.get_url() + CLUSTER_ID + CLUSTER_SECERT + str(time.time())).encode("utf-8")).digest())).hexdigest(), time.time())
token = Token(
hashlib.sha256(
zlib.compress(
hashlib.sha512(
(
request.get_ip()
+ request.get_user_agent()
+ request.get_url()
+ CLUSTER_ID
+ CLUSTER_SECERT
+ str(time.time())
).encode("utf-8")
).digest()
)
).hexdigest(),
time.time(),
)
tokens.append(token)
return token


def token_isvaild(value) -> bool:
for token in tokens:
if token.value == value and token.create_at + 86400 > time.time():
return True
return False
return False
Loading

0 comments on commit 3323a21

Please sign in to comment.