#message.text
Explore tagged Tumblr posts
Text
else:
if message.text == " ":
bot.send_message(message.chat.id,
""")
bot.polling(none_stop=True, interval=0)
1 note
·
View note
Text
How to Create Gradient Chat Bubbles in Flutter?

In the present scenario, many developers focus on the best way to build a professional and beautiful chat bubble in an application. If you are a programmer and want an application with a perfect platform, you can switch to flutter. Creating a gradient chat bubble in Flutter is so easy.
Flutter development companies has complete information regarding Flutter platform. Some professionals write code from scratch. On the other hand, in-built stuff for the Flutter, like transform and custompainter widget is a good option for the chat bubble.
Traditionally, chat apps show a message in a chat bubble with a solid background.
Many users want modern chat apps that show chat bubbles with a gradient.
For this concern, expertise puts effort into fulfilling user requirements by adding gradient chat bubbles in the project.
Experts use gradients depending on the bubble position on the screen.
Dedicated team may also modernize the chat messaging app UI with a gradient background for the chat bubble.
Which challenges are recognized?
Traditional chat bubbles utilize decoratedBox or other widgets to paint a rounded rectangle in each chat message. It is suitable for a solid color and gradient repeated in every bubble.
Moreover, gradient, modern, and full-screen bubble backgrounds need a different approach. Complete screen gradient that merges with bubble scroll up and down screen involves approach. It lets developers make an informed decision for painting that suits layout information.
Experienced programmers have the proper knowledge and skill to create gradient chat bubbles in an application.
Every bubble gradient needs a bubble location on the screen.
Painting behavior involves access to layout information.
Such painting behavior is never possible with the widget due to widgets such as decoratedBox and Container widget.
You can make the right decision about the background color before the layout happens.
You can use custom painting behavior in that scenario and never go for custom layout behavior.
CustomPainter is an impressive option for completing a job.
In certain cases, you can gain complete control over child layout and never control over painting or hit testing. You may consider a flow widget. Custom RenderBox is best when you require control over painting, hit testing, and layout.
Also Read: How to Solve Command Not Found in Flutter?
How to change original background widget?
Change widget is responsible for drawing background with a new widget like BubbleBackground. You must add color property and represent a complete screen gradient related to the bubble.
BubbleBackground( colors: message.isMine ? const [Color(0xFF6C7689), Color(0xFF3A364B)] : const [Color(0xFF19B7FF), Color(0xFF491CCB)], child: DefaultTextStyle.merge( style: const TextStyle( fontSize: 18.0, color: Colors.white, ), child: Padding( padding: const EdgeInsets.all(12.0), child: Text(message.text), ), ), );
How to build custom painter?
Developers implement BubbleBackground as a stateless widget. It is vital to define the build () method to return CustomPaint with a CustomPainter like BubblePainter. BubblePainter is ideal for painting a bubble gradient.
@immutable class BubbleBackground extends StatelessWidget { const BubbleBackground({ super.key, required this.colors, this.child, }); final List<Color> colors; final Widget? child; @override Widget build(BuildContext context) { return CustomPaint( painter: BubblePainter( colors: colors, ), child: child, ); } } class BubblePainter extends CustomPainter { BubblePainter({ required List<Color> colors, }) : _colors = colors; final List<Color> _colors; @override void paint(Canvas canvas, Size size) { // TODO: } @override bool shouldRepaint(BubblePainter oldDelegate) { // TODO: return false; } }
Also Read: How to get all data from a Firestore collection in flutter?
How to bring access to scrolling details?
CustomPainter needs information mandatory to evaluate where the bubble is within bound. The viewport is a vital asset to list view. With the help of viewport, you can determine the location and require reference to scrollable state and Bubble Background buildContext. You can get access to scrolling information to CustomPainter.
BubblePainter( colors: colors, bubbleContext: context, scrollable: ScrollableState(), ) class BubblePainter extends CustomPainter { BubblePainter({ required ScrollableState scrollable, required BuildContext bubbleContext, required List<Color> colors, }) : _scrollable = scrollable, _bubbleContext = bubbleContext, _colors = colors; final ScrollableState _scrollable; final BuildContext _bubbleContext; final List<Color> _colors; @override bool shouldRepaint(BubblePainter oldDelegate) { return oldDelegate._scrollable != _scrollable || oldDelegate._bubbleContext != _bubbleContext || oldDelegate._colors != _colors; } }
How to cover full-screen bubble gradient?
CustomPainter is reliable for bringing desired gradient color and reference to containing ScrollableState and bubble BuildContext. With the necessary information, CustomPainter covers a full-screen bubble gradient.
Implementing the paint() method is the best way to calculate bubble position and configure the shader with the given color. Developers may also utilize matrix translation to offset shader depending on bubble position with scrollable widget.
class BubblePainter extends CustomPainter { BubblePainter({ required ScrollableState scrollable, required BuildContext bubbleContext, required List<Color> colors, }) : _scrollable = scrollable, _bubbleContext = bubbleContext, _colors = colors; final ScrollableState _scrollable; final BuildContext _bubbleContext; final List<Color> _colors; @override bool shouldRepaint(BubblePainter oldDelegate) { return oldDelegate._scrollable != _scrollable || oldDelegate._bubbleContext != _bubbleContext || oldDelegate._colors != _colors; } @override void paint(Canvas canvas, Size size) { final scrollableBox = _scrollable.context.findRenderObject() as RenderBox; final scrollableRect = Offset.zero & scrollableBox.size; final bubbleBox = _bubbleContext.findRenderObject() as RenderBox; final origin = bubbleBox.localToGlobal(Offset.zero, ancestor: scrollableBox); final paint = Paint() ..shader = ui.Gradient.linear( scrollableRect.topCenter, scrollableRect.bottomCenter, _colors, [0.0, 1.0], TileMode.clamp, Matrix4.translationValues(-origin.dx, -origin.dy, 0.0).storage, ); canvas.drawRect(Offset.zero & size, paint); } }
Once you complete the above code, you can get a modern chat bubble UI. Each bubble gradient changes the user scroll due to the bubble background widget invoking scrollable.of (context). The method can set up an inherent dependency on the predecessor scrollable state.
You can note every step carefully and start and finish tasks on time. Hire Flutter developer for perfect guidance to implement necessary measures, ensure a smooth workflow and build your own Flutter mobile app.
A chat feature is available in different types of the app today, from messaging to an ecommerce mobile app development and education apps to social networks. Gradient bubbles have impressive attributes.
Developers make apps with different background colors for incoming and outgoing messages that suit quick identification. Right painting decision is also crucial for layout information and position widget.
Output:

Conclusion:
Flutter is an exciting and fantastic platform for quickly creating applications. You can hire Flutter developers from an award-winning Flutter app development company like Flutter agency who are happy to work with you!
Frequently Asked Questions (FAQs)
1. How many kinds of gradients are in Flutter?
Flutter has three types of gradient: Linear Gradient, Radial Gradient, and Sweep Gradient.
2. What are the stops in gradient Flutter?
Stops list the values from 0.0 to 1.0, denoting fractions along with their gradient. Also,non-null has a list which has a similar length as colors. If the first value is not 0.0, then a stop with the position of 0.0 and the color is equivalent to the first color in the colors is implied.
3. What is the method to make a chat bubble on Flutter?
Create the new dart file, known as custom_shape.dart, inside a lib folder. After that, build the custom shape with a custom painter class. This class is used to draw a custom shape at the end of the chat bubble.
Originally Published At: https://flutteragency.com/create-gradient-chat-bubbles-in-flutter/
0 notes
Text
【30分でやる】Google Spread Sheetで管理するLINE BOTの作り方
from https://qiita.com/WdknWdkn/items/b78ae572e7cb5c9dfdca?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items
// 利用しているシート var SHEET_ID = '(①スプレッドシートのIDをコピペ)'; // 利用しているSSのシート名(※変えるとみえなくなる) var SHEET_NAME = 'faq'; // 利用しているもしかしてSSのシート名(※変えるとみえなくなる) var SHEET_NAME_MAYBE = 'maybe';
// LINE Message API アクセストークン var ACCESS_TOKEN = '(②LINEのdevelopersアカウント上で取得したTOKENをコピペ)'; // 通知URL var PUSH = "https://api.line.me/v2/bot/message/push"; // リプライ時URL var REPLY = "https://api.line.me/v2/bot/message/reply"; // プロフィール取得URL var PROFILE = "https://api.line.me/v2/profile";
/** * doPOST * POSTリクエストのハンドリング */ function doPost(e) { var json = JSON.parse(e.postData.contents); reply(json); }
/** * doGet * GETリクエストのハンドリング */ function doGet(e) { return ContentService.createTextOutput("SUCCESS"); }
/** * push * botからメッセージを送る */ function push() { // リクエストヘッダ var headers = { "Content-Type" : "application/json; charset=UTF-8", "Authorization" : "Bearer " + ACCESS_TOKEN };
// メッセージ(確認テン��レートサンプル) var postData = { "to" : "U9b2a595da4f15b8781e53898e2b03644", "messages" : [ { "type" : "template", "altText" : "もしかして検索キーワードは「SUUMO」ですか?", "template": { "type": "confirm", "actions": [ { "type": "message", "label": "はい", "text": "SUUMO" }, { "type": "message", "label": "いいえ", "text": "いいえ、違います。" } ], "text": "もしかしてこちらの検索キーワードですか?" } } ] }
// POSTオプション作成 var options = { "method" : "POST", "headers" : headers, "payload" : JSON.stringify(postData), muteHttpExceptions: true, }; return UrlFetchApp.fetch(PUSH, options); }
/** * reply * ユーザからのアクションに返信する */ function reply(data) { // POST情報から必要データを抽出 var lineUserId = data.events[0].source.userId; var postMsg = data.events[0].message.text; var replyToken = data.events[0].replyToken; var action = data.events[0].message.action; // 記録用に検索語とuserIdを記録 // debug(postMsg, lineUserId); debug(action, lineUserId);
// 検索語に対しての回答をSSから取得 var answers = findResponseArray(postMsg);
// 回答メッセージを作成 var replyText = '「' + postMsg + '」ですね。かしこまりました。以下、回答です。'; // 回答の有無に応じて分岐 if (answers.length === 0) { // 「類似の検索キーワード」がないかチェック var mayBeWord = findMaybe(postMsg); if (typeof mayBeWord === "undefined") { // 回答がない場合の定型文 sendMessage(replyToken, '答えが見つかりませんでした。別のキーワードで質問してみてください。'); } else { sendMayBe(replyToken, mayBeWord); } } else { // 回答がある場合のメッセージ生成 answers.forEach(function(answer) { replyText = replyText + "\n\n=============\n\nQ:" + answer.key + "\n\nA:" + answer.value; });
// 1000文字を超える場合は途中で切る if (replyText.length > 1000) { replyText = replyText.slice(0,1000) + "……\n\n=============\n\n回答文字数オーバーです。詳細に検索キーワードを絞ってください。"; } // メッセージAPI送信 sendMessage(replyToken, replyText); } }
// SSからデータを取得 function getData() { var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME); var data = sheet.getDataRange().getValues();
return data.map(function(row) { return {key: row[0], value: row[1], type: row[2]}; }); }
// SSから「もしかして」データを取得 function getMayBeData() { var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME_MAYBE); var data = sheet.getDataRange().getValues(); return data.map(function(row) { return {key: row[0], value: row[1], type: row[2]}; }); }
// 単語が一致したセルの回答を配列で返す function findResponseArray(word) { // スペース検索用のスペースを半角に統一 word = word.replace(' ',' '); // 単語ごとに配列に分割 var wordArray = word.split(' '); return getData().reduce(function(memo, row) { // 値が入って��るか if (row.value) { // AND検索ですべての単語を含んでいるか var matchCnt = 0; wordArray.forEach(function(wordUnit) { // 単語を含んでいればtrue if (row.key.indexOf(wordUnit) > -1) { matchCnt = matchCnt + 1; } }); if (wordArray.length === matchCnt) { memo.push(row); } } return memo; }, []) || []; }
// 単語が一致したセルの回答を「もしかして」を返す function findMaybe(word) { return getMayBeData().reduce(function(memo, row) { return memo || (row.key === word && row.value); }, false) || undefined; }
// 画像形式でAPI送信 function sendMessageImage(replyToken, imageUrl) { // replyするメッセージの定義 var postData = { "replyToken" : replyToken, "messages" : [ { "type": "image", "originalContentUrl": imageUrl } ] }; return postMessage(postData); }
// LINE messaging apiにJSON形式でデータをPOST function sendMessage(replyToken, replyText) { // replyするメッセージの定義 var postData = { "replyToken" : replyToken, "messages" : [ { "type" : "text", "text" : replyText } ] }; return postMessage(postData); }
// LINE messaging apiにJSON形式で確認をPOST function sendMayBe(replyToken, mayBeWord) { // replyするメッセージの定義 var postData = { "replyToken" : replyToken, "messages" : [ { "type" : "template", "altText" : "もしかして検索キーワードは「" + mayBeWord + "」ですか?", "template": { "type": "confirm", "actions": [ { "type":"postback", "label":"はい", "data":"action=detail", }, { "type": "message", "label": "いいえ", "text": "いいえ、違います。" } ], "text": "答えが見つかりませんでした。もしかして検索キーワードは「" + mayBeWord + "」ですか?" }
} ] }; return postMessage(postData); }
// LINE messaging apiにJSON形式でデータをPOST function postMessage(postData) { // リクエストヘッダ var headers = { "Content-Type" : "application/json; charset=UTF-8", "Authorization" : "Bearer " + ACCESS_TOKEN }; // POSTオプション作成 var options = { "method" : "POST", "headers" : headers, "payload" : JSON.stringify(postData) }; return UrlFetchApp.fetch(REPLY, options); }
/** ユーザーのアカウント名を取得 */ function getUserDisplayName(userId) { var url = 'https://api.line.me/v2/bot/profile/' + userId; var userProfile = UrlFetchApp.fetch(url,{ 'headers': { 'Authorization' : 'Bearer ' + ACCESS_TOKEN, }, }) return JSON.parse(userProfile).displayName; }
// userIdシートに記載 function lineUserId(userId) { var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName('userId'); sheet.appendRow([userId]); }
// debugシートに値を記載 function debug(text, userId) { var sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName('debug'); var date = new Date(); var userName = getUserDisplayName(userId); sheet.appendRow([userId, userName, text, Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss')]); }
https://cdn.qiita.com/assets/qiita-fb-2887e7b4aad86fd8c25cea84846f2236.png
0 notes
Text
Getting Started with Ionic 4 and Socket.io
Working with Sockets has become super easy over the years, and although it might sound intimidating first we’ll learn how to easily use it in combination with Ionic 4!
In this tutorial we will craft a super simple Node server which allows socket connections and also an Ionic app that connects to our server.
We will then be able to send messages to a chatgroup from our app where everyone inside is an anonymous user. You can find more detailed courses inside my Ionic Academy, the learning platform for everything Ionic!
Creating a simple Node Server with Socket.io
Because we need two parts in this tutorial, we start with a simple server. You can create a new node project by running the below commands:
mkdir SocketServer && cd SocketServer npm init npm install express socket.io
Now you got a folder with a package.json file, but not really a server yet. Therefore, create a new index.js file and insert:
let app = require('express')(); let server = require('http').createServer(app); let io = require('socket.io')(server); io.on('connection', (socket) => { socket.on('disconnect', function(){ io.emit('users-changed', {user: socket.username, event: 'left'}); }); socket.on('set-name', (name) => { socket.username = name; io.emit('users-changed', {user: name, event: 'joined'}); }); socket.on('send-message', (message) => { io.emit('message', {msg: message.text, user: socket.username, createdAt: new Date()}); }); }); var port = process.env.PORT || 3001; server.listen(port, function(){ console.log('listening in http://localhost:' + port); });
This is our basic Socket implementation on the server-side.
All of our functions are wrapped inside the io.on('connection') block, so these will only happen once a client connects to the server. You could also add authentication to the process, but today we want to keep things easy.
We set a function for the events disconnect, set-name and add-message which means whenever our app sends out these events the server reacts.
If we send a new message, we emit that message to everyone connected as a new object with text, the name of the sending user and a date. Also, we set the name of the socket connection if a users send his nickname.
You can imagine storing more information that way like a real user ID of your backend to couple the information closely.
There’s also a tool to test your socket implementation but I haven’t worked that much with it before. Just wanted to mention it here since it can be hard to test and debug it, so check out the Socket.io Tester!
Your node backend with Socket.io is now ready! You can start it by running the command below and you should be able to reach it at http://localhost:3001
node index.js
This backend won’t store the messages, so they are only available to online users. At this point you could plug in your database and store all new messages in there so you have the functionality of a real chat!
Creating the Ionic Socket Chat App
Now we get into the perhaps better known territory for you, the Ionic app. Actually we don’t need a lot, just a blank app to get started and additionally the ngx-socket-io package to create the connection to our server:
ionic start devdacticSocket blank cd ./devdacticSocket npm install ngx-socket-io
At the time writing this I also encountered problems with the package, and the easiest way to fix it (as recommended only for other cases as well) is to change your app/polyfills.ts at the end to add one more line:
/*************************************************************************************************** * APPLICATION IMPORTS */ (window as any).global = window;
Now that the problems are gone, we can simply add the information for socket to our app/app.module.ts. You need to supply your server URL and you could add a lot more options in there that you might need in special scenarios later, but for now we don’t have to change a lot and only need the URL from the server we created before, so go ahead and change your app module to:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io'; const config: SocketIoConfig = { url: 'http://localhost:3001', options: {} }; @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, SocketIoModule.forRoot(config) ], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {}
Now the app is able to make a connection to our server and we simply call a connect() function to establish that connection.
When you add only the connect block, you can also see a new connection on your server if you put in some logs!
But we don’t want to stop there, so here’s what we want and do as well:
Create a random name when the app starts
Emit the name with the set-name event so the server knows our nickname
React to the incoming users-changed events in order to show a toast for users that joined/left the chat
Subscribe to the message event just like before to the user change and add new messages to our arry
Because the package returns Observable the implementation is super handy and matches our regular style as well.
Also, sending a new message is as easy as emitting the data to socket – the server will handle the rest and know who sent the information based on the internal socket connection information.
Now go ahead and change your app/home/home.page.ts to:
import { Component, OnInit } from '@angular/core'; import { Socket } from 'ngx-socket-io'; import { ToastController } from '@ionic/angular'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { message = ''; messages = []; currentUser = ''; constructor(private socket: Socket, private toastCtrl: ToastController) { } ngOnInit() { this.socket.connect(); let name = `user-${new Date().getTime()}`; this.currentUser = name; this.socket.emit('set-name', name); this.socket.fromEvent('users-changed').subscribe(data => { let user = data['user']; if (data['event'] === 'left') { this.showToast('User left: ' + user); } else { this.showToast('User joined: ' + user); } }); this.socket.fromEvent('message').subscribe(message => { this.messages.push(message); }); } sendMessage() { this.socket.emit('send-message', { text: this.message }); this.message = ''; } ionViewWillLeave() { this.socket.disconnect(); } async showToast(msg) { let toast = await this.toastCtrl.create({ message: msg, position: 'top', duration: 2000 }); toast.present(); } }
Finally it’s a good idea to disconnect once you are done – perhaps not always when you leave the page but maybe when the user logs out again.
Now we need to build our view and most of the following code is copied from one of the Ionic Academy Quick Wins on creating an Elastic Chat view.
We only need to iterate our messages array and have an area for composing the new message at the bottom, so open your home/home.page.html and change it to:
<ion-header> <ion-toolbar> <ion-title> Devdactic Chat </ion-title> </ion-toolbar> </ion-header> <ion-content> <ion-grid> <ion-text color="medium" text-center> <p>You joined the chat as </p> </ion-text> <ion-row *ngFor="let message of messages"> <ion-col size="9" *ngIf="message.user !== currentUser" class="message other-message"> <b></b><br> <span></span> <div class="time" text-right><br></div> </ion-col> <ion-col offset="3" size="9" *ngIf="message.user === currentUser" class="message my-message"> <b></b><br> <span></span> <div class="time" text-right><br></div> </ion-col> </ion-row> </ion-grid> </ion-content> <ion-footer> <ion-toolbar color="light"> <ion-row align-items-center> <ion-col size="10"> <ion-textarea auto-grow class="message-input" rows="1" [(ngModel)]="message"></ion-textarea> </ion-col> <ion-col size="2"> <ion-button expand="block" fill="clear" color="primary" [disabled]="message === ''" class="msg-btn" (click)="sendMessage()"> <ion-icon name="ios-send" slot="icon-only"></ion-icon> </ion-button> </ion-col> </ion-row> </ion-toolbar> </ion-footer>
Because we have a basic example everything works fine, but if you have a real chat application with a lot of messages it might make sense to also optimise your list performance with a different Ionic component!
To achieve a chat like look we also need a bit of additional CSS so copy the following into your home/home.page.scss:
.message { padding: 10px; border-radius: 10px; margin-bottom: 4px; white-space: pre-wrap; } .my-message { background: var(--ion-color-tertiary); color: #fff; } .other-message { background: var(--ion-color-secondary); color: #fff; } .time { color: #dfdfdf; float: right; font-size: small; } .message-input { margin-top: 0px; border: 1px solid var(--ion-color-medium); border-radius: 10px; background: #fff; } .msg-btn { --padding-start: 0.5em; --padding-end: 0.5em; }
Now you can run your chat and open for example a few more incognito windows so you have different users connected to your socket chat. Then go ahead and enjoy chatting with yourself (forever alone).
Conclusion
Getting started with Socket and Ionic isn’t that hard – creating a basic server and the needed app functionality only takes minutes, and you can expand this example to a full-blown chat application as well!
You can also find a video version of this tutorial below.
youtube
The post Getting Started with Ionic 4 and Socket.io appeared first on Devdactic.
via Devdactic https://ift.tt/2Y0yw4l
0 notes
Link
So your rPi is sitting there on your local network and you (hopefully!) haven't opened the telnet ports on your router, and you are not at home but you need to talk to your rPi. What's a poor boy to do? Well, if you've added this Slack Bot app to your Slack account, you can talk to your rPi from anywhere! Send bash commands, check on its health, control your devices, all from Slack!
Examples
Simple Ping
Get the Temperature of Your rPi Processor
Get Memory Utilization (Bash Command)
Get Free Disk Space (Bash Command)
Send a Command to a Device, like the LCD1602
Check on a Process (Bash Command)
Query Postgres
What You Should Already Know
You should already know:
how to create a .NET Core application
publish it with the linux-arm architecture
WinSCP (or PCSP) it over to the rPi
Fire up a terminal window in Putty to run it.
What if I Don't Have a rPi?
If you don't have an rPi, you can still run the application from Visual Studio though of course the Linux, rPi, and LCD1602 specific stuff won't work. That leaves you with sending "ping" but you can easily add additional behaviors. In fact, I did a lot of the Slack API testing from a Windows box with Visual Studio.
Creating a Bot App in Slack
(adsbygoogle = window.adsbygoogle || []).push({});
The first step is to create a bot app for your Slack account. IMPORTANT! At the point where you create your app, you will also need to create a bot. For example, my bot is called "rpichat" and is listed on the https://api.slack.com/apps page:
Click on the bot and you'll see this:
Click on "Add Features and functionality" and you'll see this:
Click on Bots:
and then "Add a Bot User". Set the display name and default user name, then click on Add Bot User:
Click on OAuth & Permissions on the left:
If you haven't already installed the app in your workspace, you'll see this button:
Install the app, authorize it, and now you can see the Bot User OAuth Access token.
The Code
To begin with, three packages need to be added to the project:
Main
This is really simple:
private static SlackSocketClient client; static void Main(string[] args) { Console.WriteLine("Initializing..."); InitializeSlack(); Console.WriteLine("Slack Ready."); Console.WriteLine("Press ENTER to exit."); Console.ReadLine(); }
SlackAPI
For this article, I'm using the SlackAPI, an open source C#, .NET Standard library which works great on the rPi. Please note that I have not investigated its robustness with regards to losing the websocket connection and restoring it.
Because we're using the Real Time Messaging (RTM) API and a bot app, we'll need to Bot User OAuth Access Token as found on the https://api.slack.com/apps page (navigate then to your app.) This is an important link to remember as it is the gateway to all your apps. In the OAuth Access section, you should see something like this, of course without the tokens blacked out:
Copy the Bot Token (and the OAuth Token if you want) into the appSettings.json file:
{ "Slack": { "AccessToken": "[you access token]", "BotToken": "your bot token]" } }
The "AccessToken" isn't used in this article but you might want it there for other things that you do.
Initializing the API and Receiving Messages
Using the API is straight forward. One method handles the startup and message routing, the comments and code, which I've modified a bit, come from the SlackAPI wiki page examples:
static void InitializeSlack() { string botToken = Configuration["Slack:BotToken"]; ManualResetEventSlim clientReady = new ManualResetEventSlim(false); client = new SlackSocketClient(botToken); client.Connect((connected) => { // This is called once the client has emitted the RTM start command clientReady.Set(); }, () => { // This is called once the RTM client has connected to the end point }); client.OnMessageReceived += (message) => { // Handle each message as you receive them Console.WriteLine(message.user + "(" + message.username + "): " + message.text); if (message.text.StartsWith("rpi:")) { // Skip any spaces after "rpi:" and get what's left of the first space, ignoring data. string cmd = message.text.RightOf("rpi:").Trim().LeftOf(" "); // Get everything to the right after the command and any number of spaces // separating the start of the data. string data = message.text.RightOf("rpi:").Trim().RightOf(" ").Trim(); Console.WriteLine("cmd: " + cmd); Console.WriteLine("data: " + data); string ret = "Error occurred."; if (router.TryGetValue(cmd, out Func<string, string> fnc)) { ret = fnc(data); } else { // Try as bash command. string cmdline = message.text.RightOf("rpi:").Trim(); ret = "```" + cmdline.Bash() + "```"; } client.PostMessage((mr) => { }, message.channel, ret); } }; clientReady.Wait(); }
There are three things to note about the message handler in the above code:
Any message that does not being with "rpi:" will be ignored. This is because when the application posts a message, the message event is fired so the application gets back the very message that was just posted. To distinguish between commands that you, the user, are sending, your commands must be prefixed with "rpi:".
For console output of bash commands is returned in markdown block quotes which uses a monospace font and preserves leading spaces, so you get back a nicely formatted result.
We always reply on the channel from which the message was received. You might be chatting with the bot in its app direct message channel, or if the bot has been invited to a "human" channel, we can chat with it there as well.
Setting Up the Configuration Parser
The configuration parser requires using Microsoft.Extensions.Configuration; and is implemented as a static getter (borrowed from here) and the two NuGet packages mentioned earlier:
public static IConfiguration Configuration { get; } = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appSettings.json", optional: false, reloadOnChange: true) .Build();
The file on the *nix side is case-sensitive, so make sure to preserve the case of the filename and how you reference it in the above code.
The Command Router
The router is simply a command key - function dictionary -- if a command has an associated function, that function is called, otherwise it's assumed to be a bash command and the process is invoked.
private static Dictionary<string, Func<string, string>> router = new Dictionary<string, Func<string, string>> { {"temp", GetTemp }, {"display", Display }, {"ping", (_) => "pong" }, };
Extend this for custom C# implementations.
The Bash Process Invoker
This code was borrowed from here:
public static string Bash(this string cmd) { var escapedArgs = cmd.Replace("\"", "\\\""); var process = new Process() { StartInfo = new ProcessStartInfo { FileName = "/bin/bash", Arguments = $"-c \"{escapedArgs}\"", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, } }; process.Start(); string result = process.StandardOutput.ReadToEnd(); process.WaitForExit(); return result; }
It implements an extension method, hence its usage looks like "df -h".Bash(). The -c in the arguments is actually telling bash the command (as an argument to bash) to run.
The Commands I've Implemented
Besides the "ping" command, I implemented a couple other things based on what I've got hooked up at the moment.
(adsbygoogle = window.adsbygoogle || []).push({});
Getting the rPi Temperature
The processor has a built-in temperature sensor and the temperature is exposed a file (I found this originally in some Python code and added the Fahrenheit math):
private static string GetTemp(string _) { string ret; string temp = System.IO.File.ReadAllText("/sys/class/thermal/thermal_zone0/temp"); Console.WriteLine(temp); double t = Convert.ToDouble(temp); string dc = String.Format("{0:N2}", t / 1000); string df = String.Format("{0:N2}", t / 1000 * 9 / 5 + 32); ret = dc + "C" + " " + df + "F"; return ret; }
Writing to the LCD1602
From my previous article, I can now display messages to the LCD1602 from Slack!
// Data must be in the format of one of these two options: // "This is line 1" // "This is line 1"[d]"This is line 2" // where [d] is an optional delimiter of any string. private static string Display(string data) { int numQuotes = data.Count(c => c == '\"'); if (data.First() != '\"' || data.Last() != '\"' && (numQuotes != 2 && numQuotes != 4)) { return "bad format"; } Lcd1602 lcd = new Lcd1602(); lcd.OpenDevice("/dev/i2c-1", LCD1602_ADDRESS); lcd.Init(); lcd.Clear(); if (numQuotes == 2) { lcd.Write(0, 0, data.Between("\"", "\"")); } else { // two lines lcd.Write(0, 0, data.Between("\"", "\"")); lcd.Write(0, 1, data.RightOf("\"").RightOf("\"").Between("\"", "\"")); } lcd.CloseDevice(); return "ok"; }
Querying Postgres
Actually, any Postgres SQL command can be executed through your Slack bot, here I show queries.
Executing the SQL, including queries, is straight forward using ADO.NET. For queries, an option for formatting (defaults to JSON) can be provided. My Match extension method would probably be replaced with the C# 8's switch statement and its lovely terseness.
The Northwind database was imported into Postgres using this GitHub repo.
Regarding fetch first 2 rows only, this is part of SQL 2008 but doesn't work in MS SQL Server!
Also, to get this to work, add the appropriate connection string to your appsettings.json file:
"ConnectionStrings": { "rpidb": "Host=[your IP];Database=Northwind;Username=pi;Password=[your password]" }
The ExecuteSQL method:
enum OutputFormat { JSON, CSV, Tabular, } private static string ExecuteSql(string data, List<string> options) { string sql = data; var outputFormat = OutputFormat.JSON; string ret = ""; string validOptionsErrorMessage = "Valid options are --json, --csv, --tabular"; try { options.Match( (o => o.Count == 0, _ => { }), (o => o.Count > 1, _ => throw new Exception(validOptionsErrorMessage)), (o => o[0] == "--json", _ => outputFormat = OutputFormat.JSON), (o => o[0] == "--csv", _ => outputFormat = OutputFormat.CSV), (o => o[0] == "--tabular", _ => outputFormat = OutputFormat.Tabular), (_ => true, _ => throw new Exception(validOptionsErrorMessage)) ); string connStr = Configuration.GetValue<string>("ConnectionStrings:rpidb"); var conn = new NpgsqlConnection(connStr); conn.Open(); var cmd = new NpgsqlCommand(sql, conn); NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd); DataTable dt = new DataTable(); da.Fill(dt); ret = outputFormat.MatchReturn( (f => f == OutputFormat.JSON, _ => Jsonify(dt)), (f => f == OutputFormat.CSV, _ => Csvify(dt)), (f => f == OutputFormat.Tabular, _ => Tabify(dt)) ); ret = "```\r\n" + ret + "```"; } catch (Exception ex) { ret = ex.Message; } return ret; }
Returning JSON
Dead simple using Newtsoft.JSON:
static string Jsonify(DataTable dt) { string ret = JsonConvert.SerializeObject(dt, Formatting.Indented); return ret.ToString(); }
Example:
Returning a CSV
It is also quite simple:
static string Csvify(DataTable dt) { StringBuilder sb = new StringBuilder(); sb.AppendLine(String.Join(", ", dt.Columns.Cast<DataColumn>().Select(dc => dc.ColumnName))); foreach (DataRow row in dt.Rows) { sb.AppendLine(String.Join(", ", dt.Columns.Cast<DataColumn>().Select(dc => row[dc].ToString()))); } return sb.ToString(); }
Example:
Returning Tabular Formatted Data
Here, the width of each column name and row's data is accounted for requires some of Math.Max for the column names and each row data. Tabify is probably not the greatest name!
static string Tabify(DataTable dt) { StringBuilder sb = new StringBuilder(); int[] colWidth = new int[dt.Columns.Count]; // Get max widths for each column. dt.Columns.Cast<DataColumn>().ForEachWithIndex((dc, idx) => colWidth[idx] = Math.Max(colWidth[idx], dc.ColumnName.Length)); // Get the max width of each row's column. dt.AsEnumerable().ForEach(r => { dt.Columns.Cast<DataColumn>().ForEachWithIndex((dc, idx) => colWidth[idx] = Math.Max(colWidth[idx], r[dc].ToString().Length)); }); // Bump all widths by 3 for better visual separation colWidth.ForEachWithIndex((n, idx) => colWidth[idx] = n + 3); // Padded column names: sb.AppendLine(string.Concat(dt.Columns.Cast<DataColumn>().Select((dc, idx) => dc.ColumnName.PadRight(colWidth[idx])))); // Padded row data: dt.AsEnumerable().ForEach(r => sb.AppendLine(string.Concat(dt.Columns.Cast<DataColumn>().Select((dc, idx) => r[dc].ToString().PadRight(colWidth[idx]))))); return sb.ToString(); }
Example:
Limitations
(adsbygoogle = window.adsbygoogle || []).push({});
There's a 4,000 character limit on what can be posted to a Slack channel, so don't go nuts querying hundreds of records and dozens of columns!
Leaving the Program Running
If you want to make the application a service so it always starts up, in the event of a power loss, or Alternatively, if you simply want to have the program keep running even after you close the terminal window:
nohup > /dev/null &
The & makes the process run in the background (this is true for any process that you start), and nohup is "no hang up" when the terminal closes. The redirect > /dev/null redirects console output to nothing rather than the nohup.out file. Read about nohup here.
In this case, I changed main, removing the "press ENTER to exit" and replaced it with a do nothing loop:
while (!stop) Thread.Sleep(1); Thread.Sleep(1000); // wait for final message to be sent. // Console.WriteLine("Press ENTER to exit."); //Console.ReadLine();
and I added a "stop" command to terminate the program from Slack:
{"stop", _ => {stop=true; return "Stopping..."; } }
Conclusion
While the code is very simple, this opens up a whole new world of bidirectional communication between Slack and the rPi (or any SBC for that matter). I can imagine using this to do things like starting and stopping services, getting the status of various devices attached to the rPi, issuing commands, and so forth. I can imagine mounting an rPi or an Arduino on a LEGO robot and using Slack messaging to drive the robot and even post image files! If I had the time and the hardware, I'd definitely play around with that some more.
0 notes
Text
LINE BOTでダイスを振る(2)
Tumblrでコードブロックってどうやって書くんだよ。
とりあえず1d1~1d999までダイス振れるコードを書いたのでメモ。
var CHANNEL_ACCESS_TOKEN = 'CHANNEL_ACCESS_TOKEN'; function doPost(e) { var reply_token= JSON.parse(e.postData.contents).events[0].replyToken; if (typeof reply_token === 'undefined') { return; } var user_message = JSON.parse(e.postData.contents).events[0].message.text; var reply_messages = 'error'; if (/^[1]d(\d{1,3})$/.test(user_message)) { var max = user_message.match(/^[1]d(\d{1,3})$/)[1]; reply_messages = Math.floor( Math.random() * (max) ) + 1 ; } else { return; } var url = 'https://api.line.me/v2/bot/message/reply'; UrlFetchApp.fetch(url, { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN, }, 'method': 'post', 'payload': JSON.stringify({ 'replyToken': reply_token, 'messages': [{ 'type': 'text', 'text': reply_messages, }], }), }); return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON); }
正規表現を勘違いしていて全然動かなかったのはナイショ… 3d6とかには対応してないけど普通に回数分乱数出して合算すればいいだけなのでまあおいおい…
0 notes
Photo
New Post has been published on https://dev-ops-notes.ru/devops/%d0%ba%d0%b0%d0%ba-%d1%81%d0%b4%d0%b5%d0%bb%d0%b0%d1%82%d1%8c-%d1%87%d0%b0%d1%82-%d0%b1%d0%be%d1%82%d0%b0-%d0%b4%d0%bb%d1%8f-telegram-%d0%b7%d0%b0-15-%d0%bc%d0%b8%d0%bd%d1%83%d1%82/?utm_source=TR&utm_medium=andrey-v-maksimov&utm_campaign=SNAP%2Bfrom%2BDev-Ops-Notes.RU
Как сделать чат бота для Telegram за 15 минут
Автоматизация, автоматизация и еще раз автоматизация! Чат боты в последнее время стали невероятно популярны. Кто-то делает их в маркетинговых целях, кто-то автоматизирует управление комьюнити, кто-то получает автоматические обновления из всевозможных сервисов в любимый мессенджер.
Расширяя собст��енные каналы доставки информации до целевой аудитории этого ресурса, я решил сделать еще и группу в Telegram, куда бот публикует новые, очень надеюсь, интересные для вас материалы. В этом посте я покажу вам, как сделать собственного бота буквально за 15 минут. А заодно и заранее обращу ваше внимание на “грабли”, которые вас могут поджидать.
Я уже как-то писал про использование облачных функций Google, пришло время показать еще один пример того, как они могут быть использованы на практике. Итак, нам понадобятся:
Google Cloud Functions или AWS Lambda + API Gateway (в них мы разместим код бота)
Node.js
Google Cloud SDK
Аккаунт в Telegram.
Прямые руки.
Код конечной облачной функции доступен на GitHub.
Регистрация чат-бота в Telegram
Я не буду дублировать большое количество информации, доступное на эту тему, а просто поделюсь с вами прекрасными ссылками на русскую и английскую документацию. Итак, процесс регистрации бота в Telegram очень прост. Достаточно обратиться к боту @BotFather в Telegram и отправить ему команду /newbot.
Далее отвечаем на пару вопросов (задаем имя бота и его описание) и получаем API-ключ (он же идентификатор) вашего бота.
Логика работы бота
Сам по себе зарегистрированный бот совершенно бесполезен. Ему надо приделать мозг. Мозг в данном случае ни что иное как небольшой Web-сервис, содержащий логику работы бота. Этот Web-сервис можно хостить на общедоступной виртуальной машине в любом облаке или физическом сервере, главное, чтобы до него можно было достучаться из интернет.
Для тех из вас, кто хочет пойти по пути написания и хостинга собственного Web-сервиса, рекомендую отличное русское руководство по написанию бекенда для Telegram бота на Python.
Арендовать целую виртуальную машину под бота мне было жалко денег, поэтому я пошел по более простому пути – использование облачных функций (Google Cloud Functions или Lambda + API Gateway). Да, у AWS придется использовать два сервиса вместо одного, т.к. в отличии от Google к AWS Lambda функциям у AWS нельзя обратиться напрямую по HTTP.
Для тех, кто все таки хочет сделать это в AWS, рекомендую отличную статью Creating a server-less Telegram bot with AWS Lambda and AWS API Gateway.
Не смотря на то, что я дал вам аж 3 варианта для реализации, рекомендую начать с облачных функций Google или AWS. Я покажу вам как это сделать в Google Cloud, а для AWS все будет ровно точно так же.
Telegram бот на Google Cloud Functions
В этом примере мы напишем бота, который в ответ на сообщение /docker будет выдавать содержимое RSS ленты этого блога по категории Docker.
Как обычно, создаем отдельную директорию, например myAwesomeTestBot. В которой необходимо разметить 2 файла package.json (тут будут описаны зависимости) и index.js (тут будет код бота).
Содержимое package.json:
"name": "myAwesomeTestBot", "version": "0.1.0", "description": "Awesome Telegram Bot Example - Google Cloud Functions", "main": "index.js", "scripts": "test": "echo \"Error: no test specified\" && exit 1" , "keywords": [], "author": "", "license": "GPL", "dependencies": "node-telegram-bot-api": "^0.28.0", "rss-parser": "^2.10.4"
В этом файле делается описание нашего модуля, и указываются все зависимости Nodejs, которые понадобятся нам для реализации логики работы бота. В нашем случае внешние зависимости 2:
node-telegram-bot-api – собственно основная библиотека для работы с Telegram API
rss-parser – библиотека, упрощающая работу с RSS на JavaScript
Далее идет основной файл облачной функции (web-сервиса), которая будет реализовывать логику работу для нашего Telegram бота. Но прежде чем реализовывать логику, давайте взглянем на структуру типичного с��общения, получаемого Telegram ботом:
"update_id":399206834, "message": "message_id":5, "from": "id":61193397, "is_bot":false, "first_name":"Andrey", "last_name":"Maksimov", "username":"amaksimov", "language_code":"en-RU" , "chat": "id":61193397, "first_name":"Andrey", "last_name":"Maksimov", "username":"amaksimov", "type":"private" , "date":1504273127, "text":"/docker", "entities":[ "offset":0, "length":7, "type":"bot_command" ]
Как видите, ничего сложного в этой структуре нет. Нам нужна структура message, определяющая полученное сообщения, а в ней вложенные структуры:
from – от кого получено сообщение, обратите внимание на language_code, бот может быть легко локализован.
chat – чат или по сути канал, по которому получено сообщение
text – непосредственно текст сообщения
Именно с этими данными мы и будем работать в коде ниже. Содержимое index.js:
var parser = require('rss-parser'); const TelegramBot = require('node-telegram-bot-api'); const token = '362883343:AAHEUJIhx7Gc5Qp240uyrIgrZd8wqLtoxA0'; var bot = new TelegramBot(token, polling: false); exports.myAwesomeTestBot = function telegramBot (req, res) // Логируем запрос (пригодится для отладки) console.log('Request body: ' + JSON.stringify(req.body)); var request = req.body; var message = req.body.message; if (typeof message.chat !== "undefined") var chat = message.chat; if (chat.type == "private") // Это сообщение отправлено в личный чат с ботом // Из какого чата пришло сообщение и текст сообщения var chatId = chat.id; var messageText = message.text; switch (messageText) // Обработка команд case '/docker': console.log('Processing command: ' + messageText); // Получить ссылки из RSS ленты и отправить в чат var feed_url = 'https://dev-ops-notes.ru/category/docker/feed/'; parser.parseURL(feed_url, function(err, parsed) parsed.feed.entries.forEach(function(entry) var msg = decodeURIComponent(entry.link); // Собственно отправка сообщения ботом bot.sendMessage(chatId, msg); ); ); break; default: bot.sendMessage(chatId, 'Привет! Отправь мне /docker и получи последние статьи о Docker!'); break; res.status(201).send('Done!');
В верхней части файла идет подключение библиотек и инициализация глобальных переменных (можно не радоваться “засвеченному” токену, бот был удален еще до публикации этой статьи):
var parser = require('rss-parser'); const TelegramBot = require('node-telegram-bot-api'); const token = '362883343:AAHEUJIhx7Gc5Qp240uyrIgrZd8wqLtoxA0'; var bot = new TelegramBot(token, polling: false);
Далее определяется облачная функция:
exports.myAwesomeTestBot = function telegramBot (req, res)
Более подробно о написании http-облачных функций в Google Cloud можно посмотреть тут: https://cloud.google.com/functions/docs/writing/http.
Далее, Telegram будет передавать нашей функции от бота различные сообщения: бот может находиться в канале и получать статусные сообщения о входах\выходах пользователей с\из каналов, реагировать на нажатие кнопок с определяемой вами клавиатуры и т.д. Давайте явно обезопасим себя от того, что не будем отвечать на все сообщения:
if (typeof message.chat !== "undefined") { var chat = message.chat; if (chat.type == "private")
Ну, а далее очень примитивный разбор команды и реакция только на команду /docker в switch блоке.
Публикация логики бота в Google Cloud Functions
Чтобы опубликовать мозг нашего бота в виде доступной для вызова облачной функции (Web-сервиса), нужно скачать все требующиеся нам зависимости:
$ npm install
Опубликовать функцию командой:
$ gcloud beta functions deploy myAwesomeTestBot --stage-bucket=dev-ops-notes-cloud_functions --trigger-http
В выводе команды увидеть строки:
httpsTrigger: url: https://us-central1-dev-ops-notes-ru.cloudfunctions.net/myAwesomeTestBot
Из которых нам нужно запомнить URL, по которому можно обращаться к нашей функции. И сообщить Telegram о том, что все сообщения для бота необходимо передавать на обработку ей (короче, установить Web-hook):
$ curl -XPOST https://api.telegram.org/bot362883343:AAHEUJIhx7Gc5Qp240uyrIgrZd8wqLtoxA0/setWebhook\?url\=https://us-central1-dev-ops-notes-ru.cloudfunctions.net/myAwesomeTestBot "ok":true,"result":true,"description":"Webhook was set"
В данной команде используется ключ доступа\идентификатор нашего бота и URL нашей облачной функции. Все, теперь у вас есть ваш первый персональный Telegram бот, развивать который дальше – одно удовольствие. Он может делать для вас абсолютно все что угодно!
Тестируем Telegram бота
Находим бота в списке пользователей Telegram, нажимаем /start. Получаем приветствие. Жмем или пишем /docker и получаем список статей из RSS ленты.
Вот так вот очень просто пишется бот для Telegram. Далее будут разобраны чуть более сложные вопросы.
Дополнительные комментарии
Написанный нами бот совсем не интеллектуален, но надо же было с чего-то начать. Следующим вполне очевидным вопросом будет “А как реализовать диалог?”. Для не сильно сложных сценариев есть два подхода:
Необходимо добавить к вашему сервису БД, в которую сохранять получаемые сообщения, отслеживать сообщения по chat.id и from.id для принятия решения в логике вашей программы.
Использовать inline клавиатуру, в процессе “диалога”
Для более сложных сценариев, например, с использованием машинного обучения большого количества сторонних сервисов лучше всего ��спользовать Node-Red, пример использования в Облаке IBM.
Еще один нюанс: как только логики станет больше, писать все в одном файле будет не приятно и сложно. Как написать Telegram бота с использованием БД и более того нормально структурируя код, отлично написано в парочке статей (кстати, очень свежих):
Bot Dev: Write a stateful Telegram bot – Part 1
Bot Dev: Write a stateful Telegram bot – Part 2
Заключение
В этой статье мы с вами буквально за 15 минут сделали своего собственного Telegram бота. Он приветствует нас и отвечает на команду. Решение как обычно облачное и полностью масштабируемое. Оно проглотит любое количество сообщений, которое необходимо будет переваривать, чтобы обслуживать работу вашего online комьюнити, отдела продаж, автоматизацию и вообще все, что угодно.
Кстати, подписывайтесь на наш Telegram канал, мы начали и туда публиковать наши статьи! Более того, у нашего бота @Dev-Ops-Notes.RU в этом канале уже совсем скоро можно будет в любое время попросить скидку на обучение на Udemy на любой интересующий вас курс! Оставайтесь с нами и следите за нашими новостями!
0 notes
Text
BULK SMS MARKETING FOR ADVERTISING AGENCIES
Bulk SMS marketing is a need of every industry.It provides you the efficient way to reach your customers or clients.Its a powerful tool in for Advertising agencies.If you have Marketing or advertising Agency,you know how competitive your industry is there are several distinct advantages to reaching out to your audience via text message.Text messages help you acquire loyal customers and repeat business.
Bulk sms also gives you the ability to reach to your client or customers base whenever you want. You can also offer them special promotions and announce new services.
Know more bulk sms service please visit: www.emssgo.com or mail us: [email protected]
0 notes
Text
mattata's Channel's Post @ March 5, 2017 at 12:38PM
--[[ This example will echo messages back to the user who sent them, with an inline keyboard which tells the user the JSON for the callback_query.from object. ]] local api = require('telegram-bot-lua.core').configure('') -- Enter your token local json = require('dkjson') function api.on_message(message) if message.text then api.send_message( message, message.text, nil, true, false, nil, api.inline_keyboard():row( api.row():callback_data_button( 'Button', 'callback_data' ) ) ) end end function api.on_callback_query(callback_query) api.answer_callback_query( callback_query.id, json.encode(callback_query.from) ) end api.run()
By: Matt via mattata's Channel
0 notes
Text
Skype bot (BotFramework) can't recognize messages in goups
Skype bot (BotFramework) can’t recognize messages in goups
Today I have a little problem: my bot stopped recognize messages in groups, but successfully recognize messages in 1:1 dialog. Few month ago I solved this problem with usage this issue https://github.com/Microsoft/BotBuilder/issues/860.
Example:
if (address.channelId === "skype" && address.conversation.isGroup) { if (message.entities.length > 0) { var content = message.text;…
View On WordPress
0 notes
Note
What type of vacuum cleaner would Serena and Ash use?
omg well probably serena would want one that works well but isnt very noisy, and ash probably wouldnt give a fuck since he probably isnt gonna be doing any cleaning lol
3 notes
·
View notes
Text
Ionic Realtime Chat with Socket.io
There are many ways to build a chat application with Ionic. You could use Firebase as a realtime database, or you can use your own Node server with some Socket.io, and that’s what we gonna do today.
In this tutorial we will craft a super simple Node.js server and implement Socket.io on the server-side to open realtime connections to the server so we can chat with other participants of a chatroom.
This is a super lightweight example as we don’t store any of the messages on the server – if you are nor in the chat room you will never get what happened. The result will look like in the image below.
Building our Node Server
This tutorial starts with the actual backend for our app. It’s good to have some Node skills so you could potentially build your own little backend from time to time. First of all we create a new folder and inside an NPM package file, where we also install Express as a minimal framework for our backend:
mkdir SocketServer && cd SocketServer npm init npm install --save express socket.io
After creating and installing you should have a package.json inside that file. Make sure inside that file the main file is set to index.js so the scripts knows which file to start!
{ "name": "socket-server", "version": "1.0.0", "main": "index.js", "dependencies": { "express": "^4.15.3", "socket.io": "^2.0.3" } }
Finally we got the actual index.js which contains the logic of our server. As said before, we stay really low here and just implement some basic socket functions!
All of our functions are wrapped inside the io.on('connection') block, so these will only happen once a client connects to the server.
We set a function for the events disconnect, set-nickname and add-message which means whenever our app sends out these events the server does something.
If we send a new message, we emit that message to everyone connected as a new object with text, the name of the sending user and a date. Also, we set the name of the socket connection if a users send his nickname.
Finally if a user disconnects, we inform everyone that somebody just left the room. Put all of that code into your index.js:
let app = require('express')(); let http = require('http').Server(app); let io = require('socket.io')(http); io.on('connection', (socket) => { socket.on('disconnect', function(){ io.emit('users-changed', {user: socket.nickname, event: 'left'}); }); socket.on('set-nickname', (nickname) => { socket.nickname = nickname; io.emit('users-changed', {user: nickname, event: 'joined'}); }); socket.on('add-message', (message) => { io.emit('message', {text: message.text, from: socket.nickname, created: new Date()}); }); }); var port = process.env.PORT || 3001; http.listen(port, function(){ console.log('listening in http://localhost:' + port); });
Your node backend with Socket.io is now ready! You can start it by running the command below and you should be able to reach it at http://localhost:3001
node index.js
Starting the Ionic Chat App
Inside our Ionic chat app we need 2 screens: On the first screen we will pick a name and join the chat, on the second screen is the actual chatroom with messages.
First of all we create a blank new Ionic app and install the ng-socket-io package to easily connect to our Socket backend, so go ahead and run:
ionic start devdacticSocket blank cd devdacticSocket npm install ng-socket-io --save ionic g page chatRoom
Now make sure to add the package to our src/app/app.module.ts and pass in your backend URL as a parameter:
import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { SocketIoModule, SocketIoConfig } from 'ng-socket-io'; const config: SocketIoConfig = { url: 'http://localhost:3001', options: {} }; @NgModule({ declarations: [ MyApp, HomePage ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), SocketIoModule.forRoot(config) ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler} ] }) export class AppModule {}
Your app is now configured to use the backend, so make sure to run the backend when launching your app!
Joining a Chatroom
First of all a user needs to pick a name to join a chatroom. This is just an example so we can actually show who wrote which message, so our view consists of the input field and a button to join the chat. Open your src/pages/home/home.html and change it to:
<ion-header> <ion-navbar> <ion-title> Join Chat </ion-title> </ion-navbar> </ion-header> <ion-content padding> <ion-item> <ion-label stacked>Set Nickname</ion-label> <ion-input type="text" [(ngModel)]="nickname" placeholder="Nickname"></ion-input> </ion-item> <button ion-button full (click)="joinChat()" [disabled]="nickname === ''">Join Chat as </button> </ion-content>
Inside the class for this view we have the first interaction with Socket. Once we click to join a chat, we need to call connect() so the server recognises a new connection. Then we emit the first message to the server which is to set our nickname.
Once both of this happened we push the next page which is our chatroom, go ahead and change your src/pages/home/home.ts to:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { Socket } from 'ng-socket-io'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { nickname = ''; constructor(public navCtrl: NavController, private socket: Socket) { } joinChat() { this.socket.connect(); this.socket.emit('set-nickname', this.nickname); this.navCtrl.push('ChatRoomPage', { nickname: this.nickname }); } }
If you put in some logs you should now already receive a connection and the event on the server-side, but we haven’t added the actual chat functionality so let’s do this.
Building the Chat functionality
To receive new chat messages inside the room we have a function getMessages() which returns an observable. Also, this message listens to Socket events of the type ‘message’ and always calls next() on the observable to pass the new value through.
Whenever we get such a message we simply push the new message to an array of messages. Remember, we are not loading historic data, we will only get messages that come after we are connected!
Sending a new message is almost the same like setting a nickname before, we simply emit our event to the server with the right type.
Finally, we also subscribe to the events of users joining and leaving the room and display a little toast whenever someone comes in or leaves the room. It’s the same logic again, with the socket.on() we can listen to all the events broadcasted from our server!
Go ahead and change your app/pages/chat-room/chat-room.ts to:
import { Component } from '@angular/core'; import { NavController, IonicPage, NavParams, ToastController } from 'ionic-angular'; import { Socket } from 'ng-socket-io'; import { Observable } from 'rxjs/Observable'; @IonicPage() @Component({ selector: 'page-chat-room', templateUrl: 'chat-room.html', }) export class ChatRoomPage { messages = []; nickname = ''; message = ''; constructor(private navCtrl: NavController, private navParams: NavParams, private socket: Socket, private toastCtrl: ToastController) { this.nickname = this.navParams.get('nickname'); this.getMessages().subscribe(message => { this.messages.push(message); }); this.getUsers().subscribe(data => { let user = data['user']; if (data['event'] === 'left') { this.showToast('User left: ' + user); } else { this.showToast('User joined: ' + user); } }); } sendMessage() { this.socket.emit('add-message', { text: this.message }); this.message = ''; } getMessages() { let observable = new Observable(observer => { this.socket.on('message', (data) => { observer.next(data); }); }) return observable; } getUsers() { let observable = new Observable(observer => { this.socket.on('users-changed', (data) => { observer.next(data); }); }); return observable; } ionViewWillLeave() { this.socket.disconnect(); } showToast(msg) { let toast = this.toastCtrl.create({ message: msg, duration: 2000 }); toast.present(); } }
The last missing part is now the view for the chatroom. We have to iterate over all of our messages and distinguish if the message was from us or another user. Therefore, we create 2 different ion-col blocks as we want our messages to have some offset to a side. We could also do this only with CSS but I like using the Ionic grid for styling as far as possible.
With some additional styling added to both our and other people’s messages the chatroom will look almost like iMessages or any familiar chat application, so open your src/pages/chat-room/chat-room.html and insert:
<ion-header> <ion-navbar> <ion-title> Chat </ion-title> </ion-navbar> </ion-header> <ion-content> <ion-grid> <ion-row *ngFor="let message of messages"> <ion-col col-9 *ngIf="message.from !== nickname" class="message" [ngClass]="{'my_message': message.from === nickname, 'other_message': message.from !== nickname}"> <span class="user_name">:</span><br> <span></span> <div class="time"></div> </ion-col> <ion-col offset-3 col-9 *ngIf="message.from === nickname" class="message" [ngClass]="{'my_message': message.from === nickname, 'other_message': message.from !== nickname}"> <span class="user_name">:</span><br> <span></span> <div class="time"></div> </ion-col> </ion-row> </ion-grid> </ion-content> <ion-footer> <ion-toolbar> <ion-row class="message_row"> <ion-col col-9> <ion-item no-lines> <ion-input type="text" placeholder="Message" [(ngModel)]="message"></ion-input> </ion-item> </ion-col> <ion-col col-3> <button ion-button clear color="primary" (click)="sendMessage()" [disabled]="message === ''"> Send </button> </ion-col> </ion-row> </ion-toolbar> </ion-footer>
Below our messages we also have the footer bar which holds another input to send out messages, nothing really fancy.
To make the chat finally look like a chat, add some more CSS to your src/pages/chat-room/chat-room.scss:
page-chat-room { .user_name { color: #afafaf; } .message { padding: 10px !important; transition: all 250ms ease-in-out !important; border-radius: 10px !important; margin-bottom: 4px !important; } .my_message { background: color($colors, primary) !important; color: #000 !important; } .other_message { background: #dcdcdc !important; color: #000 !important; } .time { color: #afafaf; float: right; font-size: small; } .message_row { background-color: #fff; } }
Now launch your app and make sure your backend is up and running!
For testing, you can open a browser and another incognito browser like in my example at the top to chat with yourself.
Conclusion
Don’t be scared of Socket.io and a Node backend, you can easily implement your own realtime backend connection without any problems! Firebase seems often like the easy alternative, but actually we were able to build a live chat app with only a super small backend.
To make this a real chat you might want to add a database and store all the messages once you receive them and add some routes to return the history of a chatroom. Or you might want to create different chatrooms and separate conversations, but this post could be the starting point to your own chat implementation!
You can watch a video version of this article below.
Happy Coding, Simon
The post Ionic Realtime Chat with Socket.io appeared first on Devdactic.
via Devdactic http://ift.tt/2w0ywjy
0 notes
Text
BULK SMS MARKETING FOR ADVERTISING AGENCIES
Bulk SMS marketing is a need of every industry.It provides you the efficient way to reach your customers or clients.Its a powerful tool in for Advertising agencies.If you have Marketing or advertising Agency,you know how competitive your industry is there are several distinct advantages to reaching out to your audience via text message.Text messages help you acquire loyal customers and repeat business.
Bulk sms also gives you the ability to reach to your client or customers base whenever you want. You can also offer them special promotions and announce new services.
Know more bulk sms service please visit: www.emssgo.com or mail us: [email protected]
0 notes
Text
mattata's Channel's Post @ February 26, 2017 at 08:07PM
local api = require('mattata-api.core').configure('') -- Enter your token function api.on_message(message) if message.text then return api.send_message(message, message.text) end end api.run()
By: Matt via mattata's Channel
0 notes