mirror of
https://github.com/status-im/codimd.git
synced 2025-02-12 06:06:44 +00:00
ts: lib/realtime/realtime.ts
Signed-off-by: Raccoon <raccoon@hackmd.io>
This commit is contained in:
parent
16618e1e61
commit
7cea9a29a9
@ -1,62 +1,53 @@
|
|||||||
'use strict'
|
|
||||||
// realtime
|
// realtime
|
||||||
// external modules
|
// external modules
|
||||||
const cookie = require('cookie')
|
import * as cookie from "cookie";
|
||||||
const cookieParser = require('cookie-parser')
|
import * as cookieParser from "cookie-parser";
|
||||||
const url = require('url')
|
import * as url from "url";
|
||||||
const randomcolor = require('randomcolor')
|
import * as randomcolor from "randomcolor";
|
||||||
const Chance = require('chance')
|
import * as Chance from "chance";
|
||||||
const chance = new Chance()
|
import * as moment from "moment";
|
||||||
const moment = require('moment')
|
import {get} from "lodash";
|
||||||
|
|
||||||
const get = require('lodash/get')
|
|
||||||
|
|
||||||
// core
|
// core
|
||||||
const config = require('../config')
|
import * as config from "../config";
|
||||||
const logger = require('../logger')
|
import * as logger from "../logger";
|
||||||
const history = require('../history')
|
import * as history from "../history";
|
||||||
const models = require('../models')
|
import * as models from "../models";
|
||||||
|
|
||||||
// ot
|
// ot
|
||||||
const ot = require('../ot')
|
import * as ot from "../ot";
|
||||||
|
|
||||||
const { ProcessQueue } = require('./processQueue')
|
import {ProcessQueue} from "./processQueue";
|
||||||
const { RealtimeClientConnection } = require('./realtimeClientConnection')
|
import {RealtimeClientConnection} from "./realtimeClientConnection";
|
||||||
const { UpdateDirtyNoteJob } = require('./realtimeUpdateDirtyNoteJob')
|
import {UpdateDirtyNoteJob} from "./realtimeUpdateDirtyNoteJob";
|
||||||
const { CleanDanglingUserJob } = require('./realtimeCleanDanglingUserJob')
|
import {CleanDanglingUserJob} from "./realtimeCleanDanglingUserJob";
|
||||||
const { SaveRevisionJob } = require('./realtimeSaveRevisionJob')
|
import {SaveRevisionJob} from "./realtimeSaveRevisionJob";
|
||||||
|
|
||||||
|
const chance = new Chance()
|
||||||
|
|
||||||
|
export let io = null
|
||||||
|
export let maintenance = true
|
||||||
|
|
||||||
// public
|
// public
|
||||||
const realtime = {
|
|
||||||
io: null,
|
|
||||||
onAuthorizeSuccess: onAuthorizeSuccess,
|
|
||||||
onAuthorizeFail: onAuthorizeFail,
|
|
||||||
secure: secure,
|
|
||||||
connection: connection,
|
|
||||||
getStatus: getStatus,
|
|
||||||
isReady: isReady,
|
|
||||||
maintenance: true
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectProcessQueue = new ProcessQueue({})
|
const connectProcessQueue = new ProcessQueue({})
|
||||||
const disconnectProcessQueue = new ProcessQueue({})
|
export const disconnectProcessQueue = new ProcessQueue({})
|
||||||
const updateDirtyNoteJob = new UpdateDirtyNoteJob(realtime)
|
const updateDirtyNoteJob = new UpdateDirtyNoteJob(exports)
|
||||||
const cleanDanglingUserJob = new CleanDanglingUserJob(realtime)
|
const cleanDanglingUserJob = new CleanDanglingUserJob(exports)
|
||||||
const saveRevisionJob = new SaveRevisionJob(realtime)
|
export const saveRevisionJob = new SaveRevisionJob(exports)
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function onAuthorizeSuccess (data, accept) {
|
export function onAuthorizeSuccess(data, accept) {
|
||||||
accept()
|
accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function onAuthorizeFail (data, message, error, accept) {
|
export function onAuthorizeFail(data, message, error, accept) {
|
||||||
accept() // accept whether authorize or not to allow anonymous usage
|
accept() // accept whether authorize or not to allow anonymous usage
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
// secure the origin by the cookie
|
// secure the origin by the cookie
|
||||||
function secure (socket, next) {
|
export function secure(socket, next) {
|
||||||
try {
|
try {
|
||||||
var handshakeData = socket.request
|
var handshakeData = socket.request
|
||||||
if (handshakeData.headers.cookie) {
|
if (handshakeData.headers.cookie) {
|
||||||
@ -82,7 +73,7 @@ function secure (socket, next) {
|
|||||||
|
|
||||||
// TODO: only use in `updateDirtyNote`
|
// TODO: only use in `updateDirtyNote`
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function emitCheck (note) {
|
export function emitCheck(note) {
|
||||||
var out = {
|
var out = {
|
||||||
title: note.title,
|
title: note.title,
|
||||||
updatetime: note.updatetime,
|
updatetime: note.updatetime,
|
||||||
@ -91,50 +82,50 @@ function emitCheck (note) {
|
|||||||
authors: note.authors,
|
authors: note.authors,
|
||||||
authorship: note.authorship
|
authorship: note.authorship
|
||||||
}
|
}
|
||||||
realtime.io.to(note.id).emit('check', out)
|
io.to(note.id).emit('check', out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
var users = {}
|
export var users = {}
|
||||||
var notes = {}
|
export var notes = {}
|
||||||
|
|
||||||
function getNotePool () {
|
export function getNotePool() {
|
||||||
return notes
|
return notes
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNoteExistsInPool (noteId) {
|
export function isNoteExistsInPool(noteId) {
|
||||||
return !!notes[noteId]
|
return !!notes[noteId]
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNote (note) {
|
export function addNote(note) {
|
||||||
if (exports.isNoteExistsInPool(note.id)) return false
|
if (exports.isNoteExistsInPool(note.id)) return false
|
||||||
notes[note.id] = note
|
notes[note.id] = note
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotePoolSize () {
|
export function getNotePoolSize() {
|
||||||
return Object.keys(notes).length
|
return Object.keys(notes).length
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteNoteFromPool (noteId) {
|
export function deleteNoteFromPool(noteId) {
|
||||||
delete notes[noteId]
|
delete notes[noteId]
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteAllNoteFromPool () {
|
export function deleteAllNoteFromPool() {
|
||||||
Object.keys(notes).forEach(noteId => {
|
Object.keys(notes).forEach(noteId => {
|
||||||
delete notes[noteId]
|
delete notes[noteId]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteFromNotePool (noteId) {
|
export function getNoteFromNotePool(noteId) {
|
||||||
return notes[noteId]
|
return notes[noteId]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserPool () {
|
export function getUserPool() {
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserFromUserPool (userId) {
|
export function getUserFromUserPool(userId) {
|
||||||
return users[userId]
|
return users[userId]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +134,7 @@ updateDirtyNoteJob.start()
|
|||||||
cleanDanglingUserJob.start()
|
cleanDanglingUserJob.start()
|
||||||
saveRevisionJob.start()
|
saveRevisionJob.start()
|
||||||
|
|
||||||
function disconnectSocketOnNote (note) {
|
export function disconnectSocketOnNote(note) {
|
||||||
note.socks.forEach((sock) => {
|
note.socks.forEach((sock) => {
|
||||||
if (sock) {
|
if (sock) {
|
||||||
sock.emit('delete')
|
sock.emit('delete')
|
||||||
@ -154,7 +145,7 @@ function disconnectSocketOnNote (note) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNote (note, callback) {
|
export function updateNote(note, callback) {
|
||||||
_updateNoteAsync(note).then(_note => {
|
_updateNoteAsync(note).then(_note => {
|
||||||
callback(null, _note)
|
callback(null, _note)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
@ -247,7 +238,7 @@ async function _updateNoteAsync (note) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function getStatus () {
|
export function getStatus() {
|
||||||
return models.Note.count()
|
return models.Note.count()
|
||||||
.then(function (notecount) {
|
.then(function (notecount) {
|
||||||
var distinctaddresses = []
|
var distinctaddresses = []
|
||||||
@ -308,8 +299,8 @@ function getStatus () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function isReady () {
|
export function isReady() {
|
||||||
return realtime.io &&
|
return io &&
|
||||||
Object.keys(notes).length === 0 && Object.keys(users).length === 0 &&
|
Object.keys(notes).length === 0 && Object.keys(users).length === 0 &&
|
||||||
connectProcessQueue.queue.length === 0 && !connectProcessQueue.lock &&
|
connectProcessQueue.queue.length === 0 && !connectProcessQueue.lock &&
|
||||||
disconnectProcessQueue.queue.length === 0 && !disconnectProcessQueue.lock
|
disconnectProcessQueue.queue.length === 0 && !disconnectProcessQueue.lock
|
||||||
@ -329,7 +320,7 @@ function parseUrl (data) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractNoteIdFromSocket (socket) {
|
export function extractNoteIdFromSocket(socket) {
|
||||||
function extractNoteIdFromReferer(referer) {
|
function extractNoteIdFromReferer(referer) {
|
||||||
if (referer) {
|
if (referer) {
|
||||||
const hostUrl = parseUrl(referer)
|
const hostUrl = parseUrl(referer)
|
||||||
@ -362,7 +353,7 @@ function extractNoteIdFromSocket (socket) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseNoteIdFromSocketAsync (socket) {
|
export async function parseNoteIdFromSocketAsync(socket) {
|
||||||
const noteId = extractNoteIdFromSocket(socket)
|
const noteId = extractNoteIdFromSocket(socket)
|
||||||
if (!noteId) {
|
if (!noteId) {
|
||||||
return null
|
return null
|
||||||
@ -382,7 +373,7 @@ async function parseNoteIdFromSocketAsync (socket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function emitOnlineUsers (socket) {
|
export function emitOnlineUsers(socket) {
|
||||||
var noteId = socket.noteId
|
var noteId = socket.noteId
|
||||||
if (!noteId || !notes[noteId]) return
|
if (!noteId || !notes[noteId]) return
|
||||||
var users = []
|
var users = []
|
||||||
@ -395,11 +386,11 @@ function emitOnlineUsers (socket) {
|
|||||||
var out = {
|
var out = {
|
||||||
users: users
|
users: users
|
||||||
}
|
}
|
||||||
realtime.io.to(noteId).emit('online users', out)
|
io.to(noteId).emit('online users', out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function emitUserStatus (socket) {
|
export function emitUserStatus(socket) {
|
||||||
var noteId = socket.noteId
|
var noteId = socket.noteId
|
||||||
var user = users[socket.id]
|
var user = users[socket.id]
|
||||||
if (!noteId || !notes[noteId] || !user) return
|
if (!noteId || !notes[noteId] || !user) return
|
||||||
@ -408,7 +399,7 @@ function emitUserStatus (socket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function emitRefresh (socket) {
|
export function emitRefresh(socket) {
|
||||||
var noteId = socket.noteId
|
var noteId = socket.noteId
|
||||||
if (!noteId || !notes[noteId]) return
|
if (!noteId || !notes[noteId]) return
|
||||||
var note = notes[noteId]
|
var note = notes[noteId]
|
||||||
@ -428,7 +419,7 @@ function emitRefresh (socket) {
|
|||||||
socket.emit('refresh', out)
|
socket.emit('refresh', out)
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkViewPermission (req, note) {
|
export function checkViewPermission(req, note) {
|
||||||
if (note.permission === 'private') {
|
if (note.permission === 'private') {
|
||||||
if (req.user && req.user.logged_in && req.user.id === note.owner) {
|
if (req.user && req.user.logged_in && req.user.id === note.owner) {
|
||||||
return true
|
return true
|
||||||
@ -509,7 +500,7 @@ function makeNewServerNote (note) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function failConnection (code, err, socket) {
|
export function failConnection(code, err, socket) {
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
// emit error info
|
// emit error info
|
||||||
socket.emit('info', {
|
socket.emit('info', {
|
||||||
@ -518,7 +509,7 @@ function failConnection (code, err, socket) {
|
|||||||
return socket.disconnect(true)
|
return socket.disconnect(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function queueForDisconnect (socket) {
|
export function queueForDisconnect(socket) {
|
||||||
disconnectProcessQueue.push(socket.id, async function () {
|
disconnectProcessQueue.push(socket.id, async function () {
|
||||||
if (users[socket.id]) {
|
if (users[socket.id]) {
|
||||||
delete users[socket.id]
|
delete users[socket.id]
|
||||||
@ -559,7 +550,7 @@ function queueForDisconnect (socket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildUserOutData (user) {
|
export function buildUserOutData(user) {
|
||||||
var out = {
|
var out = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
login: user.login,
|
login: user.login,
|
||||||
@ -575,7 +566,7 @@ function buildUserOutData (user) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function updateUserData (socket, user) {
|
export function updateUserData(socket, user) {
|
||||||
// retrieve user data from passport
|
// retrieve user data from passport
|
||||||
if (socket.request.user && socket.request.user.logged_in) {
|
if (socket.request.user && socket.request.user.logged_in) {
|
||||||
var profile = models.User.getProfile(socket.request.user)
|
var profile = models.User.getProfile(socket.request.user)
|
||||||
@ -606,7 +597,7 @@ function canEditNote (notePermission, noteOwnerId, currentUserId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ifMayEdit (socket, callback) {
|
export function ifMayEdit(socket, callback) {
|
||||||
const note = getNoteFromNotePool(socket.noteId)
|
const note = getNoteFromNotePool(socket.noteId)
|
||||||
if (!note) return
|
if (!note) return
|
||||||
const mayEdit = canEditNote(note.permission, note.owner, socket.request.user.id)
|
const mayEdit = canEditNote(note.permission, note.owner, socket.request.user.id)
|
||||||
@ -666,7 +657,7 @@ function operationCallback (socket, operation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function updateHistory (userId, note, time) {
|
export function updateHistory(userId, note, time) {
|
||||||
var noteId = note.alias ? note.alias : models.Note.encodeNoteId(note.id)
|
var noteId = note.alias ? note.alias : models.Note.encodeNoteId(note.id)
|
||||||
if (note.server) history.updateHistory(userId, noteId, note.server.document, time)
|
if (note.server) history.updateHistory(userId, noteId, note.server.document, time)
|
||||||
}
|
}
|
||||||
@ -792,47 +783,14 @@ function queueForConnect (socket) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function connection (socket) {
|
export function connection(socket) {
|
||||||
if (realtime.maintenance) return
|
if (maintenance) return
|
||||||
queueForConnect(socket)
|
queueForConnect(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test it
|
// TODO: test it
|
||||||
function terminate () {
|
export function terminate() {
|
||||||
disconnectProcessQueue.stop()
|
disconnectProcessQueue.stop()
|
||||||
connectProcessQueue.stop()
|
connectProcessQueue.stop()
|
||||||
updateDirtyNoteJob.stop()
|
updateDirtyNoteJob.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports = realtime
|
|
||||||
exports.extractNoteIdFromSocket = extractNoteIdFromSocket
|
|
||||||
exports.updateNote = updateNote
|
|
||||||
exports.failConnection = failConnection
|
|
||||||
exports.updateUserData = updateUserData
|
|
||||||
exports.emitRefresh = emitRefresh
|
|
||||||
exports.emitUserStatus = emitUserStatus
|
|
||||||
exports.emitOnlineUsers = emitOnlineUsers
|
|
||||||
exports.checkViewPermission = checkViewPermission
|
|
||||||
exports.getUserFromUserPool = getUserFromUserPool
|
|
||||||
exports.buildUserOutData = buildUserOutData
|
|
||||||
exports.emitCheck = emitCheck
|
|
||||||
exports.disconnectSocketOnNote = disconnectSocketOnNote
|
|
||||||
exports.queueForDisconnect = queueForDisconnect
|
|
||||||
exports.terminate = terminate
|
|
||||||
exports.updateHistory = updateHistory
|
|
||||||
exports.ifMayEdit = ifMayEdit
|
|
||||||
exports.parseNoteIdFromSocketAsync = parseNoteIdFromSocketAsync
|
|
||||||
exports.disconnectProcessQueue = disconnectProcessQueue
|
|
||||||
exports.users = users
|
|
||||||
exports.getUserPool = getUserPool
|
|
||||||
|
|
||||||
exports.notes = notes
|
|
||||||
exports.getNotePool = getNotePool
|
|
||||||
exports.getNotePoolSize = getNotePoolSize
|
|
||||||
exports.isNoteExistsInPool = isNoteExistsInPool
|
|
||||||
exports.addNote = addNote
|
|
||||||
exports.getNoteFromNotePool = getNoteFromNotePool
|
|
||||||
exports.deleteNoteFromPool = deleteNoteFromPool
|
|
||||||
exports.deleteAllNoteFromPool = deleteAllNoteFromPool
|
|
||||||
|
|
||||||
exports.saveRevisionJob = saveRevisionJob
|
|
Loading…
x
Reference in New Issue
Block a user