Skip to content

Commit

Permalink
Resolved #1; #2
Browse files Browse the repository at this point in the history
  • Loading branch information
phoeluga committed Apr 6, 2022
1 parent 7c98bd3 commit 5e7dad4
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 200 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ Thumbs.db

# i18n intermediate files
admin/i18n/flat.txt
admin/i18n/*/flat.txt
admin/i18n/*/flat.txt
.DS_Store
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
],
"url": "https://json.schemastore.org/io-package"
}
],
"cSpell.words": [
"Synochat"
]
}
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ For more details on how to handle integrations within Synlogy chat, please refer
Disable this property to turn off certificate validation.

#### 2.2.2. Channel configuration:
![IobrokerInstanceSettingsChannelConfiguration](./docs/images/diIobrokerInstanceSettingsChannelConfiguration.png)
![IobrokerInstanceSettingsChannelConfiguration](./docs/images/diIobrokerInstanceSettingsChannelConfiguration02.png)

* **Channel name**

Expand All @@ -93,12 +93,17 @@ For more details on how to handle integrations within Synlogy chat, please refer
***NOTE:***\
*The channel type must be specified from the perspective of the Synology chat. For example, selecting 'Incoming' in the configuration means that the messages will be sent to the Synology chat.*

* **Validate SSL certificate for non-text messages**

