jason-rails 0.5.0 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/Gemfile.lock +1 -1
- data/README.md +141 -5
- data/app/controllers/jason/api/pusher_controller.rb +15 -0
- data/app/controllers/jason/api_controller.rb +46 -4
- data/client/lib/JasonContext.d.ts +1 -1
- data/client/lib/JasonContext.js +4 -1
- data/client/lib/JasonProvider.js +1 -1
- data/client/lib/createJasonReducers.js +7 -0
- data/client/lib/createPayloadHandler.d.ts +6 -3
- data/client/lib/createPayloadHandler.js +8 -4
- data/client/lib/createTransportAdapter.d.ts +5 -0
- data/client/lib/createTransportAdapter.js +20 -0
- data/client/lib/index.d.ts +2 -0
- data/client/lib/index.js +3 -1
- data/client/lib/makeEager.js +2 -2
- data/client/lib/pruneIdsMiddleware.js +9 -11
- data/client/lib/restClient.d.ts +1 -1
- data/client/lib/transportAdapters/actionCableAdapter.d.ts +5 -0
- data/client/lib/transportAdapters/actionCableAdapter.js +35 -0
- data/client/lib/transportAdapters/pusherAdapter.d.ts +5 -0
- data/client/lib/transportAdapters/pusherAdapter.js +68 -0
- data/client/lib/useEager.d.ts +1 -0
- data/client/lib/useEager.js +12 -0
- data/client/lib/useJason.js +30 -35
- data/client/lib/useJason.test.js +8 -2
- data/client/lib/useSub.d.ts +1 -1
- data/client/lib/useSub.js +5 -3
- data/client/package.json +2 -1
- data/client/src/JasonContext.ts +4 -1
- data/client/src/JasonProvider.tsx +1 -1
- data/client/src/createJasonReducers.ts +7 -0
- data/client/src/createPayloadHandler.ts +9 -4
- data/client/src/createTransportAdapter.ts +13 -0
- data/client/src/index.ts +3 -1
- data/client/src/makeEager.ts +2 -2
- data/client/src/pruneIdsMiddleware.ts +11 -11
- data/client/src/restClient.ts +2 -1
- data/client/src/transportAdapters/actionCableAdapter.ts +38 -0
- data/client/src/transportAdapters/pusherAdapter.ts +72 -0
- data/client/src/useEager.ts +9 -0
- data/client/src/useJason.test.ts +8 -2
- data/client/src/useJason.ts +31 -36
- data/client/src/useSub.ts +5 -3
- data/client/yarn.lock +12 -0
- data/config/routes.rb +5 -1
- data/lib/jason.rb +56 -8
- data/lib/jason/broadcaster.rb +19 -0
- data/lib/jason/channel.rb +10 -3
- data/lib/jason/graph_helper.rb +165 -0
- data/lib/jason/includes_helper.rb +108 -0
- data/lib/jason/lua_generator.rb +23 -1
- data/lib/jason/publisher.rb +21 -17
- data/lib/jason/subscription.rb +208 -179
- data/lib/jason/version.rb +1 -1
- metadata +18 -2
@@ -0,0 +1,13 @@
|
|
1
|
+
import actionCableAdapter from './transportAdapters/actionCableAdapter'
|
2
|
+
import pusherAdapter from './transportAdapters/pusherAdapter'
|
3
|
+
|
4
|
+
export default function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect) {
|
5
|
+
const { transportService } = jasonConfig
|
6
|
+
if (transportService === 'action_cable') {
|
7
|
+
return actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnect)
|
8
|
+
} else if (transportService === 'pusher') {
|
9
|
+
return pusherAdapter(jasonConfig, handlePayload, dispatch)
|
10
|
+
} else {
|
11
|
+
throw(`Transport adapter does not exist for ${transportService}`)
|
12
|
+
}
|
13
|
+
}
|
data/client/src/index.ts
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
import _JasonProvider from './JasonProvider'
|
2
2
|
import _useAct from './useAct'
|
3
3
|
import _useSub from './useSub'
|
4
|
+
import _useEager from './useEager'
|
4
5
|
|
5
6
|
export const JasonProvider = _JasonProvider
|
6
7
|
export const useAct = _useAct
|
7
|
-
export const useSub = _useSub
|
8
|
+
export const useSub = _useSub
|
9
|
+
export const useEager = _useEager
|
data/client/src/makeEager.ts
CHANGED
@@ -36,9 +36,9 @@ export default function (schema) {
|
|
36
36
|
|
37
37
|
function useEager(entity, id = null, relations = []) {
|
38
38
|
if (id) {
|
39
|
-
return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations))
|
39
|
+
return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations), _.isEqual)
|
40
40
|
} else {
|
41
|
-
return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations))
|
41
|
+
return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations), _.isEqual)
|
42
42
|
}
|
43
43
|
}
|
44
44
|
|
@@ -2,20 +2,20 @@ import _ from 'lodash'
|
|
2
2
|
import pluralize from 'pluralize'
|
3
3
|
|
4
4
|
const pruneIdsMiddleware = schema => store => next => action => {
|
5
|
-
const { type } = action
|
5
|
+
const { type, payload } = action
|
6
6
|
const result = next(action)
|
7
|
+
|
7
8
|
const state = store.getState()
|
8
|
-
if (type === 'jasonModels/setSubscriptionIds') {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
})
|
15
|
-
// Find IDs currently in Redux that aren't in any subscription
|
16
|
-
const idsToRemove = _.difference(state[pluralize(model)].ids, ids)
|
17
|
-
store.dispatch({ type: `${pluralize(model)}/removeMany`, payload: idsToRemove })
|
9
|
+
if (type === 'jasonModels/setSubscriptionIds' || type === 'jasonModels/removeSubscriptionIds') {
|
10
|
+
const { model, ids } = payload
|
11
|
+
|
12
|
+
let idsInSubs = []
|
13
|
+
_.map(state.jasonModels[model], (subscribedIds, k) => {
|
14
|
+
idsInSubs = _.union(idsInSubs, subscribedIds)
|
18
15
|
})
|
16
|
+
// Find IDs currently in Redux that aren't in any subscription
|
17
|
+
const idsToRemove = _.difference(state[pluralize(model)].ids, idsInSubs)
|
18
|
+
store.dispatch({ type: `${pluralize(model)}/removeMany`, payload: idsToRemove })
|
19
19
|
}
|
20
20
|
|
21
21
|
return result
|
data/client/src/restClient.ts
CHANGED
@@ -4,10 +4,11 @@ import { validate as isUuid } from 'uuid'
|
|
4
4
|
|
5
5
|
const csrfToken = (document?.querySelector("meta[name=csrf-token]") as any)?.content
|
6
6
|
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
|
7
|
+
|
7
8
|
const restClient = applyCaseMiddleware(axios.create() as any, {
|
8
9
|
preservedKeys: (key) => {
|
9
10
|
return isUuid(key)
|
10
11
|
}
|
11
|
-
})
|
12
|
+
}) as any
|
12
13
|
|
13
14
|
export default restClient
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { createConsumer } from "@rails/actioncable"
|
2
|
+
|
3
|
+
export default function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
|
4
|
+
const consumer = createConsumer()
|
5
|
+
const subscription = (consumer.subscriptions.create({
|
6
|
+
channel: 'Jason::Channel'
|
7
|
+
}, {
|
8
|
+
connected: () => {
|
9
|
+
dispatch({ type: 'jason/upsert', payload: { connected: true } })
|
10
|
+
console.debug('Connected to ActionCable')
|
11
|
+
|
12
|
+
// When AC loses connection - all state is lost, so we need to re-initialize all subscriptions
|
13
|
+
onConnected()
|
14
|
+
},
|
15
|
+
received: payload => {
|
16
|
+
handlePayload(payload)
|
17
|
+
console.debug("ActionCable Payload received: ", payload)
|
18
|
+
},
|
19
|
+
disconnected: () => {
|
20
|
+
dispatch({ type: 'jason/upsert', payload: { connected: false } })
|
21
|
+
console.warn('Disconnected from ActionCable')
|
22
|
+
}
|
23
|
+
}));
|
24
|
+
|
25
|
+
function getPayload(config, options) {
|
26
|
+
subscription.send({ getPayload: config, ...options })
|
27
|
+
}
|
28
|
+
|
29
|
+
function createSubscription(config) {
|
30
|
+
subscription.send({ createSubscription: config })
|
31
|
+
}
|
32
|
+
|
33
|
+
function removeSubscription(config) {
|
34
|
+
subscription.send({ removeSubscription: config })
|
35
|
+
}
|
36
|
+
|
37
|
+
return { getPayload, createSubscription, removeSubscription }
|
38
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import Pusher from 'pusher-js'
|
2
|
+
import { createConsumer } from "@rails/actioncable"
|
3
|
+
import restClient from '../restClient'
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
5
|
+
import _ from 'lodash'
|
6
|
+
|
7
|
+
export default function pusherAdapter(jasonConfig, handlePayload, dispatch) {
|
8
|
+
let consumerId = uuidv4()
|
9
|
+
|
10
|
+
const { pusherKey, pusherRegion, pusherChannelPrefix } = jasonConfig
|
11
|
+
const pusher = new Pusher(pusherKey, {
|
12
|
+
cluster: 'eu',
|
13
|
+
forceTLS: true,
|
14
|
+
authEndpoint: '/jason/api/pusher/auth'
|
15
|
+
})
|
16
|
+
pusher.connection.bind('state_change', ({ current }) => {
|
17
|
+
if (current === 'connected') {
|
18
|
+
dispatch({ type: 'jason/upsert', payload: { connected: true } })
|
19
|
+
} else {
|
20
|
+
dispatch({ type: 'jason/upsert', payload: { connected: false } })
|
21
|
+
}
|
22
|
+
})
|
23
|
+
pusher.connection.bind( 'error', error => {
|
24
|
+
dispatch({ type: 'jason/upsert', payload: { connected: false } })
|
25
|
+
});
|
26
|
+
|
27
|
+
const configToChannel = {}
|
28
|
+
|
29
|
+
function createSubscription(config) {
|
30
|
+
restClient.post('/jason/api/create_subscription', { config, consumerId })
|
31
|
+
.then(({ data: { channelName } }) => {
|
32
|
+
configToChannel[JSON.stringify(config)] = channelName
|
33
|
+
subscribeToChannel(channelName)
|
34
|
+
})
|
35
|
+
.catch(e => console.error(e))
|
36
|
+
}
|
37
|
+
|
38
|
+
function removeSubscription(config) {
|
39
|
+
const channelName = configToChannel[JSON.stringify(config)]
|
40
|
+
unsubscribeFromChannel(fullChannelName(channelName))
|
41
|
+
restClient.post('/jason/api/remove_subscription', { config, consumerId })
|
42
|
+
.catch(e => console.error(e))
|
43
|
+
}
|
44
|
+
|
45
|
+
function getPayload(config, options) {
|
46
|
+
restClient.post('/jason/api/get_payload', {
|
47
|
+
config,
|
48
|
+
options
|
49
|
+
})
|
50
|
+
.then(({ data }) => {
|
51
|
+
_.map(data, (payload, modelName) => {
|
52
|
+
handlePayload(payload)
|
53
|
+
})
|
54
|
+
})
|
55
|
+
.catch(e => console.error(e))
|
56
|
+
}
|
57
|
+
|
58
|
+
function subscribeToChannel(channelName) {
|
59
|
+
const channel = pusher.subscribe(fullChannelName(channelName))
|
60
|
+
channel.bind('changed', message => handlePayload(message))
|
61
|
+
}
|
62
|
+
|
63
|
+
function unsubscribeFromChannel(channelName) {
|
64
|
+
const channel = pusher.unsubscribe(fullChannelName(channelName))
|
65
|
+
}
|
66
|
+
|
67
|
+
function fullChannelName(channelName) {
|
68
|
+
return `private-${pusherChannelPrefix}-${channelName}`
|
69
|
+
}
|
70
|
+
|
71
|
+
return { getPayload, createSubscription, removeSubscription }
|
72
|
+
}
|
data/client/src/useJason.test.ts
CHANGED
@@ -5,7 +5,10 @@ import restClient from './restClient'
|
|
5
5
|
jest.mock('./restClient')
|
6
6
|
|
7
7
|
test('it works', async () => {
|
8
|
-
const resp = { data: {
|
8
|
+
const resp = { data: {
|
9
|
+
schema: { post: {} },
|
10
|
+
transportService: 'action_cable'
|
11
|
+
} };
|
9
12
|
// @ts-ignore
|
10
13
|
restClient.get.mockResolvedValue(resp);
|
11
14
|
|
@@ -45,7 +48,10 @@ test('it works', async () => {
|
|
45
48
|
})
|
46
49
|
|
47
50
|
test('pruning IDs', async () => {
|
48
|
-
const resp = { data: {
|
51
|
+
const resp = { data: {
|
52
|
+
schema: { post: {} },
|
53
|
+
transportService: 'action_cable'
|
54
|
+
} };
|
49
55
|
|
50
56
|
// @ts-ignore
|
51
57
|
restClient.get.mockResolvedValue(resp);
|
data/client/src/useJason.ts
CHANGED
@@ -5,8 +5,8 @@ import createOptDis from './createOptDis'
|
|
5
5
|
import createServerActionQueue from './createServerActionQueue'
|
6
6
|
import restClient from './restClient'
|
7
7
|
import pruneIdsMiddleware from './pruneIdsMiddleware'
|
8
|
+
import createTransportAdapater from './createTransportAdapter'
|
8
9
|
|
9
|
-
import { createConsumer } from "@rails/actioncable"
|
10
10
|
import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
|
11
11
|
|
12
12
|
import makeEager from './makeEager'
|
@@ -18,17 +18,17 @@ import React, { useState, useEffect } from 'react'
|
|
18
18
|
export default function useJason({ reducers, middleware = [], extraActions }: { reducers?: any, middleware?: any[], extraActions?: any }) {
|
19
19
|
const [store, setStore] = useState(null as any)
|
20
20
|
const [value, setValue] = useState(null as any)
|
21
|
-
const [connected, setConnected] = useState(false)
|
22
21
|
|
23
22
|
useEffect(() => {
|
24
|
-
restClient.get('/jason/api/
|
25
|
-
.then(({ data:
|
23
|
+
restClient.get('/jason/api/config')
|
24
|
+
.then(({ data: jasonConfig }) => {
|
25
|
+
const { schema: snakey_schema } = jasonConfig
|
26
26
|
const schema = camelizeKeys(snakey_schema)
|
27
27
|
console.debug({ schema })
|
28
28
|
|
29
29
|
const serverActionQueue = createServerActionQueue()
|
30
30
|
|
31
|
-
|
31
|
+
|
32
32
|
const allReducers = {
|
33
33
|
...reducers,
|
34
34
|
...createJasonReducers(schema)
|
@@ -45,65 +45,60 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
45
45
|
|
46
46
|
let payloadHandlers = {}
|
47
47
|
let configs = {}
|
48
|
+
let subOptions = {}
|
48
49
|
|
49
50
|
function handlePayload(payload) {
|
50
51
|
const { md5Hash } = payload
|
51
52
|
|
52
|
-
const
|
53
|
-
if (
|
54
|
-
|
53
|
+
const { handlePayload } = payloadHandlers[md5Hash]
|
54
|
+
if (handlePayload) {
|
55
|
+
handlePayload(payload)
|
55
56
|
} else {
|
56
57
|
console.warn("Payload arrived with no handler", payload, payloadHandlers)
|
57
58
|
}
|
58
59
|
}
|
59
60
|
|
60
|
-
const
|
61
|
-
channel: 'Jason::Channel'
|
62
|
-
}, {
|
63
|
-
connected: () => {
|
64
|
-
setConnected(true)
|
65
|
-
dispatch({ type: 'jason/upsert', payload: { connected: true } })
|
66
|
-
console.debug('Connected to ActionCable')
|
67
|
-
|
68
|
-
// When AC loses connection - all state is lost, so we need to re-initialize all subscriptions
|
69
|
-
_.values(configs).forEach(config => createSubscription(config))
|
70
|
-
},
|
71
|
-
received: payload => {
|
72
|
-
handlePayload(payload)
|
73
|
-
console.debug("ActionCable Payload received: ", payload)
|
74
|
-
},
|
75
|
-
disconnected: () => {
|
76
|
-
setConnected(false)
|
77
|
-
dispatch({ type: 'jason/upsert', payload: { connected: false } })
|
78
|
-
console.warn('Disconnected from ActionCable')
|
79
|
-
}
|
80
|
-
}));
|
61
|
+
const transportAdapter = createTransportAdapater(jasonConfig, handlePayload, dispatch, () => _.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])))
|
81
62
|
|
82
|
-
function createSubscription(config) {
|
63
|
+
function createSubscription(config, options = {}) {
|
83
64
|
// We need the hash to be consistent in Ruby / Javascript
|
84
65
|
const hashableConfig = _({ conditions: {}, includes: {}, ...config }).toPairs().sortBy(0).fromPairs().value()
|
85
66
|
const md5Hash = md5(JSON.stringify(hashableConfig))
|
86
|
-
payloadHandlers[md5Hash] = createPayloadHandler({ dispatch, serverActionQueue,
|
67
|
+
payloadHandlers[md5Hash] = createPayloadHandler({ dispatch, serverActionQueue, transportAdapter, config })
|
87
68
|
configs[md5Hash] = hashableConfig
|
69
|
+
subOptions[md5Hash] = options
|
70
|
+
|
71
|
+
setTimeout(() => transportAdapter.createSubscription(hashableConfig), 500)
|
72
|
+
let pollInterval = null as any;
|
88
73
|
|
89
|
-
|
74
|
+
// This is only for debugging / dev - not prod!
|
75
|
+
// @ts-ignore
|
76
|
+
if (options.pollInterval) {
|
77
|
+
// @ts-ignore
|
78
|
+
pollInterval = setInterval(() => transportAdapter.getPayload(hashableConfig, { forceRefresh: true }), options.pollInterval)
|
79
|
+
}
|
90
80
|
|
91
81
|
return {
|
92
|
-
remove
|
82
|
+
remove() {
|
83
|
+
removeSubscription(hashableConfig)
|
84
|
+
if (pollInterval) clearInterval(pollInterval)
|
85
|
+
},
|
93
86
|
md5Hash
|
94
87
|
}
|
95
88
|
}
|
96
89
|
|
97
90
|
function removeSubscription(config) {
|
98
|
-
|
91
|
+
transportAdapter.removeSubscription(config)
|
99
92
|
const md5Hash = md5(JSON.stringify(config))
|
93
|
+
payloadHandlers[md5Hash].tearDown()
|
100
94
|
delete payloadHandlers[md5Hash]
|
101
95
|
delete configs[md5Hash]
|
96
|
+
delete subOptions[md5Hash]
|
102
97
|
}
|
103
98
|
|
104
99
|
setValue({
|
105
100
|
actions: actions,
|
106
|
-
subscribe:
|
101
|
+
subscribe: createSubscription,
|
107
102
|
eager,
|
108
103
|
handlePayload
|
109
104
|
})
|
@@ -111,5 +106,5 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
111
106
|
})
|
112
107
|
}, [])
|
113
108
|
|
114
|
-
return [store, value
|
109
|
+
return [store, value]
|
115
110
|
}
|
data/client/src/useSub.ts
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import JasonContext from './JasonContext'
|
2
2
|
import { useContext, useEffect } from 'react'
|
3
3
|
|
4
|
-
export default function useSub(config) {
|
4
|
+
export default function useSub(config, options = {}) {
|
5
|
+
// useEffect uses strict equality
|
6
|
+
const configJson = JSON.stringify(config)
|
5
7
|
const subscribe = useContext(JasonContext).subscribe
|
6
8
|
|
7
9
|
useEffect(() => {
|
8
10
|
// @ts-ignore
|
9
|
-
return subscribe(config)
|
10
|
-
}, [])
|
11
|
+
return subscribe(config, options).remove
|
12
|
+
}, [configJson])
|
11
13
|
}
|
data/client/yarn.lock
CHANGED
@@ -3645,6 +3645,13 @@ punycode@^2.1.0, punycode@^2.1.1:
|
|
3645
3645
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
3646
3646
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
3647
3647
|
|
3648
|
+
pusher-js@^7.0.3:
|
3649
|
+
version "7.0.3"
|
3650
|
+
resolved "https://registry.yarnpkg.com/pusher-js/-/pusher-js-7.0.3.tgz#f81c78cdf2ad32f546caa7532ec7f9081ef00b8d"
|
3651
|
+
integrity sha512-HIfCvt00CAqgO4W0BrdpPsDcAwy51rB6DN0VMC+JeVRRbo8mn3XTeUeIFjmmlRLZLX8rPhUtLRo7vPag6b8GCw==
|
3652
|
+
dependencies:
|
3653
|
+
tweetnacl "^1.0.3"
|
3654
|
+
|
3648
3655
|
qs@~6.5.2:
|
3649
3656
|
version "6.5.2"
|
3650
3657
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
@@ -4358,6 +4365,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
|
4358
4365
|
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
4359
4366
|
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
4360
4367
|
|
4368
|
+
tweetnacl@^1.0.3:
|
4369
|
+
version "1.0.3"
|
4370
|
+
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
|
4371
|
+
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
|
4372
|
+
|
4361
4373
|
type-check@~0.3.2:
|
4362
4374
|
version "0.3.2"
|
4363
4375
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
|
data/config/routes.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
Jason::Engine.routes.draw do
|
2
|
-
get '/api/
|
2
|
+
get '/api/config', to: 'api#configuration'
|
3
3
|
post '/api/action', to: 'api#action'
|
4
|
+
post '/api/create_subscription', to: 'api#create_subscription'
|
5
|
+
post '/api/remove_subscription', to: 'api#remove_subscription'
|
6
|
+
post '/api/get_payload', to: 'api#get_payload'
|
7
|
+
post '/api/pusher/auth', to: 'api/pusher#auth'
|
4
8
|
end
|
data/lib/jason.rb
CHANGED
@@ -7,22 +7,70 @@ require 'jason/api_model'
|
|
7
7
|
require 'jason/channel'
|
8
8
|
require 'jason/publisher'
|
9
9
|
require 'jason/subscription'
|
10
|
+
require 'jason/broadcaster'
|
10
11
|
require 'jason/engine'
|
11
12
|
require 'jason/lua_generator'
|
13
|
+
require 'jason/includes_helper'
|
14
|
+
require 'jason/graph_helper'
|
12
15
|
|
13
16
|
module Jason
|
14
17
|
class Error < StandardError; end
|
15
18
|
|
16
|
-
|
19
|
+
self.mattr_accessor :schema
|
20
|
+
self.mattr_accessor :transport_service
|
21
|
+
self.mattr_accessor :redis
|
22
|
+
self.mattr_accessor :pusher
|
23
|
+
self.mattr_accessor :pusher_key
|
24
|
+
self.mattr_accessor :pusher_region
|
25
|
+
self.mattr_accessor :pusher_channel_prefix
|
26
|
+
self.mattr_accessor :authorization_service
|
17
27
|
|
28
|
+
self.schema = {}
|
29
|
+
self.transport_service = :action_cable
|
30
|
+
self.pusher_region = 'eu'
|
31
|
+
self.pusher_channel_prefix = 'jason'
|
18
32
|
|
19
|
-
|
20
|
-
|
21
|
-
|
33
|
+
def self.init
|
34
|
+
# Check if the schema has changed since last time app was started. If so, do some work to ensure cache contains the correct data
|
35
|
+
got_lock = $redis_jason.set('jason:schema:lock', nx: true, ex: 3600) # Basic lock mechanism for multi-process environments
|
36
|
+
return if !got_lock
|
22
37
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
previous_schema = JSON.parse($redis_jason.get('jason:last_schema') || '{}')
|
39
|
+
current_schema = Jason.schema.deep_stringify_keys.deep_transform_values { |v| v.is_a?(Symbol) ? v.to_s : v }
|
40
|
+
pp current_schema
|
41
|
+
current_schema.each do |model, config|
|
42
|
+
if config != previous_schema[model]
|
43
|
+
puts "Config changed for #{model}"
|
44
|
+
puts "Old config was #{previous_schema[model]}"
|
45
|
+
puts "New config is #{config}"
|
46
|
+
puts "Rebuilding cache for #{model}"
|
47
|
+
model.classify.constantize.cache_all
|
48
|
+
puts "Done"
|
49
|
+
end
|
50
|
+
end
|
27
51
|
|
52
|
+
$redis_jason.set('jason:last_schema', current_schema.to_json)
|
53
|
+
ensure
|
54
|
+
$redis_jason.del('jason:schema:lock')
|
55
|
+
|
56
|
+
previous_config = 'test'
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# this function maps the vars from your app into your engine
|
61
|
+
def self.setup(&block)
|
62
|
+
yield self
|
63
|
+
|
64
|
+
$redis_jason = self.redis || ::ConnectionPool::Wrapper.new(size: 5, timeout: 3) { ::Redis.new(url: ENV['REDIS_URL']) }
|
65
|
+
|
66
|
+
if ![:action_cable, :pusher].include?(self.transport_service)
|
67
|
+
raise "Unknown transport service '#{self.transport_service}' specified"
|
68
|
+
end
|
69
|
+
|
70
|
+
if self.transport_service == :pusher && self.pusher.blank?
|
71
|
+
raise "Pusher specified as transport service but no Pusher client provided. Please configure with config.pusher = Pusher::Client.new(...)"
|
72
|
+
end
|
73
|
+
|
74
|
+
init
|
75
|
+
end
|
28
76
|
end
|