Перейти к содержимому
swg2you

Подмена computer.pullSignal или методика построения резидентных программ в OpenOS

Рекомендуемые сообщения

Из того,что я прочитал - такой демон может отвечать,к примеру,на автоматическое монтирование дисков(ивент peripheralAdded, на сколько я помню), автоматически прогружать в глобал АПИ компонентов(что бы каждый раз не писать modem=component.modem), работать корзиной и т.п. Вобщем - может быть не только вирусом. Часики swg тоже демон,в винде его бы назвали "служба гаджета часов"

Службы, демоны, резиденты - каких только имен не наплодили для фоновых задач )

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

swg2you, я смотрю, ты как и некоторые здесь, любитель переопределять системные функции. Предлагаю тебе и другим желающим реализовать совместно проект FTP. Для доступа к дисковому пространству удаленного компьютера по вайфаю или ОпенНет.

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

легче создать proxy диска компьютера, который сам будет обращаться к другому компу и получать с него данные, а потом возвращать. потом через fs.mount смонтировать, или работать напрямую через прокси

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
легче создать proxy диска компьютера, который сам будет обращаться к другому компу и получать с него данные, а потом возвращать. потом через fs.mount смонтировать, или работать напрямую через прокси
Да я уж давно сделал и забыл про это.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

легче создать proxy диска компьютера, который сам будет обращаться к другому компу и получать с него данные, а потом возвращать. потом через fs.mount смонтировать, или работать напрямую через прокси

дадададададдадададада классная идея это надо будет изменить component.proxy к примеру чтобы если она получила "network" то тогда возвратила прокси сети компов с этой же прогой. Но это не все - ведь если резидентная программа будет только требовать файлы из сети - кто ей даст? Никто. Поэтому нужно сделать функцию распространения файликов к примеру через копирование файлов в папку "network/mf" ("network" - туда мы смонтируем сетевую FS) и выбрав загрузочную ФС для хранения сетевых файлов (т. е. в папке etc создать mf которая будет отображаться также и в прокси сетевой FS). Это будет шикарно если сделать. Суперская ФТП получится

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Подмена computer.pullSignal или методика построения резидентных программ в OpenOS

Допустим, захотелось нам иметь резидентную программу, которая будет работать на фоне OpenOS и, периодически, или по какому либо событию, что-то полезное делать.

 

Воспользуемся нашим маленьким bibi, а в качестве boot.lua напишем такой код:

local cl=component.list
local gp=component.proxy(cl("gpu")())

--сохраняем исходные функции из _G.computer, для внутреннего пользования
local cp={} for k,v in pairs(computer) do cp[k]=v end

