How do I run/execute an instance of a node file by providing some parameters from another programs by knowing the location and content of file.
When I add a device from my web application which also run on node (adonis js), it create a device with provided params like, device_name, type, lat, lng etc. when device successful added, an instance or copy of the following code should starts automatically with provided params when device was added.
file which need to started with given parameters
// c:/device/test.js
var mqtt = require('mqtt');
function UserModule() {
var client = mqtt.connect('mqtt://test.mosquitto.org');
client.on('connect', function () {
let latitude = 777
let lngitude = 999
setInterval(function() {
let device_data = {
'device_name':'{params.devcie_name}',
'topic_topic':'MyProject/{params.type_of_device}/{params.user_id}/{params.topic_name}',
'type':'GPS',
'data':{
'lat':'35.'+latitude++,
'lng':'-74.'+lngitude++,
'alt':22,
'acc':25.10101,
'name': 'my car2',
'type': 'car'
},
'status': 'OK'
}
client.publish(device_data.topic_topic, JSON.stringify(device_data));
console.log('data published for', device_data.device_name);
}, 1000);
});
}
module.exports = UserModule;
controller for adding device
//app/controllers/http/devicecontroller.js
async store({ params, request, response, view, session, auth }) {
try {
const deviceData = request.only(['cat_id', 'device_name', 'type', 'device_type_id'])
deviceData.device_owner_id = auth.current.user.id
deviceData.is_deleted = 0
deviceData.is_active = 1
const device = new Device();
let rules = Config.get('rules.device')
let messages = Config.get('messages.device')
const validation = await validate(deviceData, rules, messages)
if (validation.fails()) {
console.log(JSON.stringify(validation.messages()))
session.flash({ type: 'danger', message: validation.messages()[0].message })
return response.redirect('back')
}
let dev = await deviceService.addDevice(deviceData);
session.flash({ type: 'success', message: 'Device added successfully' })
//here to run a code which execute that file
//sudo-code
File f = new File('c:/device/test.js')
let content = await f.readAll()
content = string.format(content, params1, params2, params3..)
f.content = content;
f.eecute()
return response.redirect('/dashboard/device-manage')
} catch (error) {
session.flash({ type: 'danger', message: error.message })
return response.redirect('back')
}
}
Ho I execute the code every time when I add a device, every time with new parameters, means executing same file with new instance with new parameters.
To start a new process, use the node package child_process
https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options
To send messages to that child_process, use child_process.fork
const cp = require('child_process');
const n = cp.fork(`${__dirname}/sub.js`);
n.on('message', (m) => {
console.log('PARENT got message:', m);
});
// Causes the child to print: CHILD got message: { hello: 'world' }
n.send({ hello: 'world' });
https://nodejs.org/api/child_process.html#child_process_subprocess_send_message_sendhandle_options_callback
Related
I have been encountering an issue for a long time but I haven't found any solution yet, despite reading the protocol version 5 standard and the emqx documentation.
I want to publish messages with a time limit to simulate a situation where my device is unavailable so that, after the time limit has expired, the broker will delete the message and my device will not receive it.
I want the reason that my device will not be available (and therefore will not receive messages), to be because it is in a closed area, like a tunnel, or in a area with no cellular cove-range and not because it initiated a disconnect from the broker or because the “keepalive” value has expired.
My understanding is that I can use the “messageExpiryInterval” property (in protocol 5) to implement my goal.
I used EMQX broker as follows:
const connectUrl = 'mqtt://broker.emqx.io:1883';
Along with the following connection configuration:
const client = mqtt.connect(connectUrl, {
clientId: 'mqtt_dani_pub',
protocolVersion: 5,
keepalive: 1800,
clean: true
});
And when sending a message, I put the following values:
const options = {
qos: 0,
retain: false,
properties: { messageExpiryInterval: 30 }
};
As you can see, I used a high value, 1800, for “keepalive” to ensure that the device will be connected to the broker for a long time.
To simulate this situation, I used one publisher on one PC, and one subscriber on another PC.
The scenario is as follows:
Connect publisher and subscriber to emqx broker
a. Verify MQTT v5 protocol.
Publish the message (when the subscriber is connected) to emqx with MessageExpiryInterval: 30
a. Subscribe receive the message
Turn OFF the Wi-Fi on the subscriber computer.
Publish the message to emqx with MessageExpiryInterval: 30
Wait for 120 seconds
Turn ON the Wi-Fi on the subscriber computer.
a. Subscriber does not receive the message ==> but it does get the message!
In addition to this, I saw in the standard of protocol 5 section 3.3.2.3.3 (Message Expiry Interval - https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.pdf ) that the PUBLISH packet sent to a Client by the Server MUST contain a Message Expiry Interval set to the received value minus the time that the Application Message has been waiting in the Server, so this may be the problem.
my publisher js code:
import mqtt, { MqttClient } from 'mqtt';
import * as readline from 'node:readline'
import { stdin, stdout } from 'process';
const connectUrl = 'mqtt://broker.emqx.io:1883';
const clientId = 'mqtt_dani_pub';
const topic = 'dani/test';
const subject = 'Publisher';
const rl = readline.createInterface({
input:stdin,
output:stdout
});
const client = mqtt.connect(connectUrl, {
clientId,
protocolVersion: 5,
keepalive: 1800,
clean: true
});
client.on('connect', () => {
console.log(`${subject} client connected..`)
client.subscribe([topic], () => {
console.log(`Subscribe to topic '${topic}'`);
})
});
const options = {
qos: 0,
retain: false,
properties: { messageExpiryInterval: 30 }
};
const publishMsg = (message) => {
client.publish(topic,
`${clientId} - ${Date.now()} - ${message}`,
options,
(error) => {
if (error) {
console.error(error)
}
}
);
};
const input2topic = () => {
return new Promise(resolve => {
rl.question(`send message to topic ${topic}: `,
(input) => {
if(input !== 'exit'){
console.log(`writing to topic ${topic}..`);
publishMsg(input);
resolve(true);
} else{
console.log('exit...');
resolve(false);
}
});
});
}
const main = async () => {
publishMsg('first message');
let flag = true;
while(flag){
await new Promise(resolve => setTimeout(resolve, 1000));
flag = await input2topic();
}
rl.close();
client.end();
}
main();
my subscriber js code:
import mqtt, { MqttClient } from 'mqtt';
const connectUrl = 'mqtt://broker.emqx.io:1883';
const clientId = 'mqtt_dani_sub';
const topic = 'dani/test';
const subject = 'Subscriber';
const client = mqtt.connect(connectUrl, {
clientId,
keepalive: 1800,
protocolVersion: 5,
})
client.on('connect', () => {
console.log(`${subject} client connected`)
client.subscribe([topic], {qos: 0}, () => {
console.log(`Subscribe to topic '${topic}'`)
})
});
client.on('message', (topic, payload, packet) => {
console.log('\nReceived Message:', {
...packet,
message: payload.toString(),
msg_length: payload.toString().length,
time: new Date(),
});
});
I have an OPC-UA server up and running with some pre-configured tags, now I want to add a new Variable from my NodeJS OPC-UA client when my certain tag changes.
For e.g.
import {
OPCUAClient,
MessageSecurityMode, SecurityPolicy,
AttributeIds,
} from "node-opcua-client";
const connectionStrategy = {
initialDelay: 1000,
maxRetry: 1
}
const options = {
applicationName: "MyClient",
connectionStrategy: connectionStrategy,
securityMode: MessageSecurityMode.SignAndEncrypt,
securityPolicy: SecurityPolicy.Basic256Sha256,
endpointMustExist: false,
};
const client = OPCUAClient.create(options);
const endpointUrl = "{opc_url}";
try {
// step 1 : connect to
await client.connect(endpointUrl).then(res => console.log('connected!'))
// console.log("connected !");
// step 2 : createSession
await client.createSession({userName: "user_name", password: "password"}, async (err, session) => {
if(err){
console.log(err)
}
if(!err){
// do something
}
}
}
Above in the do something part I tried:
var nodeId = "nodeId";
var nodesToWrite = [{
nodeId: nodeId,
attributeId: AttributeIds.Value,
value: /*new DataValue(*/{
value: {/* Variant */
dataType: 1,
value: false
}
}
}];
session.write(nodesToWrite, (err, statusCodes) => {
if(!err){
console.log("success", statusCodes);
} else {
console.log(err, statusCodes)
}
}
);
But since the nodeId doesn't exist so it will throw the error that it doesn't exist.
I found a snippet example to add variables from the server-side, but is it possible to do it from the client's side as we want to add some variables based on the other variables which I am monitoring from the client's side.
Please see the link
https://reference.opcfoundation.org/Core/docs/Part4/5.7.2/
And check with SDK/Server vendor, whether they support NodeManagement Service Set or not.
If yes, you can find a method in the session context like
session.addNodes()
Reading this docs https://www.twilio.com/blog/implementing-programmable-chat-php-laravel-vue-js
I try to add in my Laravel 8 / jQuery 3.5.1 / vue 2.6 / Bootstrap 4.5
chat when logged user select another user I run axios request to check if channel was
created priorly(or create a new channel). On client part
connectClientWithUsername(){
this.tc.username = this.loggedUser.name
let vm = this;
axios.post('/admin/team-chat/check_channel', {
sender_id : vm.loggedUser.id,
receiver_id : vm.selectedTeamUser.id
})
.then(({data}) => {
console.log('check_channel data::')
console.log(data)
vm.newChartCreated= data.newChartCreated // Flag if new chat was created
vm.currentChatChannelName= data.currentChatChannelName // Name of requested channel
vm.fetchAccessToken(vm.tc.username, vm.connectMessagingClient);
})
.catch(error => {
console.error(error)
popupAlert('Team Chat', error.response.data.message, 'warn')
vm.is_page_loaded = true
})
},
fetchAccessToken(username, handler) {
let vm = this;
axios.post('/token', {
identity: this.tc.username,
device: 'browser'
})
.then(function (response) {
handler(response.data);
})
.catch(function (error) {
console.log(error);
});
},
And on server part in app/Http/Controllers/Admin/TeamChatController.php:
public function check_channel(Request $request)
{
$requestData = $request->all();
$chatName= "public_oo_team_chat_" . $requestData['sender_id'] . '_' . $requestData['receiver_id'];
$newChartCreated = false;
$chatChannel = null;
try {
$channel = $this->twilio->chat->v2->services(config('app.TWILIO_SERVICE_SID'))
->channels($chatName)
->fetch();
} catch(RestException $e) {
$channel = $this->twilio->chat->v2->services(config('app.TWILIO_SERVICE_SID'))
->channels->create([
'uniqueName' => $chatName,
'friendlyName' => $chatName,
'type' => 'public' // New channel was created
]);
if($channel->sid) {
$chatChannel= new ChatChannel(); // Ref to newly created channel was saved in db
$chatChannel->sender_id= $requestData['sender_id'];
$chatChannel->receiver_id= $requestData['receiver_id'];
$chatChannel->channel_name= $chatName;
$chatChannel->last_chat_at= Carbon::now(config('app.timezone'));
$chatChannel->save();
}
$newChartCreated= true;
}
return response()->json([
'message' => '',
'chatChannel' => $chatChannel,
'newChartCreated' => $newChartCreated, // return name of current Channel
'currentChatChannelName' => $chatName], HTTP_RESPONSE_OK);
} // check_channel
public function getToken(Request $request)
{
$this->identity = $request->identity;
$token = new AccessToken(
$this->twilio_account_sid,
$this->twilio_api_key,
$this->twilio_api_secret,
3600,
$this->identity
);
// Create Chat grant
$chat_grant = new ChatGrant();
$chat_grant->setServiceSid($this->service_sid);
// Add grant to token
$token->addGrant($chat_grant);
// render token to string
echo $token->toJWT();
}
and I when I get token from server I create client and try to conect to channel
connectMessagingClient(token) { // connects the user to the Twilio Chat client.
// Initialize the Chat messaging client
let vm = this;
this.tc.accessManager = new Twilio.AccessManager(token);
new Twilio.Chat.Client.create(token).then(function(client) {
vm.tc.messagingClient = client;
vm.updateConnectedUI();
vm.connectToActiveChannel(client) // I try to connect to channel I need
// vm.tc.messagingClient.on('channelAdded', _.throttle(vm.loadChannelList));
// vm.tc.messagingClient.on('channelRemoved', _.throttle(vm.loadChannelList));
// vm.tc.messagingClient.on('tokenExpired', vm.refreshToken);
});
},
connectToActiveChannel(messagingClient) {
let vm = this
// Get all public channels
messagingClient.getPublicChannelDescriptors().then(function(channels) {
for (let i = 0; i < channels.items.length; i++) {
const channel = channels.items[i];
}
vm.tc.channelArray = channels.items;
vm.tc.channelArray.forEach(vm.addChannel); // Check for selected channel
});
},
addChannel(channel){
console.log('addChannel channel::')
console.log(typeof channel)
if (channel.uniqueName === this.currentChatChannelName) {
this.tc.generalChannel = channel;
console.log('FOUND this.tc.generalChannel!!!')
console.log( this.tc.generalChannel )
return this.joinChannel(channel);
}
},
joinChannel(_channel) { // the member joins the channel (general or a personally created channel)
console.log(" joinChannel _channel");
console.log(_channel);
let vm = this;
return _channel.join()
.then(function(joinedChannel) {
console.log('Joined channel ' + joinedChannel.friendlyName);
vm.updateChannelUI(_channel);
vm.tc.currentChannel = _channel;
vm.loadMessages();
return joinedChannel;
})
.catch(function(err) {
alert("Couldn't join channel " + _channel.friendlyName + ' because ' + err);
});
},
and in joinChannel I got error :
vue.common.dev.js?4650:630 [Vue warn]: Error in render: "TypeError: Converting circular structure to JSON
--> starting at object with constructor 'l'
| property '_fsm' -> object with constructor 'o'
--- property 'context' closes the circle"
on line:
return _channel.join()
I see in the browser's console :
https://prnt.sc/wekctp
and
https://prnt.sc/wekspu
Looks like there is an error in my flow, but it seems to me that I passwed valid object to line :
_channel.join
Why error and how it can be fixed?
Thanks!
Twilio developer evangelist here.
In this code:
connectToActiveChannel(messagingClient) {
let vm = this
// Get all public channels
messagingClient.getPublicChannelDescriptors().then(function(channels) {
for (let i = 0; i < channels.items.length; i++) {
const channel = channels.items[i];
}
vm.tc.channelArray = channels.items;
vm.tc.channelArray.forEach(vm.addChannel); // Check for selected channel
});
}
This line doesn't seem to do anything (it iterates over the list of channel descriptors, creating a new channel const for each of them, but then immediately discarding it.
Then, you set the vm.tc.channelArray to the list of channel descriptors and call vm.addChannel for each of the descriptors.
Note here that getPublicChannelDescriptors() returns a list of ChannelDescriptor objects. ChannelDescriptors cannot be joined and contain a snapshot of data about a channel at the time it was requested.
To join a channel, you would need to first call getChannel() on the channel descriptor first, then perform the rest of your code.
Let me know if that helps.
I apologize if this is unclear, it's late and I don't know how best to explain it.
I'm using an event emitter to pass data from a server response to a function inside of a separate class in another file, but when trying to use methods in those classes, the this keyword obviously doesn't work (because in this scenario, this refers to the server event emitter) - how would I reference a function within the class itself? I've provided code to help illustrate my point a bit better
ServiceClass.js
class StreamService {
/**
*
* #param {} database
* #param {Collection<Guild>} guilds
*/
constructor (database, guilds,) {
.....
twitchListener.on('live', this.sendLiveAlert) // fire test method when we get a notification
// if there are streamers to monitor, being monitoring
winston.info('Stream service initialized')
}
..............
async get (url, params = null, headers = this.defaultHeaders) {
// check oauth token
const expirationDate = this.token.expires_in || 0
if (expirationDate <= Date.now() || !this.token) await this.getAccessToken()
// build URL
const index = 0
let paramsString = ''
for (const [key, value] of params.entries()) {
if (index === 0) {
paramsString += `?${key}=${value}`
} else {
paramsString += `&${key}=${value}`
}
}
const res = await fetch(url + paramsString, { method: 'GET', headers: headers })
if (!res.ok) {
winston.error(`Error performing GET request to ${url}`)
return null
}
return await res.json()
}
async sendLiveAlert(streamTitle, streamURL, avatar, userName, gameId, viewerCount, thumbnail, startDateTime) {
// get game name first (no headers needed)
const params = new Map()
params.set('id', gameId)
const gameData = await this.get('https://api.twitch.tv/heliix/games', params, this.defaultHeaders)
if(gameData) {
// get webhook and send message to channel
const webhookClient = new WebhookClient('755641606555697305', 'OWZvI01kUUf4AAIR9uv2z4CxRse3Ik8b0LKOluaOYKmhE33h0ypMLT0JJm3laomlZ05o')
const embed = new MessageEmbed()
.setTitle(`${userName} just went live on Twitch!`)
.setURL(streamURL)
.setThumbnail(avatar)
.addFields(
{ name: 'Now Playing', value: gameData.data[0].name },
{ name: 'Stream Title', value: streamTitle }
)
.setImage(thumbnail)
}
webhookClient.send('Webhook test', embed)
}
}
Server.js
class TwitchWebhookListener extends EventEmitter {
......................
// Routes
server
.post((req, res) => {
console.log('Incoming POST request on /webhooks')
............................
const data = req.body.data[0]
if(!this.streamerLiveStatus.get(data.user_id) && data.type === 'live') {
// pass request body to bot for processing
this.emit(
'live',
data.title, // stream title
`https://twitch.tv/${data.user_name}`, // channel link
`https://avatar.glue-bot.xyz/twitch/${data.user_name}`, // streamer avatar
data.user_name,
data.game_id,
data.viewer_count,
data.thumbnail_url,
data.started_at // do we need this?
)
}
break
default:
res.send(`Unknown webhook for ${req.params.id}`)
break
}
} else {
console.log('The Signature did not match')
res.send('Ok')
}
} else {
console.log('It didn\'t seem to be a Twitch Hook')
res.send('Ok')
}
})
}
}
const listener = new TwitchWebhookListener()
listener.listen()
module.exports = listener
Within the sendLiveAlert method, I'm trying to call the get method of the StreamService class - but because it's called directly via the emitter within server.js, this refers specifically to the Server.js class - is there any way I can use StreamService.get()? I could obviously just rewrite the code inside the method itself, but that seems unnecessary when its right there?
Change this:
twitchListener.on('live', this.sendLiveAlert)
to this:
twitchListener.on('live', this.sendLiveAlert.bind(this))
Or, you could also do this:
twitchListener.on('live', (...args) => {
this.sendLiveAlert(...args);
});
With .bind() it creates a function wrapper that resets the proper value of this for you. In the case of the arrow function, it preserves the lexical value of this for you.
First of all please note that this is not about creating a bot.
My goal is to create an application that will simply listen to any number of telegram channels that the account I will provide it with is subscribed to and retrieve all messages sent to those channels (as if I was a normal user). My guess is that I will need to
Authenticate myself using my account's phone number
Be able to setup a callback listener either per channel or a general listener for all incoming messages
I've been looking around the telegram api for a couple of days now and I am extremely confused as to how it works. After giving up on it, I started looking at readymade implementations, mostly for NodeJS but was still not able to find a concrete solution. I'm testing some things with the telegram-js api but running it directly using node didn't work. Does it need to run in a browser? Is there any more streamlined approach to this? Preferably something with good documentation.
PS: I'm fluent in Java and Javascript mostly so I've prioritized libraries based on those languages.
EDIT:
Here is the code that I've written (essentially copied an example)
var { Telegram } = require("../libs/telegram");
var TypeLanguage = require("telegram-tl-node") ;
var MTProto = require("telegram-mt-node");
var schema = require("../libs/api-schema.json");
const APP_ID = "111111";
const APP_HASH = "fb6da8f6abdf876abd6a9d7bf6";
const SERVER = { host: "111.111.111.11", port: "443" };
const config = {
id: APP_ID,
hash: APP_HASH,
version: '0.0.1',
lang_code: 'en',
authKey: null
};
let telegram = new Telegram(MTProto, TypeLanguage);
telegram.useSchema(schema);
addPublicKeys(telegram);
let connection = new MTProto.net.HttpConnection(SERVER);
let client = telegram.createClient();
client.setConnection(connection);
connection.connect(function() {
let ready = client.setup(config);
ready.then(function(client) {
// it never resolves this promise
function callback(response) {
console.log(response);
}
client.callApi("help.getConfig").then(callback, callback);
});
});
It uses those 2 libs:
telegram-mt-node
telegram-tl-node
Late answer but might help others.
You can utilize mtproto-core to authenticate with a regular telegram account and listen to updates (or do anything you can with telegram clients, really)
Here is a sample script I've written that listens to new messages from channels/supergroups the user is subscribed to:
const { MTProto, getSRPParams } = require('#mtproto/core');
const prompts = require('prompts');
const api_id = ...; // insert api_id here
const api_hash = ' ... '; // insert api_hash here
async function getPhone() {
return (await prompts({
type: 'text',
name: 'phone',
message: 'Enter your phone number:'
})).phone
}
async function getCode() {
// you can implement your code fetching strategy here
return (await prompts({
type: 'text',
name: 'code',
message: 'Enter the code sent:',
})).code
}
async function getPassword() {
return (await prompts({
type: 'text',
name: 'password',
message: 'Enter Password:',
})).password
}
const mtproto = new MTProto({
api_id,
api_hash,
});
function startListener() {
console.log('[+] starting listener')
mtproto.updates.on('updates', ({ updates }) => {
const newChannelMessages = updates.filter((update) => update._ === 'updateNewChannelMessage').map(({ message }) => message) // filter `updateNewChannelMessage` types only and extract the 'message' object
for (const message of newChannelMessages) {
// printing new channel messages
console.log(`[${message.to_id.channel_id}] ${message.message}`)
}
});
}
// checking authentication status
mtproto
.call('users.getFullUser', {
id: {
_: 'inputUserSelf',
},
})
.then(startListener) // means the user is logged in -> so start the listener
.catch(async error => {
// The user is not logged in
console.log('[+] You must log in')
const phone_number = await getPhone()
mtproto.call('auth.sendCode', {
phone_number: phone_number,
settings: {
_: 'codeSettings',
},
})
.catch(error => {
if (error.error_message.includes('_MIGRATE_')) {
const [type, nextDcId] = error.error_message.split('_MIGRATE_');
mtproto.setDefaultDc(+nextDcId);
return sendCode(phone_number);
}
})
.then(async result => {
return mtproto.call('auth.signIn', {
phone_code: await getCode(),
phone_number: phone_number,
phone_code_hash: result.phone_code_hash,
});
})
.catch(error => {
if (error.error_message === 'SESSION_PASSWORD_NEEDED') {
return mtproto.call('account.getPassword').then(async result => {
const { srp_id, current_algo, srp_B } = result;
const { salt1, salt2, g, p } = current_algo;
const { A, M1 } = await getSRPParams({
g,
p,
salt1,
salt2,
gB: srp_B,
password: await getPassword(),
});
return mtproto.call('auth.checkPassword', {
password: {
_: 'inputCheckPasswordSRP',
srp_id,
A,
M1,
},
});
});
}
})
.then(result => {
console.log('[+] successfully authenticated');
// start listener since the user has logged in now
startListener()
});
})
You can find the values for api_id and api_hash from https://my.telegram.org.
On the first run the script prompts the user for phone_number, code, and password.
[+] You must log in
√ Enter your phone number: ... <phone_number>
√ Enter the code sent: ... <code>
√ Enter Password: ... <2FA password>
and after the authentication is over
a sample run outputs:
[+] starting listener
[13820XXXXX] Ja
[13820XXXXX] Bis bald guys��
[13820XXXXX] Ja. �
[13820XXXXX] Bis später
[13820XXXXX] Jaaa�
The way I've checked the authentication status was taken from here.
Alternative libraries worth checking out that are active the time of writing (and can be used to create the same behavior with): Airgram (tdlib) and GramJs
I used gram.js library and essentially did this:
import { TelegramClient } from 'telegram'
TelegramClient().addEventHandler(handler, { chats: [1234567890] })
The bot does NOT need to be a member of the channel you want to listen to.
My code runs as a Node.js app.
You need to first create a token by talking to #BotFather with Telegram.
here is my working code by using gramjs and its purely on nodejs.
Getting all the messages from all the channels without any delay's.
import {
TelegramClient
} from "telegram";
import {
NewMessage,
NewMessageEvent
} from "telegram/events";
import {
StringSession
} from "telegram/sessions";
const input = require("input");
const apiId = 1233456677;
const apiHash = "xxxxxxxxxxxxxxxxx";
let stringSession = new StringSession("xxxxxxxxxxxxxxxxx");
(async() => {
console.log("Loading interactive example...");
const client = new TelegramClient(stringSession, apiId, apiHash, {
connectionRetries: 5,
});
await client.start({
phoneNumber: async() => await input.text("Please enter your number: "),
password: async() => await input.text("Please enter your password: "),
phoneCode: async() =>
await input.text("Please enter the code you received: "),
onError: (err) => console.log(err),
});
console.log("You should now be connected.");
const session: any = client.session.save();
stringSession = new StringSession(session); // Save this string to avoid logging in again - specially in nodemon
console.log(client.session.save()); // --> you can also copy this session from your console once you get it and paste it in line number 8 - new StringSession("XXXXXXXXXXXXXX")
// once you saved add the JWT Token on line no. 8 as mention above next time you will getting directly connected.
await client.sendMessage("me", {
message: "Hello!"
});
async function handler(event: NewMessageEvent) {
console.log("[newmessage]", event);
}
client.addEventHandler(handler, new NewMessage({}));
})();
Note - Ignore the "Run Code Snippet" as found it best way to add whole code instead of formatting.
You can use the gram.js library in the following way:
Install these:
npm install properties-reader
npm install telegram
npm install input
Then get your apiId and apiHash from Telegram Auth in the App Configuration section.
Create a file config.properties with a content similar to that:
[telegram]
apiId=12345678
apiHash=12345678901234567890123456789012
Inside of your nodejs code you can listen to a specific chat like this (see chatId inside of the code below):
const PropertiesReader = require('properties-reader');
const configs = PropertiesReader('config.properties');
getProp = (bundle, key) => {return configs.get(`${bundle}.${key}`);}
const { TelegramClient } = require("telegram");
const { StoreSession } = require("telegram/sessions");
const { NewMessage } = require("telegram/events");
const { EditedMessage } = require("telegram/events/EditedMessage");
const input = require("input");
const apiId = getProp("telegram", "apiId")
const apiHash = getProp("telegram", "apiHash")
const storeSession = new StoreSession("telegram_session"); // see: https://painor.gitbook.io/gramjs/getting-started/authorization#store-session
(async () => {
console.log("Loading interactive example...");
const client = new TelegramClient(storeSession, apiId, apiHash, {
connectionRetries: 5,
});
await client.start({
phoneNumber: async () => await input.text("Please enter your number: "),
password: async () => await input.text("Please enter your password: "),
phoneCode: async () =>
await input.text("Please enter the code you received: "),
onError: (err) => console.log(err),
});
console.log("You should now be connected.");
client.session.save(); // Save the session to avoid logging in again
async function eventPrint(event) {
// see 'node_modules/telegram/tl/custom/message.d.ts'
const message = event.message
const isNew = message.editDate === undefined
const text = message.text
const date = new Date(message.date*1000)
console.log(`The message is ${isNew ? 'new' : 'an update'}`)
console.log(`The text is: ${text}`)
console.log(`The date is: ${date}`)
}
// to get the chatId:
// option 1: open telegram on a web browser, go to the chat, and look the url in the address bar
// option 2: open telegram app, copy link to any message, it should be something like: https://t.me/c/1234567890/12345, the first number after "/c/" is the chatId
const chatId = 1234567890
client.addEventHandler(eventPrint, new NewMessage({ chats: [chatId] }));
client.addEventHandler(eventPrint, new EditedMessage({ chats: [chatId] }));
})();