Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Separate relevant parts into their own "mixin" classes / continue adding missing pieces #25

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"node": true,
"jest": true
},
"extends": ["google","eslint:recommended"],
"extends": ["eslint:recommended"],
"globals": {
"BigInt": true,
"Atomics": "readonly",
Expand All @@ -16,8 +16,17 @@
"ecmaVersion": 2018
},
"rules": {
"semi": [1,"never"],
"arrow-parens": ["error", "as-needed"],
"brace-style": ["error", "1tbs"],
"comma-dangle": ["error", "always-multiline"],
"curly": ["error", "all"],
"indent": ["error", 4],
"linebreak-style": ["error", "unix"],
"no-var": "error",
"operator-linebreak": ["error", "after"],
"prefer-const": ["error", { "destructuring": "all" }],
"quotes": ["error", "single", { "avoidEscape": true }],
"semi": ["error", "never"],
"max-len": [
"error",
{
Expand All @@ -26,9 +35,6 @@
"ignoreStrings": true,
"ignoreTemplateLiterals": true
}
],
"object-curly-spacing": ["error", "always"],
"require-jsdoc": "off",
"valid-jsdoc": "off"
]
}
}
58 changes: 29 additions & 29 deletions examples/betterLogging.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
/* eslint-env browser */

rewireLoggingToElement(
() => document.getElementById("log"),
() => document.getElementById("log-container"),
true
);
() => document.getElementById('log'),
() => document.getElementById('log-container'),
true,
)

function rewireLoggingToElement(eleLocator, eleOverflowLocator, autoScroll) {
fixLoggingFunc("log");
fixLoggingFunc('log')

function fixLoggingFunc(name) {
console.old = console.log
console.log = function(...arg) {
const output = produceOutput(name, arg);
const eleLog = eleLocator();
function fixLoggingFunc(name) {
console.old = console.log
console.log = function(...arg) {
const output = produceOutput(name, arg)
const eleLog = eleLocator()

if (autoScroll) {
const eleContainerLog = eleOverflowLocator();
const isScrolledToBottom =
if (autoScroll) {
const eleContainerLog = eleOverflowLocator()
const isScrolledToBottom =
eleContainerLog.scrollHeight - eleContainerLog.clientHeight <=
eleContainerLog.scrollTop + 1;
eleLog.innerHTML += output + "<br>";
if (isScrolledToBottom) {
eleContainerLog.scrollTop =
eleContainerLog.scrollHeight - eleContainerLog.clientHeight;
eleContainerLog.scrollTop + 1
eleLog.innerHTML += output + '<br>'
if (isScrolledToBottom) {
eleContainerLog.scrollTop =
eleContainerLog.scrollHeight - eleContainerLog.clientHeight
}
} else {
eleLog.innerHTML += output + '<br>'
}
}
} else {
eleLog.innerHTML += output + "<br>";
}

};
}
}

function produceOutput(name, args) {
arg = args[0].replace("%c","")
return '<span style="'+ args[1]+'">'+arg+"</span>&nbsp;"

}
function produceOutput(name, args) {
const arg = args[0].replace('%c', '')
return '<span style="'+ args[1]+'">' + arg + '</span>&nbsp;'
}
}
22 changes: 22 additions & 0 deletions examples/getMe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Be sure to run interactiveLogin.js before this in
// order to generate a session file.

const { TelegramClient } = require('../gramjs')

;(async () => {
const apiId = 65534 // Put your API ID here
const apiHash = 'e3e522e32853d0767df7b2113d5e2497' // Put your API hash here

const client = new TelegramClient('gramjs', apiId, apiHash)
await client.connect()

// const me = await client.getMe()
// console.log(me)
// await client.disconnect()
// process.exit(0)

const iter = client.iterMessages(198850229)
for await (const message of iter) {
console.log(message)
}
})()
32 changes: 32 additions & 0 deletions examples/interactiveLogin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const readline = require('readline-promise')
const { TelegramClient } = require('../gramjs')
const { Logger } = require('../gramjs/extensions')

const logger = new Logger('error')

const rl = readline.default.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
})

;(async () => {
console.log('Loading interactive example...')

const apiId = 12345 // Put your API ID here
const apiHash = '123456789abcdef' // Put your API hash here

// Create a client
const client = new TelegramClient('gramjs', apiId, apiHash, { baseLogger: logger })
await client.connect()

// Send the code
const phone = await rl.questionAsync('Please enter your phone number: ')
await client.sendCodeRequest(phone, null)
const code = await rl.questionAsync('Plase enter the code sent by Telegram: ')

// Start the authentication proceedure and generate the session file
await client.start({ phone, code })
console.log('Generated session file as gramjs.session')
client.disconnect().then(() => process.exit(0))
})()
13 changes: 0 additions & 13 deletions examples/main.js

This file was deleted.

12 changes: 3 additions & 9 deletions examples/simpleLogin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const phoneDiv = document.getElementById('phoneDiv')
/* eslint-env browser */
/* global gramjs */

