Получать уведомления, когда кто-то использовал ваш бот

Проводя ответ по просьбе комментаторов на мой ответ на аналогичный вопрос , где тот же метод использовался для мутации последней строки файла, а не просто для этого.

Для файла значительного размера mmap - лучший способ сделать это. Чтобы улучшить существующий ответ mmap, эта версия переносима между Windows и Linux и должна работать быстрее (хотя она не будет работать без каких-либо изменений на 32-битном Python с файлами в диапазоне GB, см. other ответ для подсказок по обработке этого и для изменения работы на Python 2 ).

import io  # Gets consistent version of open for both Py2.7 and Py3.x
import itertools
import mmap

def skip_back_lines(mm, numlines, startidx):
    '''Factored out to simplify handling of n and offset'''
    for _ in itertools.repeat(None, numlines):
        startidx= mm.rfind(b'\n', 0, startidx)
        if startidx< 0:
            break
    return startidx

def tail(f, n, offset=0):
    # Reopen file in binary mode
    with io.open(f.name, 'rb') as binf, mmap.mmap(binf.fileno(), 0, access=mmap.ACCESS_READ) as mm:
        # len(mm) - 1 handles files ending w/newline by getting the prior line
        startofline = skip_back_lines(mm, offset, len(mm) - 1)
        if startofline < 0:
            return []  # Offset lines consumed whole file, nothing to return
            # If using a generator function (yield-ing, see below),
            # this should be a plain return, no empty list

        endoflines = startofline + 1  # Slice end to omit offset lines

        # Find start of lines to capture (add 1 to move from newline to beginning of following line)
        startofline = skip_back_lines(mm, n, startofline) + 1

        # Passing True to splitlines makes it return the list of lines without
        # removing the trailing newline (if any), so list mimics f.readlines()
        return mm[startofline:endoflines].splitlines(True)
        # If Windows style \r\n newlines need to be normalized to \n, and input
        # is ASCII compatible, can normalize newlines with:
        # return mm[startofline:endoflines].replace(os.linesep.encode('ascii'), b'\n').splitlines(True)

Это предполагает, что количество хвостов хвоста достаточно мало, вы можете спокойно прочитать их все в памяти на один раз; вы также можете сделать это функцией генератора и вручную прочитать строку за раз, заменив последнюю строку:

        mm.seek(startofline)
        # Call mm.readline n times, or until EOF, whichever comes first
        for line in itertools.islice(iter(mm.readline, b''), n):
            yield line

Наконец, это прочитано в двоичном режиме (необходимо использовать mmap), чтобы он дает строки str (Py2) и bytes (Py3); если вы хотите unicode (Py2) или str (Py3), итеративный подход может быть изменен для декодирования для вас и / или исправления новых строк:

        lines = itertools.islice(iter(mm.readline, b''), n)
        if f.encoding:  # Decode if the passed file was opened with a specific encoding
            lines = (line.decode(f.encoding) for line in lines)
        if 'b' not in f.mode:  # Fix line breaks if passed file opened in text mode
            lines = (line.replace(os.linesep, '\n') for line in lines)
        for line in lines:
            yield line

Примечание: я набрал все это на машине, где мне не хватает доступа к Python для тестирования. Пожалуйста, дайте мне знать, если я что-то опечалил; это было похоже на мой другой ответ , что я думаю, он должен работать, но твики (например, обработка offset) могут привести к тонким ошибкам. Пожалуйста, дайте мне знать в комментариях, если есть какие-либо ошибки.

-1
задан Charlotte6789 19 March 2019 в 09:08
поделиться

1 ответ

Есть несколько способов сделать это. Вверху головы:

Вы можете установить электронную почту в качестве канала для вашего бота, но это просто означает, что пользователь будет общаться с вашим ботом по электронной почте. Но вы можете отслеживать контакты клиентов по этому адресу.

В противном случае, как сказал D4CKCIDE выше, вы можете встроить некоторую простую логику для генерации уведомления, как только в вашей логике бота будет запущен определенный процесс. Например, я встроил быструю функцию отправки электронной почты с одного адреса электронной почты на другой (в данном случае с моей электронной почты outlook на мою почту gmail), как только будет выполнено действие 'speechUpdate', потому что это означает, что новый пользователь подключился к мой бот Он не отправляет мне всю историю, а просто пинг в качестве напоминания, для целей отслеживания:

else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
{
    if (turnContext.Activity.MembersAdded != null)
    {
        // Iterate over all new members added to the conversation
        foreach (var member in turnContext.Activity.MembersAdded)
        {
            // Greet anyone that was not the target (recipient) of this message
            // the 'bot' is the recipient for events from the channel,
            // turnContext.Activity.MembersAdded == turnContext.Activity.Recipient.Id 
            // indicates the bot was added to the conversation.
            if (member.Id != turnContext.Activity.Recipient.Id)
            {
                await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken: cancellationToken);
                await turnContext.SendActivityAsync(InfoMessage, cancellationToken: cancellationToken);
                await turnContext.SendActivityAsync(PatternMessage, cancellationToken: cancellationToken);
            }
            EmailPingFunction();
        }
    }
}

Затем я построил функцию EmailPingFunction следующим образом:

private static void EmailPingFunction()
{
    // setup strings
    string sender = "BotsyJohnson@outlook.com";
    string password = "********"; // put your email's password here ^_^
    string recipient = "BotsyJohnson@gmail.com";

    // set the client:
    SmtpClient outlookSmtp = new SmtpClient("smtp-mail.outlook.com");

    // use the 587 TLS port
    outlookSmtp.Port = 587;

    // set the delivery method
    outlookSmtp.DeliveryMethod = SmtpDeliveryMethod.Network;

    // set the credentials
    outlookSmtp.UseDefaultCredentials = false;
    System.Net.NetworkCredential credentials =
    new System.Net.NetworkCredential(sender, password);
    outlookSmtp.Credentials = credentials;

    // enable SS1
    outlookSmtp.EnableSsl = true;

    // set up and send the MailMessage
    try
    {
        Console.WriteLine("start to send email over TLS...");
        MailMessage message = new MailMessage(sender, recipient);
        message.Subject = "This is a test of the not-emergency alert system";
        message.Body = "Someone just pinged your bot. Please go into your set storage account to review";
        outlookSmtp.Send(message);
        Console.WriteLine("email was sent successfully!");
    }
    catch (Exception ex)
    {
        Console.WriteLine("failed to send email with the following error:");
        Console.WriteLine(ex.Message);
    }
}

Просто для Подчеркните, что сказал Николас Р., потому что он абсолютно прав: это обычай, и только один вариант того, как вы можете это сделать. Это простой и грязный вариант ОДНОГО способа создать какое-то уведомление.

0
ответ дан JJ_Wailes 19 March 2019 в 09:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: