Add native token based authentication (#247)

* Replace request with axios for the client side.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Remove 3rd party naming.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Refactor all groupable parameters and add auth header configuration parameter.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Introduce token based authentication via configuration parameter.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Make local LSP also use primary Extension Output Channel.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Add basic auth token check on config change.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Added warn message with authToken config recommendation.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Move Utils into new utils folder. Adapt import paths.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Introduce new config manager class to handle config parameters and logic.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Adapt repo settings for continous watching for file changes.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Move handler for config errors to ConfigManager. Add warning for deprecated config values.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Small improvements for config calls and warning messages.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Fix nested view for items and things TreeViewProvider

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Typo + brackets

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Add basic migration script.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Adapt launch and task config.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Improve migration script. Respect config scopes.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Refactor util classes and types.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Remove migration routine.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Small language client improvements. Add Changelog and major version.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>

* Add missing deprecated parameters back for proper error handling.

Signed-off-by: Jerome Luckenbach <github@luckenba.ch>
pull/253/head
Jerome Luckenbach 2021-03-27 18:42:55 +01:00 committed by GitHub
parent a9a957cc44
commit 8f3f597880
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1346 additions and 359 deletions

2
.vscode/launch.json vendored
View File

@ -14,7 +14,7 @@
"${workspaceRoot}/client/out/**/*.js", "${workspaceRoot}/client/out/**/*.js",
"${workspaceRoot}/serverJS/out/**/*.js" "${workspaceRoot}/serverJS/out/**/*.js"
], ],
"preLaunchTask": "npm" "preLaunchTask": "npm: watch"
}, },
{ {
"name": "Launch Tests", "name": "Launch Tests",

15
.vscode/tasks.json vendored
View File

@ -15,7 +15,7 @@
"label": "npm", "label": "npm",
"type": "shell", "type": "shell",
"command": "npm", "command": "npm",
"args": ["run", "compile", "--loglevel", "silent"], //custom script "compile" as defined in package.json "args": ["run", "watch"], //custom script "watch" as defined in package.json
"presentation": { "presentation": {
"echo": false, "echo": false,
"reveal":"silent", "reveal":"silent",
@ -25,6 +25,19 @@
}, },
"isBackground": true, // tsc compiler is started in watching mode "isBackground": true, // tsc compiler is started in watching mode
"problemMatcher": ["$tsc-watch"] "problemMatcher": ["$tsc-watch"]
},
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
} }
] ]

View File

@ -5,6 +5,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
- Add native token based authentication (#247)
- Refactor configuration entries (#247)
- Remove 3rd Party references and rename console setting (#247)
- Replace deprecated http library (#247)
## [0.8.2] - 2021-03-19 ## [0.8.2] - 2021-03-19
- Dependency fixes (#239) - Dependency fixes (#239)

608
client/package-lock.json generated
View File

@ -1,9 +1,602 @@
{ {
"name": "openhab-vscode-extension", "name": "openhab-vscode-extension",
"version": "0.8.0", "version": "0.8.0",
"lockfileVersion": 1, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": {
"": {
"name": "openhab-vscode-extension",
"version": "0.8.0",
"license": "SEE LICENSE IN LICENSE",
"dependencies": { "dependencies": {
"ascii-table": "0.0.9",
"axios": "^0.21.1",
"copy-paste": "^1.3.0",
"lodash": "^4.17.20",
"request": "^2.88.2",
"request-promise-native": "^1.0.9",
"vscode-languageclient": "6.0.0-next.1"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/vscode": "^1.14.0"
},
"engines": {
"vscode": "^1.37.0"
}
},
"node_modules/@types/axios": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
"integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=",
"deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!",
"dev": true,
"dependencies": {
"axios": "*"
}
},
"node_modules/@types/vscode": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz",
"integrity": "sha512-Kt3bvWzAvvF/WH9YEcrCICDp0Z7aHhJGhLJ1BxeyNP6yRjonWqWnAIh35/pXAjswAnWOABrYlF7SwXR9+1nnLA==",
"dev": true
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"node_modules/ascii-table": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/ascii-table/-/ascii-table-0.0.9.tgz",
"integrity": "sha1-BqZgTWpV1L9BqaR9mHLXp42jHnM="
},
"node_modules/asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"engines": {
"node": ">=0.8"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"engines": {
"node": "*"
}
},
"node_modules/aws4": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
},
"node_modules/axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"dependencies": {
"follow-redirects": "^1.10.0"
}
},
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dependencies": {
"tweetnacl": "^0.14.3"
}
},
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/copy-paste": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/copy-paste/-/copy-paste-1.3.0.tgz",
"integrity": "sha1-p+bEocKP3t8rCB5yuX3y75X0ce0=",
"dependencies": {
"iconv-lite": "^0.4.8"
},
"optionalDependencies": {
"sync-exec": "~0.6.x"
}
},
"node_modules/core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dependencies": {
"assert-plus": "^1.0.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"node_modules/extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"engines": [
"node >=0.6.0"
]
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/follow-redirects": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"engines": {
"node": "*"
}
},
"node_modules/form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 0.12"
}
},
"node_modules/getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dependencies": {
"assert-plus": "^1.0.0"
}
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"engines": {
"node": ">=4"
}
},
"node_modules/har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"dependencies": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dependencies": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
},
"engines": {
"node": ">=0.8",
"npm": ">=1.3.7"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"node_modules/jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"node_modules/json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"node_modules/jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"engines": [
"node >=0.6.0"
],
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"node_modules/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"node_modules/mime-db": {
"version": "1.45.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.28",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
"integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"dependencies": {
"mime-db": "1.45.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"engines": {
"node": "*"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"engines": {
"node": ">=6"
}
},
"node_modules/qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/request-promise-core": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
"integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
"dependencies": {
"lodash": "^4.17.19"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/request-promise-native": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
"integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
"dependencies": {
"request-promise-core": "1.1.4",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
},
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
},
"bin": {
"sshpk-conv": "bin/sshpk-conv",
"sshpk-sign": "bin/sshpk-sign",
"sshpk-verify": "bin/sshpk-verify"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sync-exec": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz",
"integrity": "sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=",
"optional": true
},
"node_modules/tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dependencies": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"engines": [
"node >=0.6.0"
],
"dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"node_modules/vscode-jsonrpc": {
"version": "5.0.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz",
"integrity": "sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg==",
"engines": {
"node": ">=8.0.0 || >=10.0.0"
}
},
"node_modules/vscode-languageclient": {
"version": "6.0.0-next.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz",
"integrity": "sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg==",
"dependencies": {
"semver": "^6.3.0",
"vscode-languageserver-protocol": "^3.15.0-next.9"
},
"engines": {
"vscode": "^1.38.0"
}
},
"node_modules/vscode-languageclient/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/vscode-languageserver-protocol": {
"version": "3.15.0-next.9",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz",
"integrity": "sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g==",
"dependencies": {
"vscode-jsonrpc": "^5.0.0-next.2",
"vscode-languageserver-types": "^3.15.0-next.5"
}
},
"node_modules/vscode-languageserver-types": {
"version": "3.15.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz",
"integrity": "sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw=="
}
},
"dependencies": {
"@types/axios": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz",
"integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=",
"dev": true,
"requires": {
"axios": "*"
}
},
"@types/vscode": { "@types/vscode": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.52.0.tgz",
@ -54,6 +647,14 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
}, },
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"bcrypt-pbkdf": { "bcrypt-pbkdf": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@ -131,6 +732,11 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
}, },
"follow-redirects": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
},
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",

