Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: JavaScript namespaces, JSON-Schema Bundles, Bi-directional JSON-RPC changes #179

Open
wants to merge 64 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
c9896f7
Push new workflow
kschrief Feb 23, 2024
0372e6e
Remove scary github actions
kschrief Feb 23, 2024
82f409f
Update
kschrief Feb 23, 2024
fa37994
Trigger
kschrief Feb 23, 2024
b1fe3bd
Trigger
kschrief Feb 23, 2024
f5ac990
Trigger
kschrief Feb 23, 2024
806e737
Introduce conflict
kschrief Feb 23, 2024
b423f5c
Yes. Good.
kschrief Feb 23, 2024
2aa497c
Get version number
kschrief Feb 27, 2024
337d36e
Get version number
kschrief Feb 27, 2024
90895c6
Get version number
kschrief Feb 27, 2024
d829527
Commit version change
kschrief Feb 27, 2024
3cdbd3c
Commit version change
kschrief Feb 27, 2024
814e1b5
Commit version change
kschrief Feb 27, 2024
37a11a0
Exit 0
kschrief Feb 27, 2024
a6bd102
Versions
kschrief Feb 27, 2024
70025d4
Versions
kschrief Feb 27, 2024
39fe788
Versions
kschrief Feb 27, 2024
9849b7c
Versions
kschrief Feb 27, 2024
63c4013
Conflict
kschrief Feb 27, 2024
cf09ec1
Conflict
kschrief Feb 27, 2024
dddf189
Conflict
kschrief Feb 27, 2024
0848c86
Conflict
kschrief Feb 27, 2024
e6171a9
Conflict
kschrief Feb 27, 2024
fa25feb
Finishing touches
kschrief Feb 28, 2024
b2a5c5f
Finishing touches
kschrief Feb 28, 2024
d4690ba
Merge to main
kschrief Feb 28, 2024
e67ba1f
Change next->main script
kschrief Feb 28, 2024
682a750
Better commit message
kschrief Feb 28, 2024
8aab3df
Better commit message
kschrief Feb 28, 2024
3b81a54
Reverse temporary changes
kschrief Mar 8, 2024
40c70b6
Reverse versioning override
kschrief Mar 25, 2024
5ebcecc
Silly change
kschrief Mar 25, 2024
2ca3e70
Forgot to checkout next-major
kschrief Mar 25, 2024
d064d2f
feat: Latest changes
jlacivita Mar 26, 2024
abb4dee
Merge branch 'next' into major/rpc
jlacivita Mar 27, 2024
74136cd
fix: Add promoteAndName
jlacivita Mar 27, 2024
7d70f92
feat: JavaScript now has distinct imports for shared schemas
jlacivita Mar 27, 2024
6980e1b
fix: Propogate namespace based on copySchemasIntoModules
jlacivita Mar 28, 2024
0a45045
feat: Added Gateway
jlacivita Apr 1, 2024
23bc305
Merge branch 'next' into next
kschrief Apr 2, 2024
23ea7c9
Merge pull request #175 from kschrief/next
kschrief Apr 2, 2024
649a17a
fix: Optimized generateAggregateMacros logic
jlacivita Apr 4, 2024
2730b20
fix: Latest changes
jlacivita May 9, 2024
3d3a657
chore: Latest work
jlacivita May 16, 2024
f54ed16
chore: Provider updates
jlacivita Jun 3, 2024
c7190c1
fix: More provider stuff
jlacivita Jun 3, 2024
ebc9b07
Merge branch 'next' into major/rpc
jlacivita Jun 4, 2024
9082dc6
fix: Latest
jlacivita Jun 4, 2024
6930b91
Merge branch 'next' into major/rpc
jlacivita Jun 4, 2024
98268d0
fix: Bugs
jlacivita Jun 5, 2024
3e0b584
fix: Support provider interface in separate file
jlacivita Jun 5, 2024
6a90892
fix: Updating test SDK
jlacivita Jun 6, 2024
8949a47
Merge branch 'next' into major/rpc
jlacivita Jun 6, 2024
d3c7b5c
fix: Merge fixes
jlacivita Jun 6, 2024
8810817
fix: Happy path npm run build working
jlacivita Jun 7, 2024
9305aa7
chore: WIP
jlacivita Jun 7, 2024
131dbb1
fix: Get all tests passing
jlacivita Jun 10, 2024
e52ef87
fix: Validatilon and Transforms
jlacivita Jun 12, 2024
7336ee4
fix: More validiation
jlacivita Jun 12, 2024
b13d4cd
fix: Transforms
jlacivita Jun 12, 2024
7bedf0b
feat: Support for both Bi- and Uni-directional SDKs
jlacivita Jun 18, 2024
8ecb0df
fix: Removed support for ${EXAMPLE:method:index} macro
jlacivita Jun 18, 2024
e2e57bf
fix: Test transport layers back to using string, not json
jlacivita Jun 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion languages/cpp/templates/codeblocks/provider.h

