Поддержка клиентских соединений с FTP-серверами прям из проводника

This commit is contained in:
Igor Timofeev 2018-03-15 22:39:31 +03:00
parent 51ba069e45
commit 7e86a4e1d7
10 changed files with 780 additions and 272 deletions

View File

@ -25,6 +25,7 @@ local favourites = {
local resourcesPath = MineOSCore.getCurrentScriptDirectory()
local favouritesPath = MineOSPaths.applicationData .. "Finder/Favourites3.cfg"
local sidebarFromY = 1
local iconFieldYOffset = 2
local scrollTimerID
@ -37,34 +38,35 @@ local mainContainer, window = MineOSInterface.addWindow(MineOSInterface.filledWi
local titlePanel = window:addChild(GUI.panel(1, 1, 1, 3, 0xE1E1E1))
local prevButton = window:addChild(GUI.adaptiveRoundedButton(9, 2, 1, 0, 0xFFFFFF, 0x3C3C3C, 0x3C3C3C, 0xFFFFFF, "<"))
local prevButton = window:addChild(GUI.adaptiveRoundedButton(9, 2, 1, 0, 0xFFFFFF, 0x4B4B4B, 0x3C3C3C, 0xFFFFFF, "<"))
prevButton.colors.disabled.background = prevButton.colors.default.background
prevButton.colors.disabled.text = 0xC3C3C3
local nextButton = window:addChild(GUI.adaptiveRoundedButton(14, 2, 1, 0, 0xFFFFFF, 0x3C3C3C, 0x3C3C3C, 0xFFFFFF, ">"))
local nextButton = window:addChild(GUI.adaptiveRoundedButton(14, 2, 1, 0, 0xFFFFFF, 0x4B4B4B, 0x3C3C3C, 0xFFFFFF, ">"))
nextButton.colors.disabled = prevButton.colors.disabled
local FTPButton = window:addChild(GUI.adaptiveRoundedButton(20, 2, 1, 0, 0xFFFFFF, 0x4B4B4B, 0x3C3C3C, 0xFFFFFF, MineOSCore.localization.networkFTPNewConnection))
nextButton.colors.disabled = prevButton.colors.disabled
local sidebarContainer = window:addChild(GUI.container(1, 4, 20, 1))
sidebarContainer.panel = sidebarContainer:addChild(GUI.panel(1, 1, sidebarContainer.width, 1, 0xFFFFFF, MineOSCore.properties.transparencyEnabled and 0.24))
sidebarContainer.itemsContainer = sidebarContainer:addChild(GUI.container(1, 1, sidebarContainer.width, 1))
local searchInput = window:addChild(GUI.input(1, 2, 36, 1, 0xFFFFFF, 0x696969, 0xA5A5A5, 0xFFFFFF, 0x2D2D2D, nil, MineOSCore.localization.search, true))
local searchInput = window:addChild(GUI.input(1, 2, 36, 1, 0xFFFFFF, 0x4B4B4B, 0xA5A5A5, 0xFFFFFF, 0x2D2D2D, nil, MineOSCore.localization.search, true))
local iconField = window:addChild(
MineOSInterface.iconField(
1, 4, 1, 1, 2, 2, 0x3C3C3C, 0x3C3C3C,
MineOSPaths.desktop
)
)
local updatingListLabel = window:addChild(GUI.label(1, 4, 1, 1, 0x696969, MineOSCore.localization.updatingFileList):setAlignment(GUI.alignment.horizontal.center, GUI.alignment.vertical.center))
updatingListLabel.hidden = true
local scrollBar = window:addChild(GUI.scrollBar(1, 4, 1, 1, 0xC3C3C3, 0x444444, iconFieldYOffset, 1, 1, 1, 1, true))
local iconField = window:addChild(MineOSInterface.iconField(1, 4, 1, 1, 2, 2, 0x3C3C3C, 0x3C3C3C, MineOSPaths.desktop))
local scrollBar = window:addChild(GUI.scrollBar(1, 4, 1, 1, 0xC3C3C3, 0x4B4B4B, iconFieldYOffset, 1, 1, 1, 1, true))
scrollBar.eventHandler = nil
local statusBar = window:addChild(GUI.object(1, 1, 1, 1))
statusBar.draw = function(object)
buffer.square(object.x, object.y, object.width, object.height, 0xFFFFFF, 0x3C3C3C, " ")
buffer.text(object.x + 1, object.y, 0x3C3C3C, string.limit(("root/" .. iconField.workpath):gsub("/+$", ""):gsub("%/+", ""), object.width - 1, "start"))
buffer.text(object.x + 1, object.y, 0x3C3C3C, string.limit(("root/" .. iconField.workpath):gsub("/+$", ""):gsub("%/+", ""), object.width - 2, "left"))
end
local sidebarResizer = window:addChild(GUI.resizer(1, 4, 3, 5, 0xFFFFFF, 0x0))
@ -116,49 +118,25 @@ local function addWorkpath(path)
iconField:setWorkpath(path)
end
local function newSidebarItem(textColor, text, path)
local object = sidebarContainer.itemsContainer:addChild(
GUI.object(
1,
#sidebarContainer.itemsContainer.children > 0 and sidebarContainer.itemsContainer.children[#sidebarContainer.itemsContainer.children].localY + 1 or 1,
1,
1
)
)
local function newSidebarItem(y, textColor, text, path)
local object = sidebarContainer.itemsContainer:addChild(GUI.object(1, y, 1, 1))
if text then
object.text = text
object.textColor = textColor
object.path = path
object.draw = function(object)
object.width = sidebarContainer.itemsContainer.width
if object.path == iconField.workpath then
local currentTextColor = textColor
if path == iconField.workpath then
buffer.square(object.x, object.y, object.width, 1, 0x3366CC, 0xFFFFFF, " ")
buffer.text(object.x + 1, object.y, 0xFFFFFF, string.limit(object.text, object.width - 4, "center"))
if object.favouriteIndex and object.favouriteIndex > 1 then
buffer.text(object.x + object.width - 2, object.y, 0xCCFFFF, "x")
end
else
buffer.text(object.x + 1, object.y, object.textColor, string.limit(object.text, object.width - 2, "center"))
currentTextColor = 0xFFFFFF
end
buffer.text(object.x + 1, object.y, currentTextColor, string.limit(text, object.width - 2, "center"))
end
object.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "touch" then
if object.favouriteIndex and object.favouriteIndex > 1 and eventData[3] == object.x + object.width - 2 then
table.remove(favourites, object.favouriteIndex)
saveFavourites()
computer.pushSignal("Finder", "updateFavourites")
elseif fs.isDirectory(object.path) then
addWorkpath(object.path)
MineOSInterface.OSDraw()
updateFileListAndDraw()
end
object.onTouch(eventData)
end
end
end
@ -166,32 +144,129 @@ local function newSidebarItem(textColor, text, path)
return object
end
local function updateSidebar()
local function onFavouriteTouch(path)
if fs.exists(path) then
addWorkpath(path)
updateFileListAndDraw()
else
GUI.error("Path doesn't exists: " .. path)
end
end
local openFTP, updateSidebar
openFTP = function(...)
local mountPath = MineOSNetwork.mountPaths.FTP .. MineOSNetwork.getFTPProxyName(...) .. "/"
local proxy, reason = MineOSNetwork.connectToFTP(...)
if proxy then
MineOSNetwork.umountFTPs()
fs.mount(proxy, mountPath)
addWorkpath(mountPath)
updateSidebar()
updateFileListAndDraw()
else
GUI.error(reason)
end
end
updateSidebar = function()
local y = sidebarFromY
sidebarContainer.itemsContainer:deleteChildren()
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x3C3C3C, MineOSCore.localization.favourite))
newSidebarItem(y, 0x3C3C3C, MineOSCore.localization.favourite)
y = y + 1
for i = 1, #favourites do
local object = sidebarContainer.itemsContainer:addChild(newSidebarItem(0x555555, " " .. fs.name(favourites[i].name), favourites[i].path))
object.favouriteIndex = i
local object = newSidebarItem(y, 0x555555, " " .. fs.name(favourites[i].name), favourites[i].path)
object.onTouch = function(eventData)
if eventData[5] == 1 then
local menu = GUI.contextMenu(eventData[3], eventData[4])
menu:addItem(MineOSCore.localization.removeFromFavourites).onTouch = function()
table.remove(favourites, i)
saveFavourites()
updateSidebar()
MineOSInterface.OSDraw()
end
menu:show()
else
onFavouriteTouch(favourites[i].path)
end
end
y = y + 1
end
if MineOSCore.properties.network.enabled and MineOSNetwork.getProxyCount() > 0 then
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x3C3C3C))
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x3C3C3C, MineOSCore.localization.network))
for proxy, path in fs.mounts() do
if proxy.network then
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x555555, " " .. MineOSNetwork.getProxyName(proxy), path .. "/"))
local added = false
for proxy, path in fs.mounts() do
if proxy.MineOSNetworkModem then
if not added then
y = y + 1
newSidebarItem(y, 0x3C3C3C, MineOSCore.localization.network)
y, added = y + 1, true
end
newSidebarItem(y, 0x555555, " " .. MineOSNetwork.getModemProxyName(proxy), path .. "/").onTouch = function()
addWorkpath(path .. "/")
updateFileListAndDraw()
end
y = y + 1
end
end
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x3C3C3C))
if #MineOSCore.properties.FTPConnections > 0 then
y = y + 1
newSidebarItem(y, 0x3C3C3C, MineOSCore.localization.networkFTPConnections)
y = y + 1
for i = 1, #MineOSCore.properties.FTPConnections do
local connection = MineOSCore.properties.FTPConnections[i]
local name = MineOSNetwork.getFTPProxyName(connection.address, connection.port, connection.user)
local mountPath = MineOSNetwork.mountPaths.FTP .. name .. "/"
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x3C3C3C, MineOSCore.localization.mounts))
newSidebarItem(y, 0x555555, " " .. name, mountPath).onTouch = function(eventData)
if eventData[5] == 1 then
local menu = GUI.contextMenu(eventData[3], eventData[4])
menu:addItem(MineOSCore.localization.delete).onTouch = function()
table.remove(MineOSCore.properties.FTPConnections, i)
MineOSCore.saveProperties()
updateSidebar()
MineOSInterface.OSDraw()
end
menu:show()
else
openFTP(connection.address, connection.port, connection.user, connection.password)
end
end
y = y + 1
end
end
y = y + 1
newSidebarItem(y, 0x3C3C3C, MineOSCore.localization.mounts)
y = y + 1
for proxy, path in fs.mounts() do
if path ~= "/" and not proxy.network then
sidebarContainer.itemsContainer:addChild(newSidebarItem(0x555555, " " .. (proxy.getLabel() or fs.name(path)), path .. "/"))
if path ~= "/" and not proxy.MineOSNetworkModem and not proxy.MineOSNetworkFTP then
newSidebarItem(y, 0x555555, " " .. (proxy.getLabel() or fs.name(path)), path .. "/").onTouch = function()
onFavouriteTouch(path .. "/")
end
y = y + 1
end
end
end
sidebarContainer.itemsContainer.eventHandler = function(mainContainer, object, eventData)
if eventData[1] == "scroll" then
if (eventData[5] > 0 and sidebarFromY < 1) or (eventData[5] < 0 and sidebarContainer.itemsContainer.children[#sidebarContainer.itemsContainer.children].localY > 1) then
sidebarFromY = sidebarFromY + eventData[5]
updateSidebar()
MineOSInterface.OSDraw()
end
end
end
@ -233,6 +308,57 @@ prevButton.onTouch = function()
prevOrNextWorkpath(false)
end
FTPButton.onTouch = function()
local container = MineOSInterface.addUniversalContainer(MineOSInterface.mainContainer, MineOSCore.localization.networkFTPNewConnection)
local ad, po, us, pa, la = "ftp.example.com", "21", "root", "1234"
if #MineOSCore.properties.FTPConnections > 0 then
local la = MineOSCore.properties.FTPConnections[#MineOSCore.properties.FTPConnections]
ad, po, us, pa = la.address, tostring(la.port), la.user, la.password
end
local addressInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x696969, 0x696969, 0xE1E1E1, 0x2D2D2D, ad, MineOSCore.localization.networkFTPAddress, true))
local portInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x696969, 0x696969, 0xE1E1E1, 0x2D2D2D, po, MineOSCore.localization.networkFTPPort, true))
local userInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x696969, 0x696969, 0xE1E1E1, 0x2D2D2D, us, MineOSCore.localization.networkFTPUser, true))
local passwordInput = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x696969, 0x696969, 0xE1E1E1, 0x2D2D2D, pa, MineOSCore.localization.networkFTPPassword, true, "*"))
container.layout:addChild(GUI.button(1, 1, 36, 3, 0xA5A5A5, 0xFFFFFF, 0x2D2D2D, 0xE1E1E1, "OK")).onTouch = function()
container:delete()
local port = tonumber(portInput.text)
if port then
local found = false
for i = 1, #MineOSCore.properties.FTPConnections do
if
MineOSCore.properties.FTPConnections[i].address == addressInput.text and
MineOSCore.properties.FTPConnections[i].port == port and
MineOSCore.properties.FTPConnections[i].user == userInput.text and
MineOSCore.properties.FTPConnections[i].password == passwordInput.text
then
found = true
break
end
end
if not found then
table.insert(MineOSCore.properties.FTPConnections, {
address = addressInput.text,
port = port,
user = userInput.text,
password = passwordInput.text
})
MineOSCore.saveProperties()
updateSidebar()
MineOSInterface.OSDraw()
openFTP(addressInput.text, port, userInput.text, passwordInput.text)
end
end
end
MineOSInterface.OSDraw()
end
statusBar.eventHandler = function(mainContainer, object, eventData)
if (eventData[1] == "component_added" or eventData[1] == "component_removed") and eventData[3] == "filesystem" then
updateSidebar()
@ -278,7 +404,6 @@ iconField.eventHandler = function(mainContainer, object, eventData)
end
saveFavourites()
updateSidebar()
MineOSInterface.OSDraw()
end
end
@ -301,7 +426,12 @@ end
local overrideUpdateFileList = iconField.updateFileList
iconField.updateFileList = function(...)
iconField.hidden, updatingListLabel.hidden = true, false
MineOSInterface.OSDraw()
overrideUpdateFileList(...)
iconField.hidden, updatingListLabel.hidden = false, true
updateScrollBar()
end
@ -322,6 +452,10 @@ local function calculateSizes(width, height)
window.backgroundPanel.localX = sidebarContainer.width + 1
window.backgroundPanel.localY = 4
updatingListLabel.localX = window.backgroundPanel.localX
updatingListLabel.width = window.backgroundPanel.width
updatingListLabel.height = window.backgroundPanel.height
statusBar.localX = sidebarContainer.width + 1
statusBar.localY = height
statusBar.width = window.backgroundPanel.width