View File

@ -18,10 +18,9 @@
}, },
"dependencies": { "dependencies": {
"ascii-table": "0.0.9", "ascii-table": "0.0.9",
"axios": "^0.21.1",
"copy-paste": "^1.3.0", "copy-paste": "^1.3.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"request": "^2.88.2",
"request-promise-native": "^1.0.9",
"vscode-languageclient": "6.0.0-next.1" "vscode-languageclient": "6.0.0-next.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -3,8 +3,10 @@ import {
MarkdownString MarkdownString
} from 'vscode' } from 'vscode'
import * as utils from '../Utils' import * as utils from '../Utils/Utils'
import * as request from 'request-promise-native' import axios, { AxiosRequestConfig } from 'axios'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
/** /**
* Handles hover actions in editor windows. * Handles hover actions in editor windows.
@ -92,10 +94,20 @@ export class HoverProvider {
private getRestItemHover(hoveredText: string): Thenable<Hover> { private getRestItemHover(hoveredText: string): Thenable<Hover> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
console.log(`Requesting => ${utils.getHost()}/rest/items/${hoveredText} <= now`) console.log(`Requesting => ${utils.getHost()}/rest/items/${hoveredText} <= now`)
let config: AxiosRequestConfig = {
url: utils.getHost() + `/rest/items/${hoveredText}`,
headers: {}
}
request(`${utils.getHost()}/rest/items/${hoveredText}`) if(ConfigManager.tokenAuthAvailable()){
config.headers = {
'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken)
}
}
axios(config)
.then((response) => { .then((response) => {
let result = JSON.parse(response) let result = response.data
if (!result.error) { if (!result.error) {
let resultText = new MarkdownString() let resultText = new MarkdownString()
@ -146,13 +158,23 @@ export class HoverProvider {
* @returns **true** when update was successful, **false** otherwise * @returns **true** when update was successful, **false** otherwise
*/ */
public updateItems() : Boolean { public updateItems() : Boolean {
let config: AxiosRequestConfig = {
url: utils.getHost() + '/rest/items',
headers: {}
}
request(`${utils.getHost()}/rest/items/`) if(ConfigManager.tokenAuthAvailable()){
config.headers = {
'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken)
}
}
axios(config)
.then((response) => { .then((response) => {
// Clear prossible existing array // Clear prossible existing array
this.knownItems = new Array<String>() this.knownItems = new Array<String>()
let result = JSON.parse(response) let result = response.data
result.forEach(item => { result.forEach(item => {
this.knownItems.push(item.name) this.knownItems.push(item.name)

View File

@ -11,6 +11,8 @@ import {
import { Item } from './Item' import { Item } from './Item'
import { ItemsModel } from './ItemsModel' import { ItemsModel } from './ItemsModel'
import * as _ from 'lodash' import * as _ from 'lodash'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
/** /**
* Produces a list of openHAB items completions * Produces a list of openHAB items completions
@ -30,9 +32,7 @@ export class ItemsCompletion implements CompletionItemProvider {
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable<CompletionItem[]> { public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable<CompletionItem[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let config = workspace.getConfiguration('openhab') if (ConfigManager.get(OH_CONFIG_PARAMETERS.useRestApi)) {
if (config.useRestApi) {
this.model.completions.then(completions => { this.model.completions.then(completions => {
resolve(completions.map((item: Item) => { resolve(completions.map((item: Item) => {
let completionItem = _.assign(new CompletionItem(item.name), { let completionItem = _.assign(new CompletionItem(item.name), {

View File

@ -5,10 +5,12 @@ import {
workspace workspace
} from 'vscode' } from 'vscode'
import { Item } from './Item' import { Item } from './Item'
import * as utils from '../Utils' import * as utils from '../Utils/Utils'
import * as _ from 'lodash' import * as _ from 'lodash'
import * as request from 'request-promise-native' import axios, { AxiosRequestConfig } from 'axios'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
/** /**
* Collects Items in JSON format from REST API * Collects Items in JSON format from REST API
@ -59,16 +61,21 @@ export class ItemsModel {
* @param transform callback * @param transform callback
*/ */
private sendRequest(uri: string, transform): Thenable<Item[]> { private sendRequest(uri: string, transform): Thenable<Item[]> {
let options = { let config: AxiosRequestConfig = {
uri: uri || utils.getHost() + '/rest/items', url: uri || utils.getHost() + '/rest/items',
json: true, headers: {}
encoding: 'utf8' }
if(ConfigManager.tokenAuthAvailable()){
config.headers = {
'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken)
}
} }
return new Promise((resolve, _reject) => { return new Promise((resolve, _reject) => {
request(options) axios(config)
.then(function (response: Item[] | Item) { .then(function (response) {
resolve(transform(response)) resolve(transform(response.data as Item[] | Item))
}.bind(this)) }.bind(this))
.catch(err => { .catch(err => {
utils.appendToOutput(`Could not reload items for Items Explorer`) utils.appendToOutput(`Could not reload items for Items Explorer`)

View File

@ -7,7 +7,9 @@ import {
LanguageClient, LanguageClient,
LanguageClientOptions, LanguageClientOptions,
TransportKind, TransportKind,
ServerOptions ServerOptions,
ErrorAction,
CloseAction
} from 'vscode-languageclient' } from 'vscode-languageclient'
import * as path from 'path' import * as path from 'path'
@ -46,10 +48,16 @@ export class LocalLanguageClientProvider {
configurationSection: "openhab", configurationSection: "openhab",
fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), fileEvents: workspace.createFileSystemWatcher("**/.clientrc"),
}, },
// Disable the default error handler
errorHandler: {
error: () => ErrorAction.Continue,
closed: () => CloseAction.DoNotRestart
}
} }
// Create the language client and start the client. // Create the language client and start the client.
const lc = new LanguageClient("openhabLanguageServer", "Openhab Language Server", serverOptions, clientOptions) const lc = new LanguageClient("openhabLanguageServer", "Openhab Language Server", serverOptions, clientOptions)
return lc.start() return lc.start()
} }
} }

View File

@ -10,17 +10,21 @@ import {
LanguageClient, LanguageClient,
LanguageClientOptions LanguageClientOptions
} from 'vscode-languageclient' } from 'vscode-languageclient'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
import * as utils from '../Utils/Utils'
export class RemoteLanguageClientProvider { export class RemoteLanguageClientProvider {
constructor() { constructor() {
} }
public connect(): Disposable { public connect(): Disposable {
let config = workspace.getConfiguration('openhab') let hostConfig = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.host) as string
let host = config.host.includes('://') ? config.host.split('://')[1] : config.host let host = hostConfig.includes('://') ? hostConfig.split('://')[1] : hostConfig
let connectionInfo = { let connectionInfo = {
host: host, host: host,
port: config.remoteLspPort port: ConfigManager.get(OH_CONFIG_PARAMETERS.languageserver.remotePort) as number
} }
let extensions = [ let extensions = [
@ -49,7 +53,9 @@ export class RemoteLanguageClientProvider {
synchronize: { synchronize: {
configurationSection: "openhab", configurationSection: "openhab",
fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), fileEvents: workspace.createFileSystemWatcher("**/.clientrc"),
} },
outputChannelName: "openHAB Extension",
outputChannel: utils.getOutputChannel()
} }
// Create the language client and start the client. // Create the language client and start the client.

View File

@ -9,7 +9,7 @@ import * as AsciiTable from 'ascii-table'
import { Thing } from './Thing' import { Thing } from './Thing'
import { Channel } from './Channel' import { Channel } from './Channel'
import { humanize } from '../Utils' import { humanize } from '../Utils/Utils'
/** generate an Item name from a Thing label by using the configured casing */ /** generate an Item name from a Thing label by using the configured casing */
function generateItemName(label: string) : string { function generateItemName(label: string) : string {

View File

@ -1,15 +1,11 @@
import {
commands,
Uri,
window,
workspace
} from 'vscode'
import { Thing } from './Thing' import { Thing } from './Thing'
import { Channel } from './Channel' import { Channel } from './Channel'
import * as utils from '../Utils' import * as utils from '../Utils/Utils'
import * as _ from 'lodash' import * as _ from 'lodash'
import * as request from 'request-promise-native' import axios, { AxiosRequestConfig } from 'axios'
import { ConfigManager } from '../Utils/ConfigManager'
import { OH_CONFIG_PARAMETERS } from '../Utils/types'
/** /**
@ -41,16 +37,21 @@ export class ThingsModel {
} }
private sendRequest(uri: string, transform): Thenable<Thing[]> { private sendRequest(uri: string, transform): Thenable<Thing[]> {
let options = { let config: AxiosRequestConfig = {
uri: uri || utils.getHost() + '/rest/things', url: uri || utils.getHost() + '/rest/things',
json: true, headers: {}
encoding: 'utf8' }
if(ConfigManager.tokenAuthAvailable()){
config.headers = {
'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken)
}
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request(options) axios(config)
.then(function (response: Thing[] | Thing) { .then(function (response) {
resolve(this.sort(transform(response))) resolve(this.sort(transform(response.data as Thing[] | Thing)))
}.bind(this)) }.bind(this))
.catch(err => { .catch(err => {
utils.appendToOutput(`Could not reload items for Things Explorer`) utils.appendToOutput(`Could not reload items for Things Explorer`)

View File

@ -0,0 +1,265 @@
import axios, { AxiosRequestConfig } from 'axios'
import * as vscode from 'vscode'
import { OH_CONFIG_DEPRECATED, OH_CONFIG_PARAMETERS, OH_MESSAGESTRINGS } from './types'
import * as utils from './Utils'
/**
* Handles the extension configuration.
* Provides additional logic for config changes and deprecated parameters.
*
* @author Jerome Luckenbach - Initial contribution
*
*/
export class ConfigManager {
private static instance: ConfigManager|undefined
private currentConfig: vscode.WorkspaceConfiguration
private static ENCODING_MATCH: RegExp = /^(username|password)$/
private deprecationWarningShown: boolean
private static DEPRECATION_WARNING_MESSAGE = `You are using deprecated config values for the openHAB Extension!\n
Those values are still used for the moment, but will be removed in newer extension versions.\n
Please take a look at the current extension settings\nand update to the new config parameters and also remove the deprecated ones.`
/**
* Initialize the ConfigManager
*/
private constructor() {
this.deprecationWarningShown = false
this.updateConfig()
if(this.hasDeprecatedParameters()){
this.showDeprecationWarning()
}
}
/**
* Returns the ConfigManager instance and instanciates it before if not yet available
* @returns {ConfigManager} The ConfigManager instance
*/
private static getInstance(): ConfigManager {
// Create a new instance if there is none available yet
if(!ConfigManager.instance){
ConfigManager.instance = new ConfigManager()
}
return ConfigManager.instance
}
/**
* Fetch and store the latest WorkspaceConfiguration
*/
private updateConfig() {
this.currentConfig = vscode.workspace.getConfiguration('openhab')
console.log("Update Config Manager")
}
/**
* Searches and returns a config value or null
*
* @param configParameter The parameter to search for. Can be used with OH_CONFIG_PARAMETERS constant.
* @returns The config value or null
*/
public static get(configParameter: string): string|number|boolean|null {
let config = ConfigManager.getInstance().currentConfig;
// Check if current parameter is available
if(config.has(configParameter) && config.get(configParameter) !== null){
// Double check if auth token is available and valid
if (configParameter == OH_CONFIG_PARAMETERS.connection.authToken && !ConfigManager.tokenAuthAvailable())
return null
return config.get(configParameter)
}
// If no current Parameter is available, check if a deprecated parameter is available
let parameterObject = configParameter.split('.')
let parameter = parameterObject[parameterObject.length - 1]
let returnValue = null // Return null if nothing is found at all
// Use deprecated version as return value
switch (parameterObject[0]) {
case 'connection':
returnValue = this.checkAndGet(config, parameter)
break
case 'consoleCommand':
returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.consoleCommand)
break
case 'languageserver':
switch (parameter) {
case 'remoteEnabled':
returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.remoteLspEnabled)
break
case 'remotePort':
returnValue = this.checkAndGet(config, OH_CONFIG_DEPRECATED.remoteLspPort)
break
}
break
}
// Output a warning with a "Dismiss" button to prevent warning from showing too often
if(returnValue !== null){
utils.appendToOutput(`Usage of deprecated config ${parameter} detected.`)
}
return returnValue
}
/**
* Checks if ther is an authToken property available and valid
* @returns {boolean} true when tokenAuth is available and useable, false otherwise
*/
public static tokenAuthAvailable(): boolean {
let tokenResult = ConfigManager.getInstance().currentConfig.get(OH_CONFIG_PARAMETERS.connection.authToken, null)
return (!tokenResult || tokenResult === '') ? false : true
}
/**
* Checks if a parameter is available in the given config and if it has a value and returns it.
* Also encodes needed parameters directly
* @param config The workspace configuration to search in
* @param parameter The parameter to search for
* @returns The configuration value, the encoded configuration value when needed or null
*/
private static checkAndGet(config: vscode.WorkspaceConfiguration, parameter: string): string|number|boolean|null {
if(config.has(parameter) && config.get(parameter) !== null){
// Encode basic auth credentials
if(parameter.match(ConfigManager.ENCODING_MATCH))
return encodeURIComponent(config.get(parameter))
return config.get(parameter)
}
return null
}
/**
* Updates an openHAB specific config parameter.
*/
public static update(configParameter: string, value: any, target?: vscode.ConfigurationTarget) {
let config = vscode.workspace.getConfiguration('openhab')
if(config.has(configParameter)) {
if(target == undefined) {
config.update(configParameter, value)
}
else {
config.update(configParameter, value, target)
}
ConfigManager.getInstance().updateConfig()
}
}
/**
* Watches for configuration changes and updates or reacts to openHAB config related changes.
*
* @param context The extension context
*/
public static attachConfigChangeWatcher(context){
let instance = ConfigManager.getInstance()
// Subscribe to all configuration changed events
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
if(e.affectsConfiguration('openhab')){
instance.updateConfig()
}
// Check for api token changes and check if a valid apitoken has been set.
// Output an error ortherwise
if(e.affectsConfiguration('openhab.connection.authToken') ){
console.debug(`Auth token config has been changed. Validating token now.`)
const token = instance.currentConfig.get(OH_CONFIG_PARAMETERS.connection.authToken, null)
let config: AxiosRequestConfig = {
url: utils.getHost() + '/rest/auth/apitokens',
headers: {
'X-OPENHAB-TOKEN': `${token}`
}
}
axios(config)
.then((_response) => {
utils.appendToOutput(`Newly configured auth token validated successfully!`)
})
.catch((error) => {
if(error.response.status === 401){
console.error(`Could not validate configured auth token.`, error)
utils.appendToOutput(`Could not validate configured auth token.`)
ConfigManager.getInstance().handleConfigError(error, `Could not validate configured auth token.`)
}
else {
utils.handleRequestError(error)
}
})
}
// Refresh treeviews when a openHAB connection related setting has changed
if(e.affectsConfiguration('openhab.connection') ){
console.debug("openHAB Extension configuration has changed.")
vscode.commands.executeCommand('openhab.command.refreshEntry');
}
}))
}
/**
* Generate an error message and provide some options for solving the error
*
* @param err The current error
* @param message The specific error message
* @param baseMessage The base message available for overwriting the title
*/
private async handleConfigError(err, message: string = OH_MESSAGESTRINGS.moreInfo, baseMessage: string = OH_MESSAGESTRINGS.errors.configValidation) {
// Show error message with action buttons
const showOutput = 'Show Output'
const result = await vscode.window.showErrorMessage(`${baseMessage}\n\n${message}`, showOutput)
// Action based on user input
if(result == showOutput)
utils.getOutputChannel().show()
}
/**
* Check the current config for deprecated and used parameters
* @returns An array of deprecated parameter strings or a boolean
*/
private hasDeprecatedParameters() : string[]|boolean {
let currentConfig = this.currentConfig
let deprecatedParameters : string[] = []
// Append the parameter, if it exists and at least one config value scope has been set manually
for(const parameter in OH_CONFIG_DEPRECATED){
if(currentConfig.has(parameter)){
let inspectresult = currentConfig.inspect(parameter)
if(inspectresult.globalValue != undefined || inspectresult.workspaceValue != undefined){
deprecatedParameters.push(parameter)
}
}
}
return (deprecatedParameters.length != 0) ? deprecatedParameters : false;
}
/**
* Show a warning message, when deprecated config values are used
*/
private async showDeprecationWarning() {
if(!this.deprecationWarningShown){
this.deprecationWarningShown = true
// const migrateStandardValues = 'Migrate minimal config directly!'
// let result = await vscode.window.showWarningMessage(ConfigManager.DEPRECATION_WARNING_MESSAGE, { modal: true }, migrateStandardValues)
vscode.window.showWarningMessage(ConfigManager.DEPRECATION_WARNING_MESSAGE)
// // Action based on user input
// if(result == migrateStandardValues)
// ConfigManager.migrateDeprecatedParameters()
}
}
}

View File

@ -1,20 +1,16 @@
import { import * as vscode from 'vscode'
commands,
Uri,
window,
workspace,
} from 'vscode'
import {PreviewPanel} from './WebView/PreviewPanel'
import * as _ from 'lodash'
import * as request from 'request-promise-native'
import { OutputChannel } from 'vscode' import { OutputChannel } from 'vscode'
import * as _ from 'lodash'
import axios, { AxiosRequestConfig } from 'axios'
import {PreviewPanel} from '../WebView/PreviewPanel'
import { ConfigManager } from './ConfigManager'
import { OH_CONFIG_PARAMETERS, OH_MESSAGESTRINGS } from './types'
/** /**
* Create output channel as user display for relevant informations * Create output channel as user display for relevant informations
*/ */
let extensionOutput: OutputChannel = null let extensionOutput: OutputChannel = null
let warningShownAlready: boolean = false
/** /**
* Humanize function adapter from the previously included underscore.string library * Humanize function adapter from the previously included underscore.string library
@ -43,12 +39,8 @@ export function humanize(str: string) : string {
* Return value may vary depending on the user configuration (e.g. Authentication settings) * Return value may vary depending on the user configuration (e.g. Authentication settings)
*/ */
export function getHost() { export function getHost() {
let config = workspace.getConfiguration('openhab') let host = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.host) as string
let host = config.host let port = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.port) as number
let port = config.port
let username = encodeURIComponent(config.username)
let password = encodeURIComponent(config.password)
let protocol = 'http' let protocol = 'http'
if (host.includes('://')) { if (host.includes('://')) {
@ -57,23 +49,36 @@ export function getHost() {
protocol = split[0] protocol = split[0]
} }
let authentication = (username || '') + (password ? ':' + password : '') let generatedHost = protocol + '://'
authentication += authentication ? '@' : ''
return protocol + '://' + authentication + host + (port === 80 ? '' : ':' + port) // Prefer token auth over basic auth, if available
if(!ConfigManager.tokenAuthAvailable()){
let username = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.basicAuth.username) as string|null
// Also make sure that there is at least a username given
if(username != null && username != ''){
let password = ConfigManager.get(OH_CONFIG_PARAMETERS.connection.basicAuth.password) as string|null
// Check if given username is a openHAB 3 token
let usernameSegments = username.split('.')
if(usernameSegments.length === 3 && usernameSegments[0] === 'oh'){
const warningString = `Detected openHAB 3 token as username.\nConsider using the recommended **openhab.connection.authToken** config parameter instead.\n\n`
appendToOutput(warningString)
if(!warningShownAlready){
vscode.window.showWarningMessage(warningString)
warningShownAlready = true
}
} }
/** let basicAuth = (username ? username : '') + (password ? ':' + password : '') + '@'
* Returns the current simple mode status retreived via rest api generatedHost += basicAuth
*/ }
export function getSimpleModeState(): Thenable<Boolean> {
return new Promise((resolve, reject) => { }
request(getHost() + '/rest/services/org.eclipse.smarthome.links/config')
.then((response) => { generatedHost += host + (port === 80 ? '' : ':' + port)
let responseJson = JSON.parse(response);
resolve(responseJson.autoLinks) return generatedHost
}).catch(() => reject([]))
})
} }
/** /**
@ -81,22 +86,32 @@ export function getSimpleModeState(): Thenable<Boolean> {
*/ */
export function getSitemaps(): Thenable<any[]> { export function getSitemaps(): Thenable<any[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request(getHost() + '/rest/sitemaps') let config: AxiosRequestConfig = {
url: getHost() + '/rest/sitemaps',
headers: {}
}
if(ConfigManager.tokenAuthAvailable()){
config.headers = {
'X-OPENHAB-TOKEN': ConfigManager.get(OH_CONFIG_PARAMETERS.connection.authToken)
}
}
axios(config)
.then((response) => { .then((response) => {
resolve(JSON.parse(response)) resolve(response.data)
}).catch(() => reject([])) }).catch(() => reject([]))
}) })
} }
/** /**
* Opens an external browser with the given url. * Opens an external browser with the given url.
*
* @param url The url to navigate to * @param url The url to navigate to
*/ */
export function openBrowser(url) { export function openBrowser(url) {
let editor = window.activeTextEditor let editor = vscode.window.activeTextEditor
if (!editor) { if (!editor) {
window.showInformationMessage('No editor is active') vscode.window.showInformationMessage('No editor is active')
return return
} }
@ -104,12 +119,11 @@ export function openBrowser(url) {
let text = editor.document.getText(selection) let text = editor.document.getText(selection)
url = url.startsWith('http') ? url : getHost() + url url = url.startsWith('http') ? url : getHost() + url
url = url.replace('%s', text.replace(' ', '%20')) url = url.replace('%s', text.replace(' ', '%20'))
return commands.executeCommand('vscode.open', Uri.parse(url)) return vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(url))
} }
/** /**
* Opens a vscode Webview panel aside, with the given data. * Opens a vscode Webview panel aside, with the given data.
*
* @param extensionPath The path of this extension * @param extensionPath The path of this extension
* @param query The query to append. Defaults to the basic ui node. * @param query The query to append. Defaults to the basic ui node.
* @param title The title, that will be shown for the UI tab. * @param title The title, that will be shown for the UI tab.
@ -127,34 +141,25 @@ export function openUI(extensionPath: string, query: string = "/basicui/app", ti
/** /**
* Handle a occuring request error. * Handle a occuring request error.
*
* @param err The current error * @param err The current error
*/ */
export async function handleRequestError(err) { export async function handleRequestError(err) {
let config = workspace.getConfiguration('openhab')
const setHost = 'Set openHAB host'
const disableRest = 'Disable REST API' const disableRest = 'Disable REST API'
const showOutput = 'Show Output' const showOutput = 'Show Output'
// Show error message with action buttons // Show error message with action buttons
const baseMessage = `Error while connecting to openHAB REST API.` const baseMessage = `Error while connecting to openHAB REST API.`
const message = typeof err.error === 'string' ? err.error : err.error.message const message = typeof err.isAxiosError === 'string' ? err.message : err.toString()
const result = await window.showErrorMessage(`${baseMessage}\nMore information may be found int the openHAB Extension output!`, setHost, disableRest, showOutput) const result = await vscode.window.showErrorMessage(`${baseMessage}\n${OH_MESSAGESTRINGS.moreInfo}`, disableRest, showOutput)
// Action based on user input // Action based on user input
switch (result) { switch (result) {
case setHost: case disableRest:
commands.executeCommand('workbench.action.openWorkspaceSettings') ConfigManager.update(OH_CONFIG_PARAMETERS.useRestApi, false)
break break
case showOutput: case showOutput:
extensionOutput.show() extensionOutput.show()
break break
case disableRest:
config.update('useRestApi', false)
break
default:
break
} }
appendToOutput(`--- appendToOutput(`---
@ -169,19 +174,23 @@ export async function handleRequestError(err) {
/** /**
* This will send a message from the extension to its output channel. * This will send a message from the extension to its output channel.
* If the channel isn't existing already, it will be created during method run. * If the channel isn't existing already, it will be created during method run.
*
* @param message The message to append to the extensions output Channel * @param message The message to append to the extensions output Channel
*/ */
export function appendToOutput(message: string){ export function appendToOutput(message: string){
getOutputChannel().appendLine(message)
}
if(!extensionOutput) { extensionOutput = window.createOutputChannel("openHAB Extension") } /**
* Gets the extensions output channel for referencing
extensionOutput.appendLine(message) * @returns The extensions output channel
*/
export function getOutputChannel(): OutputChannel {
if(!extensionOutput) { extensionOutput = vscode.window.createOutputChannel("openHAB Extension") }
return extensionOutput
} }
/** /**
* Sleep for some time * Sleep for some time
*
* @param sleepTime wanted time in milliseconds * @param sleepTime wanted time in milliseconds
*/ */
export async function sleep(sleepTime: number){ export async function sleep(sleepTime: number){

36
client/src/Utils/types.ts Normal file
View File

@ -0,0 +1,36 @@
export const OH_CONFIG_PARAMETERS = {
connection : {
host : 'connection.host',
port : 'connection.port',
authToken : 'connection.authToken',
basicAuth : {
username : 'connection.basicAuth.username',
password : 'connection.basicAuth.password',
}
},
languageserver : {
remoteEnabled : 'languageserver.remoteEnabled',
remotePort : 'languageserver.remotePort',
},
itemCasing : 'itemCasing',
consoleCommand : 'consoleCommand',
useRestApi : 'useRestApi',
}
export const OH_CONFIG_DEPRECATED = {
host : 'host',
port : 'port',
username : 'username',
password : 'password',
remoteLspEnabled : 'remoteLspEnabled',
remoteLspPort : 'remoteLspPort',
consoleCommand : 'karafCommand',
sitemapPreview : 'sitemapPreviewUI',
}
export const OH_MESSAGESTRINGS = {
moreInfo : `More information may be found int the openHAB Extension output!`,
errors : {
configValidation : `Error during config validation`,
},
}

View File

@ -1,6 +1,6 @@
import * as path from 'path' import * as path from 'path'
import * as vscode from 'vscode' import * as vscode from 'vscode'
import { appendToOutput } from "../Utils" import { appendToOutput } from "../Utils/Utils"
/** /**
* Manages the extension WebView panel * Manages the extension WebView panel
* *

View File

@ -1,18 +1,7 @@
'use strict' 'use strict'
import { import * as vscode from 'vscode'
commands, import * as utils from './Utils/Utils'
Disposable,
extensions,
ExtensionContext,
languages,
window,
workspace,
StatusBarItem,
StatusBarAlignment
} from 'vscode'
import * as utils from './Utils'
import { ItemsExplorer } from './ItemsExplorer/ItemsExplorer' import { ItemsExplorer } from './ItemsExplorer/ItemsExplorer'
import { ThingsExplorer } from './ThingsExplorer/ThingsExplorer' import { ThingsExplorer } from './ThingsExplorer/ThingsExplorer'
@ -31,9 +20,11 @@ import * as _ from 'lodash'
import * as ncp from 'copy-paste' import * as ncp from 'copy-paste'
import * as path from 'path' import * as path from 'path'
import * as fs from 'fs' import * as fs from 'fs'
import axios, { AxiosRequestConfig } from 'axios'
import { ConfigManager } from './Utils/ConfigManager'
let _extensionPath: string let _extensionPath: string
let ohStatusBarItem: StatusBarItem let ohStatusBarItem: vscode.StatusBarItem
/** /**
* Initializes the openHAB extension * Initializes the openHAB extension
@ -43,20 +34,15 @@ let ohStatusBarItem: StatusBarItem
* @param config The extension configuration * @param config The extension configuration
* @param context The extension context * @param context The extension context
*/ */
async function init(disposables: Disposable[], config, context): Promise<void> { async function init(disposables: vscode.Disposable[], config, context): Promise<void> {
context.subscriptions.push(workspace.onDidChangeConfiguration(e => { // Handle configuration changes
ConfigManager.attachConfigChangeWatcher(context)
// Refresh treeviews when a connection related setting gets changed disposables.push(vscode.commands.registerCommand('openhab.basicUI', () => {
if(e.affectsConfiguration('openhab.host') || e.affectsConfiguration('openhab.password') || e.affectsConfiguration('openhab.port') || e.affectsConfiguration('openhab.username') ){ let editor = vscode.window.activeTextEditor
commands.executeCommand('openhab.command.refreshEntry');
}
}))
disposables.push(commands.registerCommand('openhab.basicUI', () => {
let editor = window.activeTextEditor
if (!editor) { if (!editor) {
window.showInformationMessage('No editor is active') vscode.window.showInformationMessage('No editor is active')
return return
} }
@ -102,19 +88,19 @@ async function init(disposables: Disposable[], config, context): Promise<void> {
})) }))
disposables.push(commands.registerCommand('openhab.searchCommunity', (phrase?) => { disposables.push(vscode.commands.registerCommand('openhab.searchCommunity', (phrase?) => {
let query: string = phrase || '%s' let query: string = phrase || '%s'
utils.openBrowser(`https://community.openhab.org/search?q=${query}`) utils.openBrowser(`https://community.openhab.org/search?q=${query}`)
})) }))
disposables.push(commands.registerCommand('openhab.openConsole', () => { disposables.push(vscode.commands.registerCommand('openhab.openConsole', () => {
let command = config.karafCommand.replace(/%openhabhost%/g, config.host) let command = config.consoleCommand.replace(/%openhabhost%/g, config.connection.host)
const terminal = window.createTerminal('openHAB') const terminal = vscode.window.createTerminal('openHAB')
terminal.sendText(command, true) terminal.sendText(command, true)
terminal.show(false) terminal.show(false)
})) }))
disposables.push(commands.registerCommand('openhab.command.things.docs', (query: Thing) => disposables.push(vscode.commands.registerCommand('openhab.command.things.docs', (query: Thing) =>
utils.openBrowser(`https://www.openhab.org/addons/bindings/${query.binding}/`))) utils.openBrowser(`https://www.openhab.org/addons/bindings/${query.binding}/`)))
if (config.useRestApi) { if (config.useRestApi) {
@ -123,39 +109,39 @@ async function init(disposables: Disposable[], config, context): Promise<void> {
const itemsCompletion = new ItemsCompletion() const itemsCompletion = new ItemsCompletion()
const ohHoverProvider = new HoverProvider() const ohHoverProvider = new HoverProvider()
disposables.push(window.registerTreeDataProvider('openhabItems', itemsExplorer)) disposables.push(vscode.window.registerTreeDataProvider('openhabItems', itemsExplorer))
disposables.push(window.registerTreeDataProvider('openhabThings', thingsExplorer)) disposables.push(vscode.window.registerTreeDataProvider('openhabThings', thingsExplorer))
disposables.push(commands.registerCommand('openhab.command.refreshEntry', () => { disposables.push(vscode.commands.registerCommand('openhab.command.refreshEntry', () => {
itemsExplorer.refresh() itemsExplorer.refresh()
thingsExplorer.refresh() thingsExplorer.refresh()
})) }))
disposables.push(commands.registerCommand('openhab.command.copyName', (query) => disposables.push(vscode.commands.registerCommand('openhab.command.copyName', (query) =>
ncp.copy(query.name || query.label))) ncp.copy(query.name || query.label)))
disposables.push(commands.registerCommand('openhab.command.items.copyState', (query: Item) => disposables.push(vscode.commands.registerCommand('openhab.command.items.copyState', (query: Item) =>
ncp.copy(query.state))) ncp.copy(query.state)))
disposables.push(commands.registerCommand('openhab.command.items.addRule', (query: Item) => { disposables.push(vscode.commands.registerCommand('openhab.command.items.addRule', (query: Item) => {
const ruleProvider = new RuleProvider(query) const ruleProvider = new RuleProvider(query)
ruleProvider.addRule() ruleProvider.addRule()
})) }))
disposables.push(commands.registerCommand('openhab.command.items.addToSitemap', (query: Item) => { disposables.push(vscode.commands.registerCommand('openhab.command.items.addToSitemap', (query: Item) => {
const sitemapProvider = new SitemapPartialProvider(query) const sitemapProvider = new SitemapPartialProvider(query)
sitemapProvider.addToSitemap() sitemapProvider.addToSitemap()
})) }))
disposables.push(commands.registerCommand('openhab.command.things.addItems', (query: Thing | Channel) => { disposables.push(vscode.commands.registerCommand('openhab.command.things.addItems', (query: Thing | Channel) => {
const itemsProvider = new ItemsProvider(query) const itemsProvider = new ItemsProvider(query)
itemsProvider.addToItems() itemsProvider.addToItems()
})) }))
disposables.push(commands.registerCommand('openhab.command.things.copyUID', (query) => disposables.push(vscode.commands.registerCommand('openhab.command.things.copyUID', (query) =>
ncp.copy(query.UID || query.uid))) ncp.copy(query.UID || query.uid)))
disposables.push(languages.registerHoverProvider({ language: 'openhab', scheme: 'file'}, { disposables.push(vscode.languages.registerHoverProvider({ language: 'openhab', scheme: 'file'}, {
provideHover(document, position, token){ provideHover(document, position, token){
@ -181,7 +167,7 @@ async function init(disposables: Disposable[], config, context): Promise<void> {
) )
// Listen for document save events, to update the cached items // Listen for document save events, to update the cached items
workspace.onDidSaveTextDocument((savedDocument) => { vscode.workspace.onDidSaveTextDocument((savedDocument) => {
let fileEnding = savedDocument.fileName.split(".").slice(-1)[0] let fileEnding = savedDocument.fileName.split(".").slice(-1)[0]
if(fileEnding === "items"){ if(fileEnding === "items"){
@ -195,7 +181,7 @@ async function init(disposables: Disposable[], config, context): Promise<void> {
}) })
} }
if (config.remoteLspEnabled) { if (config.languageserver.remoteEnabled) {
const remoteLanguageClientProvider = new RemoteLanguageClientProvider() const remoteLanguageClientProvider = new RemoteLanguageClientProvider()
disposables.push(remoteLanguageClientProvider.connect()) disposables.push(remoteLanguageClientProvider.connect())
} }
@ -203,18 +189,18 @@ async function init(disposables: Disposable[], config, context): Promise<void> {
const localLanguageClientProvider = new LocalLanguageClientProvider() const localLanguageClientProvider = new LocalLanguageClientProvider()
disposables.push(localLanguageClientProvider.connect(context)) disposables.push(localLanguageClientProvider.connect(context))
ohStatusBarItem = window.createStatusBarItem(StatusBarAlignment.Right, 20) ohStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 20)
ohStatusBarItem.text = `$(home) openHAB` ohStatusBarItem.text = `$(home) openHAB`
ohStatusBarItem.tooltip = `openHAB extension is active currently.` ohStatusBarItem.tooltip = `openHAB extension is active currently.`
ohStatusBarItem.show() ohStatusBarItem.show()
} }
// This method is called when the extension is activated // This method is called when the extension is activated
export function activate(context: ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
// Keep the stable extension deactivated, when beta version is installed // Keep the stable extension deactivated, when beta version is installed
let thisExtension = JSON.parse(fs.readFileSync(path.join(context.extensionPath, "package.json"), 'utf8')).name let thisExtension = JSON.parse(fs.readFileSync(path.join(context.extensionPath, "package.json"), 'utf8')).name
let betaExtension = extensions.getExtension('openhab.openhab-beta') let betaExtension = vscode.extensions.getExtension('openhab.openhab-beta')
// When beta is available and we are not beta itself, this extension should not get activated // When beta is available and we are not beta itself, this extension should not get activated
if(betaExtension !== undefined && thisExtension !== "openhab-beta"){ if(betaExtension !== undefined && thisExtension !== "openhab-beta"){
@ -223,12 +209,12 @@ export function activate(context: ExtensionContext) {
} }
// Prepare disposables array, context and config // Prepare disposables array, context and config
const disposables: Disposable[] = [] const disposables: vscode.Disposable[] = []
_extensionPath = context.extensionPath _extensionPath = context.extensionPath
let config = workspace.getConfiguration('openhab') let config = vscode.workspace.getConfiguration('openhab')
// Spread in the disposables array to the subscription (This will include all disposables from the init method) // Spread in the disposables array to the subscription (This will include all disposables from the init method)
context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose())) context.subscriptions.push(new vscode.Disposable(() => vscode.Disposable.from(...disposables).dispose()))
init(disposables, config, context) init(disposables, config, context)
.catch(err => console.error(err)) .catch(err => console.error(err))

View File

@ -9,10 +9,10 @@ description: "The openHAB vscode extension provides useful features for configur
You are able to configure the hostname and port for the Sitemap preview. You are able to configure the hostname and port for the Sitemap preview.
- `openhab.host` (mandatory), default: openhabianpi - `openhab.connection.host` (mandatory), default: openhabianpi
- `openhab.port` (optional), default: 8080 - `openhab.connection.port` (optional), default: 8080
*openhab.host* will also work with the IP address of your openHAB instance, instead of the hostname. *openhab.connection.host* will also work with the IP address of your openHAB instance, instead of the hostname.
These settings should work fine on Windows machines and openHAB installations using the recommended [openHABian](https://www.openhab.org/docs/installation/openhabian.html) setup. These settings should work fine on Windows machines and openHAB installations using the recommended [openHABian](https://www.openhab.org/docs/installation/openhabian.html) setup.
They should be edited if you use macOS or &ast;NIX systems or manual openHAB installations. They should be edited if you use macOS or &ast;NIX systems or manual openHAB installations.
@ -25,8 +25,8 @@ For further informations on how to change your settings, visit the official [Vis
```json ```json
{ {
"openhab.host": "localhost", "openhab.connection.host": "localhost",
"openhab.port": 80 "openhab.connection.port": 80
} }
``` ```
@ -34,8 +34,8 @@ For further informations on how to change your settings, visit the official [Vis
```json ```json
{ {
"openhab.host": "openhabianpi.local", "openhab.connection.host": "openhabianpi.local",
"openhab.port": 8080 "openhab.connection.port": 8080
} }
``` ```
@ -60,8 +60,8 @@ You may need to reload the VSCode window to take effect.
Since openHAB 3 (with its on default activated api authentication) has been released you have to fulllfil some additional steps to get a working connection. Since openHAB 3 (with its on default activated api authentication) has been released you have to fulllfil some additional steps to get a working connection.
1. Generate an api token for your user 1. Generate an api token for your user
2. Add the generated token as `openhab.username` configuration 2. Add the generated token as `openhab.connection.basicAuth.username` configuration
3. Leave `openhab.password` empty 3. Leave `openhab.connection.basicAuth.password` empty
4. Reload vscode window 4. Reload vscode window
### openHAB REST API and SSL Certificates ### openHAB REST API and SSL Certificates
@ -119,7 +119,7 @@ In the unlikely case that your language server is running on a port other than t
```json ```json
{ {
"openhab.remoteLspPort": 5007 "openhab.languageserver.remotePort": 5007
} }
``` ```
@ -127,7 +127,7 @@ If you don't want to have your openHAB files validated by Language Server, simpl
```json ```json
{ {
"openhab.remoteLspEnabled": false "openhab.languageserver.remoteEnabled": false
} }
``` ```
@ -140,11 +140,11 @@ Note that LSP (content assist for rules and syntax validation) won't be exposed,
The following configuration will allow you to access REST API remotely: The following configuration will allow you to access REST API remotely:
```json ```json
"openhab.host": "https://home.myopenhab.org", "openhab.connection.host": "https://home.myopenhab.org",
"openhab.port": 80, "openhab.connection.port": 80,
"openhab.remoteLspEnabled": false, "openhab.languageserver.remoteEnabled": false,
"openhab.username": "your_myopenhab_email", "openhab.connection.basicAuth.username": "your_myopenhab_email",
"openhab.password": "your_myopenhab_password", "openhab.connection.basicAuth.password": "your_myopenhab_password",
``` ```
## Sitemap preview with Basic UI ## Sitemap preview with Basic UI
@ -170,10 +170,10 @@ Note that you need to have:
- `ssh` installed on your environment - `ssh` installed on your environment
- Console exposed to the external interface - Console exposed to the external interface
- `openhab.host` configuration parameter set properly - `openhab.connection.host` configuration parameter set properly
This feature allows you to modify the new param and e.g. show the openHAB logs immediately: This feature allows you to modify the new param and e.g. show the openHAB logs immediately:
```bash ```bash
"openhab.karafCommand": "ssh openhab@%openhabhost% -p 8101 -t 'log:tail'", "openhab.consoleCommand": "ssh openhab@%openhabhost% -p 8101 -t 'log:tail'",
``` ```

View File

@ -2,7 +2,7 @@
"name": "openhab", "name": "openhab",
"displayName": "openHAB", "displayName": "openHAB",
"description": "Robust tool for openHAB textual configurations. Includes code snippets, syntax highlighting, language server integration and more.", "description": "Robust tool for openHAB textual configurations. Includes code snippets, syntax highlighting, language server integration and more.",
"version": "0.8.2", "version": "1.0.0",
"publisher": "openhab", "publisher": "openhab",
"icon": "openhab.png", "icon": "openhab.png",
"repository": { "repository": {
@ -107,79 +107,105 @@
], ],
"configuration": { "configuration": {
"type": "object", "type": "object",
"title": "openHAB Configuration", "title": "openHAB",
"properties": { "properties": {
"openhab.host": { "openhab.host": {
"type": [
"string"
],
"default": "openhabianpi",
"description": "Specifies the URL or IP address for the openHAB preview. (Use 'localhost' when developing locally)"
},
"openhab.itemCasing": {
"type": "string", "type": "string",
"default": "camel", "default": "openhabianpi",
"enum": [ "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.host#` instead."
"camel",
"snake"
],
"markdownDescription": "Choose how the `Create Items from Channels` command generates Item names. Use `camel` for `CamelCase` or `snake` for `Upper_Snake_Case`."
}, },
"openhab.karafCommand": { "openhab.karafCommand": {
"type": [ "type": "string",
"string"
],
"default": "ssh openhab@%openhabhost% -p 8101", "default": "ssh openhab@%openhabhost% -p 8101",
"description": "Directly log into openHAB console. Note that this option is available only if you exposed openHAB console." "markdownDescription": "**Deprecated**: Please use `#openhab.consoleCommand#` instead."
}, },
"openhab.password": { "openhab.password": {
"type": [ "type": "string",
"string"
],
"default": "", "default": "",
"description": "(optional) Specifies the Basic Auth password for accessing the openHAB preview/REST API.\nPlease leave this parameter EMPTY when you are using an api token in openHAB 3!" "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.basicAuth.password#` instead."
}, },
"openhab.port": { "openhab.port": {
"type": [ "type": ["number", "null"],
"number",
"null"
],
"default": 8080, "default": 8080,
"description": "Specifies the port for the openHAB preview." "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.port#` instead."
},
"openhab.username": {
"type": "string",
"default": "",
"markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.connection.basicAuth.username#` instead."
}, },
"openhab.remoteLspEnabled": { "openhab.remoteLspEnabled": {
"type": [ "type": "boolean",
"boolean"
],
"default": true, "default": true,
"description": "Enables communication with Language Server of openHAB instance.\nIf you are facing connection problems make sure to connect your config folder through a dedicated network drive." "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.languageserver.remoteLspEnabled#` instead."
}, },
"openhab.remoteLspPort": { "openhab.remoteLspPort": {
"type": [ "type": ["number", "null"],
"number",
"null"
],
"default": 5007, "default": 5007,
"description": "Specifies the port where openHAB is running its Language Server." "markdownDeprecationMessage": "**Deprecated**: Please use `#openhab.languageserver.remoteLspPort#` instead."
}, },
"openhab.sitemapPreviewUI": { "openhab.sitemapPreviewUI": {
"type": [ "type": [
"string" "string"
], ],
"default": "basicui", "default": "basicui",
"description": "This parameter is deprecated and will be removed with the next major update." "markdownDeprecationMessage": "**Deprecated**: This parameter is deprecated and will be removed with one of the next updates."
},
"openhab.connection.authToken":{
"type": ["string", "null"],
"default": null,
"markdownDescription": "Specifies the **auth token**, you can generate for your openHAB 3 api access.\n\nSee [Apitoken Documentation](https://openhab.org/docs/configuration/apitokens.html) for further Information!"
},
"openhab.connection.host": {
"type": ["string", "null"],
"default": null,
"markdownDescription": "Specifies the **url** or **IP address** for your openHAB environment.\n\n(Use 'localhost' when developing locally)"
},
"openhab.connection.port": {
"type": ["number", "null"],
"default": null,
"markdownDescription": "Specifies the **port** for your openHAB environment."
},
"openhab.connection.basicAuth.password": {
"type": ["string", "null"],
"default": null,
"markdownDescription": "*OPTIONAL*:\n\nSpecifies the Basic Auth password for accessing the openHAB preview/REST API.\n\nPlease leave this parameter **empty** when you are using an api token in openHAB 3!"
},
"openhab.connection.basicAuth.username": {
"type": ["string", "null"],
"default": null,
"markdownDescription": "*OPTIONAL*:\n\nSpecifies the Basic Auth username for accessing the openHAB preview/REST API."
},
"openhab.languageserver.remoteEnabled": {
"type": "boolean",
"default": true,
"markdownDescription": "Enables communication with Language Server of openHAB instance.\n\nIf you are facing connection problems make sure to connect your config folder through a dedicated network drive."
},
"openhab.languageserver.remotePort": {
"type": ["number", "null"],
"default": 5007,
"markdownDescription": "Specifies the port where openHAB is running its Language Server."
},
"openhab.itemCasing": {
"type": "string",
"default": "camel",
"enum": ["camel", "snake"],
"markdownDescription": "Choose how the `Create Items from Channels` command generates Item names.\n\nUse `camel` for `CamelCase` or `snake` for `Upper_Snake_Case`.",
"markdownEnumDescriptions": [
"Uses the `CamelCase` naming scheme.",
"Uses the `Upper_Snake_Case` naming scheme."
]
},
"openhab.consoleCommand": {
"type": "string",
"default": "ssh openhab@%openhabhost% -p 8101",
"markdownDescription": "Directly log into openHAB console.\n\n**Note** that this option is available only if you exposed openHAB console."
}, },
"openhab.useRestApi": { "openhab.useRestApi": {
"type": "boolean", "type": "boolean",
"default": true, "default": true,
"description": "Connects to openHAB REST API if set to true. If not, Items tree view and things tree view are disabled." "markdownDescription": "Connects to *openHAB REST API* if set to **true**.\n\nIf not, items tree view and things tree view are **disabled**."
},
"openhab.username": {
"type": [
"string"
],
"default": "",
"description": "(optional) Specifies the Basic Auth username for accessing the openHAB preview/REST API.\nPlease use this parameter for the API TOken too on openHAB 3."
} }
} }
}, },
@ -352,14 +378,12 @@
"vscode:prepublish": "npm run webpack", "vscode:prepublish": "npm run webpack",
"watch": "tsc -b -w", "watch": "tsc -b -w",
"webpack": "webpack --mode production --config ./client/webpack.config.js && webpack --mode production --config ./serverJS/webpack.config.js", "webpack": "webpack --mode production --config ./client/webpack.config.js && webpack --mode production --config ./serverJS/webpack.config.js",
"webpack-dev": "webpack --mode none --config ./client/webpack.config.js && webpack --mode none --config ./serverJS/webpack.config.js" "webpack-dev": "webpack --mode development --config ./client/webpack.config.js && webpack --mode development --config ./serverJS/webpack.config.js"
}, },
"devDependencies": { "devDependencies": {
"@types/form-data": "^2.2.1", "@types/form-data": "^2.2.1",
"@types/lodash": "^4.14.167", "@types/lodash": "^4.14.167",
"@types/node": "^8.10.66", "@types/node": "^8.10.66",
"@types/request": "^2.48.5",
"@types/request-promise-native": "^1.0.15",
"@typescript-eslint/eslint-plugin": "^4.13.0", "@typescript-eslint/eslint-plugin": "^4.13.0",
"@typescript-eslint/parser": "^4.13.0", "@typescript-eslint/parser": "^4.13.0",
"eslint": "^7.18.0", "eslint": "^7.18.0",