--подменяем функцию computer.pullSignal
computer.pullSignal = function (...)
  local e={cp.pullSignal(...)}
 --для примера, по тильде (~) будем ребутать компьютер
  if e[1]=='key_down' and e[4]==41 then cp.shutdown(true) end
  --а по lAlt будем выводить список компонентов используя определенную в OpenOS функцию print и сохраненную cl
  if e[1]=='key_down' and e[4]==56 then
    for k,v in cl() do print(k,v) end
  end
  --OpenOS периодически сама дергает эвенты (чтобы курсор мигал и прочее) подробнее смотрите в lib/event.lua
  --поэтому мы можем выводить свои часики, куда-ж без них то ) и прочие полезности, например инфу о памяти
  local s=tostring(math.floor(cp.freeMemory()/1024))..'/'..tostring(cp.totalMemory()/1024)..' kb free '..os.date('!%R')
  local w,h = gp.maxResolution()
  gp.set(w-#s+1,1,s)
  --в конце мы должны вернуть событие ничего не подозревающей OpenOS
  return table.unpack(e)
end

--функцию мы подменили, теперь загружаем, компилируем и выполняем init.lua
local fs=component.proxy(computer.getBootAddress())
local h=fs.open('init.lua')
local s,r='',''
while r do
  r=fs.read(h,math.huge)
  s=s..(r or "")
end
fs.close(h)
load(s)()
Запускаем компьютер, bibi пискнув и подождав секундочку, выполняет наш boot.lua, который хитро подменив pullSignal выполнит init.lua и после загрузки OpenOS в углу экрана радостно затикают часики.

 

h_1434887575_1643213_5ca46d9108.png

 

Теперь мы можем нажать lAlt и лицезреть список компонентов, или нажать тильду, и компьютер перезапустится.

--==--

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

 

На основе этого метода можно построить API для TSR программ, а комбинируя его с перехватом component.proxy, component.invoke и последующей подменой gpu на виртуальный терминал, и вовсе, написать свою операционную систему. Для которой, кстати говоря, было бы неплохо уметь запускать OpenOS в окошке, но самое главное, в изолированной среде, чтобы труд программистов писавших ПО под OpenOS не пропадал зря.

 

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

 

Посмотрим что выйдет.

--==--

Небольшое дополнение:

Если вам не охота играть с bibi, но нужно запустить резидентную программу прямо из-под OpenOS, то это сделать еще проще.

local component = require("component")
local cp = require("computer")
local gpu = component.gpu
local pullSignal = cp.pullSignal

cp.pullSignal = function (...)
  local e={pullSignal(...)}
  if e[1]=='key_down' and e[4]==41 then cp.shutdown(true) end
  if e[1]=='key_down' and e[4]==56 then for k,v in component.list() do print(k,v) end end
  local s=' '..math.floor(cp.freeMemory()/1024)..'/'..(cp.totalMemory()/1024)..' kb free  '..os.date('!%R')
  local w,h = gpu.maxResolution() gpu.set(w-#s+1,1,s)  
  return table.unpack(e)
end
Сохраняем этот код в файл, допустим tsr.lua и запускаем его под OpenOS

Программа выполнится, завершится, а резидентный участок останется в памяти.

--==--

Если выбросить все что относится к демонстрации работы, у нас останется маленькая обертка

local cp = require("computer")
local pullSignal = cp.pullSignal
cp.pullSignal = function (...)
  local e={pullSignal(...)}

  --код TSR программы

  return table.unpack(e)
end
Заключив в которую код своей TSR программы мы получим резидента, который будет выполнять TSR-код, где-то раз в пол секунды.

 

А как убрать это из памяти?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А как убрать это из памяти?

Гм, может, "Войну и мир" в цитату ещё запихнуть, чтобы потом написать " :smile9: "? Отрезайте ту часть цитаты, на которую отвечаете (а тут цитировать вообще не нужно было).

 

По поводу вопроса самого. Прежнее значение computer.pullSignal должно быть сохранено в другую переменную. Заменой переопределённой функции на изначальную можно остановить выполнение программы.

Из памяти затем программа будет потёрта при следующей сборке мусора, если на неё не осталось ссылок.

Изменено пользователем Fingercomp

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

Гм, может, "Войну и мир" в цитату ещё запихнуть, чтобы потом написать " "? Отрезайте ту часть цитаты, на которую отвечаете (а тут цитировать вообще не нужно было).

 

Постараюсь. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

должно быть сохранено в другую переменную. Заменой переопределённой функции на изначальную
 

То есть? Можешь как для дебила объяснить,а то я не умней этого статуса :\ 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

То есть? Можешь как для дебила объяснить,а то я не умней этого статуса :\ 

Да без проблем, я тут для этого и сижу.

 

computer.pullSignal — это low-level функция, то есть в обычных программах её напрямую нечасто используют (редко когда действительно необходимо). Всё, что она делает — получает события из некоторой копилки событий. Например, 100 раз тыкнул на клавишу — в копилке появилось 100 событий, и этой функцией они могут быть получены в коде.

Но пока напрямую используют немногие, косвенно — вызовом os.sleep и event.pull — почти во всех.

 

И появляется интересная мысль. Что если заменить функцию computer.pullSignal на свою? Она всё ещё будет делать изначальную работу, но при каждом запросе ивента заодно выполнит какой-то дополнительный код, как, например, отрисовку часиков, как в оригинальном посте.

 

Первое, что приходит на ум:

function computer.pullSignal(...)
  print("Hello, world!")
  return computer.pullSignal(...)
end

Переопределённая функция наша тогда возьмёт все переданные ей аргументы и скормит их изначальной, попутно написав "Hello, world!" В теории.

На практике получается так, что мы переопределили computer.pullSignal и для самой себя, поэтому потонем в бесконечной рекурсии. Прикольно, но вряд ли нам это нужно. Наверное.

 

Чтобы такого не было, надо сохранить прежнее значение computer.pullSignal в отдельную переменную и использовать уже её.

-- сохранились
local pullSignal = computer.pullSignal

function computer.pullSignal(...)
  print("Hello, world!")
  return pullSignal(...)
end

Та-дам: всё работает.

 

Теперь попробуем отключить переопределённую функцию. Тут всё очень просто. Например, вот как можно сделать так, чтобы отключаться при нажатии "Enter":

local kbd = require("keyboard")

local pullSignal = computer.pullSignal

function computer.pullSignal(...)
  local e = table.pack(pullSignal(...))
  if e[1] == "key_down" and e[4] == kbd.keys.enter then
    computer.pullSignal = pullSignal
  end
  return table.unpack(e)
end

По сравнению с предыдущим сниппетом кода, поменялось вот что:

  1. Мы получаем событие до выполнения своего кода и сохраняем в таблицу e.
  2. Выполняем свой код (при нажатии Enter снова подменяем computer.pullSignal, но на этот раз на стандартное значение).
  3. Возвращаем ивент.

 

У такого метода использования есть недостатки. Если два скрипта подменят одну и ту же функцию, проблематично будет отключить программы. Ещё функция запускается только при вызове computer.pullSignal, а не с каким-то интервалом. Система будет тормозить, если эту функцию заменить на какую-то, которая будет небыстро работать. И так далее.

 

Поэтому лучше для обработки ивентов использовать event.listen, для вызова функции по интервалу — event.listen, а для поочерёдной работы нескольких потов — стандартную в грядущей OpenOS 1.6.4 и выше библиотеку "thread" — или, пока OC не обновился, либу от @Zer0Galaxy.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

либу от Zer0Galaxy.
 

Я пытался но не работает файлы не выполняються.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

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

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...