mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
reimplement api, with namespaces
This commit is contained in:
parent
8d42494f10
commit
a09b79aaea
@ -35,7 +35,7 @@ export default [
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.request.post.updateUser({
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
fullName: value
|
||||
@ -52,7 +52,7 @@ export default [
|
||||
"icon": "Delete",
|
||||
"title": "Unset",
|
||||
"onClick": async () => {
|
||||
window.app.request.post.unsetPublicName()
|
||||
window.app.api.withEndpoints("main").post.unsetPublicName()
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -78,7 +78,7 @@ export default [
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.request.post.updateUser({
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
email: value
|
||||
@ -105,7 +105,7 @@ export default [
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.request.post.updateUser({
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
avatar: value
|
||||
@ -132,7 +132,7 @@ export default [
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.request.post.updateUser({
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
cover: value
|
||||
@ -173,7 +173,7 @@ export default [
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.request.post.updateUser({
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
description: value
|
||||
|
@ -313,12 +313,19 @@ class App extends React.Component {
|
||||
const initializationTasks = [
|
||||
async () => {
|
||||
try {
|
||||
await this.props.cores.ApiCore.attachAPIConnection()
|
||||
// mount main api bridge
|
||||
await this.props.cores.ApiCore.connectBridge("main", {
|
||||
locked: true
|
||||
})
|
||||
|
||||
// and initialize it
|
||||
await this.props.cores.ApiCore.namespaces["main"].initialize()
|
||||
|
||||
app.eventBus.emit("app.initialization.api_success")
|
||||
} catch (error) {
|
||||
app.eventBus.emit("app.initialization.api_error", error)
|
||||
|
||||
console.error(`[App] Error while initializing api`, error)
|
||||
|
||||
throw {
|
||||
cause: "Cannot connect to API",
|
||||
details: `Sorry but we cannot connect to the API. Please try again later. [${config.remotes.mainApi}]`,
|
||||
@ -353,20 +360,6 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
await this.__WSInit()
|
||||
|
||||
app.eventBus.emit("app.initialization.ws_success")
|
||||
} catch (error) {
|
||||
app.eventBus.emit("app.initialization.ws_error", error)
|
||||
|
||||
throw {
|
||||
cause: "Cannot connect to WebSocket",
|
||||
details: error.message,
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
await Promise.tasked(initializationTasks).catch((reason) => {
|
||||
@ -394,14 +387,6 @@ class App extends React.Component {
|
||||
await this.setState({ session })
|
||||
}
|
||||
|
||||
__WSInit = async () => {
|
||||
if (!this.state.session) {
|
||||
return false
|
||||
}
|
||||
|
||||
await this.props.cores.ApiCore.attachWSConnection()
|
||||
}
|
||||
|
||||
__UserInit = async () => {
|
||||
if (!this.state.session) {
|
||||
return false
|
||||
|
@ -71,7 +71,7 @@ export default class UserDataManager extends React.Component {
|
||||
loading: false,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
if (!this.props.user && this.props.userId) {
|
||||
|
@ -12,7 +12,7 @@ export default class UserRolesManager extends React.Component {
|
||||
roles: null,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
await this.fetchRoles()
|
||||
|
@ -12,7 +12,7 @@ export default class ImageUploader extends React.Component {
|
||||
urlList: [],
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
handleChange = ({ fileList }) => {
|
||||
this.setState({ fileList })
|
||||
|
@ -309,7 +309,7 @@ export const PostCard = React.memo(({
|
||||
|
||||
React.useEffect(() => {
|
||||
// first listen to post changes
|
||||
window.app.ws.listen(`post.dataUpdate.${data._id}`, onDataUpdate)
|
||||
window.app.api.namespaces["main"].listenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
|
||||
|
||||
// proccess post info
|
||||
// {...}
|
||||
@ -319,7 +319,7 @@ export const PostCard = React.memo(({
|
||||
|
||||
return () => {
|
||||
// remove the listener
|
||||
window.app.ws.unlisten(`post.dataUpdate.${data._id}`, onDataUpdate)
|
||||
window.app.api.namespaces["main"].unlistenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
@ -12,7 +12,7 @@ import "./index.less"
|
||||
const maxMessageLength = 512
|
||||
|
||||
export default (props) => {
|
||||
const api = window.app.request
|
||||
const api = window.app.api.withEndpoints("main")
|
||||
|
||||
const additionsRef = React.useRef(null)
|
||||
const [pending, setPending] = React.useState([])
|
||||
|
@ -30,7 +30,7 @@ export default class PostsFeed extends React.Component {
|
||||
renderList: [],
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints()
|
||||
|
||||
listRef = React.createRef()
|
||||
|
||||
@ -48,7 +48,7 @@ export default class PostsFeed extends React.Component {
|
||||
|
||||
// load ws events
|
||||
Object.keys(this.wsEvents).forEach((event) => {
|
||||
window.app.ws.listen(event, this.wsEvents[event])
|
||||
window.app.api.namespaces["main"].listenEvent(event, this.wsEvents[event])
|
||||
})
|
||||
|
||||
// TODO: register keybindings to handle directions key scrolling to posts (use app.shortcuts)
|
||||
@ -67,7 +67,7 @@ export default class PostsFeed extends React.Component {
|
||||
componentWillUnmount = async () => {
|
||||
// unload ws events
|
||||
Object.keys(this.wsEvents).forEach((event) => {
|
||||
window.app.ws.unlisten(event, this.wsEvents[event])
|
||||
window.app.api.namespaces["main"].unlistenEvent(event, this.wsEvents[event])
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ export default class StepsForm extends React.Component {
|
||||
renderStep: null,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
if (this.props.defaultValues) {
|
||||
|
@ -66,7 +66,7 @@ const steps = [
|
||||
]
|
||||
|
||||
export default (props) => {
|
||||
const api = window.app.request
|
||||
const api = window.app.api.withEndpoints("main")
|
||||
|
||||
const onSubmit = async (values) => {
|
||||
const result = await api.post.register(values).catch((err) => {
|
||||
|
@ -14,7 +14,7 @@ export default class UserSelector extends React.Component {
|
||||
searchValue: null,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
this.toogleLoading(true)
|
||||
|
@ -7,50 +7,40 @@ export default class ApiCore extends Core {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.apiBridge = this.createBridge()
|
||||
this.namespaces = Object()
|
||||
|
||||
this.WSInterface = {
|
||||
...this.apiBridge.wsInterface,
|
||||
request: this.WSRequest,
|
||||
listen: this.listenEvent,
|
||||
unlisten: this.unlistenEvent,
|
||||
mainSocketConnected: false
|
||||
this.ctx.registerPublicMethod("api", this)
|
||||
}
|
||||
|
||||
request = (namespace = "main", method, endpoint, ...args) => {
|
||||
if (!this.namespaces[namespace]) {
|
||||
throw new Error(`Namespace ${namespace} not found`)
|
||||
}
|
||||
|
||||
this.ctx.registerPublicMethod("api", this.apiBridge)
|
||||
this.ctx.registerPublicMethod("ws", this.WSInterface)
|
||||
this.ctx.registerPublicMethod("request", this.apiBridge.endpoints)
|
||||
this.ctx.registerPublicMethod("WSRequest", this.WSInterface.wsEndpoints)
|
||||
if (!this.namespaces[namespace].endpoints[method]) {
|
||||
throw new Error(`Method ${method} not found`)
|
||||
}
|
||||
|
||||
if (!this.namespaces[namespace].endpoints[method][endpoint]) {
|
||||
throw new Error(`Endpoint ${endpoint} not found`)
|
||||
}
|
||||
|
||||
return this.namespaces[namespace].endpoints[method][endpoint](...args)
|
||||
}
|
||||
|
||||
async intialize() {
|
||||
this.WSInterface.sockets.main.on("authenticated", () => {
|
||||
console.debug("[WS] Authenticated")
|
||||
})
|
||||
this.WSInterface.sockets.main.on("authenticateFailed", (error) => {
|
||||
console.error("[WS] Authenticate Failed", error)
|
||||
})
|
||||
withEndpoints = (namespace = "main") => {
|
||||
if (!this.namespaces[namespace]) {
|
||||
throw new Error(`Namespace ${namespace} not found`)
|
||||
}
|
||||
|
||||
this.WSInterface.sockets.main.on("connect", () => {
|
||||
this.ctx.eventBus.emit("websocket_connected")
|
||||
|
||||
this.WSInterface.mainSocketConnected = true
|
||||
})
|
||||
|
||||
this.WSInterface.sockets.main.on("disconnect", (...context) => {
|
||||
this.ctx.eventBus.emit("websocket_disconnected", ...context)
|
||||
|
||||
this.WSInterface.mainSocketConnected = false
|
||||
})
|
||||
|
||||
this.WSInterface.sockets.main.on("connect_error", (...context) => {
|
||||
this.ctx.eventBus.emit("websocket_connection_error", ...context)
|
||||
|
||||
this.WSInterface.mainSocketConnected = false
|
||||
})
|
||||
return this.namespaces[namespace].endpoints
|
||||
}
|
||||
|
||||
createBridge() {
|
||||
connectBridge = (key, params) => {
|
||||
this.namespaces[key] = this.createBridge(params)
|
||||
}
|
||||
|
||||
createBridge(params = {}) {
|
||||
const getSessionContext = async () => {
|
||||
const obj = {}
|
||||
const token = await Session.token
|
||||
@ -80,111 +70,103 @@ export default class ApiCore extends Core {
|
||||
}
|
||||
}
|
||||
|
||||
return new Bridge({
|
||||
origin: config.remotes.mainApi,
|
||||
wsOrigin: config.remotes.websocketApi,
|
||||
if (typeof params !== "object") {
|
||||
throw new Error("Params must be an object")
|
||||
}
|
||||
|
||||
const bridgeOptions = {
|
||||
wsOptions: {
|
||||
autoConnect: false,
|
||||
},
|
||||
onRequest: getSessionContext,
|
||||
onResponse: handleResponse,
|
||||
})
|
||||
}
|
||||
|
||||
async attachWSConnection() {
|
||||
if (!this.WSInterface.sockets.main.connected) {
|
||||
await this.WSInterface.sockets.main.connect()
|
||||
...params,
|
||||
origin: params.httpAddress ?? config.remotes.mainApi,
|
||||
wsOrigin: params.wsAddress ?? config.remotes.websocketApi,
|
||||
}
|
||||
|
||||
let startTime = null
|
||||
let latency = null
|
||||
let latencyWarning = false
|
||||
const bridge = new Bridge(bridgeOptions)
|
||||
|
||||
let pingInterval = setInterval(() => {
|
||||
if (!this.WSInterface.mainSocketConnected) {
|
||||
return clearTimeout(pingInterval)
|
||||
// handle main ws events
|
||||
const mainWSSocket = bridge.wsInterface.sockets["main"]
|
||||
|
||||
mainWSSocket.on("authenticated", () => {
|
||||
console.debug("[WS] Authenticated")
|
||||
})
|
||||
|
||||
mainWSSocket.on("authenticateFailed", (error) => {
|
||||
console.error("[WS] Authenticate Failed", error)
|
||||
})
|
||||
|
||||
mainWSSocket.on("connect", () => {
|
||||
this.ctx.eventBus.emit(`api.ws.${mainWSSocket.id}.connect`)
|
||||
})
|
||||
|
||||
mainWSSocket.on("disconnect", (...context) => {
|
||||
this.ctx.eventBus.emit(`api.ws.${mainWSSocket.id}.disconnect`, ...context)
|
||||
})
|
||||
|
||||
mainWSSocket.on("connect_error", (...context) => {
|
||||
this.ctx.eventBus.emit(`api.ws.${mainWSSocket.id}.connect_error`, ...context)
|
||||
})
|
||||
|
||||
// generate functions
|
||||
bridge.listenEvent = this.generateMainWSEventListener(bridge.wsInterface)
|
||||
bridge.unlistenEvent = this.generateMainWSEventUnlistener(bridge.wsInterface)
|
||||
|
||||
// return bridge
|
||||
return bridge
|
||||
}
|
||||
|
||||
generateMainWSEventListener(obj) {
|
||||
return (to, fn) => {
|
||||
if (typeof to === "undefined") {
|
||||
console.error("handleWSListener: to must be defined")
|
||||
return false
|
||||
}
|
||||
if (typeof fn !== "function") {
|
||||
console.error("handleWSListener: fn must be function")
|
||||
return false
|
||||
}
|
||||
|
||||
startTime = Date.now()
|
||||
this.WSInterface.sockets.main.emit("ping")
|
||||
}, 2000)
|
||||
let ns = "main"
|
||||
let event = null
|
||||
|
||||
this.WSInterface.sockets.main.on("pong", () => {
|
||||
latency = Date.now() - startTime
|
||||
|
||||
if (latency > 800 && this.WSInterface.mainSocketConnected) {
|
||||
latencyWarning = true
|
||||
console.error("[WS] Latency is too high > 800ms", latency)
|
||||
window.app.eventBus.emit("websocket_latency_too_high", latency)
|
||||
} else if (latencyWarning && this.WSInterface.mainSocketConnected) {
|
||||
latencyWarning = false
|
||||
window.app.eventBus.emit("websocket_latency_normal", latency)
|
||||
if (typeof to === "string") {
|
||||
event = to
|
||||
} else if (typeof to === "object") {
|
||||
ns = to.ns
|
||||
event = to.event
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async attachAPIConnection() {
|
||||
await this.apiBridge.initialize()
|
||||
}
|
||||
|
||||
listenEvent = (to, fn) => {
|
||||
if (typeof to === "undefined") {
|
||||
console.error("handleWSListener: to must be defined")
|
||||
return false
|
||||
}
|
||||
if (typeof fn !== "function") {
|
||||
console.error("handleWSListener: fn must be function")
|
||||
return false
|
||||
}
|
||||
|
||||
let ns = "main"
|
||||
let event = null
|
||||
|
||||
if (typeof to === "string") {
|
||||
event = to
|
||||
} else if (typeof to === "object") {
|
||||
ns = to.ns
|
||||
event = to.event
|
||||
}
|
||||
|
||||
return window.app.ws.sockets[ns].on(event, async (...context) => {
|
||||
return await fn(...context)
|
||||
})
|
||||
}
|
||||
|
||||
unlistenEvent = (to, fn) => {
|
||||
if (typeof to === "undefined") {
|
||||
console.error("handleWSListener: to must be defined")
|
||||
return false
|
||||
}
|
||||
if (typeof fn !== "function") {
|
||||
console.error("handleWSListener: fn must be function")
|
||||
return false
|
||||
}
|
||||
|
||||
let ns = "main"
|
||||
let event = null
|
||||
|
||||
if (typeof to === "string") {
|
||||
event = to
|
||||
} else if (typeof to === "object") {
|
||||
ns = to.ns
|
||||
event = to.event
|
||||
}
|
||||
|
||||
return window.app.ws.sockets[ns].removeListener(event, fn)
|
||||
}
|
||||
|
||||
WSRequest = (socket = "main", channel, ...args) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const request = await window.app.ws.sockets[socket].emit(channel, ...args)
|
||||
|
||||
request.on("responseError", (...errors) => {
|
||||
return reject(...errors)
|
||||
return obj.sockets[ns].on(event, async (...context) => {
|
||||
return await fn(...context)
|
||||
})
|
||||
request.on("response", (...responses) => {
|
||||
return resolve(...responses)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
generateMainWSEventUnlistener(obj) {
|
||||
return (to, fn) => {
|
||||
if (typeof to === "undefined") {
|
||||
console.error("handleWSListener: to must be defined")
|
||||
return false
|
||||
}
|
||||
if (typeof fn !== "function") {
|
||||
console.error("handleWSListener: fn must be function")
|
||||
return false
|
||||
}
|
||||
|
||||
let ns = "main"
|
||||
let event = null
|
||||
|
||||
if (typeof to === "string") {
|
||||
event = to
|
||||
} else if (typeof to === "object") {
|
||||
ns = to.ns
|
||||
event = to.event
|
||||
}
|
||||
|
||||
return obj.sockets[ns].removeListener(event, fn)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import { Storage } from '@capacitor/storage'
|
||||
|
||||
export default class Session {
|
||||
static get bridge() {
|
||||
return window.app?.request
|
||||
return window.app?.api.withEndpoints("main")
|
||||
}
|
||||
|
||||
static capStorage = async (method, value) => {
|
||||
|
@ -2,7 +2,7 @@ import Session from "../session"
|
||||
|
||||
export default class User {
|
||||
static get bridge() {
|
||||
return window.app?.request
|
||||
return window.app?.api.withEndpoints("main")
|
||||
}
|
||||
|
||||
static async data() {
|
||||
|
@ -82,7 +82,7 @@ export default class Account extends React.Component {
|
||||
isNotExistent: false,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
const token = await Session.decodedToken()
|
||||
|
@ -136,7 +136,7 @@ export default class StreamViewer extends React.Component {
|
||||
}
|
||||
|
||||
gatherStreamInfo = async () => {
|
||||
const result = await app.request.get.streamInfoFromUsername(undefined, {
|
||||
const result = await app.api.withEndpoints("main").get.streamInfoFromUsername(undefined, {
|
||||
username: this.state.streamKey,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
@ -152,7 +152,7 @@ export default class StreamViewer extends React.Component {
|
||||
}
|
||||
|
||||
gatherUserInfo = async () => {
|
||||
const result = await app.request.get.user(undefined, {
|
||||
const result = await app.api.withEndpoints("main").get.user(undefined, {
|
||||
username: this.state.streamKey,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
|
@ -35,7 +35,7 @@ export default (props) => {
|
||||
const [serverTier, setServerTier] = React.useState(null)
|
||||
|
||||
const checkStreamingKey = async () => {
|
||||
const result = await app.request.get.streamingKey().catch((error) => {
|
||||
const result = await app.api.withEndpoints("main").get.streamingKey().catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
|
||||
@ -48,7 +48,7 @@ export default (props) => {
|
||||
}
|
||||
|
||||
const checkTagetServer = async () => {
|
||||
const result = await app.request.get.targetStreamingServer()
|
||||
const result = await app.api.withEndpoints("main").get.targetStreamingServer()
|
||||
|
||||
if (result) {
|
||||
const targetServer = `${result.protocol}://${result.address}:${result.port}/${result.space}`
|
||||
@ -61,7 +61,7 @@ export default (props) => {
|
||||
title: "Regenerate streaming key",
|
||||
content: "Are you sure you want to regenerate the streaming key? After this, all other generated keys will be deleted.",
|
||||
onOk: async () => {
|
||||
const result = await app.request.post.regenerateStreamingKey().catch((error) => {
|
||||
const result = await app.api.withEndpoints("main").post.regenerateStreamingKey().catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
|
||||
|
@ -10,7 +10,7 @@ export default class Streams extends React.Component {
|
||||
list: [],
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
await this.updateStreamsList()
|
||||
|
@ -11,7 +11,7 @@ export default class Users extends React.Component {
|
||||
selectionEnabled: false,
|
||||
}
|
||||
|
||||
api = window.app.request
|
||||
api = window.app.api.withEndpoints("main")
|
||||
|
||||
componentDidMount = async () => {
|
||||
await this.loadData()
|
||||
|
Loading…
x
Reference in New Issue
Block a user