123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- const jwtSecret = '4atikJgznM'
- const jwt = require('jsonwebtoken')
- const express = require('express');
- const express_graphql = require('express-graphql');
- const { buildSchema, printSchema, GraphQLString } = require('graphql');
- const expand = require('mm-graphql/expand')
- const fs = require('fs')
- const uploadPath = `${__dirname}/public/images/`;
- const upload = require('multer')({ dest: uploadPath })
- ;(async () => {
- const {Savable, slice, getModels} = await require('./models.js')()
- const { jwtGQLAnon, jwtCheck } = require('mm-graphql/jwt')
- let schema = buildSchema(`
- type User {
- _id: ID
- createdAt: String
- login: String
- nick : String
- acl: [String]
- avatar: Media
- chats: [Chat]
- }
- input UserInput {
- _id: ID
- login: String
- nick : String
- password: String
- acl: [String]
- avatar: MediaInput
- chats: [ChatInput]
- }
- type Message {
- _id: ID
- createdAt: String
- owner: User
- chat: Chat
- text: String
- media: [Media]
- replies: [Message]
- replyTo: Message
- forwarded: Message
- forwardWith: [Message]
- }
- input MessageInput {
- _id: ID
- text: String
- chat: ChatInput
- media: [MediaInput]
- replies: [MessageInput]
- replyTo: MessageInput
- forwarded: MessageInput
- forwardWith: [MessageInput]
- }
- type Chat {
- _id: ID
- createdAt: String
- lastModified: String
- lastMessage: Message
- owner: User
- title: String
- members: [User]
- messages: [Message]
- avatar: Media
- }
- input ChatInput {
- _id: ID
- title: String
- members: [UserInput]
- messages: [MessageInput]
- }
- type Media {
- _id: ID,
- createdAt: String
- owner: User
- text: String,
- url: String,
- originalFileName: String,
- type: String
- userAvatar: User
- chatAvatars: [Chat]
- messages: [Message]
- }
- input MediaInput {
- _id: ID,
- text: String,
- userAvatar: UserInput,
- chatAvatars: [ChatInput]
- messages: [MessageInput]
- }
- `);
- schema = expand(schema, {
- login:{
- type: GraphQLString,
- args: {login: {type: GraphQLString},
- password: {type: GraphQLString},
- },
- async resolve(root, {login, password}, context, info){
- const Savable = context.models.Savable
- if (!login || !password) return null;
- const user = await Savable.m.User.findOne({login, password})
- console.log(user, {login, password})
- if (!user)
- return null;
- const token = jwt.sign({ sub: {id: user._id, login, acl: user.acl}}, jwtSecret); //подписывам токен нашим ключем
- return token
- }
- }
- })
- console.log(printSchema(schema))
- const app = express();
- const http = require('http').Server(app);
- const io = require('socket.io')(http);
- app.use(require('cors')())
- app.use(express.static('public'));
- app.use('/graphql', express_graphql(jwtGQLAnon({schema, createContext: decoded => getModels(decoded, messageWatcher, chatWatcher), graphiql: true, secret: jwtSecret})))
- app.post('/upload', upload.single('media'), async (req, res, next) => {
- let decoded;
- if (decoded = jwtCheck(req, jwtSecret)){
- console.log('SOME UPLOAD', decoded, req.file)
- let {models: {Media }} = await getModels(decoded.sub)
- let media = await Media.fromFileData(req.file)
- res.end(JSON.stringify({_id: media._id, url: media.url}))
- }
- else {
- res.status(503).send('permission denied')
- }
- })
- app.use(express.static('public'));
- const sockets = {}
- async function messageWatcher(msg){
- console.log('NEW MSG', msg.text, msg.chat.title, msg.owner.login)
- for (let [id,{user, socket}] of Object.entries(sockets)){
- if (user.chats.some(chat => chat._id.toString() === msg.chat._id.toString())){
- let {_id, createdAt, text, chat, media, replyTo, forwarded, owner} = msg
- await chat;
- await Promise.all(media || []);
- await replyTo;
- await forwarded;
- owner = await owner;
- await owner.avatar
- console.log('MEDIA', media)
- socket.emit('msg', {_id, createdAt: createdAt.getTime(), text, chat: chat && {_id: chat._id, title: chat.title},
- media: media && media.map(media => ({_id: media._id, url: media.url, type: media.type})),
- replyTo: replyTo && {_id: replyTo._id, text: replyTo.text},
- forwarded: forwarded && {_id: forwarded._id, text: forwarded.text},
- owner: {_id: owner._id, login: owner.login, nick: owner.nick, avatar: owner.avatar && {url: owner.avatar.url}}})
- }
- }
- }
- async function chatWatcher({_loadRelations, members, _id, createdAt, title, messages, avatar, lastModified}){
- console.log('CHAT SAVE', _id, title)
- for (let [id,socketData] of Object.entries(sockets)){
- const {user, socket} = socketData
- const isMember = members.some(member => member._id.toString() === user._id.toString())
- const wasMember =(_loadRelations.members && _loadRelations.members.some(member => member._id.toString() === user._id.toString()))
- if (isMember || wasMember){
- //await chat;
- //await media;
- //await replyTo;
- //await forwarded;
- await avatar;
- await Promise.all(members)
- //owner = await owner;
- console.log('EMIT', _id, createdAt.getTime(), title)
- socket.emit(isMember ? 'chat' : 'chat_left', {_id, createdAt: createdAt.getTime(), title, avatar: avatar && {_id: avatar._id, url: avatar.url}, members: members.map(({_id, login, nick}) => ({_id, login, nick})), lastModified})
- socketData.user = (await getModels(socketData.decoded.sub)).thisUser //re-read chat permissions
- }
- }
- }
- io.on('connection', socket => {
- console.log('connect', socket.id)
- socket.on('disconnect', () => {
- console.log('disconnect', socket.id)
- delete sockets[socket.id]
- })
- socket.on('jwt', async token =>{
- let decoded;
- try {
- decoded = jwt.verify(token, jwtSecret)
- }
- catch (e){
- socket.emit('jwt_fail', e)
- return
- }
- socket.emit('jwt_ok', decoded)
- //sockets[socket.id] = decoded
- sockets[socket.id] = {decoded, user: (await getModels(decoded.sub)).thisUser, socket}
- })
- })
- let socketPath = 5001
- http.listen(socketPath, () => {
- console.log(`Express GraphQL Server Now Running On ${socketPath}/graphql`);
- });
- })()
|