const phone = document.getElementById('phone')
const phoneSend = document.getElementById('phoneSend')
const codeDiv = document.getElementById('codeDiv')
Expand All @@ -7,7 +9,6 @@ const codeSend = document.getElementById('codeSend')
const passDiv = document.getElementById('passDiv')
const pass = document.getElementById('pass')
const passSend = document.getElementById('passSend')
const logger = document.getElementById('log')

function phoneCallback() {
phone.disabled = false
Expand All @@ -22,7 +23,6 @@ function phoneCallback() {
})
}


function passwordCallback() {
passDiv.style.visibility = 'visible'

Expand All @@ -33,7 +33,6 @@ function passwordCallback() {

resolve(pass.value)
alert('welcome')

})
})
}
Expand All @@ -53,7 +52,6 @@ function codeCallback() {
})
}


const { TelegramClient } = gramjs
const { StringSession } = gramjs.session
const apiId = process.env.APP_ID // put your api id here [for example 123456789]
Expand All @@ -71,8 +69,4 @@ client.start({
console.log('%c you should now be connected', 'color:#B54128')
console.log('%c your string session is ' + client.session.save(), 'color:#B54128')
console.log('%c you can save it to login with it next time', 'color:#B54128')

})



114 changes: 106 additions & 8 deletions gramjs/Helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,23 +230,33 @@ function getRandomInt(min, max) {
* @param ms time in milliseconds
* @returns {Promise}
*/
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

/**
* Checks if the obj is an array
* @param obj
* @returns {boolean}
*/
function isArrayLike(obj) {
if (!obj) return false
if (!obj) {
return false
}
const l = obj.length
if (typeof l != 'number' || l < 0) return false
if (Math.floor(l) !== l) return false
if (typeof l != 'number' || l < 0) {
return false
}
if (Math.floor(l) !== l) {
return false
}
// fast check
if (l > 0 && !(l - 1 in obj)) return false
if (l > 0 && !(l - 1 in obj)) {
return false
}
// more complete check (optional)
for (let i = 0; i < l; ++i) {
if (!(i in obj)) return false
if (!(i in obj)) {
return false
}
}
return true
}
Expand All @@ -257,15 +267,19 @@ function isArrayLike(obj) {
* is greater or equal to one, and that their length is not out of bounds.
*/
function stripText(text, entities) {
if (!entities || entities.length === 0) return text.trim()
if (!entities || entities.length === 0) {
return text.trim()
}

entities = Array.isArray(entities) ? entities : [entities]
while (text && text.slice(-1).match(/\s/)) {
const e = entities.slice(-1)
if (e.offset + e.length === text.length) {
if (e.length === 1) {
delete entities[entities.length - 1]
if (!entities) return text.trim()
if (!entities) {
return text.trim()
}
} else {
e.length -= 1
}
Expand Down Expand Up @@ -302,6 +316,84 @@ function regExpEscape(str) {
return str.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g, '\\$&')
}

function sum(...args) {
return args.reduce((a, b) => a + b, 0)
}

/**
* Returns `true` if the object is a function, false otherwise
* @param {*} obj Object to test
*/
function callable(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply)
}

class MixinBuilder {
constructor(superclass) {
this.superclass = superclass
}

with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.superclass)
}
}

// Makes mixin classes easier. For information on mixins,
// see https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/
const mix = superclass => new MixinBuilder(superclass)

const EntityType = {
USER: 0,
CHAT: 1,
CHANNEL: 2,
}

/**
* This could be a `utils` method that just ran a few `isinstance` on
* `utils.getPeer(...)`'s result. However, there are *a lot* of auto
* casts going on, plenty of calls and temporary short-lived objects.
*
* So we just check if a string is in the class name.
* Still, assert that it's the right type to not return false results.
*/
function entityType(entity) {
if (!entity.SUBCLASS_OF_ID) {
throw new TypeError('${entity} is not a TLObject, cannot determine entity type')
}

if (![
0x2d45687, // crc32 of Peer
0xc91c90b6, // crc32 of InputPeer
0xe669bf46, // crc32 of InputUser
0x40f202fd, // crc32 of InputChannel
0x2da17977, // crc32 of User
0xc5af5d94, // crc32 of Chat
0x1f4661b9, // crc32 of UserFull
0xd49a2697, // crc32 of ChatFull
].includes(entity.SUBCLASS_OF_ID)) {
throw new TypeError(`${entity} does not have any entity type`)
}

const name = entity.constructor.name
if (name.includes('User') || name.includes('Self')) {
return EntityType.USER
} else if (name.includes('Chat')) {
return EntityType.CHAT
} else if (name.includes('Channel')) {
return EntityType.CHANNEL
}
}

function isinstance(object, types) {
types = Array.isArray(types) ? types : [types]
for (const type of types) {
if (object instanceof type) {
return true
}
}
return false
}

module.exports = {
readBigIntFromBuffer,
readBufferFromBigInt,
Expand All @@ -320,4 +412,10 @@ module.exports = {
ensureParentDirExists,
stripText,
regExpEscape,
sum,
callable,
mix,
EntityType,
entityType,
isinstance,
}
Loading