added openmct plugin and embedding
This commit is contained in:
parent
93be82f416
commit
8b8619dd8a
8
http.go
8
http.go
|
@ -69,6 +69,10 @@ func extractLimitModifier(r *http.Request) (*LimitOffsetModifier, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
type RouterMod func (chi.Router)
|
||||
var RouterMods = []RouterMod{}
|
||||
|
||||
|
||||
func TelemRouter(log *slog.Logger, broker *Broker, db *TelemDb) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
|
@ -84,6 +88,9 @@ func TelemRouter(log *slog.Logger, broker *Broker, db *TelemDb) http.Handler {
|
|||
|
||||
r.Mount("/api/v1", apiV1(broker, db))
|
||||
|
||||
for _, mod := range RouterMods {
|
||||
mod(r)
|
||||
}
|
||||
// To future residents - you can add new API calls/systems in /api/v2
|
||||
// Don't break anything in api v1! keep legacy code working!
|
||||
|
||||
|
@ -301,3 +308,4 @@ func apiV1GetRecord(db *TelemDb) http.HandlerFunc {
|
|||
func apiV1UpdateRecord(db *TelemDb) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {}
|
||||
}
|
||||
|
||||
|
|
29
openmct.go
Normal file
29
openmct.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
//go:build openmct
|
||||
package gotelem
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// this package provides a web router for the statif openmct build.
|
||||
// it should only be included if the build has been run,
|
||||
// to do so, run npm install and then npm run build.
|
||||
|
||||
//go:embed web/dist
|
||||
var public embed.FS
|
||||
|
||||
func OpenMCTRouter(r chi.Router) {
|
||||
// strip the subdirectory
|
||||
pfs, _ := fs.Sub(public, "web/dist")
|
||||
|
||||
// default route.
|
||||
r.Handle("/*", http.FileServerFS(pfs))
|
||||
}
|
||||
|
||||
func init() {
|
||||
RouterMods = append(RouterMods, OpenMCTRouter)
|
||||
}
|
131
web/.gitignore
vendored
Normal file
131
web/.gitignore
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
8710
web/package-lock.json
generated
Normal file
8710
web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
30
web/package.json
Normal file
30
web/package.json
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "g1_openmct",
|
||||
"version": "1.0.0",
|
||||
"description": "dev environment for openmct plugins for g1 strategy tool",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack",
|
||||
"serve": "webpack serve"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"dotenv-webpack": "^8.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"openmct": "^2.0.5",
|
||||
"socket.io": "^4.6.0",
|
||||
"socket.io-client": "^4.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"eslint": "^8.28.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
}
|
||||
}
|
12
web/src/app.js
Normal file
12
web/src/app.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import openmct from 'openmct';
|
||||
import PhoebusPlugin from "./phoebusPlugin";
|
||||
openmct.setAssetPath('openmct');
|
||||
openmct.install(openmct.plugins.LocalStorage());
|
||||
openmct.install(openmct.plugins.MyItems());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.time.clock('local', {start: -5 * 60 * 1000, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
openmct.install(openmct.plugins.Espresso());
|
||||
openmct.install(PhoebusPlugin());
|
||||
|
||||
openmct.start();
|
11
web/src/index.html
Normal file
11
web/src/index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Open MCT Tutorials</title>
|
||||
<script src="openmct/openmct.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
243
web/src/phoebusPlugin.js
Normal file
243
web/src/phoebusPlugin.js
Normal file
|
@ -0,0 +1,243 @@
|
|||
// import openmct from "openmct";
|
||||
import {_} from "lodash";
|
||||
import { io } from "socket.io-client";
|
||||
// Pho
|
||||
function PhoebusObjectProvider(identifier) {
|
||||
// console.log("obj provider", identifier)
|
||||
const board_regex = /^board\.([a-z-_]+)$/
|
||||
const packet_regex = /^board\.([a-z-_]+)\.([a-z-_]+)$/
|
||||
const data_field_regex = /^board\.([a-z-_]+)\.([a-z-_]+)\.([a-z-_]+)$/ // board.wavesculptor.wsl_heatsink_motor_temp.motor_temp
|
||||
const data_field_regex_num = /^board\.([a-z-_]+)\.([a-z-_]+)\.([A-Za-z0-9]+)$/ // board.car_control.dashboard_system_timeout_test.flag_set0
|
||||
const packet_regex_underscore_num = /^board\.([a-z-_]+)\.([a-z-_]+(_[A-Za-z0-9]+)+)$/ // board.steering.steering_press_count_1
|
||||
const data_field_regex_underscore_num1 = /^board\.([a-z-_]+)\.([a-z-_]+(_[A-Za-z0-9]+)+)\.([A-Za-z0-9]+)$/ // board.steering.steering_press_count_1.button1
|
||||
const data_field_regex_underscore_num2 = /^board\.([a-z-_]+)\.([a-z-_]+)\.([a-z-_]+(_[A-Za-z0-9]+)+)$/ // board.wavesculptor.wsr_status_information.error_flags_0
|
||||
const data_field_regex_underscore_num3 = /^board\.([a-z-_]+)\.([a-z-_]+(_[A-Za-z0-9]+)+)\.([A-Za-z0-9]+(_[A-Za-z0-9]+)+)$/ // board.wavesculptor.wsr_15_165_voltage_rail.reference_165v
|
||||
if (identifier.key === 'car') {
|
||||
// get the car schema from the phoebus server
|
||||
return Promise.resolve({
|
||||
identifier: identifier,
|
||||
name: "car!",
|
||||
type: 'folder',
|
||||
location: "ROOT"
|
||||
})
|
||||
} else if (board_regex.test(identifier.key)) {
|
||||
// it's a board object. get the last word (ie board.bms -> bms)
|
||||
// then use it to construct a get request
|
||||
// console.log("doing board for ", identifier)
|
||||
const board_name = identifier.key.match(board_regex)[1]
|
||||
return fetch(`${process.env.VUE_APP_TELEM}/schema/` + board_name).then((resp) => {
|
||||
return resp.json()
|
||||
})
|
||||
} else if (packet_regex.test(identifier.key)) {
|
||||
const m = identifier.key.match(packet_regex)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name].join("/")).then((resp) => {
|
||||
return resp.json()
|
||||
})
|
||||
} else if (data_field_regex.test(identifier.key)) {
|
||||
const m = identifier.key.match(data_field_regex)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
const df_name = m[3]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name, df_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
} else if (data_field_regex_num.test(identifier.key)) {
|
||||
const m = identifier.key.match(data_field_regex_num)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
const df_name = m[3]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name, df_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
} else if (packet_regex_underscore_num.test(identifier.key)) {
|
||||
const m = identifier.key.match(packet_regex_underscore_num)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
} else if (data_field_regex_underscore_num1.test(identifier.key)) {
|
||||
const m = identifier.key.match(data_field_regex_underscore_num1)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
const df_name = m[4]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name, df_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
} else if (data_field_regex_underscore_num2.test(identifier.key)) {
|
||||
const m = identifier.key.match(data_field_regex_underscore_num2)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
const df_name = m[3]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name, df_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
} else if (data_field_regex_underscore_num3.test(identifier.key)) {
|
||||
const m = identifier.key.match(data_field_regex_underscore_num3)
|
||||
const board_name = m[1]
|
||||
const pkt_name = m[2]
|
||||
const df_name = m[4]
|
||||
return fetch([`${process.env.VUE_APP_TELEM}/schema`, board_name, pkt_name, df_name].join("/")).then((resp) => {
|
||||
return resp.json();
|
||||
})
|
||||
}
|
||||
|
||||
console.error("bad! no match for object.")
|
||||
return {}
|
||||
}
|
||||
|
||||
function getSchema() {
|
||||
return fetch(`${process.env.VUE_APP_TELEM}/schema`).then((resp) => {
|
||||
const res = resp.json()
|
||||
console.log("got schema", res)
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
||||
const CarCompositionProvider = {
|
||||
appliesTo: function (domainObject) {
|
||||
return domainObject.identifier.namespace === "umnsvp.phoebus" &&
|
||||
domainObject.identifier.key === "car"
|
||||
},
|
||||
load: function (domainObject) {
|
||||
return getSchema()
|
||||
}
|
||||
}
|
||||
|
||||
// the board composition provider takes a board type object, and gets all the telem objects for that board.
|
||||
// it's like a folder.
|
||||
const BoardCompositionProvider = {
|
||||
appliesTo: function (domainObject) {
|
||||
return domainObject.identifier.namespace === "umnsvp.phoebus" &&
|
||||
domainObject.type === "umnsvp-board"
|
||||
},
|
||||
load: function (domainObject) {
|
||||
// console.log("board comp provider for ", domainObject.packets)
|
||||
return Promise.resolve(domainObject.packets)
|
||||
// const board_name = domainObject.identifier.key.match(/^board\.([a-z-_]+)$/)
|
||||
// return fetch("${process.env.VUE_APP_TELEM}/schema/" + board_name[1] + "/packets").then((resp) => {
|
||||
// return resp.json()
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
const PacketCompositionProvider = {
|
||||
appliesTo: function (domainObject) {
|
||||
return domainObject.identifier.namespace === "umnsvp.phoebus" && domainObject.type === "umnsvp-packet"
|
||||
},
|
||||
load: function (domainObject) {
|
||||
// console.log("packet comp provider for ", domainObject.data_fields)
|
||||
return Promise.resolve(domainObject.data_fields)
|
||||
}
|
||||
}
|
||||
|
||||
const PhoebusCompositionProviders = [
|
||||
CarCompositionProvider,
|
||||
BoardCompositionProvider,
|
||||
PacketCompositionProvider
|
||||
]
|
||||
|
||||
|
||||
function PhoebusRealTime() {
|
||||
const socket = io(`ws://localhost:${process.env.VUE_APP_TELEM_PORT}`)
|
||||
let callback_list = {};
|
||||
socket.on("packet", (data) => {
|
||||
// if (data[0].packet_name === "wsl_bus_measurement") {
|
||||
// console.log("got a wave meas packt", data[0])
|
||||
// }
|
||||
try {
|
||||
const data_fields = data[0].data[0] // object that defines the measurement in each packet which are sent to openmct
|
||||
// const key = ["board", data[0].board, data[0].packet_name].join(".")
|
||||
console.log(Object.keys(data_fields))
|
||||
console.log(callback_list)
|
||||
// for (let i = 0; i < callback_list.length; i++) {
|
||||
// if (Object.keys(data_fields).includes())
|
||||
// }
|
||||
Object.keys(data_fields).forEach((data_field) => {
|
||||
let key = ["board", data[0].board, data[0].packet_name, data_field].join(".");
|
||||
if (Object.keys(callback_list).includes(key)) {
|
||||
let callBack = callback_list[key];
|
||||
let timestamp = new Date().getTime();
|
||||
// let realTimeData = data_fields;
|
||||
let realTimeData = {}
|
||||
realTimeData[data_field] = data_fields[data_field]
|
||||
realTimeData.timestamp = timestamp;
|
||||
realTimeData.id = key;
|
||||
// console.log(realTimeData)
|
||||
callBack(realTimeData);
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
console.warn("a", e)
|
||||
}
|
||||
})
|
||||
|
||||
const provider = {
|
||||
supportsSubscribe(domainObject) {
|
||||
console.log("checking if supports subscribe", domainObject)
|
||||
return domainObject.type === "umnsvp-data"
|
||||
},
|
||||
subscribe(domainObject, callback) {
|
||||
console.log("subscribing for ", domainObject)
|
||||
console.log("callback", callback)
|
||||
// register us in the callback list
|
||||
callback_list[domainObject.identifier.key] = callback
|
||||
return function unsubscribe() {
|
||||
delete callback_list[domainObject.identifier.key]
|
||||
}
|
||||
}
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
function PhoebusHistorical() {
|
||||
return {
|
||||
supportsRequest(domainObject) {
|
||||
return domainObject.type === "umnsvp-packet"
|
||||
},
|
||||
request(domainObject, options) {
|
||||
// return fetch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function PhoebusPlugin() {
|
||||
return function install(openmct) {
|
||||
openmct.types.addType('umnsvp-board', {
|
||||
name: "UMN SVP Board",
|
||||
description: 'A board that sends telemetry packets/data',
|
||||
createable: false,
|
||||
cssClass: "icon-suitcase"
|
||||
})
|
||||
openmct.types.addType('umnsvp-packet', {
|
||||
name: "UMN SVP Packet",
|
||||
description: "A packet of telemetry from the car",
|
||||
creatable: false,
|
||||
cssClass: "icon-suitcase"
|
||||
})
|
||||
openmct.types.addType('umnsvp-data', {
|
||||
name: "UMN SVP Data Field",
|
||||
description: "A data field of a packet from the car",
|
||||
creatable: false,
|
||||
cssClass: "icon-telemetry"
|
||||
})
|
||||
openmct.objects.addRoot({
|
||||
namespace: "umnsvp.phoebus",
|
||||
key: 'car'
|
||||
})
|
||||
|
||||
openmct.objects.addProvider('umnsvp.phoebus', {get:PhoebusObjectProvider})
|
||||
|
||||
openmct.telemetry.addProvider(PhoebusRealTime())
|
||||
PhoebusCompositionProviders.forEach((provider) => {
|
||||
openmct.composition.addProvider((provider))
|
||||
})
|
||||
|
||||
console.log("hello~!")
|
||||
}
|
||||
}
|
||||
|
||||
export default PhoebusPlugin;
|
11
web/tsconfig.json
Normal file
11
web/tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./src",
|
||||
"target": "es6",
|
||||
"checkJs": true,
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"openmct": ["node_modules/openmct/dist/openmct.d.ts"]
|
||||
}
|
||||
}
|
||||
}
|
47
web/webpack.config.js
Normal file
47
web/webpack.config.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const Dotenv = require('dotenv-webpack');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/app.js',
|
||||
mode: "development",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'src/index.html',
|
||||
filename: 'index.html',
|
||||
}),
|
||||
new Dotenv(),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: "**/*", to: "openmct/", context: "node_modules/openmct/dist"},
|
||||
]
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
externals: {
|
||||
openmct: "openmct",
|
||||
},
|
||||
devServer: {
|
||||
static: [{
|
||||
// eslint-disable-next-line no-undef
|
||||
directory: path.join(__dirname, '/node_modules/openmct/dist'),
|
||||
publicPath: '/node_modules/openmct/dist'
|
||||
}]
|
||||
},
|
||||
output: {
|
||||
filename: 'main.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
};
|
Loading…
Reference in a new issue