View File

@ -672,22 +672,25 @@ local function newFile()
end
local function loadFile(path)
newFile()
local file = io.open(path, "r")
for line in file:lines() do
line = removeWindowsLineEndings(removeTabs(line))
table.insert(mainContainer.codeView.lines, line)
mainContainer.codeView.maximumLineLength = math.max(mainContainer.codeView.maximumLineLength, unicode.len(line))
local file, reason = io.open(path, "r")
if file then
newFile()
for line in file:lines() do
line = removeWindowsLineEndings(removeTabs(line))
table.insert(mainContainer.codeView.lines, line)
mainContainer.codeView.maximumLineLength = math.max(mainContainer.codeView.maximumLineLength, unicode.len(line))
end
file:close()
if #mainContainer.codeView.lines > 1 then
table.remove(mainContainer.codeView.lines, 1)
end
mainContainer.leftTreeView.selectedItem = path
updateAutocompleteDatabaseFromFile()
else
GUI.error(reason)
end
file:close()
if #mainContainer.codeView.lines > 1 then
table.remove(mainContainer.codeView.lines, 1)
end
mainContainer.leftTreeView.selectedItem = path
updateAutocompleteDatabaseFromFile()
end
local function saveFile(path)

View File

@ -1,4 +1,11 @@
{
networkFTPNewConnection = "FTP-connection",
networkFTPConnections = "FTP-connections",
networkFTPAddress = "Server address",
networkFTPPort = "Server port",
networkFTPUser = "User",
networkFTPPasswprd = "Password",
updatingFileList = "Updating file list...",
network = "Network",
networkTimeout = "Remote computer is not responding",
networkAccessDenied = "Access to the filesystem of the remote computer is denied. Contact it's owner to get appropriate privileges",
@ -72,6 +79,7 @@
archive = "Add to archive",
delete = "Delete",
addToFavourites = "Add to favourites",
removeFromFavourites = "Remove from favourites",
setAsWallpaper = "Set as wallpaper",
showPackageContent = "Show package content",
showContainingFolder = "Show containing folder",

View File

@ -1,4 +1,11 @@
{
networkFTPNewConnection = "FTP-подключение",
networkFTPConnections = "FTP-подключения",
networkFTPAddress = "Адрес сервера",
networkFTPPort = "Порт сервера",
networkFTPUser = "Пользователь",
networkFTPPasswprd = "Пароль",
updatingFileList = "Обновление списка файлов...",
network = "Сеть",
networkTimeout = "Удаленный компьютер не ответил на запрос",
networkAccessDenied = "Доступ к файловой системе удаленного компьютера запрещен. Свяжитесь с его владельцем для предоставления соответствующих привилегий",
@ -72,6 +79,7 @@
archive = "Добавить в архив",
delete = "Удалить",
addToFavourites = "Добавить в избранное",
removeFromFavourites = "Удалить из избранного",
setAsWallpaper = "Установить как обои",
showPackageContent = "Показать содержимое пакета",
showContainingFolder = "Открыть содержащую папку",

4
OS.lua
View File

@ -572,8 +572,8 @@ local function createOSWidgets()
comboBox:clear()
for proxy, path in fs.mounts() do
if proxy.network then
local item = comboBox:addItem(MineOSNetwork.getProxyName(proxy))
if proxy.MineOSNetworkModem then
local item = comboBox:addItem(MineOSNetwork.getModemProxyName(proxy))
item.proxyAddress = proxy.address
item.onTouch = function()
allowReadAndWriteSwitchAndLabel.switch:setState(MineOSCore.properties.network.users[item.proxyAddress].allowReadAndWrite)

View File

@ -2347,7 +2347,7 @@ local function filesystemChooserEventHandler(mainContainer, object, eventData)
filesystemDialog:setMode(object.IOMode, object.filesystemMode)
if #object.path > 0 then
if object.path and #object.path > 0 then
-- local path = object.path:gsub("/+", "/")
filesystemDialog.filesystemTree.selectedItem = object.IOMode == GUI.filesystemModes.open and object.path or fs.path(object.path)
filesystemDialog.input.text = fs.name(object.path)

View File

@ -3,7 +3,7 @@ require("advancedLua")
local web = require("web")
local component = require("component")
local buffer = require("doubleBuffering")
local filesystem = require("filesystem")
local fs = require("filesystem")
local unicode = require("unicode")
local image = require("image")
local color = require("color")
@ -17,15 +17,24 @@ MineOSCore.localization = {}
----------------------------------------------------------------------------------------------------------------
function MineOSCore.getCurrentScriptDirectory()
return filesystem.path(getCurrentScript())
return fs.path(getCurrentScript())
end
function MineOSCore.getTemporaryPath()
local temporaryPath
repeat
temporaryPath = MineOSPaths.temporary .. string.format("%08X", math.random(0xFFFFFFFF))
until not fs.exists(temporaryPath)
return temporaryPath
end
function MineOSCore.getLocalization(pathToLocalizationFolder)
local localizationFileName = pathToLocalizationFolder .. MineOSCore.properties.language .. ".lang"
if filesystem.exists(localizationFileName) then
if fs.exists(localizationFileName) then
return table.fromFile(localizationFileName)
else
return table.fromFile(pathToLocalizationFolder .. filesystem.list(pathToLocalizationFolder)())
return table.fromFile(pathToLocalizationFolder .. fs.list(pathToLocalizationFolder)())
end
end
@ -44,7 +53,7 @@ end
-----------------------------------------------------------------------------------------------------------------------------------
function MineOSCore.createShortcut(where, forWhat)
filesystem.makeDirectory(filesystem.path(where))
fs.makeDirectory(fs.path(where))
local file = io.open(where, "w")
file:write(forWhat)
file:close()
@ -67,7 +76,7 @@ end
function MineOSCore.loadPropeties()
local saveLater = false
if filesystem.exists(MineOSPaths.properties) then
if fs.exists(MineOSPaths.properties) then
MineOSCore.properties = table.fromFile(MineOSPaths.properties)
else
MineOSCore.properties = {}
@ -103,6 +112,7 @@ function MineOSCore.loadPropeties()
enabled = true,
signalStrength = 512,
},
FTPConnections = {},
}
MineOSCore.associateExtension(".pic", MineOSPaths.applications .. "/Photoshop.app/Main.lua", MineOSPaths.icons .. "/Image.pic", MineOSPaths.extensionAssociations .. "Pic/ContextMenu.lua")
@ -152,15 +162,15 @@ end
function MineOSCore.associationsExtensionAutomatically()
local path, extension = MineOSPaths.extensionAssociations
for file in filesystem.list(path) do
if filesystem.isDirectory(path .. file) then
for file in fs.list(path) do
if fs.isDirectory(path .. file) then
extension = "." .. unicode.sub(file, 1, -2)
if filesystem.exists(path .. file .. "ContextMenu.lua") then
if fs.exists(path .. file .. "ContextMenu.lua") then
MineOSCore.associateExtensionContextMenu(extension, path .. file .. "Context menu.lua")
end
if filesystem.exists(path .. file .. "Launcher.lua") then
if fs.exists(path .. file .. "Launcher.lua") then
MineOSCore.associateExtensionLauncher(extension, path .. file .. "Launcher.lua")
end
end
@ -239,7 +249,7 @@ function MineOSCore.safeLaunch(path, ...)
local oldResolutionWidth, oldResolutionHeight = buffer.getResolution()
local finalSuccess, finalPath, finalLine, finalTraceback = true
if filesystem.exists(path) then
if fs.exists(path) then
local loadSuccess, loadReason = loadfile("/" .. path)
if loadSuccess then
local success, path, line, traceback = MineOSCore.call(loadSuccess, ...)
@ -262,6 +272,8 @@ end
-----------------------------------------------------------------------------------------------------------------------------------
fs.remove(MineOSPaths.temporary)
fs.makeDirectory(MineOSPaths.temporary)
MineOSCore.loadPropeties()
-----------------------------------------------------------------------------------------------------------------------------------

