Skip to content

Commit 220ffaf

Browse files
authored
Merge pull request #88 from nineaiyu/dev
Dev
2 parents b0b22d8 + 865ef10 commit 220ffaf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+7614
-6644
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM nineaiyu/xadmin-server-base:20250224_065028 AS stage-build
1+
FROM nineaiyu/xadmin-server-base:20250326_075546 AS stage-build
22
ARG VERSION
33

44
WORKDIR /data/xadmin-server

common/base/magic.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ def invalid_caches(keys):
210210
logger.warning(
211211
f"invalid_cache_data cache_key:{delete_keys[0]}... {len(delete_keys)} count. delete count:{count}")
212212

213+
213214
class MagicCacheResponse(object):
214215
def __init__(self, timeout=60 * 10, invalid_time=0, key_func=None):
215216
self.timeout = timeout

common/cache/channel.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python
2+
# -*- coding:utf-8 -*-
3+
# project : xadmin-server
4+
# filename : channel
5+
# author : ly_13
6+
# date : 3/29/2025
7+
import time
8+
9+
from channels_redis.core import RedisChannelLayer as _RedisChannelLayer
10+
11+
12+
class RedisChannelLayer(_RedisChannelLayer):
13+
layer_expire = 30 # 需要心跳方式发送在线状态,否则将channel移除
14+
15+
async def group_discard(self, group, channel):
16+
"""
17+
Removes the channel from the named group if it is in the group;
18+
does nothing otherwise (does not error)
19+
"""
20+
assert self.valid_channel_name(channel), "Channel name not valid"
21+
connection, key = await self.auto_expire_layers(group)
22+
await connection.zrem(key, channel)
23+
24+
async def auto_expire_layers(self, group):
25+
assert self.valid_group_name(group), "Group name not valid"
26+
key = self._group_key(group)
27+
connection = self.connection(self.consistent_hash(group))
28+
29+
# Discard old channels based on group_expiry
30+
await connection.zremrangebyscore(
31+
key, min=0, max=int(time.time()) - self.layer_expire
32+
)
33+
34+
return connection, key
35+
36+
async def get_layers(self, group):
37+
connection, key = await self.auto_expire_layers(group)
38+
return [x.decode("utf8") for x in await connection.zrange(key, 0, -1)]
39+
40+
async def update_active_layers(self, group, channel):
41+
connection, key = await self.auto_expire_layers(group)
42+
await connection.zadd(key, {channel: time.time()})
43+
await connection.expire(key, self.group_expiry)
44+
45+
async def get_groups(self):
46+
groups = []
47+
group = self._group_key("*")
48+
for index in range(self.ring_size):
49+
connection = self.connection(index)
50+
cursor = 0
51+
while True:
52+
cursor, keys = await connection.scan(cursor, match=group)
53+
for key in keys:
54+
groups.append(key.decode("utf8").split(":")[-1])
55+
if cursor == 0:
56+
break
57+
return groups

common/cache/redis.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def __init__(self, key):
3939
def lock(self, *args, **kwargs):
4040
return self.connect.lock(f"{self.key}_locker", *args, **kwargs)
4141

42+
def expire(self, timeout=None):
43+
return self.connect.expire(self.key, timeout)
44+
4245

4346
class CacheList(CacheRedis):
4447

common/cache/storage.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,9 @@ class CommonResourceIDsCache(RedisCacheBase):
103103
def __init__(self, prefix_key):
104104
self.cache_key = f"{settings.CACHE_KEY_TEMPLATE.get('common_resource_ids_key')}_{prefix_key}"
105105
super().__init__(self.cache_key)
106+
107+
108+
class WebSocketMsgResultCache(RedisCacheBase):
109+
def __init__(self, prefix_key):
110+
self.cache_key = f"{settings.CACHE_KEY_TEMPLATE.get('websocket_message_result_key')}_{prefix_key}"
111+
super().__init__(self.cache_key)

common/core/fields.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ def get_choices(self, cutoff=None):
128128
result = []
129129
for item in queryset:
130130
data = self.to_representation(item)
131-
data['value'] = data.get("pk")
131+
if isinstance(data, dict):
132+
if "pk" in data:
133+
data['value'] = data.get("pk")
134+
else:
135+
data = {"value": data, "label": data}
132136
result.append(data)
133137
else:
134138
result = {}

common/core/modelset.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
# date : 6/2/2023
77
import itertools
88
import json
9+
import math
910
import uuid
1011
from hashlib import md5
1112
from typing import Callable
1213

13-
import math
1414
from django.conf import settings
1515
from django.db import transaction
1616
from django.forms.widgets import SelectMultiple, DateTimeInput
@@ -41,6 +41,7 @@
4141

4242
logger = get_logger(__name__)
4343

44+
4445
def run_view_by_celery_task(view, request, kwargs, data, batch_length=100):
4546
task = kwargs.get("task", request.query_params.get('task', 'true').lower() in ['true', '1', 'yes']) # 默认为任务异步导入
4647
if task:

common/core/response.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# filename : response
55
# author : ly_13
66
# date : 6/2/2023
7+
import datetime
78

89
from django.utils.translation import gettext_lazy as _
910
from rest_framework.response import Response
@@ -16,7 +17,8 @@ def __init__(self, code=1000, detail=None, data=None, status=None, headers=None,
1617
dic = {
1718
'code': code,
1819
'detail': detail if detail else (_("Operation successful") if code == 1000 else _("Operation failed")),
19-
'requestId': str(getattr(get_current_request(), 'request_uuid', ""))
20+
'requestId': str(getattr(get_current_request(), 'request_uuid', "")),
21+
'timestamp': str(datetime.datetime.now()),
2022
}
2123
if data is not None:
2224
dic['data'] = data

common/core/serializers.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,3 @@ def build_standard_field(self, field_name, model_field):
8585
default = default()
8686
field_kwargs.setdefault("default", default)
8787
return field_class, field_kwargs
88-

common/fields/image.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def get_thumbnail(source, index, force=False):
3939
return file.name
4040

4141

42-
4342
class ProcessedImageFieldFile(ImageFieldFile):
4443
is_local_storage = isinstance(default_storage, FileSystemStorage)
4544

0 commit comments

Comments
 (0)