fix: users_version param in SSE

This commit is contained in:
Tristan Yang
2022-08-25 11:22:26 +08:00
parent 30453587ca
commit 54a0c7a4ef
+217 -212
View File
@@ -60,236 +60,241 @@ export default function useStreaming() {
// 开始初始化
initializing = true;
await fetchEventSource(
`${BASE_URL}/user/events?${getQueryString({
"api-key": token,
users_version: `${usersVersion}`,
after_mid: `${afterMid}`
})}`,
{
openWhenHidden: true,
signal: controller.signal,
async onopen(response) {
initializing = false;
if (response.ok && response.headers.get("content-type") === EventStreamContentType) {
console.log("sse everything ok");
initialized = true;
return; // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// 重新登录
// client-side errors are usually non-retriable:
console.log("sse debug: open fatal");
throw new FatalError();
} else {
// server error
console.log("sse debug: open retry");
throw new RetriableError();
}
},
onmessage(evt) {
initializing = false;
console.log("sse message", evt.data);
// if the server emits an error message, throw an exception
// so it gets handled by the onerror callback below:
if (evt.event === "FatalError") {
console.log("sse debug: error message fatal");
throw new FatalError(evt.data);
}
const data: ServerEvent = JSON.parse(evt.data);
const { type } = data;
switch (type) {
case "heartbeat":
console.log("heartbeat", loginUid);
break;
case "ready":
console.log("streaming ready");
dispatch(setReady());
break;
case "users_snapshot":
{
console.log("users snapshot");
const { version } = data;
dispatch(updateUsersVersion(version));
}
break;
case "users_log":
{
console.log("users change logs");
const { logs } = data;
dispatch(updateUsersByLogs(logs));
}
break;
case "user_settings":
case "user_settings_changed":
{
console.log("users settings");
Object.keys(data).forEach((key) => {
switch (key) {
case "read_index_groups":
dispatch(updateReadChannels(data[key]));
break;
case "read_index_users":
dispatch(updateReadUsers(data[key]));
break;
case "add_mute_users":
case "mute_users":
case "add_mute_groups":
case "mute_groups":
{
const arr = data[key];
if (arr && arr.length) {
const _key = key.endsWith("users") ? "add_users" : "add_groups";
dispatch(updateMute({ [_key]: arr }));
}
const params: {
"api-key": string;
after_mid: string;
users_version?: string;
} = {
"api-key": token,
after_mid: `${afterMid}`
};
// 如果usersVersion是0,则不传该参数
if (usersVersion !== 0) {
params.users_version = `${usersVersion}`;
}
await fetchEventSource(`${BASE_URL}/user/events?${getQueryString(params)}`, {
openWhenHidden: true,
signal: controller.signal,
async onopen(response) {
initializing = false;
if (response.ok && response.headers.get("content-type") === EventStreamContentType) {
console.log("sse everything ok");
initialized = true;
return; // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// 重新登录
// client-side errors are usually non-retriable:
console.log("sse debug: open fatal");
throw new FatalError();
} else {
// server error
console.log("sse debug: open retry");
throw new RetriableError();
}
},
onmessage(evt) {
initializing = false;
console.log("sse message", evt.data);
// if the server emits an error message, throw an exception
// so it gets handled by the onerror callback below:
if (evt.event === "FatalError") {
console.log("sse debug: error message fatal");
throw new FatalError(evt.data);
}
const data: ServerEvent = JSON.parse(evt.data);
const { type } = data;
switch (type) {
case "heartbeat":
console.log("heartbeat", loginUid);
break;
case "ready":
console.log("streaming ready");
dispatch(setReady());
break;
case "users_snapshot":
{
console.log("users snapshot");
const { version } = data;
dispatch(updateUsersVersion(version));
}
break;
case "users_log":
{
const { logs } = data;
console.log("users change logs", logs);
dispatch(updateUsersByLogs(logs));
}
break;
case "user_settings":
case "user_settings_changed":
{
console.log("users settings");
Object.keys(data).forEach((key) => {
switch (key) {
case "read_index_groups":
dispatch(updateReadChannels(data[key]));
break;
case "read_index_users":
dispatch(updateReadUsers(data[key]));
break;
case "add_mute_users":
case "mute_users":
case "add_mute_groups":
case "mute_groups":
{
const arr = data[key];
if (arr && arr.length) {
const _key = key.endsWith("users") ? "add_users" : "add_groups";
dispatch(updateMute({ [_key]: arr }));
}
break;
case "remove_mute_users":
case "remove_mute_groups":
{
const arr = data[key];
if (arr && arr.length) {
const _key = key.endsWith("users") ? "remove_users" : "remove_groups";
dispatch(updateMute({ [_key]: arr }));
}
}
break;
case "remove_mute_users":
case "remove_mute_groups":
{
const arr = data[key];
if (arr && arr.length) {
const _key = key.endsWith("users") ? "remove_users" : "remove_groups";
dispatch(updateMute({ [_key]: arr }));
}
break;
}
break;
default:
break;
}
});
}
break;
case "users_state":
case "users_state_changed":
{
let { type, ...rest } = data;
const onlines =
type == "users_state_changed" ? [rest] : (rest as UsersStateEvent).users;
dispatch(updateUsersStatus(onlines));
}
break;
case "kick":
{
console.log("kicked");
switch (data.reason) {
case "login_from_other_device":
dispatch(resetAuthData());
toast("kicked from the other device");
break;
case "delete_user":
dispatch(resetAuthData());
toast("sorry, your account has been deleted");
break;
default:
break;
}
});
}
break;
case "users_state":
case "users_state_changed":
{
let { type, ...rest } = data;
const onlines =
type == "users_state_changed" ? [rest] : (rest as UsersStateEvent).users;
dispatch(updateUsersStatus(onlines));
}
break;
case "kick":
{
console.log("kicked");
switch (data.reason) {
case "login_from_other_device":
dispatch(resetAuthData());
toast("kicked from the other device");
break;
case "delete_user":
dispatch(resetAuthData());
toast("sorry, your account has been deleted");
break;
default:
break;
}
break;
case "related_groups":
console.log("fill channels from streaming", data);
dispatch(fillChannels(data.groups));
break;
case "joined_group":
console.log("joined group", data.group);
dispatch(addChannel(data.group));
break;
case "group_changed":
{
const { gid, ...rest } = data;
}
break;
case "related_groups":
console.log("fill channels from streaming", data);
dispatch(fillChannels(data.groups));
break;
case "joined_group":
console.log("joined group", data.group);
dispatch(addChannel(data.group));
break;
case "group_changed":
{
const { gid, ...rest } = data;
dispatch(
updateChannel({
gid,
...rest
})
);
}
break;
case "user_joined_group":
{
console.log("new user joined group", data.gid);
const { gid, uid: uids } = data;
// 去重
dispatch(
updateChannel({
operation: "add_member",
gid,
members: uids
})
);
}
break;
case "user_leaved_group":
{
const { gid, uid: uids } = data;
if (uids.findIndex((uid) => uid == loginUid) > -1) {
dispatch(removeChannel(gid));
} else {
dispatch(
updateChannel({
gid,
...rest
})
);
}
break;
case "user_joined_group":
{
console.log("new user joined group", data.gid);
const { gid, uid: uids } = data;
// 去重
dispatch(
updateChannel({
operation: "add_member",
operation: "remove_member",
gid,
members: uids
})
);
}
break;
case "user_leaved_group":
{
const { gid, uid: uids } = data;
if (uids.findIndex((uid) => uid == loginUid) > -1) {
dispatch(removeChannel(gid));
} else {
dispatch(
updateChannel({
operation: "remove_member",
gid,
members: uids
})
);
}
}
break;
case "kick_from_group":
console.log("kicked from group", data.gid);
dispatch(removeChannel(data.gid));
break;
case "pinned_message_updated":
{
// const {gid,mid,msg}=data;
dispatch(updatePinMessage(data));
}
break;
case "chat":
{
chatMessageHandler(data, dispatch, {
ready,
loginUid,
readUsers,
readChannels
});
}
break;
default:
console.log("sse event data", data);
break;
}
},
onclose() {
// if the server closes the connection unexpectedly, retry:
console.log("sse debug: closed");
initializing = false;
throw new RetriableError();
},
onerror(err) {
initializing = false;
if (err instanceof FatalError || err.toString().indexOf("network error") > -1) {
console.log("sse debug: error fatal", err);
throw err; // rethrow to stop the operation
} else {
console.log("sse debug: error other", err);
stopStreaming();
if (inter) {
clearTimeout(inter);
}
// 重连
inter = window.setTimeout(() => {
initialized = false;
startStreaming();
}, 2000);
throw err; // rethrow to stop the operation
// do nothing to automatically retry. You can also
// return a specific retry interval here.
break;
case "kick_from_group":
console.log("kicked from group", data.gid);
dispatch(removeChannel(data.gid));
break;
case "pinned_message_updated":
{
// const {gid,mid,msg}=data;
dispatch(updatePinMessage(data));
}
break;
case "chat":
{
chatMessageHandler(data, dispatch, {
ready,
loginUid,
readUsers,
readChannels
});
}
break;
default:
console.log("sse event data", data);
break;
}
},
onclose() {
// if the server closes the connection unexpectedly, retry:
console.log("sse debug: closed");
initializing = false;
throw new RetriableError();
},
onerror(err) {
initializing = false;
if (err instanceof FatalError || err.toString().indexOf("network error") > -1) {
console.log("sse debug: error fatal", err);
throw err; // rethrow to stop the operation
} else {
console.log("sse debug: error other", err);
stopStreaming();
if (inter) {
clearTimeout(inter);
}
// 重连
inter = window.setTimeout(() => {
initialized = false;
startStreaming();
}, 2000);
throw err; // rethrow to stop the operation
// do nothing to automatically retry. You can also
// return a specific retry interval here.
}
}
);
});
initializing = false;
// for controlling
return controller;