In case that for an incoming channel type a content other than a text, for example an image, is to be sent, this is specified from an HTTP source via a URL. If this content is provided with a self-signed certificate, the certificate check can be enabled or disabled with this setting.
For details on sending non-text content, see chapter [Synology chat configuration](#synology-chat-configuration)..

#### 2.2.3. Help:
* This tab usually redirects to the official GitHub page of this project, where detailed help and usage instructions are given.
* If there are any open questions, suggestions for changes, unwanted behavior or bugs, please create a [GitHub issue](https://github.com/phoeluga/ioBroker.synochat/issues/new/choose) to ensure the quality of this project.

## 3. Usage

### 3.1 General
* After the adapter is instantiated, a respective folder is created in the objects of the respective adapter instance for the Synology chat channel specified in the instance configuration.
![IobrokerObjectOverview](./docs/images/diIobrokerObjectOverview.png)

Expand All @@ -113,6 +118,15 @@ For more details on how to handle integrations within Synlogy chat, please refer
* When the message object is changed, this message - depending on the channel type - is passed to the Synology chat in the channel published.
![SynoChatChannelIncomingMessage](./docs/images/diSynoChatChannelIncomingMessage.png)

### 3.2 Message content type

Besides sending plain text messages, other content types such as images can also be sent to an incoming channel.\
To realize this, the content must be available as a web resource. To send an image, just set the URL as the value of the the message object of the Syno-Chat adapter instance mentioned in [3. Usage > 3.1 General](#3.1-general).

**Example of a use case of a surveillance camera:**\
Many surveillance cameras provide a stream or interface to retrieve an image that is updated at a specified time interval or when motion is detected.\
This URL provides image that needs to be set as the value of the the message object.

---

## Changelog
Expand Down
22 changes: 20 additions & 2 deletions admin/index_m.html
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,29 @@
</div>
</div>
<div id="channelConfigDialog" class="dialog">
<div class="card">
<div class="card-content">
<div class="row">
<div class="col s12">
<h6>
<span class="translate">
<strong>NOTE:</strong>
<br>
<em>The channel type must be specified from the perspective of the Synology chat. For example, selecting 'Incoming' in the configuration means that the messages will be sent to the Synology chat.</em>
</span>
</h6>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-content">
<div class="row">
<div class="input-field col s6 l2">
<input class="value" id="channelName" type="text" />
<label class="translate" for="channelName">Channel name</label>
</div>
<div class="input-field col s12 l6">
<div class="input-field col s12 l4">
<input class="value" id="channelToken" type="text" />
<label class="translate" for="channelToken">Channel token</label>
</div>
Expand All @@ -172,7 +187,10 @@
</select>
<label class="translate" for="channelType">Channel type</label>
</div>

<div class="input-field col s6 l2">
<input class="value" id="channelContentCertCheck" type="checkbox" />
<label class="translate" for="channelContentCertCheck">Validate SSL certificate for non-text messages</label>
</div>
</div>
</div>
</div>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 24 additions & 23 deletions io-package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"common": {
"name": "synochat",
"version": "1.0.0",
"version": "1.0.1",
"news": {
"1.0.0": {
"en": "initial release",
"de": "Erstveröffentlichung",
"ru": "Начальная версия",
"pt": "lançamento inicial",
"nl": "Eerste uitgave",
"fr": "Première version",
"it": "Versione iniziale",
"es": "Versión inicial",
"pl": "Pierwsze wydanie",
"zh-cn": "首次出版"
}
"en": "Bug fixes; Content consideration",
"de": "Fehlerbehebung; Inhaltliche Betrachtung",
"ru": "Исправление ошибок; Рассмотрение содержания",
"pt": "Correções de bugs; Consideração de conteúdo",
"nl": "Bugfixes; Inhoudelijke overweging",
"fr": "Corrections de bogues ; Considération du contenu",
"it": "Correzioni di bug; Considerazione sui contenuti",
"es": "Corrección de errores; Consideración del contenido",
"pl": "poprawki błędów; Rozważanie treści",
"zh-cn": "Bug修复;内容考虑"
}
},
"title": "Synology-Chat",
"titleLang": {
Expand All @@ -30,16 +30,16 @@
"zh-cn": "Synology-聊天"
},
"desc": {
"en": "This adapter provides an interface between Synology-Chat and ioBroker.",
"de": "Dieser Adapter bietet Zugriff auf eingehende und ausgehende Synology-Chat-Kanäle",
"ru": "Этот адаптер обеспечивает доступ к входящим и исходящим каналам Synology-Chat.",
"pt": "Este adaptador fornece acesso aos canais Synology-Chat de entrada e saída",
"nl": "Deze adapter biedt toegang tot inkomende en uitgaande Synology-Chat-kanalen",
"fr": "Cet adaptateur permet d'accéder aux canaux Synology-Chat entrants et sortants",
"it": "Questo adattatore fornisce l'accesso ai canali Synology-Chat in entrata e in uscita",
"es": "Este adaptador proporciona acceso a los canales Synology-Chat entrantes y salientes",
"pl": "Ten adapter zapewnia dostęp do przychodzących i wychodzących kanałów Synology-Chat",
"zh-cn": "此适配器提供对传入和传出 Synology-Chat 频道的访问"
"en": "This adapter provides an interface of Synology Chat and ioBroker.",
"de": "Dieser Adapter bietet eine Schnittstelle von Synology Chat und ioBroker.",
"ru": "Этот адаптер обеспечивает интерфейс Synology Chat и ioBroker.",
"pt": "Este adaptador fornece uma interface de Synology Chat e ioBroker.",
"nl": "Deze adapter biedt een interface van Synology Chat en ioBroker.",
"fr": "Cet adaptateur fournit une interface de Synology Chat et ioBroker.",
"it": "Questo adattatore fornisce un'interfaccia di Synology Chat e ioBroker.",
"es": "Este adaptador proporciona una interfaz de Synology Chat e ioBroker.",
"pl": "Ten adapter zapewnia interfejs Synology Chat i ioBroker.",
"zh-cn": "此适配器提供 Synology Chat 和 ioBroker 的接口。"
},
"authors": [
"phoeluga <phoeluga@gmail.com>"
Expand Down Expand Up @@ -77,7 +77,8 @@
"certCheck": true,
"channelName": "",
"channelToken": "",
"channelType": ""
"channelType": "",
"channelContentCertCheck": true
},
"objects": [],
"instanceObjects": [
Expand Down
124 changes: 124 additions & 0 deletions lib/synoChatRequestHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
const https = require('https');
const axios = require('axios');

function prepareTextForSendingMessage(adapterInstance, message){
if(message.includes('"') || message.includes('&') || message.includes('%') || message.includes('\\')){
message = message.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/%/g, '%25').replace(/&/g, '%26')
adapterInstance.log.debug(`Special characters were detected in the text to be sent. > New message "${message}"`);
};
return message;
}

function isValidHttpUrl(adapterInstance, string) {
let url;

try {
url = new URL(string);
} catch (err) {
//adapterInstance.log.debug(`Message is not an URL: "${err}"`);
return false;
}

return url.protocol === "http:" || url.protocol === "https:";
}


// Deprecated functions for handling Synology-Chat requests

async function sendBaseRequest(adapterInstance, synoChatEndpointUrl, certCheck, requestProperties){
if(certCheck){
var request = axios.create();
} else {
var request = axios.create({
httpsAgent: new https.Agent({
rejectUnauthorized: false
}),
timeout: 10000
});
}

var requestResponse = null;
await request(requestProperties)
.then(res => {
if(res.status == 200){
adapterInstance.log.debug(`${synoChatEndpointUrl}: ${res.status} ${res.statusText}`);
requestResponse = res;
} else {
adapterInstance.log.error(`Unable to get valid response from Synology Chat REST API ${synoChatEndpointUrl} > ${JSON.stringify(res.statusText)} ${JSON.stringify(res.status)}\n'${JSON.stringify(res.data)}'`);
}
});

return requestResponse;
}

async function initialConnectivityCheck(adapterInstance, synoBaseUrl, certCheck){
adapterInstance.log.info(`Checking general availability of the Synology Chat REST API...`);

var synoChatEndpointUrl = synoBaseUrl + "/webapi/entry.cgi";
adapterInstance.log.debug(`Preparing REST API call for endpoint '${synoChatEndpointUrl}'...`);

var requestProperties = {
method: 'get',
url: synoChatEndpointUrl,
params: {
'api': "SYNO.Chat.External",
'method': "kuchen",
'version': "2"
}
}

try {
var response = await sendBaseRequest(adapterInstance, synoChatEndpointUrl, certCheck, requestProperties);
if(JSON.parse(JSON.stringify(response.data))['success'] == false && JSON.parse(JSON.stringify(response.data))['error']['code'] == 103){
adapterInstance.log.info(`Initial connectivity check of Synology Chat REST API successfully passed!`);
return true;
}
adapterInstance.log.error(`Unable to get valid response of Synology Chat REST API ${synoChatEndpointUrl} '${JSON.stringify(response.data)}'`);
}
catch(err) {
adapterInstance.log.error(`Unable to send message to Synology Chat REST API ${synoChatEndpointUrl}\n'${err}'`);
}

adapterInstance.log.error(`Adapter instance not in a usable state!`);
return false;
}

async function sendMessage(adapterInstance, synoBaseUrl, channelToken, synoSendMethod, certCheck, data){
var synoChatEndpointUrl = synoBaseUrl + "/webapi/entry.cgi";
adapterInstance.log.debug(`Preparing REST API call for endoint '${synoChatEndpointUrl}'...`);

var requestProperties = {
method: 'post',
url: synoChatEndpointUrl,
data: data,
params: {
'api': "SYNO.Chat.External",
'method': synoSendMethod,
'version': "2",
'token': channelToken
}
}

try {
var response = await sendBaseRequest(adapterInstance, synoChatEndpointUrl, certCheck, requestProperties);
if(JSON.parse(JSON.stringify(response.data))['success'] == true){
adapterInstance.log.debug(`Successfully sent message to ${synoChatEndpointUrl}.`);
return true;
}
}
catch(err) {
adapterInstance.log.error(`Unable to get send message to Synology Chat REST API ${synoChatEndpointUrl}\n'${err}'`);
}

adapterInstance.log.error(`Unable to send message to Synology Chat REST API ${synoChatEndpointUrl} '${JSON.stringify(response.data)}'`);
return false;
}

module.exports = {
prepareTextForSendingMessage,
isValidHttpUrl,

sendBaseRequest,
initialConnectivityCheck,
sendMessage
};
Loading

0 comments on commit 5e7dad4

Please sign in to comment.