mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Draft: Setup subsriptions for backend+frontend
Please clean up this commit and squash it later on.
This commit is contained in:
parent
1a93fcc023
commit
3be5dee08b
@ -96,6 +96,7 @@
|
|||||||
"request": "~2.88.0",
|
"request": "~2.88.0",
|
||||||
"sanitize-html": "~1.21.1",
|
"sanitize-html": "~1.21.1",
|
||||||
"slug": "~2.1.0",
|
"slug": "~2.1.0",
|
||||||
|
"subscriptions-transport-ws": "^0.9.16",
|
||||||
"trunc-html": "~1.1.2",
|
"trunc-html": "~1.1.2",
|
||||||
"uuid": "~3.4.0",
|
"uuid": "~3.4.0",
|
||||||
"validator": "^12.1.0",
|
"validator": "^12.1.0",
|
||||||
|
|||||||
@ -49,6 +49,7 @@ export const serverConfigs = {
|
|||||||
CLIENT_URI,
|
CLIENT_URI,
|
||||||
GRAPHQL_URI,
|
GRAPHQL_URI,
|
||||||
PUBLIC_REGISTRATION: process.env.PUBLIC_REGISTRATION === 'true',
|
PUBLIC_REGISTRATION: process.env.PUBLIC_REGISTRATION === 'true',
|
||||||
|
SUBSCRIPTIONS_PATH: '/subscriptions',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const developmentConfigs = {
|
export const developmentConfigs = {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import createServer from './server'
|
import createServer from './server'
|
||||||
import CONFIG from './config'
|
import CONFIG from './config'
|
||||||
|
|
||||||
const { app } = createServer()
|
const { app, server, httpServer } = createServer()
|
||||||
const url = new URL(CONFIG.GRAPHQL_URI)
|
const url = new URL(CONFIG.GRAPHQL_URI)
|
||||||
app.listen({ port: url.port }, () => {
|
httpServer.listen({ port: url.port }, () => {
|
||||||
/* eslint-disable-next-line no-console */
|
/* eslint-disable-next-line no-console */
|
||||||
console.log(`GraphQLServer ready at ${CONFIG.GRAPHQL_URI} 🚀`)
|
console.log(`🚀 Server ready at http://localhost:${url.port}${server.graphqlPath}`)
|
||||||
|
console.log(`🚀 Subscriptions ready at ws://localhost:${url.port}${server.subscriptionsPath}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,6 +5,11 @@ import { UserInputError } from 'apollo-server'
|
|||||||
import fileUpload from './fileUpload'
|
import fileUpload from './fileUpload'
|
||||||
import Resolver from './helpers/Resolver'
|
import Resolver from './helpers/Resolver'
|
||||||
import { filterForMutedUsers } from './helpers/filterForMutedUsers'
|
import { filterForMutedUsers } from './helpers/filterForMutedUsers'
|
||||||
|
import { PubSub } from 'apollo-server'
|
||||||
|
|
||||||
|
const pubsub = new PubSub();
|
||||||
|
const POST_ADDED = 'POST_ADDED';
|
||||||
|
|
||||||
|
|
||||||
const maintainPinnedPosts = params => {
|
const maintainPinnedPosts = params => {
|
||||||
const pinnedPostFilter = { pinned: true }
|
const pinnedPostFilter = { pinned: true }
|
||||||
@ -17,6 +22,12 @@ const maintainPinnedPosts = params => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Subscription: {
|
||||||
|
postAdded: {
|
||||||
|
// Additional event labels can be passed to asyncIterator creation
|
||||||
|
subscribe: () => pubsub.asyncIterator([POST_ADDED]),
|
||||||
|
},
|
||||||
|
},
|
||||||
Query: {
|
Query: {
|
||||||
Post: async (object, params, context, resolveInfo) => {
|
Post: async (object, params, context, resolveInfo) => {
|
||||||
params = await filterForMutedUsers(params, context)
|
params = await filterForMutedUsers(params, context)
|
||||||
@ -102,6 +113,7 @@ export default {
|
|||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
const [post] = await writeTxResultPromise
|
const [post] = await writeTxResultPromise
|
||||||
|
pubsub.publish(POST_ADDED, { postAdded: post });
|
||||||
return post
|
return post
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
|
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
type Subscription {
|
||||||
|
postAdded: Post
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
# Get a JWT Token for the given Email and password
|
# Get a JWT Token for the given Email and password
|
||||||
login(email: String!, password: String!): String!
|
login(email: String!, password: String!): String!
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import http from 'http'
|
||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import { ApolloServer } from 'apollo-server-express'
|
import { ApolloServer } from 'apollo-server-express'
|
||||||
|
|
||||||
|
|
||||||
import CONFIG from './config'
|
import CONFIG from './config'
|
||||||
import middleware from './middleware'
|
import middleware from './middleware'
|
||||||
import { getNeode, getDriver } from './db/neo4j'
|
import { getNeode, getDriver } from './db/neo4j'
|
||||||
@ -8,10 +11,11 @@ import decode from './jwt/decode'
|
|||||||
import schema from './schema'
|
import schema from './schema'
|
||||||
import webfinger from './activitypub/routes/webfinger'
|
import webfinger from './activitypub/routes/webfinger'
|
||||||
|
|
||||||
|
|
||||||
const driver = getDriver()
|
const driver = getDriver()
|
||||||
const neode = getNeode()
|
const neode = getNeode()
|
||||||
|
|
||||||
export const context = async ({ req }) => {
|
const getContext = async (req) => {
|
||||||
const user = await decode(driver, req.headers.authorization)
|
const user = await decode(driver, req.headers.authorization)
|
||||||
return {
|
return {
|
||||||
driver,
|
driver,
|
||||||
@ -23,11 +27,25 @@ export const context = async ({ req }) => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const context = async (options) => {
|
||||||
|
const { connection, req } = options
|
||||||
|
if (connection) {
|
||||||
|
return connection.context
|
||||||
|
} else {
|
||||||
|
return getContext(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const createServer = options => {
|
const createServer = options => {
|
||||||
const defaults = {
|
const defaults = {
|
||||||
context,
|
context,
|
||||||
schema: middleware(schema),
|
schema: middleware(schema),
|
||||||
|
subscriptions: {
|
||||||
|
onConnect: (connectionParams, webSocket) => {
|
||||||
|
console.log('connectionParams', connectionParams)
|
||||||
|
return getContext(connectionParams)
|
||||||
|
},
|
||||||
|
},
|
||||||
debug: !!CONFIG.DEBUG,
|
debug: !!CONFIG.DEBUG,
|
||||||
tracing: !!CONFIG.DEBUG,
|
tracing: !!CONFIG.DEBUG,
|
||||||
formatError: error => {
|
formatError: error => {
|
||||||
@ -46,8 +64,11 @@ const createServer = options => {
|
|||||||
app.use('/.well-known/', webfinger())
|
app.use('/.well-known/', webfinger())
|
||||||
app.use(express.static('public'))
|
app.use(express.static('public'))
|
||||||
server.applyMiddleware({ app, path: '/' })
|
server.applyMiddleware({ app, path: '/' })
|
||||||
|
const httpServer = http.createServer(app);
|
||||||
|
server.installSubscriptionHandlers(httpServer);
|
||||||
|
|
||||||
return { server, app }
|
|
||||||
|
return { server, httpServer, app }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createServer
|
export default createServer
|
||||||
|
|||||||
@ -1175,7 +1175,7 @@
|
|||||||
url-regex "~4.1.1"
|
url-regex "~4.1.1"
|
||||||
video-extensions "~1.1.0"
|
video-extensions "~1.1.0"
|
||||||
|
|
||||||
"@metascraper/helpers@^5.10.5", "@metascraper/helpers@^5.10.6":
|
"@metascraper/helpers@^5.10.6":
|
||||||
version "5.10.6"
|
version "5.10.6"
|
||||||
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.10.6.tgz#0b786607212925a577926fd0cd0313a49de3499c"
|
resolved "https://registry.yarnpkg.com/@metascraper/helpers/-/helpers-5.10.6.tgz#0b786607212925a577926fd0cd0313a49de3499c"
|
||||||
integrity sha512-/jvhlM3RKGYMoUK8D8S1r3tN03/EYizCqWF7zDx0aBMC8Ihp33DRGs9oNdsgkgwzVF7O/YpDm55l9K+qVJlsyQ==
|
integrity sha512-/jvhlM3RKGYMoUK8D8S1r3tN03/EYizCqWF7zDx0aBMC8Ihp33DRGs9oNdsgkgwzVF7O/YpDm55l9K+qVJlsyQ==
|
||||||
@ -7918,6 +7918,11 @@ serve-static@1.14.1:
|
|||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
|
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
|
||||||
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
|
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
|
||||||
|
dependencies:
|
||||||
|
encodeurl "~1.0.2"
|
||||||
|
escape-html "~1.0.3"
|
||||||
|
parseurl "~1.3.3"
|
||||||
|
send "0.17.1"
|
||||||
|
|
||||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
|||||||
@ -74,6 +74,16 @@ import { mapGetters, mapMutations } from 'vuex'
|
|||||||
import { filterPosts } from '~/graphql/PostQuery.js'
|
import { filterPosts } from '~/graphql/PostQuery.js'
|
||||||
import PostMutations from '~/graphql/PostMutations'
|
import PostMutations from '~/graphql/PostMutations'
|
||||||
import UpdateQuery from '~/components/utils/UpdateQuery'
|
import UpdateQuery from '~/components/utils/UpdateQuery'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import {
|
||||||
|
userFragment,
|
||||||
|
postFragment,
|
||||||
|
commentFragment,
|
||||||
|
postCountsFragment,
|
||||||
|
userCountsFragment,
|
||||||
|
locationAndBadgesFragment,
|
||||||
|
tagsCategoriesAndPinnedFragment,
|
||||||
|
} from '~/graphql/Fragments'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -213,6 +223,36 @@ export default {
|
|||||||
this.posts = Post
|
this.posts = Post
|
||||||
},
|
},
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
|
subscribeToMore: {
|
||||||
|
document: gql`
|
||||||
|
${userFragment}
|
||||||
|
${userCountsFragment}
|
||||||
|
${locationAndBadgesFragment('EN')}
|
||||||
|
${postFragment}
|
||||||
|
${postCountsFragment}
|
||||||
|
${tagsCategoriesAndPinnedFragment}
|
||||||
|
|
||||||
|
subscription Post {
|
||||||
|
postAdded {
|
||||||
|
...post
|
||||||
|
...postCounts
|
||||||
|
...tagsCategoriesAndPinned
|
||||||
|
author {
|
||||||
|
...user
|
||||||
|
...userCounts
|
||||||
|
...locationAndBadges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
// Mutate the previous result
|
||||||
|
updateQuery: (previousResult, { subscriptionData }) => {
|
||||||
|
console.log('previousResult', previousResult)
|
||||||
|
console.log('subscriptionData', subscriptionData)
|
||||||
|
const { data: { postAdded: newPost } } = subscriptionData
|
||||||
|
return { Post: [newPost, ...previousResult.Post] }
|
||||||
|
// Here, return the new result from the previous with the new data
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export default ({ app }) => {
|
|||||||
const backendUrl = process.env.GRAPHQL_URI || 'http://localhost:4000'
|
const backendUrl = process.env.GRAPHQL_URI || 'http://localhost:4000'
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
wsEndpoint: 'ws://localhost:4000/graphql', // optional
|
||||||
httpEndpoint: process.server ? backendUrl : '/api',
|
httpEndpoint: process.server ? backendUrl : '/api',
|
||||||
httpLinkOptions: {
|
httpLinkOptions: {
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
@ -16,7 +17,7 @@ export default ({ app }) => {
|
|||||||
credentials: true,
|
credentials: true,
|
||||||
tokenName: 'human-connection-token',
|
tokenName: 'human-connection-token',
|
||||||
persisting: false,
|
persisting: false,
|
||||||
websocketsOnly: false,
|
websocketsOnly: true,
|
||||||
cache: new InMemoryCache({ fragmentMatcher }),
|
cache: new InMemoryCache({ fragmentMatcher }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user