1 (изменено: Belo4kaVspishka, 2018-07-26 12:08:56)

Тема: AHK: Использование сервера как генератора событий на локальном скрипте

Здравствуйте. Такая ситуация: моя цель - организация взаимодействия серверного скрипта и скрипта-клиента, где генератором событий будет сервер. Но я не понимаю средств, которые мне необходимы.

Имеется AHK скрипт, который используют 15-30 пользователей одновременно (ну т.е. 15-30 копий скрипта). Необходимо подключить все скрипты к серверу, а точнее - соединить все эти скрипты для их взаимодействия. Пример нужной мне задачи:

1) Раз в n минут необходимо сервер передал один и тот же параметр всем подключенным клиентам, чтобы те выполнили одно и то же действие одновременно (ну или почти одновременно разумеется).

Я вижу один путь: Google Apps Script. (т.к. мой клиентский скрипт уже умеет взаимодействовать с макросами гугл и опыт в программировании у меня более-менее есть). По истечению определенного количества времени помещается какое-нибудь значение в таблицу, которую постоянно мониторит клиент (постоянно будет скачивать и читать, либо с помощью второго макроса будет постоянно читать таблицу). Проблема в том, что макрос вызывается только по get-запросу, а мне не понятно как организовать постоянную работу макроса. Если сможете ответить на этот вопрос, в целом, мне больше ничего не нужно будет. Хотя если есть какие нюансы, прошу вас меня заранее предупредить. Если же же это невозможно, прошу вас пояснить мне следующее:

1) Какой хостинг (бесплатный или платный (бесплатный конечно лучше, ибо для постоянной передачи двух-трех строчек текста между клиентами хватит и хостинга третьего уровня я полагаю) (желательно с названиями или ссылками) имеет возможность установки на нём серверного скрипта и не имеющий всякой капчи?
2) Как сделать на этом хостинге постоянную работу серверного скрипта (или по-другому: как сделать так, чтобы в связке сервер-клиент инициатором событий был именно сервер)?
3) На каком языке пишется серверный скрипт на этом хостинге (если возможно на разных - возможно ли на AHK)?
4) Как мне отправить параметр подключенному скрипту (каким путем идти мне для достижения этой цели)?

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

2

Re: AHK: Использование сервера как генератора событий на локальном скрипте

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

1) Раз в n минут необходимо сервер передал один и тот же параметр всем подключенным клиентам, чтобы те выполнили одно и то же действие одновременно (ну или почти одновременно разумеется).

Непонятна задача. И вообще, если есть пункт 1, то куда делись остальные пункты?

3 (изменено: Belo4kaVspishka, 2018-07-26 12:45:50)

Re: AHK: Использование сервера как генератора событий на локальном скрипте

ypppu, имеется 15 копий скрипта, запущенных на 15 разных компьютерах. Все компьютеры подключены к интернету. Задача: сделать так, чтобы по "веленью" серверного скрипта (т.е. скрипт инициализирует действие) все 15 клиентов сделали какое-нибудь действие (ну например msgbox, "Hello, world"). Подобное должно происходить в цикле, чтобы повторялось периодически. Я уверен, раз смогу решить эту задачу, то остальные задачи уже смогу решить самостоятельно (второй задачей была передача параметра от одного клиента к другому).  Возможно мои пояснения где-то непонятны, я сам пока не сильно разбираюсь во всех этих серверно-хостинговых скриптах и делах, а имею лишь очень общее представление.

4

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Тогда можно на каком-нибудь сервере завести чат. Клиентские скрипты подключаются к чату и "общаются" с серверным скриптом и/или между собой.

5

Re: AHK: Использование сервера как генератора событий на локальном скрипте

На мой взгляд, гораздо менее затратней собрать такую "упряжку" под управлением Telegram-бота, нежели заморачиваться с хостингами. Да и управлять такой сборкой можно даже с телефона, из любого места, где есть интернет.

6

Re: AHK: Использование сервера как генератора событий на локальном скрипте

KusochekDobra, не имею ничего против. Мне главное достижение результата, есть какая-нибудь инструкция или какие-нибудь примеры?

7

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Гуглите. Эта информация в открытом доступе и её ни от кого не прячут. Единственное с чем может возникнуть проблема, это нынешняя борьба РКН с Telegram, так что всё, что с ним связано требует прокси.

Если у Вас нет проблем с написанием скриптов на AHK, проблемы в освоении этой темы не должно возникнуть.

8

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Тогда этот вариант не подойдет. Заставить пользователей, которые на сообщение "ошибка, проверьте настройки" жалуются, что ничего не работает, установить прокси будет большой проблемой. Как резерв все же стоит рассмотреть, судя по всему АПИ действительно легкий, но пока что жду других идей.

