# Pyrogram Telegram Bot小纸条（二）

在我写的所有的Telegram Bot项目中，都希望它是一个灵活的部分。在以前的python-telegram-bot的项目里，我都会使用一个文件，将所有的command处理放在不同的文件里，然后一一import进去，后来也有一些朋友把它再写成配置文件什么，为的就是能够简单配置一个Bot能有不同的功能。在pyrogram里，特别提供了一套[Smart Plugins](https://docs.pyrogram.org/topics/smart-plugins)以达成这样的效果。由于我非常喜欢使用这套预制的plugins机制，所以第二个文章就用来说明这个Smart Plugins。

## 普通的Bot

我们先写一个普通的bot，如果你没有特别的需要，一个文件的bot非常适合你。以下是一个简单的代码：

```
from pyrogram import Client, filters
from pyrogram.types import Message

app = Client("hdcola")


@app.on_message(filters.command("help"))
async def help(client: Client, message: Message):
    await message.reply(f"have to help {message.text}")


@app.on_message(filters.regex("你好"))
async def hello(client: Client, message: Message):
    await message.reply("我很好")


@app.on_message(filters.text & filters.private)
async def echo(client: Client, message: Message):
    await message.reply(message.text)

app.run()
```

这个Bot实现了三个功能：

- 收到一个/help命令，回复have to help 后面跟着你发出来的命令的全部内容。
- 收到一个"你好"，回复"我很好"
- 收到别的任何信息，都echo一个相同的信息


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1659966649944/o8kBMvkas.png align="left")

## 运用Smart Plugins

在普通的Bot里，如果我们想将三个功能放到一个单独的文件里去，你就需要写单独的import，而且每增加一个文件，就需要多一个import。所以我们完全可以使用smart plugins来简化这个行为。我们只需要做以下几件事：

- 建立一个目录，名为"plugins"
- 将相关功能的代码移入这个目录，将@app更换为@Client
- 在你的启动文件里声明plugins的目录名，并在初始化Client里传入参数

比如，我们将echo功能放入plugins，我们只需要在目录中建立一个echo.py，内容如下：

```
from pyrogram import Client, filters
from pyrogram.types import Message


@Client.on_message(filters.text & filters.private)
async def echo(client: Client, message: Message):
    await message.reply(message.text)
```

在启动文件中加入plugins：

```
from pyrogram import Client, filters
from pyrogram.types import Message

plugins = dict(root="plugins")
app = Client("hdcola", plugins=plugins)
app.run()
```

Smart Plugins还可以指定加载、指定不加载以及在运行时Load和Unload plugins，高级话题，我用pyrogram一年多还没用过这功能，所以大家可以去[这里自行查阅](https://docs.pyrogram.org/topics/smart-plugins)。

## 附注

### 启动目录

在所有文档里没有提到的是，在启动程序时，**你的当前目录必须是你的plugins的父目录**，否则无法找到相应的目录。你会得到一个类似这样的提示：`[hdcola] No plugin loaded from "plugins"`。

### Session存储

#### 缺省使用的 File Storage

使用了smart plugins后，你的session文件存储目录就出了问题，这时怎么办更为优雅呢？Pyrogram 给出了一个叫做Memory Storage的存储方案，目的就是把session中的存储信息都放在内存里。普通模式下，Pyrogram的存储使用的是File Storage，它实质上就是一个SQLite的文件，当你登录认证成功后，这个文件即生成，以后你每次登录时都会打开这个DB文件，这是数据中的结构：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660052706905/ASRNevdU6.png align="left")

#### 使用Memory Storage

我们都知道，SQLite还提供一个内存模式，所以你就可以使用内存模式来存储session信息，只需要在init Client时加入in_memory=True参数即可：

```
from pyrogram import Client

async with Client("my_account", in_memory=True) as app:
    print(await app.get_me())
```

但是这样做有一个问题，每次启动都需要进行一编重新认证的过程。

#### 使用Session Strings

为了不让你使用in_memory模式时重复进行认证，pyrogram还提供了一个session strings的方式，使用起来的代码如下：

```
from pyrogram import Client

session_string = "...ZnUIFD8jsjXTb8g_vpxx48k1zkov9sapD-tzjz-S4WZv70M..."

async with Client("my_account", session_string=session_string) as app:
    print(await app.get_me())
```

通过给出session_string参数，你就可以使用in_memory模式，但不用每次都进行登录验证了。但是如何得到这个session_string呢？官方给出的代码如下：

```
from pyrogram import Client

async with Client("my_account", in_memory=True) as app:
    print(await app.export_session_string())
```

不过，这段代码并不能很好的运行，所以有一位兄弟[在replit上提供了一个getStringName的代码你可以直接运行](https://replit.com/@subinps/getStringName)。其实它的代码只是让你使用起来更为友好一些，你也可以自己将这段代码放在你自己的机器上生成session strings：

```
from pyrogram import Client
print("""
Go to my.telegram.org
Login using your Telegram account
Click on API Development Tools
Create a new application, by entering the required details
Check your Telegram saved messages section to get your SESSION_NAME
"""
)
API_ID=int(input("Enter API ID: "))
API_HASH=input("Enter API HASH: ")

with Client(":memory:" ,api_id=API_ID ,api_hash=API_HASH, hide_password=False) as pyrogram:
    SESSION_NAME = "SESSION_NAME\n\n" + (pyrogram.export_session_string())
    print("\nGenerating your SESSION_NAME...\n")
    pyrogram.send_message("me", SESSION_NAME, parse_mode="html")
    print("Your SESSION_NAME have been sent to your Telegram Saved Messages")
```

他的代码并不够好，特别是当要生成一个Bot的Session string时就会出现错误，因为bot是无法给me（自己）发送信息的。晚些我会更新一下这段代码。到时大家会在这个文章看到更新的地址和代码的。

