1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-11 03:41:12 +00:00

listen notification

optimize code

Update user-api.js

optimize code

optimize code

Update lib-content-view.js

Update lib-content-view.js

remove-userless-code

update settings

optimize cur code

add max number of reconnections
This commit is contained in:
孙永强
2024-09-27 10:16:59 +08:00
parent 56d4ebc785
commit acd1a4a957
7 changed files with 161 additions and 3 deletions

View File

@@ -32,7 +32,7 @@ import DirColumnView from '../../components/dir-view-mode/dir-column-view';
import SelectedDirentsToolbar from '../../components/toolbar/selected-dirents-toolbar'; import SelectedDirentsToolbar from '../../components/toolbar/selected-dirents-toolbar';
import MetadataPathToolbar from '../../components/toolbar/metadata-path-toolbar'; import MetadataPathToolbar from '../../components/toolbar/metadata-path-toolbar';
import { eventBus } from '../../components/common/event-bus'; import { eventBus } from '../../components/common/event-bus';
import WebSocketClient from '../../utils/websocket-service';
import '../../css/lib-content-view.css'; import '../../css/lib-content-view.css';
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
@@ -49,7 +49,6 @@ class LibContentView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
let isTreePanelShown = true; let isTreePanelShown = true;
const storedTreePanelState = localStorage.getItem(TREE_PANEL_STATE_KEY); const storedTreePanelState = localStorage.getItem(TREE_PANEL_STATE_KEY);
if (storedTreePanelState != undefined) { if (storedTreePanelState != undefined) {
@@ -59,6 +58,7 @@ class LibContentView extends React.Component {
const storedDirentDetailShowState = localStorage.getItem(DIRENT_DETAIL_SHOW_KEY); const storedDirentDetailShowState = localStorage.getItem(DIRENT_DETAIL_SHOW_KEY);
const isDirentDetailShow = storedDirentDetailShowState === 'true'; const isDirentDetailShow = storedDirentDetailShowState === 'true';
this.socket = new WebSocketClient(this.onMessageCallback, this.props.repoID);
this.state = { this.state = {
currentMode: cookie.load('seafile_view_mode') || LIST_MODE, currentMode: cookie.load('seafile_view_mode') || LIST_MODE,
isTreePanelShown: isTreePanelShown, // display the 'dirent tree' side panel isTreePanelShown: isTreePanelShown, // display the 'dirent tree' side panel
@@ -161,6 +161,38 @@ class LibContentView extends React.Component {
this.calculatePara(this.props); this.calculatePara(this.props);
} }
onMessageCallback = (data) => {
if (data.type === 'file-lock-changed') {
const currentUrl = window.location.href;
const parsedUrl = new URL(currentUrl);
const pathParts = parsedUrl.pathname.split('/').filter(part => part.length > 0);
const dirRouter = decodeURIComponent(pathParts.slice(3).join('/'));
let notiUrlIndex = '';
if (data.content.path.includes('/')) {
notiUrlIndex = data.content.path.lastIndexOf('/');
}
const notifRouter = data.content.path.slice(0, notiUrlIndex);
if (dirRouter === notifRouter) {
const dirent = { name: data.content.path.split('/').pop() };
if (data.content.change_event === 'locked') {
if (data.content.expire === -1) {
this.updateDirent(dirent, 'is_freezed', true);
} else {
this.updateDirent(dirent, 'is_freezed', false);
}
this.updateDirent(dirent, 'is_locked', true);
this.updateDirent(dirent, 'locked_by_me', true);
let lockName = data.content.lock_user.split('@');
this.updateDirent(dirent, 'lock_owner_name', lockName[0]);
} else if (data.content.change_event === 'unlocked') {
this.updateDirent(dirent, 'is_locked', false);
this.updateDirent(dirent, 'locked_by_me', false);
this.updateDirent(dirent, 'lock_owner_name', '');
}
}
}
};
UNSAFE_componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.repoID !== this.props.repoID) { if (nextProps.repoID !== this.props.repoID) {
this.setState({ path: '/', viewId: '', tagID: '', currentMode: cookie.load('seafile_view_mode') || LIST_MODE }, () => { this.setState({ path: '/', viewId: '', tagID: '', currentMode: cookie.load('seafile_view_mode') || LIST_MODE }, () => {
@@ -280,6 +312,7 @@ class LibContentView extends React.Component {
isLibView: false, isLibView: false,
currentRepoInfo: null, currentRepoInfo: null,
}); });
this.socket.close();
} }
componentDidUpdate() { componentDidUpdate() {
@@ -405,6 +438,7 @@ class LibContentView extends React.Component {
// load data // load data
loadDirData = (path) => { loadDirData = (path) => {
// list used FileTags // list used FileTags
this.updateUsedRepoTags(); this.updateUsedRepoTags();

View File

@@ -31,6 +31,7 @@ export const fileServerRoot = window.app.config.fileServerRoot;
export const useGoFileserver = window.app.config.useGoFileserver; export const useGoFileserver = window.app.config.useGoFileserver;
export const seafileVersion = window.app.config.seafileVersion; export const seafileVersion = window.app.config.seafileVersion;
export const serviceURL = window.app.config.serviceURL; export const serviceURL = window.app.config.serviceURL;
export const notificationServerUrl = window.app.config.notificationServerUrl;
export const appAvatarURL = window.app.config.avatarURL; export const appAvatarURL = window.app.config.avatarURL;
export const faviconPath = window.app.config.faviconPath; export const faviconPath = window.app.config.faviconPath;
export const loginBGPath = window.app.config.loginBGPath; export const loginBGPath = window.app.config.loginBGPath;

View File

@@ -75,6 +75,12 @@ class UserAPI {
form.append('suite_id', suiteID); form.append('suite_id', suiteID);
return this.req.put(url, form); return this.req.put(url, form);
} }
getNotificationToken(repoID) {
const url = this.server + '/api/v2.1/repos/' + repoID + '/repo-notification-jwt-token/';
return this.req.get(url);
}
} }
let userAPI = new UserAPI(); let userAPI = new UserAPI();

View File

@@ -0,0 +1,116 @@
import { userAPI } from './user-api';
import { notificationServerUrl } from './constants';
class WebSocketClient {
constructor(onMessageCallback, repoId) {
this.url = notificationServerUrl; // WebSocket address;
this.repoId = repoId;
this.socket = null;
this.shouldReconnect = true;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.onMessageCallback = onMessageCallback;
if (notificationServerUrl !== '') {
this.connect();
}
}
async connect() {
this.socket = new WebSocket(this.url);
this.socket.onopen = async () => {
const msg = await this.formatSubscriptionMsg();
this.socket.send(JSON.stringify(msg));
};
// listen message from WebSocket server
this.socket.onmessage = async (event) => {
const parsedData = JSON.parse(event.data);
// jwt-expire reconnect
if (parsedData.type === 'jwt-expired') {
const msg = await this.formatSubscriptionMsg();
this.socket.send(JSON.stringify(msg));
} else {
this.onMessageCallback(parsedData);
}
};
this.socket.onerror = (error) => {
return error;
};
// reconnect WebSocket
this.socket.onclose = () => {
if (this.shouldReconnect) {
this.reconnect();
}
};
}
async getRepoJwtToken() {
const response = await userAPI.getNotificationToken(this.repoId).then(res => {
return res.data;
}).catch(err => {
throw err;
});
return response.token;
}
async formatSubscriptionMsg() {
const repoToken = await this.getRepoJwtToken();
const jsonData = {
type: 'subscribe',
content: {
repos: [
{
id: this.repoId,
jwt_token: repoToken,
},
],
},
};
return jsonData;
}
formatUnSubscriptionMsg() {
const jsonData = {
type: 'unsubscribe',
content: {
repos: [
{
id: this.repoId
},
],
},
};
return jsonData;
}
close() {
this.shouldReconnect = false;
if (this.socket) {
if (this.socket.readyState === WebSocket.OPEN) {
const msg = this.formatUnSubscriptionMsg();
this.socket.send(JSON.stringify(msg));
}
this.socket.close();
this.socket = null;
}
}
reconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
return;
}
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
setTimeout(() => {
this.reconnectAttempts++;
this.connect();
}, delay);
}
}
export default WebSocketClient;

View File

@@ -182,6 +182,7 @@ def base(request):
'enable_seafile_ai': ENABLE_SEAFILE_AI, 'enable_seafile_ai': ENABLE_SEAFILE_AI,
'enable_whiteboard': ENABLE_WHITEBOARD, 'enable_whiteboard': ENABLE_WHITEBOARD,
'enable_excalidraw': ENABLE_EXCALIDRAW, 'enable_excalidraw': ENABLE_EXCALIDRAW,
'notification_server_url': os.environ.get('NOTIFICATION_SERVER_URL', ''),
} }
if request.user.is_staff: if request.user.is_staff:

View File

@@ -941,7 +941,6 @@ SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER = True # Whether to send email when a system
SEND_EMAIL_ON_RESETTING_USER_PASSWD = True # Whether to send email when a system staff resetting user's password. SEND_EMAIL_ON_RESETTING_USER_PASSWD = True # Whether to send email when a system staff resetting user's password.
########################## ##########################
# Settings for seadoc # # Settings for seadoc #
########################## ##########################

View File

@@ -58,6 +58,7 @@
cloudMode: {% if cloud_mode %} true {% else %} false {% endif %}, cloudMode: {% if cloud_mode %} true {% else %} false {% endif %},
isOrgContext: {% if org is not None %} true {% else %} false {% endif %}, isOrgContext: {% if org is not None %} true {% else %} false {% endif %},
enableSeafileAI: {% if enable_seafile_ai %} true {% else %} false {% endif %}, enableSeafileAI: {% if enable_seafile_ai %} true {% else %} false {% endif %},
notificationServerUrl: '{{ notification_server_url }}'
}, },
pageOptions: { pageOptions: {
csrfToken: "{{ csrf_token }}", csrfToken: "{{ csrf_token }}",