9

Re: AHK: Использование сервера как генератора событий на локальном скрипте

stealzy, проясню, что моя копия скрипта будет иметь такие же права как и все остальные копии. Чтобы мне передать информацию и считать её необходим будет прокси, верно? Если так, то всем остальным пользователям нужно будет то же самое, ведь они все тоже в РФ находятся, не так ли? Если я не прав и все это можно сделать без прокси, то тогда зачем прокси нужен?

10 (изменено: KusochekDobra, 2018-07-26 17:43:33)

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Как было верно замечено, Вы неправильно смотрите на ситуацию. Через прокси, Вы обращаетесь к API из своего кода, что подразумевает Вашу ответственность и непосредственное участие по его обогащению резервным списком их адресов. Пользователю в этом участвовать не обязательно.

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

11 (изменено: Belo4kaVspishka, 2018-07-26 17:55:06)

Re: AHK: Использование сервера как генератора событий на локальном скрипте

А-а-а, теперь понял. Да, теперь выглядит более многообещающим. Но смогу ли я с помощью этого же АПИ заставить среагировать скрипт-клиент на какое-нибудь событие? Или обязательно нужно будет мне в цикле проверять.

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

12

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Как описано в документации, есть два способа получения обновлений:
1 - Вебхук
2 - Опрос API
Для первого, нужен внешний ресурс. Для второго, частота запросов не должна превышать 1 раза в секунду.
Один раз в секунду, можно совершать в таймере, при этом, не отвлекаясь от основного занятия.

13 (изменено: Belo4kaVspishka, 2018-07-26 18:13:44)

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Что-ж, будем пробовать, спасибо.

P.S. Есть описания методов и классов на русском?

14

Re: AHK: Использование сервера как генератора событий на локальном скрипте

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

15

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Т.к. пока нет возможности возиться с телеграм, а стоять на месте совсем не хочется, попытался использовать сервис отправки уведомлений pushall. Добился получения push уведомления по get запросу со скрипта. Теперь встает вопрос: как скрипту понять, что пришел пуш в браузер, а в идеале: как узнать текст и заголовок этого сообщения?

16

Re: AHK: Использование сервера как генератора событий на локальном скрипте

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

17

Re: AHK: Использование сервера как генератора событий на локальном скрипте

А чем мне это поможет? Я уже могу отправлять уведомления, они приходят мне в браузер. Как теперь скрипт научить понимать, что пришло уведомление и читать его?

18

Re: AHK: Использование сервера как генератора событий на локальном скрипте

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

Global PROCESS_ALL_ACCESS        := 0x001F0FFF
Global PROCESS_VM_READ           := 0x10
Global PROCESS_QUERY_INFORMATION := 0x400

Global TOKEN_ALL_ACCESS        := 0xF01FF
Global TOKEN_QUERY             := 0x8
Global TOKEN_ADJUST_PRIVILEGES := 0x20

Global SE_PRIVILEGE_ENABLED := 2

Global PAGE_READWRITE         := 0x04
Global PAGE_EXECUTE_READWRITE := 0x40

Global TH32CS_SNAPMODULE := 0x00000008

Global INVALID_HANDLE_VALUE := -1

Global MODULEENTRY32_SIZE := 548

Global MODULEENTRY32_modBaseAddr := 20

Global MODULEENTRY32_hModule := 29

Global MODULEENTRY32_szModule := 32

Memory_GetProcessID(process_name)
{
    Process, Exist, %process_name%
    process_id = %ErrorLevel%

    Return, process_id
}

Memory_GetProcessHandle(process_id)
{
    process_handle := DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", false, "UInt", process_id, "Ptr") ; PROCESS_ALL_ACCESS

    Return, process_handle
}

Memory_GetModuleBase(process_id, module_name)
{
    snapshot_handle := DllCall("CreateToolhelp32Snapshot", "UInt", 0x00000008, "UInt", process_id) ; TH32CS_SNAPMODULE

    If (snapshot_handle = INVALID_HANDLE_VALUE)
    {
        Return, False
    }

    VarSetCapacity(me32, 548, 0) ; MODULEENTRY32_SIZE

    NumPut(548, me32) ; MODULEENTRY32_SIZE

    If (DllCall("Module32First", "UInt", snapshot_handle, "UInt", &me32))
    {
        While (DllCall("Module32Next", "UInt", snapshot_handle, "UInt", &me32))
        {
            If (module_name == StrGet(&me32 + 32, 256, "CP0")) ; MODULEENTRY32_szModule
            ;If (DllCall("lstrcmpi", "Str", module_name, "UInt", &me32 + 32) = -1)
            {
                DllCall("CloseHandle", "UInt", snapshot_handle)

                Return, NumGet(&me32, 20) ; MODULEENTRY32_modBaseAddr
            }
        }
    }

    DllCall("CloseHandle", "UInt", snapshot_handle)

    Return, False
}