This file was deleted.

1 change: 0 additions & 1 deletion languages/cpp/templates/imports/calls-metrics.cpp

This file was deleted.

1 change: 0 additions & 1 deletion languages/cpp/templates/imports/calls-metrics.impl

This file was deleted.

19 changes: 17 additions & 2 deletions languages/cpp/templates/modules/include/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
#pragma once

#include "error.h"
/* ${IMPORTS} */
/* ${IMPORTS:h} */
${if.callsmetrics}#include "metrics.h"
${end.if.callsmetrics}


${if.declarations}namespace Firebolt {
namespace ${info.Title} {
Expand All @@ -30,7 +33,19 @@ namespace ${info.Title} {
${if.types}
// Types
/* ${TYPES} */${end.if.types}
${if.providers}/* ${PROVIDERS} */${end.if.providers}${if.xuses}/* ${XUSES} */${end.if.xuses}
${if.providers}// Provider Interfaces
struct IProviderSession {
virtual ~IProviderSession() = default;

virtual std::string correlationId() const = 0;
};

struct IFocussableProviderSession : virtual public IProviderSession {
virtual ~IFocussableProviderSession() override = default;

virtual void focus( Firebolt::Error *err = nullptr ) = 0;
};
/* ${PROVIDER_INTERFACES} */${end.if.providers}${if.xuses}/* ${XUSES} */${end.if.xuses}
${if.methods}struct I${info.Title} {

virtual ~I${info.Title}() = default;
Expand Down
4 changes: 2 additions & 2 deletions languages/cpp/templates/modules/src/module_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
namespace Firebolt {
namespace ${info.Title} {
${if.providers}
/* ${PROVIDERS} */${end.if.providers}
/* ${PROVIDER_CLASES} */${end.if.providers}
// Methods
/* ${METHODS} */

Expand All @@ -35,5 +35,5 @@ namespace ${info.Title} {

namespace WPEFramework {

/* ${ENUMS} */
/* ${ENUM_IMPLEMENTATIONS} */
}${end.if.enums}
4 changes: 3 additions & 1 deletion languages/cpp/templates/modules/src/module_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

#include "FireboltSDK.h"
#include "IModule.h"
/* ${IMPORTS} */
/* ${IMPORTS:impl} */
${if.callsmetrics}#include "metrics_impl.h"
${end.if.callsmetrics}
#include "${info.title.lowercase}.h"

${if.implementations}
Expand Down
2 changes: 1 addition & 1 deletion languages/cpp/templates/schemas/include/common/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#pragma once

#include "error.h"
/* ${IMPORTS} */
/* ${IMPORTS:h} */

${if.declarations}namespace Firebolt {
namespace ${info.Title} {
Expand Down
2 changes: 1 addition & 1 deletion languages/cpp/templates/schemas/src/jsondata_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#pragma once

/* ${IMPORTS} */
/* ${IMPORTS:jsondata} */
#include "common/${info.title.lowercase}.h"

${if.schemas}namespace Firebolt {
Expand Down
4 changes: 2 additions & 2 deletions languages/cpp/templates/schemas/src/module_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
*/

#include "FireboltSDK.h"
/* ${IMPORTS} */
/* ${IMPORTS:cpp} */
#include "jsondata_${info.title.lowercase}.h"
${if.enums}

namespace WPEFramework {

/* ${ENUMS} */
/* ${ENUM_IMPLEMENTATIONS} */
}${end.if.enums}
2 changes: 1 addition & 1 deletion languages/cpp/templates/sdk/include/firebolt.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ struct IFireboltAccessor {
// Module Instance methods goes here.
// Instances are owned by the FireboltAcccessor and linked with its lifecycle.

${module.init}
${module.init:h}
};

}
2 changes: 1 addition & 1 deletion languages/cpp/templates/sdk/src/firebolt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ namespace Firebolt {
{
}

${module.init}
${module.init:cpp}
private:
FireboltSDK::Accessor* _accessor;
static FireboltAccessorImpl* _singleton;
Expand Down
14 changes: 0 additions & 14 deletions languages/cpp/templates/sections/provider-interfaces.h

This file was deleted.

4 changes: 4 additions & 0 deletions languages/javascript/language.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
"/index.mjs",
"/defaults.mjs"
],
"templatesPerSchema": [
"/index.mjs"
],
"createModuleDirectories": true,
"copySchemasIntoModules": true,
"mergeOnTitle": true,
"aggregateFiles": [
"/index.d.ts"
],
Expand Down
66 changes: 27 additions & 39 deletions languages/javascript/src/shared/Events/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import Transport from '../Transport/index.mjs'
import { setMockListener } from '../Transport/MockTransport.mjs'
import Gateway from '../Gateway/index.mjs'

let listenerId = 0

Expand Down Expand Up @@ -82,41 +81,30 @@ const listeners = {
}
}

// holds a map of RPC Ids => Context Key, e.g. the RPC id of an onEvent call mapped to the corresponding context parameters key for that RPC call
const keys = {}

// holds a map of ${module}.${event} => Transport.send calls (only called once per event)
// note that the keys here MUST NOT contain wild cards
const oncers = []
const validEvents = {}
const validContext = {}

let transportInitialized = false

export const emit = (id, value) => {
callCallbacks(listeners.internal[keys[id]], [value])
callCallbacks(listeners.external[keys[id]], [value])
}

export const registerEvents = (module, events) => {
validEvents[module.toLowerCase()] = events.concat()
validEvents[module] = events.concat()
}

export const registerEventContext = (module, event, context) => {
validContext[module.toLowerCase()] = validContext[module.toLowerCase()] || {}
validContext[module.toLowerCase()][event] = context.concat()
validContext[module] = validContext[module] || {}
validContext[module][event] = context.concat()
}

const callCallbacks = (cbs, args) => {
cbs &&
Object.keys(cbs).forEach(listenerId => {
let callback = cbs[listenerId]
if (oncers.indexOf(parseInt(listenerId)) >= 0) {
oncers.splice(oncers.indexOf(parseInt(listenerId)), 1)
delete cbs[listenerId]
}
callback.apply(null, args)
})
const callCallbacks = (key, args) => {
const callbacks = Object.entries(listeners.internal[key] || {}).concat(Object.entries(listeners.external[key] || {}))
callbacks.forEach( ([listenerId, callback]) => {
if (oncers.indexOf(parseInt(listenerId)) >= 0) {
oncers.splice(oncers.indexOf(parseInt(listenerId)), 1)
delete listeners.external[key][listenerId]
}
callback.apply(null, [args])
})
}

const doListen = function(module, event, callback, context, once, internal=false) {
Expand Down Expand Up @@ -146,8 +134,15 @@ const doListen = function(module, event, callback, context, once, internal=false

if (Object.values(listeners.get(key)).length === 0) {
const args = Object.assign({ listen: true }, context)
const { id, promise } = Transport.listen(module, 'on' + event[0].toUpperCase() + event.substring(1), args)
keys[id] = key

// TODO: Is subscriber -> notifer required to be a simple transform (drop 'on'?)
const subscriber = module + '.on' + event[0].toUpperCase() + event.substring(1)
const notifier = module + '.' + event

const promise = Gateway.request(subscriber, args)
Gateway.subscribe(notifier, (params) => {
callCallbacks(key, params[Object.keys(params).pop()])
})
promises.push(promise)
}

Expand Down Expand Up @@ -197,7 +192,7 @@ const getListenArgs = function(...args) {
}

const getClearArgs = function(...args) {
const module = (args.shift() || '*').toLowerCase()
const module = (args.shift() || '*')
const event = args.shift() || '*'
const context = {}

Expand Down Expand Up @@ -240,7 +235,8 @@ export const prioritize = function(...args) {
const unsubscribe = (key, context) => {
const [module, event] = key.split('.').slice(0, 2)
const args = Object.assign({ listen: false }, context)
Transport.send(module, 'on' + event[0].toUpperCase() + event.substr(1), args)
Gateway.request(module + '.on' + event[0].toUpperCase() + event.substr(1), args)
Gateway.unsubscribe(`${module}.${event}`)
}


Expand Down Expand Up @@ -270,7 +266,7 @@ const doClear = function (moduleOrId = false, event = false, context) {
})
} else if (!event) {
listeners.keys().forEach(key => {
if (key.indexOf(moduleOrId.toLowerCase()) === 0) {
if (key.indexOf(moduleOrId) === 0) {
listeners.removeKey(key)
unsubscribe(key)
}
Expand All @@ -287,18 +283,10 @@ const doClear = function (moduleOrId = false, event = false, context) {
}

const init = () => {
if (!transportInitialized) {
Transport.addEventEmitter(emit)
setMockListener(listen)
transportInitialized = true
}
}

export default {
listen: listen,
once: once,
clear: clear,
broadcast(event, value) {
emit(Object.entries(keys).find( ([k, v]) => v === 'app.'+event)[0], value)
},
clear: clear
}
104 changes: 104 additions & 0 deletions languages/javascript/src/shared/Gateway/Client.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2021 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

import Transport from "../Transport/index.mjs"

const win = typeof window !== 'undefined' ? window : {}
win.__firebolt = win.__firebolt || {}

// JSON RPC id generator, to be shared across all SDKs
class JsonRpcIdIterator {
constructor() {
this._id = 1
}
getJsonRpcId() {
return this._id++
}
}

let idGenerator = win.__firebolt.idGenerator || new JsonRpcIdIterator()
win.__firebolt.idGenerator = idGenerator

const promises = {}
const deprecated = {}

export async function bulk(requests) {
if (Array.isArray(requests)) {
const body = requests.map(req => processRequest(req.method, req.params))
Transport.send(body)
return await Promise.all(requests.map((req, i) => addPromiseToQueue(req.id, requests[i].transforms)))
}
throw `Bulk requests must be in an array`
}

// Request that the server provide fulfillment of an method
export async function request(method, params, transforms) {
const json = processRequest(method, params)
const promise = addPromiseToQueue(json.id, transforms)
Transport.send(json)
return promise
}

export async function notify(method, params) {
Transport.send(processRequest(method, params, true))
}

export function response(id, result, error) {
if (result !== undefined) {
promises[id].resolve(result)
}
else if (error !== undefined) {
promises[id].reject(error)
}
}

export function deprecate(method, alternative) {
deprecated[method] = alternative
}

function addPromiseToQueue (id, transforms) {
return new Promise((resolve, reject) => {
promises[id] = {}
promises[id].promise = this
promises[id].resolve = resolve
promises[id].reject = reject
promises[id].transforms = transforms
})
}

function processRequest(method, params, notification=false) {
if (deprecated[method]) {
console.warn(`WARNING: ${method}() is deprecated. ` + deprecated[method])
}

const id = !notification && idGenerator.getJsonRpcId()
const jsonrpc = '2.0'
const json = { jsonrpc, method, params }

!notification && (json.id = id)

return json
}


export default {
request,
bulk,
response,
deprecate
}