View File

@ -958,7 +958,6 @@ local function checkFileToExists(container, path)
buffer.draw()
else
container:delete()
fs.makeDirectory(fs.path(path))
return true
end
end
@ -1048,6 +1047,7 @@ function MineOSInterface.newApplication(parentWindow, iconField, x, y, path)
if container.inputField.text then
local finalPath = path .. container.inputField.text .. ".app/"
if checkFileToExists(container, finalPath) then
fs.makeDirectory(finalPath)
fs.copy(filesystemChooser.path or MineOSPaths.icons .. "SampleIcon.pic", finalPath .. "Icon.pic")
local file = io.open(finalPath .. "Main.lua", "w")

View File

@ -1,63 +1,415 @@
local component = require("component")
local MineOSCore = require("MineOSCore")
local computer = require("computer")
local MineOSCore = require("MineOSCore")
local MineOSPaths = require("MineOSPaths")
local GUI = require("GUI")
local event = require("event")
local filesystemComponent = require("component").proxy(computer.getBootAddress())
local filesystemLibrary = require("filesystem")
local fs = require("filesystem")
local MineOSNetwork = {}
-- Ебучие херолизы, с каких залупнинских хуев я должен учитывать их говнокод и синтаксические ошибки?
-- GGWP
if not filesystemLibrary.unmount and filesystemLibrary.umount then
filesystemLibrary.unmount = filesystemLibrary.umount
----------------------------------------------------------------------------------------------------------------
local filesystemProxy = component.proxy(computer.getBootAddress())
MineOSNetwork.filesystemHandles = {}
MineOSNetwork.modemProxy = nil
MineOSNetwork.modemPort = 1488
MineOSNetwork.modemPacketReserve = 128
MineOSNetwork.modemTimeout = 2
MineOSNetwork.internetProxy = nil
MineOSNetwork.internetDelay = 0.05
MineOSNetwork.internetTimeout = 0.25
MineOSNetwork.proxySpaceUsed = 0
MineOSNetwork.proxySpaceTotal = 1073741824
MineOSNetwork.mountPaths = {
modem = MineOSPaths.network .. "Modem/",
FTP = MineOSPaths.network .. "FTP/"
}
----------------------------------------------------------------------------------------------------------------
local function umountProxy(type)
for proxy in fs.mounts() do
if proxy[type] then
fs.umount(proxy)
end
end
end
function MineOSNetwork.updateComponents()
local modemAddress, internetAddress = component.list("modem")(), component.list("internet")()
if modemAddress then
MineOSNetwork.modemProxy = component.proxy(modemAddress)
MineOSNetwork.modemProxy.open(MineOSNetwork.modemPort)
else
MineOSNetwork.modemProxy = nil
MineOSNetwork.umountModems()
end
if internetAddress then
MineOSNetwork.internetProxy = component.proxy(internetAddress)
else
MineOSNetwork.internetProxy = nil
MineOSNetwork.umountFTPs()
end
end
----------------------------------------------------------------------------------------------------------------
local MineOSNetwork = {}
function MineOSNetwork.umountFTPs()
umountProxy("MineOSNetworkFTP")
end
MineOSNetwork.modemPort = 1488
MineOSNetwork.modemProxy = nil
MineOSNetwork.modemPacketReserve = 128
MineOSNetwork.timeout = 2
MineOSNetwork.filesystemHandles = {}
MineOSNetwork.mountPath = "/ftp/"
function MineOSNetwork.getFTPProxyName(address, port, user)
return user .. "@" .. address .. ":" .. port
end
local function FTPSocketWrite(socketHandle, data)
local success, result = pcall(socketHandle.write, data .. "\r\n")
if success then
return true, result
else
return false, result
end
end
local function FTPSocketRead(socketHandle)
os.sleep(MineOSNetwork.internetDelay)
local deadline, data, success, result = computer.uptime() + MineOSNetwork.internetTimeout, ""
while computer.uptime() < deadline do
success, result = pcall(socketHandle.read, math.huge)
if success then
if not result or #result == 0 then
if #data > 0 then
return true, data
end
else
data, deadline = data .. result, computer.uptime() + MineOSNetwork.internetTimeout
end
else
return false, result
end
end
return false, "Socket read time out"
end
local function FTPParseLines(data)
local lines = {}
for line in data:gmatch("[^\r\n]+") do
table.insert(lines, line)
end
return lines
end
local function FTPLogin(socketHandle, user, password)
FTPSocketWrite(socketHandle, "USER " .. user)
FTPSocketWrite(socketHandle, "PASS " .. password)
FTPSocketWrite(socketHandle, "TYPE I")
local success, result = FTPSocketRead(socketHandle)
if success then
if result:match("TYPE okay") then
return true
else
return false, "Authentication failed"
end
else
return false, result
end
end
local function FTPEnterPassiveModeAndRunCommand(commandSocketHandle, command, dataToWrite)
FTPSocketWrite(commandSocketHandle, "PASV")
local success, result = FTPSocketRead(commandSocketHandle)
if success then
local digits = {result:match("Entering Passive Mode %((%d+),(%d+),(%d+),(%d+),(%d+),(%d+)%)")}
if #digits == 6 then
local address, port = table.concat(digits, ".", 1, 4), tonumber(digits[5]) * 256 + tonumber(digits[6])
FTPSocketWrite(commandSocketHandle, command)
local dataSocketHandle = MineOSNetwork.internetProxy.connect(address, port)
if dataToWrite then
os.sleep(MineOSNetwork.internetDelay)
dataSocketHandle.read(1)
dataSocketHandle.write(dataToWrite)
dataSocketHandle.close()
return true
else
local success, result = FTPSocketRead(dataSocketHandle)
dataSocketHandle.close()
if success then
return true, result
else
return false, result
end
end
else
return false, "Entering passive mode failed: wrong address byte array. Socket response message was: " .. tostring(result)
end
else
return false, result
end
end
local function FTPParseFileInfo(result)
local size, year, month, day, hour, minute, sec, type, name = result:match("Size=(%d+);Modify=(%d%d%d%d)(%d%d)(%d%d)(%d%d)(%d%d)(%d%d)[^;]*;Type=([^;]+);%s([^\r\n]+)")
if size then
return
true,
name,
type == "dir",
tonumber(size),
os.time({
year = year,
day = day,
month = month,
hour = hour,
minute = minute,
sec = sec
})
else
return false, "File not exists"
end
end
local function FTPFileInfo(socketHandle, path, field)
FTPSocketWrite(socketHandle, "MLST " .. path)
local success, result = FTPSocketRead(socketHandle)
if success then
local success, name, isDirectory, size, lastModified = FTPParseFileInfo(result)
if success then
if field == "isDirectory" then
return true, isDirectory
elseif field == "lastModified" then
return true, lastModified
else
return true, size
end
else
return true, false
end
else
return false, result
end
end
local function check(...)
local result = {...}
if not result[1] then
GUI.error(table.unpack(result, 2))
end
return table.unpack(result)
end
function MineOSNetwork.connectToFTP(address, port, user, password)
local socketHandle, reason = MineOSNetwork.internetProxy.connect(address, port)
if socketHandle then
FTPSocketRead(socketHandle)
local result, reason = FTPLogin(socketHandle, user, password)
if result then
local proxy, fileHandles, label = {}, {}, MineOSNetwork.getFTPProxyName(address, port, user)
proxy.type = "filesystem"
proxy.slot = 0
proxy.address = label
proxy.MineOSNetworkFTP = true
proxy.getLabel = function()
return label
end
proxy.spaceUsed = function()
return MineOSNetwork.proxySpaceUsed
end
proxy.spaceTotal = function()
return MineOSNetwork.proxySpaceTotal
end
proxy.setLabel = function(text)
label = text
return true
end
proxy.isReadOnly = function()
return false
end
proxy.closeSocketHandle = function()
fs.umount(proxy)
return socketHandle.close()
end
proxy.list = function(path)
local success, result = FTPEnterPassiveModeAndRunCommand(socketHandle, "MLSD -a " .. path)
if success then
local list = FTPParseLines(result)
for i = 1, #list do
local success, name, isDirectory = FTPParseFileInfo(list[i])
if success then
list[i] = name .. (isDirectory and "/" or "")
end
end
return list
else
return {}
end
end
proxy.isDirectory = function(path)
local success, result = check(FTPFileInfo(socketHandle, path, "isDirectory"))
if success then
return result
else
return false
end
end
proxy.lastModified = function(path)
local success, result = check(FTPFileInfo(socketHandle, path, "lastModified"))
if success then
return result
else
return 0
end
end
proxy.size = function(path)
local success, result = check(FTPFileInfo(socketHandle, path, "size"))
if success then
return result
else
return 0
end
end
proxy.exists = function(path)
local success, result = check(FTPFileInfo(socketHandle, path))
if success then
return result
else
return false
end
end
proxy.open = function(path, mode)
local temporaryPath = MineOSCore.getTemporaryPath()
if mode == "r" or mode == "rb" or mode == "a" or mode == "ab" then
local success, result = FTPEnterPassiveModeAndRunCommand(socketHandle, "RETR " .. path)
local fileHandle = io.open(temporaryPath, "wb")
fileHandle:write(success and result or "")
fileHandle:close()
end
local fileHandle, reason = filesystemProxy.open(temporaryPath, mode)
if fileHandle then
fileHandles[fileHandle] = {
temporaryPath = temporaryPath,
path = path,
needUpload = mode ~= "r" and mode ~= "rb",
}
end
return fileHandle, reason
end
proxy.close = function(fileHandle)
filesystemProxy.close(fileHandle)
if fileHandles[fileHandle].needUpload then
local file = io.open(fileHandles[fileHandle].temporaryPath, "rb")
local data = file:read("*a")
file:close()
check(FTPEnterPassiveModeAndRunCommand(socketHandle, "STOR " .. fileHandles[fileHandle].path, data))
end
fs.remove(fileHandles[fileHandle].temporaryPath)
fileHandles[fileHandle] = nil
end
proxy.write = function(...)
return filesystemProxy.write(...)
end
proxy.read = function(...)
return filesystemProxy.read(...)
end
proxy.seek = function(...)
return filesystemProxy.seek(...)
end
proxy.remove = function(path)
if proxy.isDirectory(path) then
local list = proxy.list(path)
for i = 1, #list do
proxy.remove((path .. "/" .. list[i]):gsub("/+", "/"))
end
FTPSocketWrite(socketHandle, "RMD " .. path)
else
FTPSocketWrite(socketHandle, "DELE " .. path)
end
end
proxy.makeDirectory = function(path)
FTPSocketWrite(socketHandle, "MKD " .. path)
return true
end
proxy.rename = function(oldPath, newPath)
FTPSocketWrite(socketHandle, "RNFR " .. oldPath)
FTPSocketWrite(socketHandle, "RNTO " .. newPath)
return true
end
return proxy
else
return false, reason
end
else
return false, reason
end
end
----------------------------------------------------------------------------------------------------------------
function MineOSNetwork.getProxyName(proxy)
function MineOSNetwork.umountModems()
umountProxy("MineOSNetworkModem")
end
function MineOSNetwork.getModemProxyName(proxy)
return proxy.name and proxy.name .. " (" .. proxy.address .. ")" or proxy.address
end
function MineOSNetwork.getProxy(address)
for proxy, path in filesystemLibrary.mounts() do
if proxy.network and proxy.address == address then
function MineOSNetwork.getMountedModemProxy(address)
for proxy, path in fs.mounts() do
if proxy.MineOSNetworkModem and proxy.address == address then
return proxy
end
end
end
function MineOSNetwork.getProxyCount()
local count = 0
for proxy, path in filesystemLibrary.mounts() do
if proxy.network then
count = count + 1
end
end
return count
end
function MineOSNetwork.unmountAll()
for proxy in filesystemLibrary.mounts() do
if proxy.network then
filesystemLibrary.unmount(proxy)
end
end
end
----------------------------------------------------------------------------------------------------------------
function MineOSNetwork.sendMessage(address, ...)
if MineOSNetwork.modemProxy then
return MineOSNetwork.modemProxy.send(address, MineOSNetwork.modemPort, ...)
@ -89,32 +441,16 @@ function MineOSNetwork.setSignalStrength(strength)
end
end
function MineOSNetwork.updateModemState()
if component.isAvailable("modem") then
MineOSNetwork.modemProxy = component.proxy(component.list("modem")())
MineOSNetwork.modemProxy.open(MineOSNetwork.modemPort)
return true
else
MineOSNetwork.modemProxy = nil
MineOSNetwork.unmountAll()
return false, "Modem component is not available"
end
end
function MineOSNetwork.broadcastComputerState(state)
return MineOSNetwork.broadcastMessage("MineOSNetwork", state and "computerAvailable" or "computerNotAvailable", MineOSCore.properties.network.name)
end
----------------------------------------------------------------------------------------------------------------
local function newFilesystemProxy(address)
local function newModemProxy(address)
local function request(method, returnOnFailure, ...)
MineOSNetwork.sendMessage(address, "MineOSNetwork", "request", method, ...)
while true do
local eventData = { event.pull(MineOSNetwork.timeout, "modem_message") }
local eventData = { event.pull(MineOSNetwork.modemTimeout, "modem_message") }
if eventData[3] == address and eventData[6] == "MineOSNetwork" then
if eventData[7] == "response" and eventData[8] == method then
@ -124,9 +460,9 @@ local function newFilesystemProxy(address)
return returnOnFailure, "Access denied"
end
elseif not eventData[1] then
local proxy = MineOSNetwork.getProxy(address)
local proxy = MineOSNetwork.getMountedModemProxy(address)
if proxy then
filesystemLibrary.unmount(proxy)
fs.umount(proxy)
end
computer.pushSignal("MineOSNetwork", "timeout")
@ -136,132 +472,134 @@ local function newFilesystemProxy(address)
end
end
return {
type = "filesystem",
address = address,
slot = 0,
network = true,
getLabel = function()
return request("getLabel", "N/A")
end,
local proxy = {}
isReadOnly = function()
return request("isReadOnly", "N/A")
end,
proxy.type = "filesystem"
proxy.address = address
proxy.slot = 0
proxy.MineOSNetworkModem = true
proxy.getLabel = function()
return request("getLabel", "N/A")
end
spaceUsed = function()
return request("spaceUsed", "N/A")
end,
proxy.isReadOnly = function()
return request("isReadOnly", 0)
end
spaceTotal = function()
return request("spaceTotal", "N/A")
end,
proxy.spaceUsed = function()
return request("spaceUsed", MineOSNetwork.proxySpaceUsed)
end
exists = function(path)
return request("exists", false, path)
end,
proxy.spaceTotal = function()
return request("spaceTotal", MineOSNetwork.proxySpaceTotal)
end
isDirectory = function(path)
return request("isDirectory", false, path)
end,
proxy.exists = function(path)
return request("exists", false, path)
end
makeDirectory = function(path)
return request("makeDirectory", false, path)
end,
proxy.isDirectory = function(path)
return request("isDirectory", false, path)
end
setLabel = function(name)
return request("setLabel", false, name)
end,
proxy.makeDirectory = function(path)
return request("makeDirectory", false, path)
end
remove = function(path)
return request("remove", false, path)
end,
proxy.setLabel = function(name)
return request("setLabel", false, name)
end
lastModified = function(path)
return request("lastModified", 0, path)
end,
proxy.remove = function(path)
return request("remove", false, path)
end
size = function(path)
return request("size", 0, path)
end,
proxy.lastModified = function(path)
return request("lastModified", 0, path)
end
list = function(path)
return table.fromString(request("list", "{}", path))
end,
proxy.size = function(path)
return request("size", 0, path)
end
seek = function(handle, whence, offset)
return request("seek", 0, handle, whence, offset)
end,
proxy.list = function(path)
return table.fromString(request("list", "{}", path))
end
open = function(path, mode)
return request("open", false, path, mode)
end,
proxy.open = function(path, mode)
return request("open", false, path, mode)
end
close = function(handle)
return request("close", false, handle)
end,
proxy.close = function(handle)
return request("close", false, handle)
end
read = function(handle, count)
return request("read", "", handle, count)
end,
proxy.seek = function(...)
return request("seek", 0, ...)
end
write = function(handle, data)
local maxPacketSize = MineOSNetwork.modemProxy.maxPacketSize() - MineOSNetwork.modemPacketReserve
repeat
if not request("write", false, handle, data:sub(1, maxPacketSize)) then
return false
end
data = data:sub(maxPacketSize + 1)
until #data == 0
proxy.read = function(...)
return request("read", "", ...)
end
return true
end,
write = function(handle, data)
local maxPacketSize = MineOSNetwork.modemProxy.maxPacketSize() - MineOSNetwork.modemPacketReserve
repeat
if not request("write", false, handle, data:sub(1, maxPacketSize)) then
return false
end
data = data:sub(maxPacketSize + 1)
until #data == 0
rename = function(from, to)
local proxyFrom = filesystemLibrary.get(from)
local proxyTo = filesystemLibrary.get(to)
return true
end
if proxyFrom.network or proxyTo.network then
local success, handleFrom, handleTo, data, reason = true
handleFrom, reason = proxyFrom.open(from, "rb")
if handleFrom then
handleTo, reason = proxyTo.open(to, "wb")
if handleTo then
while true do
data, readReason = proxyFrom.read(handleFrom, 1024)
if data then
success, reason = proxyTo.write(handleTo, data)
if not success then
break
end
else
success = false
proxy.rename = function(from, to)
local proxyFrom = fs.get(from)
local proxyTo = fs.get(to)
if proxyFrom.MineOSNetworkModem or proxyTo.MineOSNetworkModem then
local success, handleFrom, handleTo, data, reason = true
handleFrom, reason = proxyFrom.open(from, "rb")
if handleFrom then
handleTo, reason = proxyTo.open(to, "wb")
if handleTo then
while true do
data, readReason = proxyFrom.read(handleFrom, 1024)
if data then
success, reason = proxyTo.write(handleTo, data)
if not success then
break
end
else
success = false
break
end
proxyFrom.close(handleTo)
else
success = false
end
proxyFrom.close(handleFrom)
proxyFrom.close(handleTo)
else
success = false
end
if success then
success, reason = proxyFrom.remove(from)
end
return success, reason
proxyFrom.close(handleFrom)
else
return request("rename", false, from, to)
success = false
end
end,
}
if success then
success, reason = proxyFrom.remove(from)
end
return success, reason
else
return request("rename", false, from, to)
end
end
return proxy
end
local exceptionMethods = {
@ -270,7 +608,7 @@ local exceptionMethods = {
end,
list = function(path)
return table.toString(filesystemComponent.list(path))
return table.toString(filesystemProxy.list(path))
end,
open = function(path, mode)
@ -284,40 +622,34 @@ local exceptionMethods = {
end
end
MineOSNetwork.filesystemHandles[ID] = filesystemComponent.open(path, mode)
MineOSNetwork.filesystemHandles[ID] = filesystemProxy.open(path, mode)
return ID
end,
close = function(ID)
local data, reason = filesystemComponent.close(MineOSNetwork.filesystemHandles[ID])
local data, reason = filesystemProxy.close(MineOSNetwork.filesystemHandles[ID])
MineOSNetwork.filesystemHandles[ID] = nil
return data, reason
end,
read = function(ID, ...)
return filesystemComponent.read(MineOSNetwork.filesystemHandles[ID], ...)
return filesystemProxy.read(MineOSNetwork.filesystemHandles[ID], ...)
end,
write = function(ID, ...)
return filesystemComponent.write(MineOSNetwork.filesystemHandles[ID], ...)
return filesystemProxy.write(MineOSNetwork.filesystemHandles[ID], ...)
end,
seek = function(ID, ...)
return filesystemComponent.seek(MineOSNetwork.filesystemHandles[ID], ...)
return filesystemProxy.seek(MineOSNetwork.filesystemHandles[ID], ...)
end,
}
local function handleRequest(eventData)
-- print("REQ", table.unpack(eventData, 6))
local function handleRequest(eventData)
if MineOSCore.properties.network.users[eventData[3]].allowReadAndWrite then
local result = { pcall(exceptionMethods[eventData[8]] or filesystemComponent[eventData[8]], table.unpack(eventData, 9)) }
if result[1] then
MineOSNetwork.sendMessage(eventData[3], "MineOSNetwork", "response", eventData[8], table.unpack(result, 2))
else
MineOSNetwork.sendMessage(eventData[3], "MineOSNetwork", "response", eventData[8], result[1], result[2])
end
local result = { pcall(exceptionMethods[eventData[8]] or filesystemProxy[eventData[8]], table.unpack(eventData, 9)) }
MineOSNetwork.sendMessage(eventData[3], "MineOSNetwork", "response", eventData[8], table.unpack(result, result[1] and 2 or 1))
else
MineOSNetwork.sendMessage(eventData[3], "MineOSNetwork", "accessDenied")
end
@ -326,8 +658,9 @@ end
----------------------------------------------------------------------------------------------------------------
function MineOSNetwork.update()
MineOSNetwork.unmountAll()
MineOSNetwork.updateModemState()
MineOSNetwork.umountModems()
MineOSNetwork.umountFTPs()
MineOSNetwork.updateComponents()
MineOSNetwork.setSignalStrength(MineOSCore.properties.network.signalStrength)
MineOSNetwork.broadcastComputerState(MineOSCore.properties.network.enabled)
@ -340,20 +673,20 @@ function MineOSNetwork.update()
local eventData = {...}
if (eventData[1] == "component_added" or eventData[1] == "component_removed") and eventData[3] == "modem" then
MineOSNetwork.updateModemState()
MineOSNetwork.updateComponents()
elseif eventData[1] == "modem_message" and MineOSCore.properties.network.enabled and eventData[6] == "MineOSNetwork" then
if eventData[7] == "request" then
handleRequest(eventData)
elseif eventData[7] == "computerAvailable" or eventData[7] == "computerAvailableRedirect" then
for proxy in filesystemLibrary.mounts() do
if proxy.network and proxy.address == eventData[3] then
filesystemLibrary.unmount(proxy)
for proxy in fs.mounts() do
if proxy.MineOSNetworkModem and proxy.address == eventData[3] then
fs.umount(proxy)
end
end
proxy = newFilesystemProxy(eventData[3])
proxy = newModemProxy(eventData[3])
proxy.name = eventData[8]
filesystemLibrary.mount(proxy, MineOSNetwork.mountPath .. eventData[3]:sub(1, 3) .. "/")
fs.mount(proxy, MineOSNetwork.mountPaths.modem .. eventData[3] .. "/")
if eventData[7] == "computerAvailable" then
MineOSNetwork.sendMessage(eventData[3], "MineOSNetwork", "computerAvailableRedirect", MineOSCore.properties.network.name)
@ -366,9 +699,9 @@ function MineOSNetwork.update()
computer.pushSignal("MineOSNetwork", "updateProxyList")
elseif eventData[7] == "computerNotAvailable" then
local proxy = MineOSNetwork.getProxy(eventData[3])
local proxy = MineOSNetwork.getMountedModemProxy(eventData[3])
if proxy then
filesystemLibrary.unmount(proxy)
fs.umount(proxy)
end
computer.pushSignal("MineOSNetwork", "updateProxyList")
@ -392,6 +725,13 @@ end
----------------------------------------------------------------------------------------------------------------
-- MineOSNetwork.updateComponents()
-- local proxy, reason = MineOSNetwork.FTPProxy("localhost", 8888, "root", "1234")
-- print(proxy, reason)
----------------------------------------------------------------------------------------------------------------
return MineOSNetwork

View File

@ -2,7 +2,7 @@
local filesystem = require("filesystem")
local MineOSPaths = {}
----------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------
MineOSPaths.OS = "/MineOS/"
MineOSPaths.downloads = MineOSPaths.OS .. "Downloads/"
@ -19,14 +19,17 @@ MineOSPaths.trash = MineOSPaths.OS .. "Trash/"
MineOSPaths.properties = MineOSPaths.system .. "Properties.cfg"
MineOSPaths.editor = MineOSPaths.applications .. "/MineCode IDE.app/Main.lua"
MineOSPaths.explorer = MineOSPaths.applications .. "/Finder.app/Main.lua"
MineOSPaths.temporary = MineOSPaths.system .. "Temporary/"
MineOSPaths.network = MineOSPaths.system .. "Network/"
----------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------
filesystem.makeDirectory(MineOSPaths.pictures)
filesystem.makeDirectory(MineOSPaths.applicationData)
filesystem.makeDirectory(MineOSPaths.trash)
filesystem.makeDirectory(MineOSPaths.desktop)
filesystem.makeDirectory(MineOSPaths.network)
----------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------
return MineOSPaths