Memory_CloseHandle(process_handle)
{
    DllCall("CloseHandle", "Ptr", process_handle)
}

Memory_Read(process_handle, address)
{
    VarSetCapacity(value, 4, 0)
    DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", value, "UInt", 4, "UInt *", 0)

    Return, NumGet(value, 0, "UInt")

    ;Return, *(&value + 3) << 24 | *(&value + 2) << 16 | *(&value + 1) << 8 | *(&value)
}

Memory_ReadEx(process_handle, address, size)
{
    VarSetCapacity(value, size, 0)
    DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", value, "UInt", size, "UInt *", 0)

    Return, NumGet(value, 0, "UInt")
}

Memory_ReadFloat(process_handle, address)
{
    VarSetCapacity(value, 4, 0)
    DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", value, "UInt", 4, "UInt *", 0)

    Return, NumGet(value, 0, "Float")
}

Memory_ReadReverse(process_handle, address)
{
    VarSetCapacity(value, 4, 0)
    DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", value, "UInt", 4, "UInt *", 0)

    Return, *(&value + 3) | *(&value + 2) << 8 | *(&value + 1) << 16 | *(&value) << 24
}

Memory_ReadString(process_handle, address, size)
{
    VarSetCapacity(value, size, 0)
    DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", value, "UInt", size, "UInt *", 0)

    Loop, %size%
    {
        current_value := NumGet(value, A_Index - 1, "UChar")

        ;MsgBox, current_value = %current_value%

        If (current_value = 0)
        {
            Break
        }

        result .= Chr(current_value)
    }

    ;MsgBox, result = %result%

    Return, result
}

Memory_ReadStringEx(process_handle, address, size)
{
    result = 

    Loop, %size%
    {
        output := "x"

        read := DllCall("ReadProcessMemory", "UInt", process_handle, "UInt", address, "Str", output, "UInt", 1, "UInt *", 0)
        If (ErrorLevel or !read)
        {
            Return, result
        }

        If output = 
        {
            Break
        }

        output_character := *(&output)

        IfEqual, output_character, 32 ; Space
        {
            result .= " "
        }
        Else
        {
            result = %result%%output%
        }

        address++
    }

    Return, result
}

Memory_Write(process_handle, address, value)
{
    DllCall("VirtualProtectEx", "UInt", process_handle, "UInt", address, "UInt", 4, "UInt", 0x04, "UInt *", 0) ; PAGE_READWRITE

    DllCall("WriteProcessMemory", "UInt", process_handle, "UInt", address, "UInt *", value, "UInt", 4, "UInt *", 0)
}

Memory_WriteEx(process_handle, address, value, size)
{
    DllCall("VirtualProtectEx", "UInt", process_handle, "UInt", address, "UInt", size, "UInt", 0x04, "UInt *", 0) ; PAGE_READWRITE

    DllCall("WriteProcessMemory", "UInt", process_handle, "UInt", address, "UInt *", value, "UInt", size, "UInt *", 0)
}

Memory_WriteFloat(process_handle, address, value)
{
    value := FloatToHex(value)

    DllCall("VirtualProtectEx", "UInt", process_handle, "UInt", address, "UInt", 4, "UInt", 0x04, "UInt *", 0) ; PAGE_READWRITE

    DllCall("WriteProcessMemory", "UInt", process_handle, "UInt", address, "UInt *", value, "UInt", 4, "UInt *", 0)
}

Memory_WriteNops(process_handle, address, size)
{
    If (size <= 0)
    {
        Return
    }

    VarSetCapacity(value, size)

    Loop, %size%
    {
        NumPut(0x90, value, A_Index - 1, "UChar")
    }

    DllCall("VirtualProtectEx", "UInt", process_handle, "UInt", address, "UInt", size, "UInt", 0x04, "UInt *", 0) ; PAGE_READWRITE

    DllCall("WriteProcessMemory", "UInt", process_handle, "UInt", address, "UInt", &value, "UInt", size, "UInt *", 0)
}

