no message
parent
206da6685f
commit
b541ee05da
File diff suppressed because it is too large
Load Diff
@ -1,126 +0,0 @@
|
|||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
stopCount: 0,
|
|
||||||
renderjsData: {
|
|
||||||
url: "",
|
|
||||||
key: 0,
|
|
||||||
body: "",
|
|
||||||
method: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
stopChat() {
|
|
||||||
this.stopCount += 1
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 开始chat对话
|
|
||||||
*/
|
|
||||||
startChat(config) {
|
|
||||||
const { body } = config;
|
|
||||||
this.renderjsData = Object.assign({}, this.renderjsData, {
|
|
||||||
key: this.renderjsData.key + 1,
|
|
||||||
...config,
|
|
||||||
body: body ? JSON.stringify(body) : 0,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
open(...args) {
|
|
||||||
this.$emit("onInnerOpen", ...args)
|
|
||||||
},
|
|
||||||
message(msg) {
|
|
||||||
this.$emit("onInnerMessage", msg)
|
|
||||||
},
|
|
||||||
error(...args) {
|
|
||||||
this.$emit("onInnerError", ...args)
|
|
||||||
this.stopChat();
|
|
||||||
},
|
|
||||||
finish() {
|
|
||||||
this.$emit("onInnerFinish")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script module="chat" lang="renderjs">
|
|
||||||
import { fetchEventSource } from '../fetch-event-source';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
ctrl: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
objToJson(obj) {
|
|
||||||
const json = {};
|
|
||||||
for (const key in obj) {
|
|
||||||
const val = obj[key];
|
|
||||||
if (typeof val === "string" || typeof val === 'number' || typeof val === 'boolean') {
|
|
||||||
json[key] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止生成
|
|
||||||
*/
|
|
||||||
stopChatCore() {
|
|
||||||
this.ctrl?.abort();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始对话
|
|
||||||
*/
|
|
||||||
startChatCore({ url, body, headers, method }) {
|
|
||||||
if (!url) return;
|
|
||||||
try {
|
|
||||||
this.ctrl = new AbortController();
|
|
||||||
fetchEventSource(
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
readJson: true,
|
|
||||||
method,
|
|
||||||
openWhenHidden: true,
|
|
||||||
signal: this.ctrl.signal,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
body: body ? body : undefined,
|
|
||||||
onopen: (response) => {
|
|
||||||
this.$ownerInstance.callMethod('open', this.objToJson(response));
|
|
||||||
},
|
|
||||||
onmessage: (data) => {
|
|
||||||
this.$ownerInstance.callMethod('message', data);
|
|
||||||
},
|
|
||||||
onerror: (err) => {
|
|
||||||
console.log(err)
|
|
||||||
this.$ownerInstance.callMethod('error', JSON.stringify(err));
|
|
||||||
},
|
|
||||||
}).then(() => {
|
|
||||||
this.$ownerInstance.callMethod('finish');
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err)
|
|
||||||
this.$ownerInstance.callMethod('error', err);
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view
|
|
||||||
:renderjsData="renderjsData"
|
|
||||||
:change:renderjsData="chat.startChatCore"
|
|
||||||
:stopCount="stopCount"
|
|
||||||
:change:stopCount="chat.stopChatCore"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
<script>
|
|
||||||
import {getLines, getMessages} from "../fetch-event-source/parse"
|
|
||||||
|
|
||||||
let requestTask;
|
|
||||||
export default {
|
|
||||||
props: {},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
onChunk: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
const onLine = getMessages(() => {}, () => {}, (line) => {
|
|
||||||
this.$emit("onInnerMessage", line)
|
|
||||||
})
|
|
||||||
this.onChunk = getLines(onLine);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
stopChat() {
|
|
||||||
requestTask.offChunkReceived(this.listener)
|
|
||||||
requestTask.abort();
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(data) {
|
|
||||||
return decodeURIComponent(escape(String.fromCharCode(...data)));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始chat对话
|
|
||||||
* @param body
|
|
||||||
* @param url
|
|
||||||
* @param headers
|
|
||||||
* @param method
|
|
||||||
*/
|
|
||||||
startChat({ body, url, headers, method }) {
|
|
||||||
requestTask = uni.request({
|
|
||||||
url: url,
|
|
||||||
method,
|
|
||||||
header: {
|
|
||||||
Accept: 'text/event-stream',
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
data: body,
|
|
||||||
enableChunked: true,
|
|
||||||
responseType: 'arraybuffer',
|
|
||||||
success: (res) => {
|
|
||||||
console.log('0000000 success',res,' url:',url)
|
|
||||||
},
|
|
||||||
fail: (error) => {
|
|
||||||
console.log('0000000 fail',error,' url:',url)
|
|
||||||
this.$emit("onInnerError", error)
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
this.$emit("onInnerFinish")
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
requestTask.onChunkReceived(this.listener)
|
|
||||||
this.$emit("onInnerOpen", requestTask)
|
|
||||||
},
|
|
||||||
|
|
||||||
listener({ data }) {
|
|
||||||
const type = Object.prototype.toString.call(data);
|
|
||||||
if (type ==="[object Uint8Array]") {
|
|
||||||
} else if (data instanceof ArrayBuffer) {
|
|
||||||
data = new Uint8Array(data);
|
|
||||||
}
|
|
||||||
this.onChunk(data)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view />
|
|
||||||
</template>
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
var __rest = (this && this.__rest) || function (s, e) {
|
|
||||||
var t = {};
|
|
||||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
||||||
t[p] = s[p];
|
|
||||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
||||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
||||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
||||||
t[p[i]] = s[p[i]];
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
import { getBytes, getLines, getMessages } from './parse';
|
|
||||||
export const EventStreamContentType = 'text/event-stream';
|
|
||||||
const DefaultRetryInterval = 1000;
|
|
||||||
const LastEventId = 'last-event-id';
|
|
||||||
export function fetchEventSource(input, _a) {
|
|
||||||
var { signal: inputSignal, headers: inputHeaders, onopen: inputOnOpen, onmessage, onclose, onerror, openWhenHidden, fetch: inputFetch } = _a, rest = __rest(_a, ["signal", "headers", "onopen", "onmessage", "onclose", "onerror", "openWhenHidden", "fetch"]);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const headers = Object.assign({}, inputHeaders);
|
|
||||||
if (!headers.accept) {
|
|
||||||
headers.accept = EventStreamContentType;
|
|
||||||
}
|
|
||||||
let curRequestController;
|
|
||||||
function onVisibilityChange() {
|
|
||||||
curRequestController.abort();
|
|
||||||
if (!document.hidden) {
|
|
||||||
create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!openWhenHidden) {
|
|
||||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
||||||
}
|
|
||||||
let retryInterval = DefaultRetryInterval;
|
|
||||||
let retryTimer = 0;
|
|
||||||
function dispose() {
|
|
||||||
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
||||||
window.clearTimeout(retryTimer);
|
|
||||||
curRequestController.abort();
|
|
||||||
}
|
|
||||||
inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener('abort', () => {
|
|
||||||
dispose();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
const fetch = inputFetch !== null && inputFetch !== void 0 ? inputFetch : window.fetch;
|
|
||||||
const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;
|
|
||||||
async function create() {
|
|
||||||
var _a;
|
|
||||||
curRequestController = new AbortController();
|
|
||||||
try {
|
|
||||||
const response = await fetch(input, Object.assign(Object.assign({}, rest), { headers, signal: curRequestController.signal }));
|
|
||||||
await onopen(response);
|
|
||||||
await getBytes(response.body, getLines(getMessages(id => {
|
|
||||||
if (id) {
|
|
||||||
headers[LastEventId] = id;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delete headers[LastEventId];
|
|
||||||
}
|
|
||||||
}, retry => {
|
|
||||||
retryInterval = retry;
|
|
||||||
}, onmessage)));
|
|
||||||
onclose === null || onclose === void 0 ? void 0 : onclose();
|
|
||||||
dispose();
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
if (!curRequestController.signal.aborted) {
|
|
||||||
try {
|
|
||||||
const interval = (_a = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a !== void 0 ? _a : retryInterval;
|
|
||||||
window.clearTimeout(retryTimer);
|
|
||||||
retryTimer = window.setTimeout(create, interval);
|
|
||||||
}
|
|
||||||
catch (innerErr) {
|
|
||||||
dispose();
|
|
||||||
reject(innerErr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
create();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function defaultOnOpen(response) {
|
|
||||||
const contentType = response.headers.get('content-type');
|
|
||||||
if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {
|
|
||||||
throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=fetch.js.map
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export { fetchEventSource, EventStreamContentType } from './fetch';
|
|
||||||
//# sourceMappingURL=index.js.map
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
export async function getBytes(stream, onChunk) {
|
|
||||||
const reader = stream.getReader();
|
|
||||||
let result;
|
|
||||||
while (!(result = await reader.read()).done) {
|
|
||||||
onChunk(result.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function getLines(onLine) {
|
|
||||||
let buffer;
|
|
||||||
let position;
|
|
||||||
let fieldLength;
|
|
||||||
let discardTrailingNewline = false;
|
|
||||||
return function onChunk(arr) {
|
|
||||||
if (buffer === undefined) {
|
|
||||||
buffer = arr;
|
|
||||||
position = 0;
|
|
||||||
fieldLength = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buffer = concat(buffer, arr);
|
|
||||||
}
|
|
||||||
const bufLength = buffer.length;
|
|
||||||
let lineStart = 0;
|
|
||||||
while (position < bufLength) {
|
|
||||||
if (discardTrailingNewline) {
|
|
||||||
if (buffer[position] === 10) {
|
|
||||||
lineStart = ++position;
|
|
||||||
}
|
|
||||||
discardTrailingNewline = false;
|
|
||||||
}
|
|
||||||
let lineEnd = -1;
|
|
||||||
for (; position < bufLength && lineEnd === -1; ++position) {
|
|
||||||
switch (buffer[position]) {
|
|
||||||
case 58:
|
|
||||||
if (fieldLength === -1) {
|
|
||||||
fieldLength = position - lineStart;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
discardTrailingNewline = true;
|
|
||||||
case 10:
|
|
||||||
lineEnd = position;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lineEnd === -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
onLine(buffer.subarray(lineStart, lineEnd), fieldLength);
|
|
||||||
lineStart = position;
|
|
||||||
fieldLength = -1;
|
|
||||||
}
|
|
||||||
if (lineStart === bufLength) {
|
|
||||||
buffer = undefined;
|
|
||||||
}
|
|
||||||
else if (lineStart !== 0) {
|
|
||||||
buffer = buffer.subarray(lineStart);
|
|
||||||
position -= lineStart;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function getMessages(onId, onRetry, onMessage) {
|
|
||||||
let message = newMessage();
|
|
||||||
let decoder;
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
decoder = {
|
|
||||||
decode(arraybuffer) {
|
|
||||||
return decodeURIComponent(escape(String.fromCharCode(...arraybuffer)))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
decoder = new TextDecoder();
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
return function onLine(line, fieldLength) {
|
|
||||||
if (line.length === 0) {
|
|
||||||
onMessage === null || onMessage === void 0 ? void 0 : onMessage(message);
|
|
||||||
message = newMessage();
|
|
||||||
}
|
|
||||||
else if (fieldLength > 0) {
|
|
||||||
const field = decoder.decode(line.subarray(0, fieldLength));
|
|
||||||
const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);
|
|
||||||
const value = decoder.decode(line.subarray(valueOffset));
|
|
||||||
switch (field) {
|
|
||||||
case 'data':
|
|
||||||
message.data = message.data
|
|
||||||
? message.data + '\n' + value
|
|
||||||
: value;
|
|
||||||
break;
|
|
||||||
case 'event':
|
|
||||||
message.event = value;
|
|
||||||
break;
|
|
||||||
case 'id':
|
|
||||||
onId(message.id = value);
|
|
||||||
break;
|
|
||||||
case 'retry':
|
|
||||||
const retry = parseInt(value, 10);
|
|
||||||
if (!isNaN(retry)) {
|
|
||||||
onRetry(message.retry = retry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const msg = decoder.decode(line, { stream: true });
|
|
||||||
message.data = msg
|
|
||||||
onMessage(message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function concat(a, b) {
|
|
||||||
const res = new Uint8Array(a.length + b.length);
|
|
||||||
res.set(a);
|
|
||||||
res.set(b, a.length);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
function newMessage() {
|
|
||||||
return {
|
|
||||||
data: '',
|
|
||||||
event: '',
|
|
||||||
id: '',
|
|
||||||
retry: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//# sourceMappingURL=parse.js.map
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- #ifdef MP-WEIXIN-->
|
|
||||||
<ChatWxApplet ref="chatRef" @onInnerOpen="open" @onInnerError="error" @onInnerMessage="message" @onInnerFinish="finish" />
|
|
||||||
<!-- #endif-->
|
|
||||||
|
|
||||||
<!-- #ifdef APP-PLUS || H5-->
|
|
||||||
<ChatAppAndWeb ref="chatRef" @onInnerOpen="open" @onInnerError="error" @onInnerMessage="message" @onInnerFinish="finish" />
|
|
||||||
<!-- #endif-->
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
import ChatWxApplet from "./children/ChatWxApplet.vue";
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
import ChatAppAndWeb from "./children/ChatAppAndWeb.vue";
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
ChatWxApplet,
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS || H5
|
|
||||||
ChatAppAndWeb,
|
|
||||||
// #endif
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
startChat(config) {
|
|
||||||
config["method"] = (config["method"] || "post").toUpperCase();
|
|
||||||
config["headers"] = config["headers"] || {};
|
|
||||||
console.log("this.$refs['chatRef']", this.$refs["chatRef"]);
|
|
||||||
this.$refs["chatRef"].startChat(config);
|
|
||||||
},
|
|
||||||
|
|
||||||
stopChat(...args) {
|
|
||||||
console.log("this.$refs['chatRef']stopChat", this.$refs["chatRef"]);
|
|
||||||
this.$refs["chatRef"].stopChat(...args);
|
|
||||||
},
|
|
||||||
|
|
||||||
open(...args) {
|
|
||||||
this.$emit("onOpen", ...args);
|
|
||||||
},
|
|
||||||
message(msg) {
|
|
||||||
this.$emit("onMessage", msg);
|
|
||||||
},
|
|
||||||
error(...args) {
|
|
||||||
this.$emit("onError", ...args);
|
|
||||||
},
|
|
||||||
finish() {
|
|
||||||
this.$emit("onFinish");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
Loading…
Reference in New Issue