Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions forge/comms/aclManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ module.exports = function (app) {
// ff/v1/<team>/d/<device>/logs/heartbeat
{ topic: /^ff\/v1\/[^/]+\/d\/[^/]+\/logs\/heartbeat$/ },
// ff/v1/<team>/d/<device>/resources/heartbeat
{ topic: /^ff\/v1\/[^/]+\/d\/[^/]+\/resources\/heartbeat$/ }
{ topic: /^ff\/v1\/[^/]+\/d\/[^/]+\/resources\/heartbeat$/ },
// ff/v1/platform/sync
{ topic: /^ff\/v1\/platform\/sync$/ }
],
pub: [
// Send commands to project launchers
Expand All @@ -130,7 +132,9 @@ module.exports = function (app) {
{ topic: /^ff\/v1\/[^/]+\/p\/[^/]+\/command$/ },
// Send commands to all application-assigned devices
// - ff/v1/+/a/+/command
{ topic: /^ff\/v1\/[^/]+\/a\/[^/]+\/command$/ }
{ topic: /^ff\/v1\/[^/]+\/a\/[^/]+\/command$/ },
// ff/v1/platform/sync
{ topic: /^ff\/v1\/platform\/sync$/ }
]
},
project: {
Expand Down
12 changes: 11 additions & 1 deletion forge/comms/commsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ class CommsClient extends EventEmitter {
}
this.emit('response/device', response)
}
} else if (ownerType === 'sync') {
// settings updated by another instance
// check if message is from this instance
const payload = message.toString()
const jsonPayload = JSON.parse(payload)
if (jsonPayload.srcId !== this.platformId) {
this.app.settings.refresh(jsonPayload.key)
}
}
})
this.client.subscribe([
Expand All @@ -106,7 +114,9 @@ class CommsClient extends EventEmitter {
// Device logs heartbeat
'ff/v1/+/d/+/logs/heartbeat',
// Device response heartbeat
'ff/v1/+/d/+/resources/heartbeat'
'ff/v1/+/d/+/resources/heartbeat',
// Platform sync messages
'ff/v1/platform/sync'
])
}
}
Expand Down
13 changes: 12 additions & 1 deletion forge/comms/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,18 @@ module.exports = fp(async function (app, _opts) {
// Setup the platform API for the comms component
app.decorate('comms', {
devices: deviceCommsHandler,
aclManager: ACLManager(app)
aclManager: ACLManager(app),
platform: {
settings: {
sync: function (key) {
const msg = {
key,
srcId: client.platformId
}
client.publish('ff/v1/platform/sync', JSON.stringify(msg))
}
}
}
})

app.addHook('onReady', async () => {
Expand Down
12 changes: 12 additions & 0 deletions forge/settings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ module.exports = fp(async function (app, _opts) {
}
settings[key] = value
await app.db.models.PlatformSettings.upsert({ key, value })
if (app.comms?.platform?.settings?.sync) {
app.comms.platform.settings.sync(key)
}
},
refresh: async (key) => {
const newSetting = await app.db.models.PlatformSettings.findOne({
where: { key }
})

if (newSetting) {
settings[key] = newSetting.value
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions test/unit/forge/comms/authRoutesV2_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ describe('Broker Auth v2 API', async function () {
topic: 'ff/v1/abc/d/ghi/command'
})
})
it('allows plaform to publish to platform settings sync topic', async function () {
await allowWrite({
username: 'forge_platform',
topic: 'ff/v1/platform/sync'
})
})
it('allows plaform to subscribe to platform settings sync topic', async function () {
await allowRead({
username: 'forge_platform',
topic: 'ff/v1/platform/sync'
})
})
})

describe('Project', async function () {
Expand Down
12 changes: 12 additions & 0 deletions test/unit/forge/comms/authRoutes_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ describe('Broker Auth API', async function () {
topic: 'ff/v1/abc/d/ghi/command'
})
})
it('allows plaform to publish to platform settings sync topic', async function () {
await allowWrite({
username: 'forge_platform',
topic: 'ff/v1/platform/sync'
})
})
it('allows plaform to subscribe to platform settings sync topic', async function () {
await allowRead({
username: 'forge_platform',
topic: 'ff/v1/platform/sync'
})
})
})

describe('Project', async function () {
Expand Down
90 changes: 90 additions & 0 deletions test/unit/forge/settings/settings_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const sleep = require('util').promisify(setTimeout)

const should = require('should') // eslint-disable-line
const setup = require('./setup')

describe('Platform Settings', function () {
let app

before(async function () {
app = await setup()
})

after(async function () {
await app.close()
})

describe('read settings', function () {
it('read default value', async function () {
const value = app.settings.get('telemetry:enabled')
value.should.equal(true)
})
})
describe('update settings', function () {
function mockSocket () {
let received = []
const handlers = {}
return {
platformId: 'test-platform-id',
publish: (topic, payload, opts, callback) => {
received.push({ topic, payload })
if (callback) {
setImmediate(() => callback())
}
},
send: (data) => {
received.push(data)
},
on: (event, callback) => {
handlers[event] = callback
},
emit: function () {
const evt = arguments[0]
const args = Array.prototype.slice.call(arguments, 1)
handlers[evt].apply(null, args)
},
received: () => received,
clearReceived: () => { received = [] }
}
}

let client

beforeEach(function () {
client = mockSocket()

app.comms.platform.settings.sync = function (key) {
const msg = {
key,
srcId: 'stub'
}
client.publish('ff/v1/platform/sync', JSON.stringify(msg))
}
})

it('value should change', async function () {
const origValue = app.settings.get('telemetry:enabled')
origValue.should.equal(true)
const origDBValue = await app.db.models.PlatformSettings.findOne({
where: { key: 'telemetry:enabled' }
})
should(origDBValue).equal(null)
await app.settings.set('telemetry:enabled', false)
const newValue = app.settings.get('telemetry:enabled')
newValue.should.equal(false)
newValue.should.not.equal(origValue)
const newDBValue = await app.db.models.PlatformSettings.findOne({
where: { key: 'telemetry:enabled' }
})
newDBValue.value.should.equal(false)
})
it('should publish when settings changed', async function () {
app.settings.set('telemetry:enabled', false)
await sleep(100)
const messages = client.received()
messages.should.have.length(1)
const payload = JSON.parse(messages[0].payload)
payload.key.should.equal('telemetry:enabled')
})
})
})
15 changes: 15 additions & 0 deletions test/unit/forge/settings/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const FF_UTIL = require('flowforge-test-utils')

async function setup (config = {}) {
config = {
housekeeper: false,
...config
}

const forge = await FF_UTIL.setupApp(config)
await forge.db.models.PlatformSettings.upsert({ key: 'setup:initialised', value: true })

return forge
}

module.exports = setup
Loading