Memory_WriteBytes(process_handle, address, bytes)
{
    bytes_size := 0
    Loop, Parse, bytes, `,
    {
        bytes_size += 1
    }

    ;Sort, bytes, D`, N R ; bytes in reverse order

    VarSetCapacity(value, bytes_size)

    Loop, Parse, bytes, `,
    {
        byte = 0x%A_LoopField% ; pre-append 0x

        NumPut(byte, value, A_Index - 1, "UChar")
    }

    DllCall("VirtualProtectEx", "UInt", process_handle, "UInt", address, "UInt", bytes_size, "UInt", 0x04, "UInt *", 0) ; PAGE_READWRITE

    DllCall("WriteProcessMemory", "UInt", process_handle, "UInt", address, "UInt", &value, "UInt", bytes_size, "UInt *", 0)
}

FloatToHex(value)
{
   format := A_FormatInteger
   SetFormat, Integer, H
   result := DllCall("MulDiv", Float, value, Int, 1, Int, 1, UInt)
   SetFormat, Integer, %format%
   Return, result
}

Вот мой код:

msgbox, % Memory_ReadString(Memory_GetProcessHandle(Memory_GetProcessID("browser.exe")), "0B1DC7C0", 12)

Уведомления приходят в яндекс-браузер. И естественно скрипт выдает пустоту либо 0 если речь идёт об функции обычного чтения памяти. Если я правильно понял, то мой адрес памяти не верный (добыл я его с помощью чит-енджина при помощи поиска строки в памяти). Адрес должен выглядеть так: 0х....... тогда функции начинают хоть что-то показывать. Но как добыть этот адрес и он ли это вообще (ибо я почти уверен что этот адрес временный а указатели найти я не смог).

Если я забрел слишком далеко и есть способ попроще принять push-уведомление (а ещё более желательно в  internet explorer) то прошу меня остановить, а то уже выходит нехорошо: заставить пользователей не только держать открытым вечно браузер (ну это допустим я буду делать автоматически со скрытым окном), то так ещё и конкретно яндекс-браузер в данном случае. Надеюсь на вашу помощь.

19

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Я думал просто "клиентский" скрипт будет командой UrlDownloadToFile периодически скачивать файлик с бесплатного хостинга и анализировать его. Ну а "серверный" скрипт будет время от времени редактировать файлик.

20

Re: AHK: Использование сервера как генератора событий на локальном скрипте

И чем Ваш подход проще и быстрее, чем тот же хорошо документированный API Telegram?

Или действительно, организуйте на хостинге сценарий, которому будете отправлять в "POST" командные параметры, он их там положит в БД до востребования с ID команды, а клиентский, "POST"-ом  будет его получать, сообщая в запросе свой идентификатор. Обработанные таким образом запросы переносите в подтверждённые, превращая в лог событий, освобождая, или обновляя БД для новых заданий. Лог, кстати можно так же отправлять командному сценарию ответом на "POST", с его командами, таким образом можно всегда быть в курсе, что твориться "на другом конце провода".

Если дружите с PHP, можете так же организовать какой-нибудь примитивный WebSocket и стримить задачи подключенным клиентам.

Можно через TCP организовать обработку, если у Вас есть выделенный IP.

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

21

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Я просто подумал, всякие там Telegram сегодня есть, а завтра нету. И вроде как не требовалась двусторонняя связь: сервер отдаёт команды, а клиент ничего не должен отвечать.

22

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Так то вы правы, двустороняя связь между сервером и скриптом не нужна. Нужна связь между несколькими клиентами, а сервер как посредник выглядит хорошо. Телеграм пока не имею возможности испытать, вариант с файлом не прокатит (ибо давно бы гугл апс скрипт использовал бы) ведь запросы могут быть адресованы одному клиенту тз десяти, а все будут их принимать... Испытав пуши на практике я понял что это один из вариантов вроде как, но как мге прочитать пуш...

23

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Просто набросал примерный, простой алгоритм, как бы я реализовал, если бы использовал связку AHK - PHP. У меня так через Telegram сделана коммутация. Довольно удобно. И думаю, он будет ещё довольно долго на рынке из подобных предложений. Как минимум, пока кабеля трансатлантические не порежут какие-нибудь негодяи-хулиганы.

И верно, что чем система проще, тем меньше у неё шансов сломаться. А файлик можно просто по FTP обновлять на сервере и не использовать никакие скрипты.

24

Re: AHK: Использование сервера как генератора событий на локальном скрипте

Так а в чём проблема с "файликом"?
Пишете в него задачу с ID для каждого идентификатора-клиента.
Любой клиент скачивает этот файл, находит в нём свой идентификатор и сравнивает текущий ID задачи с выполненным. Если текущий больше предыдущего, задача выполняется, а ID сохраняется.
Качаете клиентом этот файлик по КД. И ничего не происходит пока ID задачи не поменяется.

25

Re: AHK: Использование сервера как генератора событий на локальном скрипте

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