index.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. const jwtSecret = '4atikJgznM'
  2. const jwt = require('jsonwebtoken')
  3. const express = require('express');
  4. const express_graphql = require('express-graphql');
  5. const { buildSchema, printSchema, GraphQLString } = require('graphql');
  6. const expand = require('mm-graphql/expand')
  7. const fs = require('fs')
  8. const uploadPath = `${__dirname}/public/images/`;
  9. const upload = require('multer')({ dest: uploadPath })
  10. ;(async () => {
  11. const {Savable, slice, getModels} = await require('./models.js')()
  12. const { jwtGQLAnon, jwtCheck } = require('mm-graphql/jwt')
  13. let schema = buildSchema(`
  14. type User {
  15. _id: ID
  16. createdAt: String
  17. login: String
  18. nick : String
  19. acl: [String]
  20. avatar: Media
  21. chats: [Chat]
  22. }
  23. input UserInput {
  24. _id: ID
  25. login: String
  26. nick : String
  27. password: String
  28. acl: [String]
  29. avatar: MediaInput
  30. chats: [ChatInput]
  31. }
  32. type Message {
  33. _id: ID
  34. createdAt: String
  35. owner: User
  36. chat: Chat
  37. text: String
  38. media: [Media]
  39. replies: [Message]
  40. replyTo: Message
  41. forwarded: Message
  42. forwardWith: [Message]
  43. }
  44. input MessageInput {
  45. _id: ID
  46. text: String
  47. chat: ChatInput
  48. media: [MediaInput]
  49. replies: [MessageInput]
  50. replyTo: MessageInput
  51. forwarded: MessageInput
  52. forwardWith: [MessageInput]
  53. }
  54. type Chat {
  55. _id: ID
  56. createdAt: String
  57. lastModified: String
  58. lastMessage: Message
  59. owner: User
  60. title: String
  61. members: [User]
  62. messages: [Message]
  63. avatar: Media
  64. }
  65. input ChatInput {
  66. _id: ID
  67. title: String
  68. members: [UserInput]
  69. messages: [MessageInput]
  70. }
  71. type Media {
  72. _id: ID,
  73. createdAt: String
  74. owner: User
  75. text: String,
  76. url: String,
  77. originalFileName: String,
  78. type: String
  79. userAvatar: User
  80. chatAvatars: [Chat]
  81. messages: [Message]
  82. }
  83. input MediaInput {
  84. _id: ID,
  85. text: String,
  86. userAvatar: UserInput,
  87. chatAvatars: [ChatInput]
  88. messages: [MessageInput]
  89. }
  90. `);
  91. schema = expand(schema, {
  92. login:{
  93. type: GraphQLString,
  94. args: {login: {type: GraphQLString},
  95. password: {type: GraphQLString},
  96. },
  97. async resolve(root, {login, password}, context, info){
  98. const Savable = context.models.Savable
  99. if (!login || !password) return null;
  100. const user = await Savable.m.User.findOne({login, password})
  101. console.log(user, {login, password})
  102. if (!user)
  103. return null;
  104. const token = jwt.sign({ sub: {id: user._id, login, acl: user.acl}}, jwtSecret); //подписывам токен нашим ключем
  105. return token
  106. }
  107. }
  108. })
  109. console.log(printSchema(schema))
  110. const app = express();
  111. const http = require('http').Server(app);
  112. const io = require('socket.io')(http);
  113. app.use(require('cors')())
  114. app.use(express.static('public'));
  115. app.use('/graphql', express_graphql(jwtGQLAnon({schema, createContext: decoded => getModels(decoded, messageWatcher, chatWatcher), graphiql: true, secret: jwtSecret})))
  116. app.post('/upload', upload.single('media'), async (req, res, next) => {
  117. let decoded;
  118. if (decoded = jwtCheck(req, jwtSecret)){
  119. console.log('SOME UPLOAD', decoded, req.file)
  120. let {models: {Media }} = await getModels(decoded.sub)
  121. let media = await Media.fromFileData(req.file)
  122. res.end(JSON.stringify({_id: media._id, url: media.url}))
  123. }
  124. else {
  125. res.status(503).send('permission denied')
  126. }
  127. })
  128. app.use(express.static('public'));
  129. const sockets = {}
  130. async function messageWatcher(msg){
  131. console.log('NEW MSG', msg.text, msg.chat.title, msg.owner.login)
  132. for (let [id,{user, socket}] of Object.entries(sockets)){
  133. if (user.chats.some(chat => chat._id.toString() === msg.chat._id.toString())){
  134. let {_id, createdAt, text, chat, media, replyTo, forwarded, owner} = msg
  135. await chat;
  136. await Promise.all(media || []);
  137. await replyTo;
  138. await forwarded;
  139. owner = await owner;
  140. await owner.avatar
  141. console.log('MEDIA', media)
  142. socket.emit('msg', {_id, createdAt: createdAt.getTime(), text, chat: chat && {_id: chat._id, title: chat.title},
  143. media: media && media.map(media => ({_id: media._id, url: media.url, type: media.type})),
  144. replyTo: replyTo && {_id: replyTo._id, text: replyTo.text},
  145. forwarded: forwarded && {_id: forwarded._id, text: forwarded.text},
  146. owner: {_id: owner._id, login: owner.login, nick: owner.nick, avatar: owner.avatar && {url: owner.avatar.url}}})
  147. }
  148. }
  149. }
  150. async function chatWatcher({_loadRelations, members, _id, createdAt, title, messages, avatar, lastModified}){
  151. console.log('CHAT SAVE', _id, title)
  152. for (let [id,socketData] of Object.entries(sockets)){
  153. const {user, socket} = socketData
  154. const isMember = members.some(member => member._id.toString() === user._id.toString())
  155. const wasMember =(_loadRelations.members && _loadRelations.members.some(member => member._id.toString() === user._id.toString()))
  156. if (isMember || wasMember){
  157. //await chat;
  158. //await media;
  159. //await replyTo;
  160. //await forwarded;
  161. await avatar;
  162. await Promise.all(members)
  163. //owner = await owner;
  164. console.log('EMIT', _id, createdAt.getTime(), title)
  165. 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})
  166. socketData.user = (await getModels(socketData.decoded.sub)).thisUser //re-read chat permissions
  167. }
  168. }
  169. }
  170. io.on('connection', socket => {
  171. console.log('connect', socket.id)
  172. socket.on('disconnect', () => {
  173. console.log('disconnect', socket.id)
  174. delete sockets[socket.id]
  175. })
  176. socket.on('jwt', async token =>{
  177. let decoded;
  178. try {
  179. decoded = jwt.verify(token, jwtSecret)
  180. }
  181. catch (e){
  182. socket.emit('jwt_fail', e)
  183. return
  184. }
  185. socket.emit('jwt_ok', decoded)
  186. //sockets[socket.id] = decoded
  187. sockets[socket.id] = {decoded, user: (await getModels(decoded.sub)).thisUser, socket}
  188. })
  189. })
  190. let socketPath = 5001
  191. http.listen(socketPath, () => {
  192. console.log(`Express GraphQL Server Now Running On ${socketPath}/graphql`);
  193. });
  194. })()