1
0
mirror of https://github.com/AR2000AR/openComputers_codes.git synced 2025-09-06 21:51:14 +02:00

documentation. Lot of it

This commit is contained in:
2023-02-01 21:16:58 +01:00
parent 82a8ac6004
commit cff8213f25
42 changed files with 1775 additions and 219 deletions

View File

@@ -41,12 +41,18 @@ end
local function saveConfig()
--save the config table to a file
if (config.masterAccountCBdata) then config.masterAccountCBdata = data.encode64(serialization.serialize(config.masterAccountCBdata)) end
if (config.masterAccountCBdata) then
---@type string
config.masterAccountCBdata = data.encode64(serialization.serialize(config.masterAccountCBdata))
end
local cFile = io.open(CONFIG_FILE, "w")
assert(cFile, string.format("Could not open : %s", CONFIG_FILE))
cFile:write(serialization.serialize(config))
cFile:close()
if (config.masterAccountCBdata) then config.masterAccountCBdata = serialization.unserialize(data.decode64(config.masterAccountCBdata)) end
if (config.masterAccountCBdata) then
---@type cardData
config.masterAccountCBdata = serialization.unserialize(data.decode64(config.masterAccountCBdata--[[@as string]] ))
end
end
local function addToKnonwPlayer(playerName, accountUUID)
@@ -58,6 +64,9 @@ local function addToKnonwPlayer(playerName, accountUUID)
table.insert(knownAccounts, {playerName, accountUUID})
end
---Get the player's account uuid if exists
---@param playerName string
---@return string|boolean
local function getAccountUUID(playerName)
for _, v in ipairs(knownAccounts) do
if (v[1] == playerName) then return v[2] end
@@ -100,19 +109,25 @@ local function moveItem(source, sink, item, amount)
return request - amount
end
---Create a new card for the player
---@param playerName string
local function makeCard(playerName)
term.clear()
local acUUID = getAccountUUID(playerName)
local status
local newAccount = false
--#region getaccount
local acUUID = getAccountUUID(playerName)
if (not acUUID) then
print("Making a new account")
newAccount = true
---@diagnostic disable-next-line: cast-local-type
status, acUUID = bank.createAccount()
if (status == 0) then --ok
addToKnonwPlayer(playerName, acUUID)
if (config.masterAccountCreditPerAccount ~= 0) then
status = bank.editAccount(config.masterAccountCBdata, config.masterAccountCreditPerAccount)
status = bank.editAccount(config.masterAccountCBdata--[[@as cardData]] , config.masterAccountCreditPerAccount)
if (status ~= 0) then
local file = io.open(ERROR_FILE, "a")
assert(file, "Can't fail here")
@@ -120,8 +135,17 @@ local function makeCard(playerName)
file:close()
end
end
else
print("Server did not respond")
print("Status : " .. status)
event.pull("touch")
return
end
end
--#endregion
--#region writeCard
if (component.isAvailable("drive")) then
if (component.drive.getLabel()) then
disk_drive.eject()
@@ -138,10 +162,12 @@ local function makeCard(playerName)
repeat
if (not component.isAvailable("drive")) then event.pull("component_available", "drive") end
print("Requesting CB")
---@cast acUUID string
status, pin, rawCBdata = bank.requestNewCBdata(acUUID, component.drive.address)
if (status ~= 0) then
print("ERROR : Could not get rawCBdata\nStatus : " .. status)
else
assert(rawCBdata, "Status 0 but no rawCBdata")
print(string.format("PIN : %q", pin))
print("Writing CB")
libCB.writeCB(rawCBdata, component.drive)
@@ -149,6 +175,10 @@ local function makeCard(playerName)
end
try = try + 1
until (goodCB or try >= 3)
--#endregion
--#region initialCredit
if (try < 3) then
if (newAccount) then
if (config.newAccountCredit ~= 0) then
@@ -172,6 +202,8 @@ local function makeCard(playerName)
print("Touch to continue")
event.pull("touch")
end
--#endregion
end
--INIT=========================================================================
@@ -202,6 +234,7 @@ end
--load masterAccountCBdata if present
if (config.masterAccountCBdata and config.masterAccountCBdata ~= "") then
---@type cardData
config.masterAccountCBdata = serialization.unserialize(data.decode64(config.masterAccountCBdata))
end

View File

@@ -31,38 +31,63 @@ config.timeout = config.timeout or 5
config.secret = data.decode64(config.secret) or ""
---@class bankapi
local bank = {} --table returned by require
--protocole commands constants
local PROTOCOLE_GET_CREDIT = "GET_CREDIT"
local PROTOCOLE_MAKE_TRANSACTION = "MAKE_TRANSACTION"
local PROTOCOLE_NEW_ACCOUNT = "NEW_ACCOUNT"
local PROTOCOLE_NEW_CB = "NEW_CB"
local PROTOCOLE_EDIT = "EDIT"
--protocole status constants
local PROTOCOLE_OK = 0
local PROTOCOLE_NO_ACCOUNT = 1
local PROTOCOLE_ERROR_ACCOUNT = 2
local PROTOCOLE_ERROR_CB = 3
local PROTOCOLE_ERROR_AMOUNT = 4
local PROTOCOLE_DENIED = 4
local PROTOCOLE_ERROR_RECEIVING_ACCOUNT = 5
local PROTOCOLE_ERROR_UNKNOWN = 999
local PROTOCOLE = {}
---protocole commands
---@enum ProtocoleCommand
PROTOCOLE.COMMAND = {
GET_CREDIT = "GET_CREDIT",
MAKE_TRANSACTION = "MAKE_TRANSACTION",
NEW_ACCOUNT = "NEW_ACCOUNT",
NEW_CB = "NEW_CB",
EDIT = "EDIT",
NONE = ""
}
---protocole status
---@enum ProtocoleStatus
PROTOCOLE.STATUS = {
MODEM_TIMEDOUT = MODEM_TIMEDOUT,
OK = 0,
NO_ACCOUNT = 1,
ERROR_ACCOUNT = 2,
ERROR_CB = 3,
ERROR_AMOUNT = 4,
DENIED = 4,
ERROR_RECEIVING_ACCOUNT = 5,
ERROR_UNKNOWN = 999,
}
---@enum CommandStatus
bank.STATUS = {
TIMEOUT = PROTOCOLE.STATUS.MODEM_TIMEDOUT,
WRONG_MESSAGE = -2,
OK = PROTOCOLE.STATUS.OK,
NO_ACCOUNT = PROTOCOLE.STATUS.NO_ACCOUNT,
ACCOUNT_ERROR = PROTOCOLE.STATUS.ERROR_ACCOUNT,
CARD_ERROR = PROTOCOLE.STATUS.ERROR_CB,
AMOUNT_ERROR = PROTOCOLE.STATUS.ERROR_AMOUNT,
DENIED = PROTOCOLE.STATUS.DENIED,
RECIVEING_ACCOUNT_ERROR = PROTOCOLE.STATUS.ERROR_RECEIVING_ACCOUNT,
UNKNOWN = PROTOCOLE.STATUS.ERROR_UNKNOWN
}
--=====================================
local function reciveMessage() --recive a message from the modem component.
---recive a message from the modem component.
---@return ProtocoleStatus status, ProtocoleCommand command, table message
local function reciveMessage()
---@type unknown,unknown,string,number,unknown,ProtocoleStatus,ProtocoleCommand,string
local _, _, from, port, _, status, command, message = event.pull(config.timeout, "modem_message")
if (not status) then status = MODEM_TIMEDOUT end
--make sure no nil value is returned
if (not command) then command = "" end
if (not command) then command = PROTOCOLE.COMMAND.NONE end
if (not message) then message = "" end
return status, command, serialization.unserialize(message)
end
--send a request to the server
-- @param requestType:string
-- @param requestData:table
-- @return status:int,command:string,message:table
---send a request to the server
---@param requestType string
---@param requestData table
---@return ProtocoleStatus status,string command ,table message
local function sendRequest(requestType, requestData) --format and send a request to the server
modem.open(BANK_PORT)
modem.send(config.bank_addr, BANK_PORT, requestType, serialization.serialize(requestData))
@@ -71,28 +96,19 @@ local function sendRequest(requestType, requestData) --format and send a request
return status, command, message
end
--get the account solde
-- @param uuid_cible:string
-- @param cbData:table
-- @param amount:init
-- @return int
-- -1 : timeout
-- -2 : wrong message
-- 0 : ok
-- 1 : no account
-- 2 : account error
-- 3 : cb error
-- @return solde
---get the account solde
---@param cbData cardData
---@return CommandStatus status, number|nil balance
function bank.getCredit(cbData)
local status, command, message = sendRequest(PROTOCOLE_GET_CREDIT, {cbData = cbData})
local status, command, message = sendRequest(PROTOCOLE.COMMAND.GET_CREDIT, {cbData = cbData})
if (status == MODEM_TIMEDOUT) then
return MODEM_TIMEDOUT
return bank.STATUS.TIMEOUT
else
if (command ~= PROTOCOLE_GET_CREDIT) then
return -2 --wrong message
if (command ~= PROTOCOLE.COMMAND.GET_CREDIT) then
return bank.STATUS.WRONG_MESSAGE
else
if (status == PROTOCOLE_OK) then
return 0, message.solde
if (status == PROTOCOLE.STATUS.OK) then
return bank.STATUS.OK, message.solde
else
return status, nil
end
@@ -100,24 +116,17 @@ function bank.getCredit(cbData)
end
end
-- send credit to uuid_cible
-- @param uuid_cible:string
-- @param cbData:table
-- @param amount:init
-- @return int
-- -1 : timeout
-- -2 : wrong message
-- 0 : ok
-- 1 : no account
-- 2 : account error
-- 3 : cb error
-- 4 : amount error
---send credit to uuid_cible
---@param uuid_cible string
---@param cbData cardData
---@param amount number
---@return CommandStatus status
function bank.makeTransaction(uuid_cible, cbData, amount)
local status, command, msg = sendRequest(PROTOCOLE_MAKE_TRANSACTION, {dst = uuid_cible, cbData = cbData, amount = amount})
local status, command, msg = sendRequest(PROTOCOLE.COMMAND.MAKE_TRANSACTION, {dst = uuid_cible, cbData = cbData, amount = amount})
if (status == MODEM_TIMEDOUT) then
return MODEM_TIMEDOUT
else
if (command ~= PROTOCOLE_MAKE_TRANSACTION) then
if (command ~= PROTOCOLE.COMMAND.MAKE_TRANSACTION) then
return -2 --wrong message
else
return status
@@ -125,15 +134,17 @@ function bank.makeTransaction(uuid_cible, cbData, amount)
end
end
---create a new account
---@return CommandStatus status, string|nil accountUUID
function bank.createAccount()
local status, command, msg = sendRequest(PROTOCOLE_NEW_ACCOUNT, {secret = config.secret})
local status, command, msg = sendRequest(PROTOCOLE.COMMAND.NEW_ACCOUNT, {secret = config.secret})
if (status == MODEM_TIMEDOUT) then
return MODEM_TIMEDOUT
else
if (command ~= PROTOCOLE_NEW_ACCOUNT) then
if (command ~= PROTOCOLE.COMMAND.NEW_ACCOUNT) then
return -2 --wrong message
else
if (status == PROTOCOLE_OK) then
if (status == PROTOCOLE.STATUS.OK) then
return status, msg.uuid
else
return status
@@ -142,15 +153,20 @@ function bank.createAccount()
end
end
---Request data to write a new debit card from the server
---If cbUUID is not provided, the server will send less and unsigned data
---@param accountUUID string
---@param cbUUID? string
---@return CommandStatus status, string|nil pin, string|nil rawCBdata
function bank.requestNewCBdata(accountUUID, cbUUID)
local status, command, msg = sendRequest(PROTOCOLE_NEW_CB, {secret = config.secret, uuid = accountUUID, cbUUID = cbUUID})
local status, command, msg = sendRequest(PROTOCOLE.COMMAND.NEW_CB, {secret = config.secret, uuid = accountUUID, cbUUID = cbUUID})
if (status == MODEM_TIMEDOUT) then
return MODEM_TIMEDOUT
else
if (command ~= PROTOCOLE_NEW_CB) then
if (command ~= PROTOCOLE.COMMAND.NEW_CB) then
return -2 --wrong message
else
if (status == PROTOCOLE_OK) then
if (status == PROTOCOLE.STATUS.OK) then
return status, msg.pin, msg.rawCBdata
else
return status
@@ -159,12 +175,16 @@ function bank.requestNewCBdata(accountUUID, cbUUID)
end
end
---Edit (add or remove) the account's balance
---@param cbData cardData
---@param amount number
---@return CommandStatus status
function bank.editAccount(cbData, amount)
local status, command = sendRequest(PROTOCOLE_EDIT, {secret = config.secret, cbData = cbData, amount = amount})
local status, command = sendRequest(PROTOCOLE.COMMAND.EDIT, {secret = config.secret, cbData = cbData, amount = amount})
if (status == MODEM_TIMEDOUT) then
return MODEM_TIMEDOUT
else
if (command ~= PROTOCOLE_EDIT) then
if (command ~= PROTOCOLE.COMMAND.EDIT) then
return -2 --wrong message
else
return status
@@ -172,8 +192,8 @@ function bank.editAccount(cbData, amount)
end
end
--set the modem timeout (in s)
-- @param t:int
---set the modem timeout (in s)
---@param t number
function bank.setModemTimeout(t)
config.timeout = t
end

View File

@@ -7,11 +7,12 @@ local coin = require("libCoin")
local gui = require("libGUI")
local event = require("event")
local os = require("os")
local gpu = require("component").gpu
local transposer = require("component").transposer
local disk_drive = require("component").disk_drive
local proxy = require("component").proxy
local beep = require("component").computer.beep
local component = require("component")
local gpu = component.gpu
local transposer = component.transposer
local disk_drive = component.disk_drive
local proxy = component.proxy
local beep = component.computer.beep
local STORAGE = 0
local EXTERIOR = 0
@@ -43,8 +44,11 @@ local event_touch, event_drive, event_eject, event_magData = nil, nil, nil, nil
local old_res_x, old_res_y = nil, nil
---@type Component
local drive = nil
local cbData = false
---@type cardData
local cbData = nil
---@type encryptedCardData
local encryptedData = nil
local solde = 0
-- =============================================================================
@@ -119,7 +123,11 @@ local function makeTransaction(amount)
elseif (mode == MODE_DEPOSIT) then
b, s, g, p = coin.moveCoin(amount, EXTERIOR, STORAGE)
end
if (b ~= false) then
if (b) then
---@cast b number
---@cast s number
---@cast g number
---@cast p number
coinGiven = coin.getValue(b, s, g, p)
if (mode == MODE_WITHDRAW) then coinGiven = coinGiven * -1 end
bank.editAccount(cbData, coinGiven)
@@ -299,7 +307,6 @@ local function init()
if (blocking) then
while (self:isVisible()) do
main_screen:draw()
---@diagnostic disable-next-line: undefined-field
os.sleep()
end
end
@@ -344,7 +351,8 @@ end
init()
while (mode ~= MODE_CLOSING) do
main_screen:draw()
---@diagnostic disable-next-line: undefined-field
os.sleep()
end
closeClient()
--TODO handle keypad X

View File

@@ -4,7 +4,8 @@ local bank_api = require("bank_api")
local libCB = require("libCB")
local os = require("os")
local component = require("component")
local gpu = require("component").gpu
local gpu = component.gpu
local MODE_CLOSING = -1
local MODE_IDLE = 0
@@ -71,22 +72,27 @@ local function creerCompte(drive)
local status, acUUID = bank_api.createAccount()
printStatus("creation de compte : " .. status)
if (status == 0) then
---@cast acUUID string
local pin, rawCBdata
if (drive.type == "drive") then
status, pin, rawCBdata = bank_api.requestNewCBdata(acUUID, drive.address)
else
status, pin, rawCBdata = bank_api.requestNewCBdata(acUUID)
end
if (drive.type == "os_cardwriter") then
printStatus("Insert magnetic card in the writer...")
if (status == bank_api.STATUS.OK) then
assert(rawCBdata, "Status ok but no rawCBdata")
if (drive.type == "os_cardwriter") then
printStatus("Insert magnetic card in the writer...")
end
while (not libCB.writeCB(rawCBdata, drive)) do os.sleep(0.1) end
closePopup(diskWaitPopup)
acUUIDText:setText("uuid : " .. acUUID)
pinText:setText("pin : " .. pin)
newAccountScreen:setVisible(true)
printStatus("Card created.")
else
printStatus(string.format("Error : %d", status))
end
---@diagnostic disable-next-line: undefined-field
while (not libCB.writeCB(rawCBdata, drive)) do os.sleep(0.1) end
closePopup(diskWaitPopup)
acUUIDText:setText("uuid : " .. acUUID)
pinText:setText("pin : " .. pin)
newAccountScreen:setVisible(true)
printStatus("Card created.")
end
end
@@ -305,7 +311,6 @@ end
init()
while (mode ~= MODE_CLOSING) do
---@diagnostic disable-next-line: undefined-field
os.sleep()
screen:draw()
end

View File

@@ -16,6 +16,11 @@ local accountDir = "/srv/bank/" --default value
local PROTOCOLE_NO_ACCOUNT = 1
local PROTOCOLE_ERROR_ACCOUNT = 2
---load the keys form a file.
---@param public
--- | true # public
--- | false # private
---@return EcKey
local function getKey(public)
print("-> getKey")
local ext = ".priv"
@@ -70,7 +75,7 @@ end
local function writeAccount(accountUUID, solde)
print("-> writeAccount")
local account = {solde = solde, uuid = accountUUID}
account.sig = dataCard.encode64(dataCard.ecdsa(solde .. accountUUID, getKey(false))) --encode sig to make saving it easier
account.sig = dataCard.encode64(dataCard.ecdsa(solde .. accountUUID, getKey(false))--[[@as string]] ) --encode sig to make saving it easier
local fileContent = serialization.serialize(account) --convert the table into a string
fileContent = dataCard.encrypt(fileContent, getAES(), AES_IV) --encrypt the data
fileContent = dataCard.encode64(fileContent) --encode the encrypted data to make saving and reading it easier
@@ -132,9 +137,9 @@ elseif (args[1] == "remove") then
elseif (args[1] == 'test') then
local _, clearData = loadAccount(args[2])
assert(clearData, "Error when loading the account data")
local b, c = 0, 0
local b, c
b = dataCard.ecdsa(clearData.solde .. args[2], getKey(true), dataCard.decode64(clearData.sig))
c = dataCard.encode64(dataCard.ecdsa(clearData.solde .. args[2], getKey(false)))
c = dataCard.encode64(dataCard.ecdsa(clearData.solde .. args[2], getKey(false))--[[@as string]] )
print(b)
print("saved: " .. clearData.sig)
print("calc : " .. c)

View File

@@ -35,7 +35,7 @@ if (fs.exists(CONF_DIR .. CONF_FILE_NAME)) then --read the config file
if (confTable.keyFile) then keyFile = confTable.keyFile end
end
if (args[1]) then
local secret = data.ecdsa(args[1], getKey(false))
local secret = data.ecdsa(args[1], getKey(false)) --[[@as string]]
local secretFile = io.open(args[2] or "/home/secret", "w")
assert(secretFile, string.format("Could not open file : %s", args[2] or "/home/secret"))
secretFile:write(data.encode64(secret))

View File

@@ -114,7 +114,7 @@ end
local function writeAccount(accountUUID, solde)
log("-> writeAccount")
local account = {solde = solde, uuid = accountUUID}
account.sig = dataCard.encode64(dataCard.ecdsa(solde .. accountUUID, getKey(false))) --encode sig to make saving it easier
account.sig = dataCard.encode64(dataCard.ecdsa(solde .. accountUUID, getKey(false))--[[@as string]] ) --encode sig to make saving it easier
local fileContent = serialization.serialize(account) --convert the table into a string
fileContent = dataCard.encrypt(fileContent, getAES(), AES_IV) --encrypt the data
fileContent = dataCard.encode64(fileContent) --encode the encrypted data to make saving and reading it easier

View File

@@ -1,8 +1,8 @@
local fs = require "filesystem"
local shell = require "shell"
local crypttool = require "crypttool"
local data = require("component").data
local os = require("os")
local fs = require("filesystem")
local shell = require("shell")
local crypttool = require("crypttool")
local data = require("component").data
local os = require("os")
local args, opt = shell.parse(...)

View File

@@ -11,9 +11,15 @@ local data = component.data
local DATA_DIR = "/.crypttools/"
---@class CryptToolFilesystemProxy : ComponentFilesystem
local crypttool = {}
crypttool.Proxy = {}
---Return a new filesytem proxy
---@param filesystemComponent ComponentFilesystem|string
---@param aesKey string
---@return CryptToolFilesystemProxy
function crypttool.Proxy.new(filesystemComponent, aesKey)
checkArg(1, filesystemComponent, "string", "table")
checkArg(2, aesKey, "string")
@@ -30,7 +36,7 @@ function crypttool.Proxy.new(filesystemComponent, aesKey)
local function getSecurePath(path)
if (not path:match("^" .. DATA_DIR)) then
return string.format("%s%s", "^" .. DATA_DIR, path)
return string.format("%s%s", DATA_DIR, path)
end
return path
end

View File

@@ -0,0 +1,37 @@
---@meta
---@class ComponentComputer : Component
local computer = {}
---Tries to start the computer. Returns true on success, false otherwise. Note that this will also return false if the computer was already running. If the computer is currently shutting down, this will cause the computer to reboot instead.
---@return boolean
function computer.start() end
---Tries to stop the computer. Returns true on success, false otherwise. Also returns false if the computer is already stopped.
---@return boolean
function computer.stop() end
---Returns whether the computer is currently running.
---@return boolean
function computer.isRunning() end
---Plays a tone, useful to alert users via audible feedback. Supports frequencies from 20 to 2000Hz, with a duration of up to 5 seconds.
---@param frequency number
---@param duration number
function computer.beep(frequency, duration) end
---Returns a table of device information. Note that this is architecture-specific and some may not implement it at all.
---@return table
function computer.getDeviceInfo() end
---Attempts to crash the computer for the specified reason.
---@param reason string
function computer.crash(reason) end
---Returns the computer's current architecture.
---@return string
function computer.getArchitecture() end
---Returns whether or not the computer is, in fact, a robot.
---@return boolean
function computer.isRobot() end

View File

@@ -0,0 +1,119 @@
---@meta
---@class ComponentData : Component
local data = {}
--#region Tier 1 Callbacks
---Computes CRC-32 hash of the data. Result is in binary format.
---@param data string
---@return string
function data.crc32(data) end
---Applies base64 decoding to the data.
---@param data string
---@return string
function data.decode64(data) end
---Applies base64 encoding to the data. Result is in binary format.
---@param data string
---@return string
function data.encode64(data) end
---Computes MD5 hash of the data. Result is in binary format
---@param data string
---@return string
function data.md5(data) end
---Computes SHA2-256 hash of the data. Result is in binary format.
---@param data string
---@return string
function data.sha256(data) end
---Applies deflate compression to the data.
---@param data string
---@return string
function data.deflate(data) end
---Applies inflate decompression to the data.
---@param data string
---@return string
function data.inflate(data) end
---The maximum size of data that can be passed to other functions of the card.
---@return number
function data.getLimit() end
--endregion
--#region Tier 2 Callbacks
---Applies AES encryption to the data using the key and (preferably) random IV.
---@param data string
---@param key string
---@param iv string
---@return string
function data.encrypt(data, key, iv) end
---Reverses AES encryption on the data using the key and the IV.
---@param data string
---@param key string
---@param iv string
---@return string
function data.decrypt(data, key, iv) end
---Generates a random binary string of len length.
---@param len number
---@return string
function data.random(len) end
--#endregion
--#region Tier 3 Callbacks
---@class EcKey
local ecKey = {}
---is the key public
---@return boolean
function ecKey.isPublic() end
---serialize the key to save it
---@return string
function ecKey.serialize() end
---@class EcKeyPublic : EcKey
---@class EcKeyPrivate :EcKey
---Generates a public/private key pair for various cryptiographic functions.
---Optional second parameter specifies key length, 256 or 384 bits accepted.
---Key types include “ec-public” and “ec-private”. Keys can be serialized with
---key.serialize():string Keys also contain the function key.isPublic():boolean
---@param bitLen? 256 | 384
---@return EcKeyPublic publicKey, EcKeyPrivate privateKey
function data.generateKeyPair(bitLen) end
---Generates a signiture of data using a private key. If signature is present
---verifies the signature using the public key, the previously generated
---signature string and the original string.
---@param data string
---@param key EcKey
---@param sig? string
---@return string|boolean
function data.ecdsa(data, key, sig) end
--- Generates a Diffie-Hellman shared key using the first user's private key and
--- the second user's public key. An example of a basic key relation:
--- ecdh(userA.private, userB.public) == ecdh(userB.private, userA.public)
---@param privateKey EcKeyPrivate
---@param publicKey EcKeyPublic
---@return string
function data.ecdh(privateKey, publicKey) end
---Transforms a key from string to it's arbitrary type.
---@param data string
---@param type "ec-public" | "ec-private"
---@return table
function data.deserializeKey(data, type) end
--#endregion

View File

@@ -0,0 +1,17 @@
---@meta
---@class ComponentDiskDrive : Component
local disk_drive = {}
---Eject the currently present medium from the drive.
---@param velocity? number
---@return boolean
function disk_drive.eject(velocity) end
---Check whether some medium is currently in the drive.
---@return boolean
function disk_drive.isEmpty() end
---Return the internal floppy disk address.
---@return string|nil address, string|nil reason
function disk_drive.media() end

View File

@@ -0,0 +1,45 @@
---@meta
---@class ComponentDrive : Component
local drive = {}
---Read a single byte at the specified offset.
---@param offset number
---@return number
function drive.readByte(offset) end
---Write a single byte to the specified offset.
---@param offset number
---@param value number
function drive.writeByte(offset, value) end
---Returns the size of a single sector on the drive, in bytes.
---@return number
function drive.getSectorSize() end
---Get the current label of the drive.
---@return string
function drive.getLabel() end
---Sets the label of the drive. Returns the new value, which may be truncated.
---@param value string
---@return string
function drive.setLabel(value) end
---Read the current contents of the specified sector.
---@param sector number
---@return string
function drive.readSector(sector) end
---Write the specified contents to the specified sector.
---@param sector number
---@param value string
function drive.writeSector(sector, value) end
---Returns the number of platters in the drive.
---@return number
function drive.getPlatterCount() end
---Returns the total capacity of the drive, in bytes.
---@return number
function drive.getCapacity() end

View File

@@ -0,0 +1,96 @@
---@meta
---@class ComponentFilesystem : Component
local filesytem = {}
---The currently used capacity of the file system, in bytes.
---@return number bytes
function filesytem.spaceUsed() end
---Opens a new file descriptor and returns its handle.
---@param path string
---@param mode? string
---@return number hanlde
---@nodiscard
function filesytem.open(path, mode) end
---Seeks in an open file descriptor with the specified handle. Returns the new pointer position.
---@param handle number
---@param whence string
---@param offset number
---@return number
function filesytem.seek(handle, whence, offset) end
---Creates a directory at the specified absolute path in the file system. Creates parent directories, if necessary.
---@param path string
---@return boolean
function filesytem.makeDirectory(path) end
---Returns whether an object exists at the specified absolute path in the file system.
---@param path string
---@return boolean
function filesytem.exists(path) end
---Returns whether the file system is read-only.
---@return boolean
function filesytem.isReadOnly() end
---Writes the specified data to an open file descriptor with the specified handle.
---@param handle number
---@param value string
---@return boolean
function filesytem.write(handle, value) end
---The overall capacity of the file system, in bytes.
---@return number
function filesytem.spaceTotal() end
---Returns whether the object at the specified absolute path in the file system is a directory.
---@param path string
---@return boolean
function filesytem.isDirectory(path) end
---Renames/moves an object from the first specified absolute path in the file system to the second.
---@param from string
---@param to any
---@return boolean
function filesytem.rename(from, to) end
---Returns a list of names of objects in the directory at the specified absolute path in the file system.
---@param path string
---@return table
function filesytem.list(path) end
---Returns the (real world) timestamp of when the object at the specified absolute path in the file system was modified.
---@param path string
---@return number
function filesytem.lastModified(path) end
---Get the current label of the file system.
---@return string
function filesytem.getLabel() end
---Removes the object at the specified absolute path in the file system.
---@param path string
---@return boolean
function filesytem.remove(path) end
---Closes an open file descriptor with the specified handle.
---@param handle number
function filesytem.close(handle) end
---Returns the size of the object at the specified absolute path in the file system.
---@param path string
---@return number
function filesytem.size(path) end
---Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.
---@param handle number
---@param count number
---@return string or nil
function filesytem.read(handle, count) end
---Sets the label of the file system. Returns the new value, which may be truncated.
---@param value string
---@return string
function filesytem.setLabel(value) end

View File

@@ -0,0 +1,177 @@
---@meta
---@class ComponentGPU : Component
local gpu = {}
---Tries to bind the GPU to a screen with the specified address. Returns true on success, false and an error message on failure. Resets the screen's settings if reset is 'true'. A GPU can only be bound to one screen at a time. All operations on it will work on the bound screen. If you wish to control multiple screens at once, you'll need to put more than one graphics card into your computer.
---@param address string
---@param reset? boolean
---@return boolean sucess, string|nil reason
function gpu.bind(address, reset) end
---Get the address of the screen the GPU is bound to. Since 1.3.2.
---@return string address
function gpu.getScreen() end
---Gets the current background color. This background color is applied to all “pixels” that get changed by other operations.
---Note that the returned number is either an RGB value in hexadecimal format, i.e. 0xRRGGBB, or a palette index. The second returned value indicates which of the two it is (true for palette color, false for RGB value).
---@return number color, boolean isPaletteIndex
function gpu.getBackground() end
---Sets the background color to apply to “pixels” modified by other operations from now on. The returned value is the old background color, as the actual value it was set to (i.e. not compressed to the color space currently set). The first value is the previous color as an RGB value. If the color was from the palette, the second value will be the index in the palette. Otherwise it will be nil. Note that the color is expected to be specified in hexadecimal RGB format, i.e. 0xRRGGBB. This is to allow uniform color operations regardless of the color depth supported by the screen and GPU.
---@param color number
---@param isPaletteIndex? boolean
---@return number previousColor, number|nil paletIndex
function gpu.setBackground(color, isPaletteIndex) end
---Like getBackground, but for the foreground color.
---@return number color, boolean isPaletteIndex
function gpu.getForeground() end
---Like setBackground, but for the foreground color.
---@param color number
---@param isPaletteIndex? boolean
---@return number previousColor, number|nil paletIndex
function gpu.setForeground(color, isPaletteIndex) end
---Gets the RGB value of the color in the palette at the specified index.
---@param index number
---@return number color rbg color
function gpu.getPaletteColor(index) end
---Sets the RGB value of the color in the palette at the specified index.
---@param index number
---@param value number rbg color
---@return number oldPatetteColor rbg color
function gpu.setPaletteColor(index, value) end
---Gets the maximum supported color depth supported by the GPU and the screen it is bound to (minimum of the two).
---@return number maxDepth maximum color depth
function gpu.maxDepth() end
---The currently set color depth of the GPU/screen, in bits. Can be 1, 4 or 8.
---@return number colorDepth color depth
function gpu.getDepth() end
---Sets the color depth to use. Can be up to the maximum supported color depth. If a larger or invalid value is provided it will throw an error. Returns the old depth as one of the strings OneBit, FourBit, or EightBit.
---@param bit number
function gpu.setDepth(bit) end
---Gets the maximum resolution supported by the GPU and the screen it is bound to (minimum of the two).
---@return number x, number y
function gpu.maxResolution() end
---Gets the currently set resolution.
---@return number x, number y
function gpu.getResolution() end
---Sets the specified resolution. Can be up to the maximum supported resolution. If a larger or invalid resolution is provided it will throw an error. Returns true if the resolution was changed (may return false if an attempt was made to set it to the same value it was set before), false otherwise.
---@return number oldX, number oldY
function gpu.setResolution(width, height) end
---Get the current viewport resolution.
---@return number x, number y
function gpu.getViewport() end
---Set the current viewport resolution. Returns true if it was changed (may return false if an attempt was made to set it to the same value it was set before), false otherwise. This makes it look like screen resolution is lower, but the actual resolution stays the same. Characters outside top-left corner of specified size are just hidden, and are intended for rendering or storing things off-screen and copying them to the visible area when needed. Changing resolution will change viewport to whole screen.
---@param width number
---@param height number
---@return boolean
function gpu.setViewport(width, height) end
---Gets the size in blocks of the screen the graphics card is bound to. For simple screens and robots this will be one by one. Deprecated, use screen.getAspectRatio() instead.
---@deprecated
---@return number x, number y
function gpu.getSize() end
---Gets the character currently being displayed at the specified coordinates. The second and third returned values are the fore- and background color, as hexvalues. If the colors are from the palette, the fourth and fifth values specify the palette index of the color, otherwise they are nil.
---@return string character, number foreground, number background, number|nil frgPaletIndex, number|nil bgrPaletIndex
function gpu.get(x, y) end
---Writes a string to the screen, starting at the specified coordinates. The string will be copied to the screen's buffer directly, in a single row. This means even if the specified string contains line breaks, these will just be printed as special characters, the string will not be displayed over multiple lines. Returns true if the string was set to the buffer, false otherwise.
---The optional fourth argument makes the specified text get printed vertically instead, if true.
---@param x number
---@param y number
---@param value string
---@param vertical? boolean
function gpu.set(x, y, value, vertical) end
---Copies a portion of the screens buffer to another location. The source rectangle is specified by the x, y, width and height parameters. The target rectangle is defined by x + tx, y + ty, width and height. Returns true on success, false otherwise.
---@param x number
---@param y number
---@param width number
---@param height number
---@param tx number
---@param ty number
---@return boolean
function gpu.copy(x, y, width, height, tx, ty) end
---Fills a rectangle in the screen buffer with the specified character. The target rectangle is specified by the x and y coordinates and the rectangle's width and height. The fill character char must be a string of length one, i.e. a single character. Returns true on success, false otherwise.
---Note that filling screens with spaces ( ) is usually less expensive, i.e. consumes less energy, because it is considered a “clear” operation (see config).
---@param x number
---@param y number
---@param width number
---@param height number
---@param char string
---@return boolean
function gpu.fill(x, y, width, height, char) end
--#region video_buffer
--Returns the index of the currently selected buffer. 0 is reserved for the screen, and may return 0 even when there is no screen
---@return number index
function gpu.getActiveBuffer() end
--Sets the active buffer to index. 0 is reserved for the screen and can be set even when there is no screen. Returns nil for an invalid index (0 is valid even with no screen)
---@param index number
---@return number previousIndex
function gpu.setActiveBuffer(index) end
---Returns an array of all current page indexes (0 is not included in this list, that is reserved for the screen).
---@return table
function gpu.buffers() end
---Allocates a new buffer with dimensions width*heigh (gpu max resolution by default). Returns the index of this new buffer or error when there is not enough video memory. A buffer can be allocated even when there is no screen bound to this gpu. Index 0 is always reserved for the screen and thus the lowest possible index of an allocated buffer is always 1.
---@param width? number
---@param height? number
---@return number
function gpu.allocateBuffer(width, height) end
---Removes buffer at index (default: current buffer index). Returns true if the buffer was removed. When you remove the currently selected buffer, the gpu automatically switches back to index 0 (reserved for a screen)
---@param index? number
---@return boolean
function gpu.freeBuffer(index) end
---Removes all buffers, freeing all video memory. The buffer index is always 0 after this call.
function gpu.freeAllBuffers() end
---Returns the total memory size of the gpu vram. This does not include the screen.
---@return number
function gpu.totalMemory() end
---Returns the total free memory not allocated to buffers. This does not include the screen.
---@return number
function gpu.freeMemory() end
---Returns the buffer size at index (default: current buffer index). Returns the screen resolution for index 0. Returns nil for invalid indexes
---@param index? number
---@return number, number
function gpu.getBufferSize(index) end
---Copy a region from buffer to buffer, screen to buffer, or buffer to screen. Defaults:
--- - dst = 0, the screen
--- - col, row = 1,1
--- - width, height = resolution of the destination buffer
--- - src = the current buffer
--- - fromCol, fromRow = 1,1 bitblt should preform very fast on repeated use. If the buffer is dirty there is an initial higher cost to sync the buffer with the destination object. If you have a large number of updates to make with frequent bitblts, consider making multiple and smaller buffers. If you plan to use a static buffer (one with few or no updatse), then a large buffer is just fine. Returns true on success
---@param dst? number
---@param col? number
---@param row? number
---@param width? number
---@param height? number
---@param src? number
---@param fromCol? number
---@param fromRow? number
function gpu.bitblt(dst, col, row, width, height, src, fromCol, fromRow) end
---#endregion

View File

@@ -0,0 +1,80 @@
---@meta
---@class ComponentInternet : Component
local internet = {}
--#region component
---Returns whether TCP connections can be made (config setting).
---@return boolean
function internet.isTcpEnabled() end
---Returns whether HTTP requests can be made (config setting).
---@return boolean
function internet.isHttpEnabled() end
---Opens a new TCP connection. Returns the handle of the connection.
---@param address string
---@param port? number
---@return TcpSocket
function internet.connect(address, port) end
---Sends a new HTTP request. Returns the handle of the connection.
---@param url string
---@param postData? string
---@param headers? table
---@return HttpRequest
function internet.request(url, postData, headers) end
--#endregion
--#region tcp socket
---@class TcpSocket
local TcpSocket = {}
---Tries to read data from the socket stream. Returns the read byte array.
---@param n? number
---@return string
function TcpSocket.read(n) end
---Closes an open socket stream.
function TcpSocket.close() end
---Tries to write data to the socket stream. Returns the number of bytes written.
---@param data string
---@return number
function TcpSocket.write(data) end
---Ensures a socket is connected. Errors if the connection failed.
---@return boolean
function TcpSocket.finishConnect() end
---Returns the id for this socket.
---@return string
function TcpSocket.id() end
--#endregion
--#region http request object
---@class HttpRequest
local HttpRequest = {}
---Tries to read data from the response. Returns the read byte array.
---@param n? number
---@return string
function HttpRequest.read(n) end
---Get response code, message and headers.
---@return number status, string statusName, table headers
function HttpRequest.response() end
---Closes an open socket stream.
function HttpRequest.close() end
---Ensures a response is available. Errors if the connection failed.
---@return boolean
function HttpRequest.finishConnect() end
--#endregion

View File

@@ -0,0 +1,39 @@
---@meta
---@alias ModemSafeType string | number | number | boolean
---@class ComponentModem : Component
local modem = {}
---@return boolean
function modem.isWireless() end
---@deprecated
---@return number
function modem.maxPacketSize() end
---@param port number
---@return boolean
function modem.isOpen(port) end
---@param port number
function modem.open(port) end
---@param port number?
---@return boolean
function modem.close(port) end
---@param address string
---@param port number
---@varargs ModemSafeType
function modem.send(address, port, ...) end
---@param port number
---@varargs ModemSafeType
function modem.broadcast(port, ...) end
---@return number
function modem.getStrength() end
---@param message string
---@param fuzzy boolean?
function modem.setWakeMessage(message, fuzzy) end

View File

@@ -0,0 +1,18 @@
---@meta
---@class ComponentOsCardWriter : Component
local os_cardwriter = {}
---writes data to an magnetic/rfid card, 3rd parameter sets the card to readonly
---@param data string
---@param displayName string
---@param locked boolean
---@param color colors
---@return boolean cardWritten
function os_cardwriter.write(data, displayName, locked, color) end
---flashes data to an eeprom
---@param data string
---@param title string
---@param writelock boolean
function os_cardwriter.flash(data, title, writelock) end

View File

@@ -0,0 +1,20 @@
---@meta
---@class ComponentOsMagReader : Component
local os_magreader = {}
---Sets the event name returned when you click it with a card, default is magData
---@param eventName string
function os_magreader.setEventName(eventName) end
---Enables/disables automatic lights on the magreader. If true, it will function as it normally does when clicked with a card. If false, you have to call setLightState to change the lights on the magreader. default is true.
---@param enableLights boolean
function os_magreader.swipeIndicator(enableLights) end
---Sets the light state of the magreader. Takes in a number from 0 to 7. default is 0
--- - 1 : red
--- - 2 : yellow
--- - 4 : green
---@param lightState number light state as a binary number (1 : red, 3 red + yellow)
---@return boolean lightChanged
function os_magreader.setLightState(lightState) end

View File

@@ -0,0 +1,69 @@
---@meta
---@class ComponentStargate
local stargate = {}
---@alias stargateState
--- | "Idle" # Operating and ready to dial
--- | "Dialling" # In the process of dialling an address
--- | "Opening" # Finished dialling, wormhole in transient phase
--- | "Connected" # Wormhole is stable
--- | "Closing" # Wormhole is shutting down
--- | "Offline" # Interface not connected to a functioning stargate
---@alias stargateDirection
--- | "Outgoing" # Connection was dialled from this end
--- | "Incoming" # Connection was dialled from the other end
--- | "" # Not connected
---@alias irisState
--- | "Closed"
--- | "Opening"
--- | "Open"
--- | "Closing"
--- | "Offline"
---Return the gate state
---@return stargateState state
---@return number engaged
---@return stargateDirection direction number of engared chevron
function stargate.stargateState() end
---Returns the amount of energy in the gate's internal buffer plus the buffers of any attached Stargate Power Units. This is the energy available for the next dialling operation. If the interface is not connected to a functioning stargate, zero is returned.
---@return number su
function stargate.energyAvailable() end
---Returns the amount of energy that would be needed to connect to the stargate at the given address.
---@param address string
---@return number su
function stargate.energyToDial(address) end
---Returns the address of the attached stargate. If the interface is not connected to a functioning stargate, an empty string is returned.
---@return string
function stargate.localAddress() end
---Returns the address of the connected stargate. If there is no connection, or the interface is not connected to a functioning stargate, an empty string is returned.
---@return string
function stargate.remoteAddress() end
---Dials the given address.
---@param address string
function stargate.dial(address) end
---Closes any open connection.
function stargate.disconnect() end
---Returns a string indicating the state of the iris: Closed, Opening, Open, Closing. Returns Offline if no iris is fitted or the interface is not connected to a functioning stargate.
---@return irisState
function stargate.irisState() end
---Closes the iris, if fitted.
function stargate.closeIris() end
---Opens the iris, if fitted.
function stargate.openIris() end
---Sends a message through an open connection to any stargate interfaces attached to the destination stargate. Any number of arguments may be passed. The message is delivered to connected computers as an sgMessageReceived event. Has no effect if no stargate connection is open.
---@param arg string|number|boolean
---@param ... string|number|boolean
function stargate.sendMessage(arg, ...) end

View File

@@ -0,0 +1,116 @@
---@meta
---@class ComponentTransposer
local transposer = {}
---Transfer some fluids between two fluid handlers (pipes or tanks, etc). sourceSide is the side pulled from and sinkSide is the side transferred to. The side value is a integral value representing the cardinal directions (east, west, south, north), up, and down. The sides library has these values for convenience. count is the number of millibuckets to transfers. Returns true and the number of millibuckets transfered on success, or false and an error message on failure.
---@param sourceSide side
---@param sinkSide side
---@param count number
---@return boolean, number
function transposer.transferFluid(sourceSide, sinkSide, count) end
---Store an item stack description in the specified slot of the database with the specified address.
---@param side side
---@param slot number
---@param dbAddress string
---@param dbSlot number
---@return boolean
function transposer.store(side, slot, dbAddress, dbSlot) end
---Compare an item in the specified slot in the inventory on the specified side with one in the database with the specified address.
---@param side side
---@param slot number
---@param dbAddress string
---@param dbSlot number
---@param checkNBT? boolean
---@return boolean
function transposer.compareStackToDatabase(side, slot, dbAddress, dbSlot, checkNBT) end
---Get number of items in the specified slot of the inventory on the specified side of the device.
---@param side side
---@param slot number
---@return number
function transposer.getSlotStackSize(side, slot) end
---Get the maximum number of items in the specified slot of the inventory on the specified side of the device.
---@param side side
---@param slot number
---@return number
function transposer.getSlotMaxStackSize(side, slot) end
---Get the the name of the inventory on the specified side of the device.
---@param side side
---@return string
function transposer.getInventoryName(side) end
---Get the number of slots in the inventory on the specified side of the device.
---@param side side
---@return number
function transposer.getInventorySize(side) end
---Get a description of the fluid in the the specified tank on the specified side.
---@param side side
---@param tank number
---@return table
function transposer.getFluidInTank(side, tank) end
---Get the amount of fluid in the specified tank on the specified side.
---@param side side
---@param tank number
---@return number
function transposer.getTankLevel(side, tank) end
---Transfer some items between two inventories.
---@param sourceSide side
---@param sinkSide side
---@param count? number
---@param sourceSlot? number
---@param sinkSlot? number
---@return number
function transposer.transferItem(sourceSide, sinkSide, count, sourceSlot, sinkSlot) end
---Get whether the items in the two specified slots of the inventory on the specified side of the device are of the same type.
---@param side side
---@param slotA number
---@param slotB number
---@param checkNBT? boolean
---@return boolean
function transposer.compareStacks(side, slotA, slotB, checkNBT) end
---Get whether the items in the two specified slots of the inventory on the specified side of the device are equivalent (have shared OreDictionary IDs).
---@param side side
---@param slotA number
---@param slotB number
---@return boolean
function transposer.areStacksEquivalent(side, slotA, slotB) end
---Get the number of tanks available on the specified side.
---@param side side
---@return number
function transposer.getTankCount(side) end
---Get a description of the stack in the inventory on the specified side of the device.
---@param side side
---@param slot number
---@return table
function transposer.getStackInSlot(side, slot) end
---Get the capacity of the specified tank on the specified side.
---@param side side
---@param tank number
---@return number
function transposer.getTankCapacity(side, tank) end
---Get a description of all stacks in the inventory on the specified side of the device.
---The return value is callable. Calling it will return a table describing the stack in the inventory or nothing if the iterator reaches end.
---The return value provides the followings callbacks:
---Returns ALL the stack in the this.array. Memory intensive.
---getAll():table
---Returns the number of elements in the this.array.
---count():number
---Reset the iterator index so that the next call will return the first element.
---reset()
---@param side side
---@return userdata
function transposer.getAllStacks(side) end

View File

@@ -0,0 +1,26 @@
---@meta
---@class ComponentTunnel : Component
local tunnel = {}
---Sends the specified data to the card this one is linked to.
---@param ... string|number|boolean data
function tunnel.send(...) end
---Gets the maximum packet size (config setting).
---@return number
function tunnel.maxPacketSize() end
---Gets the tunnel address of the link card. This is also available in linkChannel using an inventory controller and getting the stack from an inventory slot.
---@return string
function tunnel.getChannel() end
---Gets the current wake-up message. When the network card detects the wake message (a string in the first argument of a network packet), on any port and the machine is off, the machine is started. This is the same functionality also provided by robots, cases, servers, drones, and tablets.
---@return string
function tunnel.getWakeMessage() end
---Sets the wake-up message to the specified string. The message matching can be fuzzy (default is false). A fuzzy match ignores additional trailing arguments in the network packet.
---@param message string
---@param fuzzy boolean
---@return string
function tunnel.setWakeMessage(message, fuzzy) end

79
definitions/globals.d.lua Normal file
View File

@@ -0,0 +1,79 @@
---@meta
---@param idx number
---@param var any
---@vararg 'string' | 'table' | 'number' | 'boolean' | 'userdata' | 'nil'
function checkArg(idx, var, ...) end
component = {
doc = function(...) end,
fields = function(...) end,
invoke = function(...) end,
list = function(...) end,
methods = function(...) end,
proxy = function(...) end,
slot = function(...) end,
type = function(...) end
}
computer = {}
_VERSION = 5.3
_OSVERSION = "OpenOS 1.7.7"
computer = require("computer")
string = require("string")
math = require("math")
table = require("table")
debug = {
getinfo = function(...) end,
traceback = function(...) end,
getlocal = function(...) end,
getupvalue = function(...) end,
}
coroutine = require("coroutine")
bit32 = {
arshift = function(...) end,
band = function(...) end,
bnot = function(...) end,
bor = function(...) end,
btest = function(...) end,
bxor = function(...) end,
extract = function(...) end,
lrotate = function(...) end,
lshift = function(...) end,
replace = function(...) end,
rrotate = function(...) end,
rshift = function(...) end,
}
os = {
clock = function(...) end,
date = function(...) end,
difftime = function(...) end,
time = function(...) end,
}
unicode = {
char = function(...) end,
charWidth = function(...) end,
isWide = function(...) end,
len = function(...) end,
lower = function(...) end,
reverse = function(...) end,
sub = function(...) end,
upper = function(...) end,
wlen = function(...) end,
wtrunc = function(...) end,
}
utf8 = {
char = function(...) end,
charpattern = function(...) end,
codes = function(...) end,
codepoint = function(...) end,
len = function(...) end,
offset = function(...) end,
}

View File

@@ -0,0 +1,19 @@
---@meta
---@alias colors
--- | 0 # white
--- | 1 # orange
--- | 2 # magenta
--- | 3 # lightblue
--- | 4 # yellow
--- | 5 # lime
--- | 6 # pink
--- | 7 # gray
--- | 8 # silver
--- | 9 # cyan
--- | 10 # purple
--- | 11 # blue
--- | 12 # brown
--- | 13 # green
--- | 14 # red
--- | 15 # black

View File

@@ -0,0 +1,95 @@
---@meta
---@class Component
---@field slot number
---@field type string
---@field address string
---The component API is used to access and interact with components available to a computer.
---@class componentlib
---@field transposer ComponentTransposer
---@field modem ComponentModem
---@field tunnel ComponentTunnel
---@field internet ComponentInternet
---@field gpu ComponentGPU
---@field drive ComponentDrive
---@field disk_drive ComponentDiskDrive
---@field filesystem ComponentFilesystem
---@field data ComponentData
---@field computer ComponentComputer
---@field os_magreader ComponentOsMagReader
---@field os_cardwriter ComponentOsCardWriter
---@field stargate ComponentStargate
local component = {}
---Returns the documentation string for the method with the specified name of the component with the specified address, if any. Note that you can also get this string by using tostring on a method in a proxy, for example tostring(component.screen.isOn).
---@param address string
---@param method string
---@return string documentation
function component.doc(address, method) end
---Calls the method with the specified name on the component with the specified address, passing the remaining arguments as arguments to that method. Returns the result of the method call, i.e. the values returned by the method. Depending on the called method's implementation this may throw.
---@param address string
---@param method string
---@param ... unknown
---@return unknown ...
function component.invoke(address, method, ...) end
---Returns a table with all components currently attached to the computer, with address as a key and component type as a value. It also provides iterator syntax via __call, so you can use it like so: for address, componentType in component.list() do ... end
---If filter is set this will only return components that contain the filter string (this is not a pattern/regular expression). For example, component.list("red") will return redstone components.
---If true is passed as a second parameter, exact matching is enforced, e.g. red will not match redstone.
---@param filter? string
---@param exact? boolean
---@return function iterator
function component.list(filter, exact) end
---Returns a table with the names of all methods provided by the component with the specified address. The names are the keys in the table, the values indicate whether the method is called directly or not.
---@param address string
---@return table methodeNames
function component.methods(address) end
---Gets a 'proxy' object for a component that provides all methods the component provides as fields, so they can be called more directly (instead of via invoke). This is what's used to generate 'primaries' of the individual component types, i.e. what you get via component.blah.
---For example, you can use it like so: component.proxy(component.list("redstone")()).getInput(sides.north), which gets you a proxy for the first redstone component returned by the component.list iterator, and then calls getInput on it.
---Note that proxies will always have at least two fields, type with the component's type name, and address with the component's address.
---@param address string
---@return Component proxy
function component.proxy(address) end
---Get the component type of the component with the specified address.
---@param address string
---@return string type
function component.type(address) end
---Return slot number which the component is installed into. Returns -1 if it doesn't otherwise make sense.
---@param address string
---@return number slotNumber
function component.slot(address) end
---Undocumented
---@param address string
---@return string
function component.fields(address) end
---Tries to resolve an abbreviated address to a full address. Returns the full address on success, or nil and an error message otherwise. Optionally filters by component type.
---@param address string
---@param componentType string
---@return string|nil address, string|nil reason
function component.get(address, componentType) end
---Checks if there is a primary component of the specified component type.
---@param componentType string
---@return boolean componentAvailable
function component.isAvailable(componentType) end
---Gets the proxy for the primary component of the specified type. Throws an error if there is no primary component of the specified type.
---@param componentType string
---@return Component proxy
function component.getPrimary(componentType) end
---Sets a new primary component for the specified component type. The address may be abbreviated, but must be valid if it is not nil. Triggers the component_unavailable and component_available signals if set to nil or a new value, respectively.
---Note that the component API has a metatable that allows the following syntax:
---@param componentType string
---@param address string
function component.setPrimary(componentType, address) end
return component

View File

@@ -0,0 +1,96 @@
---@meta
---@class computerlib
local computer = {}
---The component address of this computer.
---@return string
function computer.address() end
---The component address of the computer's temporary file system (if any), used for mounting it on startup.
---@return string
function computer.tmpAddress() end
---The amount of memory currently unused, in bytes. If this gets close to zero your computer will probably soon crash with an out of memory error. Note that for OpenOS, it is highly recommended to at least have 1x tier 1.5 RAM stick or more. The os will boot on a single tier 1 ram stick, but quickly and easily run out of memory.
---@return number
function computer.freeMemory() end
---The total amount of memory installed in this computer, in bytes.
---@return number
function computer.totalMemory() end
---The amount of energy currently available in the network the computer is in. For a robot this is the robot's own energy / fuel level.
---@return number
function computer.energy() end
---The maximum amount of energy that can be stored in the network the computer is in. For a robot this is the size of the robot's internal buffer (what you see in the robot's GUI).
---@return number
function computer.maxEnergy() end
---The time in real world seconds this computer has been running, measured based on the world time that passed since it was started - meaning this will not increase while the game is paused, for example.
---@return number
function computer.uptime() end
---Shuts down the computer. Optionally reboots the computer, if reboot is true, i.e. shuts down, then starts it again automatically. This function never returns. This example will reboot the computer if it has been running for at least 300 seconds(5 minutes)
---```lua
--- local computer = require("computer")
--- if computer.uptime() >= 300 then
--- computer.shutdown(true)
--- end
---```
---@param reboot? boolean
function computer.shutdown(reboot) end
---Get the address of the filesystem component from which to try to boot first. New since OC 1.3.
---@return string
function computer.getBootAddress() end
---Set the address of the filesystem component from which to try to boot first. Call with nil / no arguments to clear. New since OC 1.3.
---@param address string
function computer.setBootAddress(address) end
---Returns the current runlevel the computer is in. Current Runlevels in OpenOS are:
---S: Single-User mode, no components or filesystems initialized yet
---1: Single-User mode, filesystems and components initialized - OpenOS finished booting
---@return string|number
function computer.runlevel() end
---A list of all users registered on this computer, as a tuple. To iterate the result as a list, use table.pack on it, first. Please see the user rights documentation.
---@return string, ...
function computer.users() end
---Registers a new user with this computer. Returns true if the user was successfully added. Returns nil and an error message otherwise.
---The user must be currently in the game. The user will gain full access rights on the computer. In the shell, useradd USER is a command line option to invoke this method.
---@param name string
---@return boolean or nil, string
function computer.addUser(name) end
---Unregisters a user from this computer. Returns true if the user was removed, false if they weren't registered in the first place.
---The user will lose all access to this computer. When the last user is removed from the user list, the computer becomes accessible to all players. userdel USER is a command line option to invoke this method.
---@param name string
---@return boolean
function computer.removeUser(name) end
---Pushes a new signal into the queue. Signals are processed in a FIFO order. The signal has to at least have a name. Arguments to pass along with it are optional. Note that the types supported as signal parameters are limited to the basic types nil, boolean, number, string, and tables. Yes tables are supported (keep reading). Threads and functions are not supported.
---Note that only tables of the supported types are supported. That is, tables must compose types supported, such as other strings and numbers, or even sub tables. But not of functions or threads.
---@param name string
---@param ...? any
function computer.pushSignal(name, ...) end
---Tries to pull a signal from the queue, waiting up to the specified amount of time before failing and returning nil. If no timeout is specified waits forever.
---The first returned result is the signal name, following results correspond to what was pushed in pushSignal, for example. These vary based on the event type. Generally it is more convenient to use event.pull from the event library. The return value is the very same, but the event library provides some more options.
---@param timeout? number
---@return string signalName, any ...
function computer.pullSignal(timeout) end
---if frequency is a number it value must be between 20 and 2000.
---Causes the computer to produce a beep sound at frequency Hz for duration seconds. This method is overloaded taking a single string parameter as a pattern of dots . and dashes - for short and long beeps respectively.
---@param frequency? number|string
---@param duration? number
function computer.beep(frequency, duration) end
---Returns a table of information about installed devices in the computer.
---@return table
function computer.getDeviceInfo() end
return computer

View File

@@ -0,0 +1,162 @@
---@meta
---@class filesystemlib
local filesystem = {}
---Returns whether autorun is currently enabled. If this is true, newly mounted file systems will be checked for a file named autorun[.lua] in their root directory. If such a file exists, it is executed.
---@return boolean
function filesystem.isAutorunEnabled() end
---Sets whether autorun files should be ran on startup.
---@param value boolean
function filesystem.setAutorunEnabled(value) end
---Returns the canonical form of the specified path, i.e. a path containing no “indirections” such as . or ... For example, the paths /tmp/../bin/ls.lua and /bin/./ls.lua are equivalent, and their canonical form is /bin/ls.lua.
---Note that this function truncates relative paths to their topmost “known” directory. For example, ../bin/ls.lua becomes bin/ls.lua. It stays a relative path, however - mind the lack of a leading slash.
---@param path string
---@return string
function filesystem.canonical(path) end
---Returns a table containing one entry for each canonical segment of the given path. Examples:
--- - filesystem.segments("foo/bar") → {"foo","bar"}
--- - filesystem.segments("foo/bar/../baz") → {"foo","baz"}
---@param path string
---@return table
function filesystem.segments(path) end
---Concatenates two or more paths. Note that all paths other than the first are treated as relative paths, even if they begin with a slash. The canonical form of the resulting concatenated path is returned, so fs.concat("a", "..") results in an empty string.
---@param pathA string
---@param pathB string
---@param ... string
---@return string
function filesystem.concat(pathA, pathB, ...) end
---Returns the path component of a path to a file, i.e. everything before the last slash in the canonical form of the specified path.
---@param path string
---@return string
function filesystem.path(path) end
---Returns the file name component of a path to a file, i.e. everything after the last slash in the canonical form of the specified path.
---@param path string
---@return string
function filesystem.name(path) end
---Mounts a file system at the specified path. The first parameter can be either a file system component's proxy, its address or its label. The second is a path into the global directory tree. Returns true if the file system was successfully mounted, nil and an error message otherwise.
---@param fs ComponentFilesystem|string
---@param path string
---@return string
function filesystem.mount(fs, path) end
---This is similar to component.proxy, except that the specified string may also be a file system component's label. We check for the label first, if no file system has the specified label we fall back to component.proxy. Returns the proxy of the specified file system, or nil and an error message if no file system matching the specified filter was found.
---@param filter string
---@return table or nil, string
function filesystem.proxy(filter) end
---Returns an iterator function over all currently mounted file system component's proxies and the paths at which they are mounted. This means the same proxy may appear multiple times, but with different mount paths.
---@return function -> table, string
function filesystem.mounts() end
---Unmounts a file system. The parameter can either be a file system component's proxy or (abbreviated) address, in which case all mount points of this file system will be removed, or a path into the global directory structure, in which case the file system mount containing that directory will be unmounted.
---@param fsOrPath string|ComponentFilesystem
---@return boolean
function filesystem.umount(fsOrPath) end
---Checks if the object at the specified path is a symlink, if so returns the path to where it links (as of 1.3.3).
---@param path string
---@return boolean, string|nil
function filesystem.isLink(path) end
---Creates a symbolic link to the specified target path at the specified path. This is a 'soft' link, i.e. it the target file does not actually have to exist at the time of creation, and the link will not be deleted if the target file is deleted. Symbolic links do not persist across reboots.
---@param target string
---@param linkpath string
---@return boolean|nil, string
function filesystem.link(target, linkpath) end
---Gets the file system component's proxy that contains the specified path. Returns the proxy and mount path, or nil and an error message.
---@param path string
---@return table, string or nil, string
function filesystem.get(path) end
---Checks whether a file or folder exist at the specified path.
---@param path string
---@return boolean
function filesystem.exists(path) end
---Gets the file size of the file at the specified location. Returns 0 if the path points to anything other than a file.
---@param path string
---@return number
function filesystem.size(path) end
---Gets whether the path points to a directory. Returns false if not, either because the path points to a file, or file.exists(path) is false.
---@param path string
---@return boolean
function filesystem.isDirectory(path) end
---Returns the real world unix timestamp of the last time the file at the specified path was modified. For directories this is usually the time of their creation.
---@param path string
---@return number
function filesystem.lastModified(path) end
---Returns an iterator over all elements in the directory at the specified path. Returns nil and an error messages if the path is invalid or some other error occurred.
---Note that directories usually are postfixed with a slash, to allow identifying them without an additional call to fs.isDirectory.
---@param path string
---@return function -> string or nil, string
function filesystem.list(path) end
---Creates a new directory at the specified path. Creates any parent directories that do not exist yet, if necessary. Returns true on success, nil and an error message otherwise.
---@param path string
---@return boolean|nil, string
function filesystem.makeDirectory(path) end
---Deletes a file or folder. If the path specifies a folder, deletes all files and subdirectories in the folder, recursively. Return true on success, nil and an error message otherwise.
---@param path string
---@return boolean|nil, string
function filesystem.remove(path) end
---Renames a file or folder. If the paths point to different file system components this will only work for files, because it actually perform a copy operation, followed by a deletion if the copy succeeds.
---Returns true on success, nil and an error message otherwise.
---@param oldPath string
---@param newPath string
---@return boolean|nil, string
function filesystem.rename(oldPath, newPath) end
---Copies a file to the specified location. The target path has to contain the target file name. Does not support folders.
---@param fromPath string
---@param toPath string
---@return boolean|nil, string
function filesystem.copy(fromPath, toPath) end
---@class FileHandler
local file
---Opens a file at the specified path for reading or writing. If mode is not specified it defaults to “r”. Possible modes are: r, rb, w, wb, a and ab.
---Returns a file stream (see below) on success, nil and an error message otherwise.
---Note that you can only open a limited number of files per file system at the same time. Files will be automatically closed when the garbage collection kicks in, but it is generally a good idea to call close on the file stream when done with the file.
---Important*: it is generally recommended to use io.open instead of this function, to get a buffered wrapper for the file stream.
---When opening files directly via the file system API you will get a file stream, a table with four functions. These functions are thin wrappers to the file system proxy's callbacks, which also means that read/write operations are not buffered, and can therefore be slow when reading few bytes often. You'll usually want to use io.open instead.
---@param path string
---@param mode string
---@return FileHandler|nil fileHandler, string|nil reason
function filesystem.open(path, mode) end
---Closes the file stream, releasing the handle on the underlying file system.
function file:close() end
---Tries to read the specified number of bytes from the file stream. Returns the read string, which may be shorter than the specified number. Returns nil when the end of the stream was reached. Returns nil and an error message if some error occurred.
---@param n number
---@return string|nil, string|nil reason
function file:read(n) end
---Jumps to the specified position in the file stream, if possible. Only supported by file streams opened in read mode. The first parameter determines the relative location to seek from and can be cur for the current position, set for the beginning of the stream and end for the end of the stream. The second parameter is the offset by which to modify the position. Returns the new position or nil and an error message if some error occurred.
---The default value for the second parameter is 0, so f:seek("set") will reset the position to the start of the file, f:seek("cur") will return the current position in the file.
---@param whence string
---@param offset? number
---@return number|nil, string|nil reason
function file:seek(whence, offset) end
---Writes the specified data to the stream. Returns true on success, nil and an error message otherwise.
---@param str any
---@return boolean|nil, string|nil reason
function file:write(str) end
return filesystem

View File

@@ -0,0 +1,46 @@
---@meta
---@class oslib
local os = {}
---Returns an approximation of the amount in seconds of CPU time used by the program.
---@return number
function os.clock() end
---Returns a string or a table containing date and time, formatted according to the given string format.
---
---If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.
---
---If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year (four digits), month (112), day (131), hour (023), min (059), sec (061), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.
---
---If format is not "*t", then date returns the date as a string, formatted according to the same rules as the ISO C function strftime.
---
---When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")).
---
---On non-Posix systems, this function may be not thread safe because of its reliance on C function gmtime and C function localtime.
---@param format? string
---@param time? string | number
---@return string | table
function os.date(format, time) end
function os.execute() end
---@param code? any
---@param close? any
function os.exit(code, close) end
function os.setenv() end
function os.remove() end
function os.rename() end
function os.time() end
function os.tmpname() end
---Sleep for x seconds
---@param time? number
function os.sleep(time) end
return os

View File

@@ -0,0 +1,46 @@
---@meta
---@alias side
--- | 0 # "bottom",
--- | 1 # "top",
--- | 2 # "back",
--- | 3 # "front",
--- | 4 # "right",
--- | 5 # "left",
---@class sideslib
local sides = {
[0] = "bottom",
[1] = "top",
[2] = "back",
[3] = "front",
[4] = "right",
[5] = "left",
[6] = "unknown",
bottom = 0,
top = 1,
back = 2,
front = 3,
right = 4,
left = 5,
unknown = 6,
down = 0,
up = 1,
north = 2,
south = 3,
west = 4,
east = 5,
negy = 0,
posy = 1,
negz = 2,
posz = 3,
negx = 4,
posx = 5,
forward = 3
}
return sides

View File

@@ -83,7 +83,6 @@ local function readPassword()
end)
lastKey = nil
while lastKey ~= 13 do
---@diagnostic disable-next-line: undefined-field
os.sleep()
end
event.cancel(event_keyboard)
@@ -189,7 +188,6 @@ if (#config.doors > 0) then
end
print("Found " .. #doors .. " for " .. #redstoneIO .. " redstone I/O")
---@diagnostic disable-next-line: undefined-field
os.sleep(2)
if (ops.config or ops.c) then
@@ -438,7 +436,6 @@ else
mainScreen:draw()
while run do
---@diagnostic disable-next-line: undefined-field
os.sleep()
end
closeGUI()

View File

@@ -1,6 +1,8 @@
--libCB by AR2000AR=(AR2000)==========
--manage credit card (unmanaged floppy)
--=====================================
---@class libcb
local cb = {} --table returned by require
local data = require("component").data --data component used for cryptocraphic stuf
local serialization = require("serialization") --data serialization and unserialization
@@ -9,6 +11,17 @@ local proxy = require("component").proxy
local computer = require("computer")
local lastMagRead = {}
---@class cardData
---@field uuid string account UUID
---@field cbUUID string card uuid
---@field type "signed" | "unsinged" card's component type ("signed" or "unsigned")
---@field sig? string card signature made form uuid & card's drive component's uuid. Absent on magData
---@class encryptedCardData
---@field data string the encrypted data
---@field uuid string the card uuid
---@field type "driveData" | "magData"
local componentSwitch = {
__call = function(self, componentProxy, ...)
checkArg(1, componentProxy, "table")
@@ -20,6 +33,9 @@ local componentSwitch = {
end
}
---Get the most recent read of a magnetic card (max age 10s)
---@param os_magreader ComponentOsMagReader
---@return encryptedCardData|nil rawCardData encrypted card data
local function getRecentMagRead(os_magreader)
checkArg(1, os_magreader, "table")
if (not lastMagRead[os_magreader.address]) then return nil end
@@ -30,8 +46,9 @@ local function getRecentMagRead(os_magreader)
return nil
end
--wait for any compatible card format.
--@return proxy
---wait for any compatible card format.
---@param timeout number
---@return Component|boolean proxy
function cb.waitForCB(timeout)
local eventDetails = table.pack(event.pullFiltered(timeout, function(a, b, c, d, e, f)
if (a == "component_added" and c == "drive") then return true end
@@ -44,6 +61,9 @@ end
cb.loadCB = {}
setmetatable(cb.loadCB, componentSwitch)
---read the data from a card
---@param cbDrive ComponentDrive
---@return encryptedCardData
function cb.loadCB.drive(cbDrive)
--get the data from the card
--the card is in unmanaged mode (binary) and the data is writen at the start of
@@ -53,6 +73,10 @@ function cb.loadCB.drive(cbDrive)
return {data = cbData, uuid = cbDrive.address, type = "driveData"}
end
---read the data from a magnetic card
---@param os_magreader ComponentOsMagReader
---@param timeout number
---@return encryptedCardData
function cb.loadCB.os_magreader(os_magreader, timeout)
checkArg(1, os_magreader, "table")
local recent = getRecentMagRead(os_magreader)
@@ -67,27 +91,27 @@ event.listen("magData", function(eName, eAddr, player, rawData, cardUUID, locked
cb.getCB = {}
setmetatable(cb.getCB, componentSwitch)
--decrypt the card's raw data
--@param rawData:table data returned by loadCB
--@param pin:string card's pin
--@return {uuid,cbUUID,type,sig}
---decrypt the card's raw data
---@param rawData encryptedCardData data returned by loadCB
---@param pin string card's pin
---@return cardData|nil, string|nil reason
function cb.getCB.driveData(rawData, pin)
--decrypt it's content
local clearData = data.decrypt(data.decode64(rawData.data), data.md5(pin), data.md5(rawData.uuid))
if (not clearData) then return false, "Pin might be wrong" end
if (not clearData) then return nil, "Pin might be wrong" end
--unserialize the data to use it later
local cbData = serialization.unserialize(clearData)
if (not cbData or not cbData.uuid) then return false, "Pin might be wrong" end
if (not cbData or not cbData.uuid) then return nil, "Pin might be wrong" end
--add the missing card uuid to the data
cbData.cbUUID = rawData.uuid
cbData.type = "signed"
return cbData
end
--decrypt the card's raw data
--@param rawData:table data returned by loadCB
--@param pin:string card's pin
--@return {uuid,cbUUID,type}
---decrypt the card's raw data
---@param rawData encryptedCardData data returned by loadCB
---@param pin string card's pin
---@return cardData|nil, string|nil reason
function cb.getCB.magDataData(rawData, pin)
--data format :
--aesIV(24)data(64)
@@ -99,34 +123,36 @@ function cb.getCB.magDataData(rawData, pin)
if (clearData and #clearData == 39 and clearData:sub(37) == "PIN") then
return {uuid = clearData:sub(1, 36), cbUUID = rawData.uuid, type = "unsigned"}
else
return false
return nil, "Data invalid"
end
end
--read the credit card data and return it
-- @param cbDrive:proxy the floppy's component
-- @param pin: pin used to decrypt the data
---read the credit card data and return it
---@param cbDrive ComponentDrive the floppy's component
---@param pin string pin used to decrypt the data
---@return cardData
function cb.getCB.drive(cbDrive, pin)
return cb.getCB(cb.loadCB(cbDrive), pin)
end
--read the credit card data and return it
-- @param cbDrive:proxy the floppy's component
-- @param pin: pin used to decrypt the data
---read the credit card data and return it
---@param cbDrive ComponentOsMagReader the floppy's component
---@param pin string pin used to decrypt the data
---@return cardData|nil
function cb.getCB.os_magreader(cbDrive, pin)
return cb.getCB.magDataData(cb.loadCB(cbDrive))
end
-- check if the cb is valide
-- @param cbData:table (see man libCB for more info about cbData)
-- @param publicKey:userdata
-- @return boolean
---check if the cb is valide. A unsinged card will always return true
---@param cbData cardData (see man libCB for more info about cbData)
---@param publicKey EcKeyPublic
---@return boolean| "unsigned"
function cb.checkCBdata(cbData, publicKey)
return cbData.type == "unsigned" or data.ecdsa(cbData.uuid .. cbData.cbUUID, publicKey, data.decode64(cbData.sig))
end
-- generate a random 4 digit pin
-- @return string
---generate a random 4 digit pin
---@return string
local function randomPin()
local pin = "" .. math.floor(math.random(9999))
while (#pin < 4) do
@@ -135,12 +161,11 @@ local function randomPin()
return pin
end
-- create a new rawCBdata
-- @param uuid:string account uuid
-- @param cbUUID:string new cb's uuid
-- @param privateKey:userdata key used to sign the cb
-- @retrun rawCBdata:table
-- @return pin:string
---create a new rawCBdata
---@param uuid string account uuid
---@param cbUUID string new cb's uuid
---@param privateKey EcKeyPrivate used to sign the cb
---@return string rawCardData,string pin
function cb.createNew(uuid, cbUUID, privateKey)
if (cbUUID) then --for floppy
local pin = randomPin()
@@ -148,7 +173,8 @@ function cb.createNew(uuid, cbUUID, privateKey)
local aesIV = data.md5(cbUUID)
local newCB = {}
newCB.uuid = uuid
newCB.sig = data.encode64(data.ecdsa(uuid .. cbUUID, privateKey))
newCB.sig = data.encode64(data.ecdsa(uuid .. cbUUID, privateKey)--[[@as string]] )
---@diagnostic disable-next-line: cast-local-type
newCB = data.encode64(data.encrypt(serialization.serialize(newCB), aesKey, aesIV))
return newCB, pin
else --magCard
@@ -160,18 +186,22 @@ function cb.createNew(uuid, cbUUID, privateKey)
end
end
-- write rawCBdata to a unmanaged floppy or a magcard
-- @param rawCBdata:table the table provided by cb.createNew(...)
-- @param cbDrive:proxy the floppy's component proxy
---write rawCBdata to a unmanaged floppy or a magcard
---@param rawCBdata string data provided by cb.createNew(...)
---@param cbDrive ComponentDrive|ComponentOsCardWriter the floppy's component proxy
---@return boolean cardWritten
function cb.writeCB(rawCBdata, cbDrive)
if (cbDrive.type == "drive") then
---@cast cbDrive ComponentDrive
local buffer = serialization.serialize(rawCBdata)
cbDrive.writeSector(1, buffer)
cbDrive.setLabel("CB")
return true
elseif (cbDrive.type == "os_cardwriter") then
---@cast cbDrive ComponentOsCardWriter
return cbDrive.write(rawCBdata, "CB", true, 11) --11 == color.blue
end
return false
end
return cb --return the table containing all the public functions

View File

@@ -1,4 +1,5 @@
local transposer = require("component").transposer
assert(transposer, "This library require a transposer")
local CONVERTION_RATE = 100
local COIN_BRONZE = 1
@@ -12,6 +13,12 @@ local ID_COIN_PLATINUM = "ordinarycoins:coinplatinum"
local coin = {}
---count the coins
---@param side side
---@return number
---@return number
---@return number
---@return number
function coin.getCoin(side)
local bronze, silver, gold, platinum = 0, 0, 0, 0
local stack = nil
@@ -26,6 +33,12 @@ function coin.getCoin(side)
return math.floor(bronze), math.floor(silver), math.floor(gold), math.floor(platinum)
end
---get the total value of coins
---@param bronze number
---@param silver number
---@param gold number
---@param platinum number
---@return number
function coin.getValue(bronze, silver, gold, platinum)
bronze = bronze or 0
silver = silver or 0
@@ -34,6 +47,13 @@ function coin.getValue(bronze, silver, gold, platinum)
return (bronze * COIN_BRONZE) + (silver * COIN_SILVER) + (gold * COIN_GOLD) + (platinum * COIN_PLATINUM)
end
---find how much space is left for each kind of coins
---@param side side
---@return number
---@return number
---@return number
---@return number
---@return number
function coin.getEmptySpace(side)
local bronze, silver, gold, platinum, air = 0, 0, 0, 0, 0
local stack = nil
@@ -53,6 +73,10 @@ function coin.getEmptySpace(side)
return math.floor(bronze), math.floor(silver), math.floor(gold), math.floor(platinum), air
end
---find the first stack containing the item
---@param side side
---@param name string
---@return number|boolean
function coin.findFirstStack(side, name)
local i = 1
for stack in transposer.getAllStacks(side) do
@@ -62,6 +86,14 @@ function coin.findFirstStack(side, name)
return false
end
---move a certain value of coins
---@param amount number
---@param from side
---@param to side
---@return number|boolean
---@return number|nil
---@return number|nil
---@return number|nil
function coin.moveCoin(amount, from, to)
if (coin.getValue(coin.getCoin(from)) >= amount) then
local bronze, silver, gold, platinum = coin.getCoin(from)
@@ -92,7 +124,7 @@ function coin.moveCoin(amount, from, to)
local moved_bronze, moved_silver, moved_gold, moved_platinum = 0, 0, 0, 0
while (moved_bronze < need_bronze) do
local moved_coin = transposer.transferItem(from, to, need_bronze, coin.findFirstStack(from, ID_COIN_BRONZE))
local moved_coin = transposer.transferItem(from, to, need_bronze, coin.findFirstStack(from, ID_COIN_BRONZE)--[[@as number]] )
if (moved_coin == 0) then
break
else
@@ -100,7 +132,7 @@ function coin.moveCoin(amount, from, to)
end
end
while (moved_silver < need_silver) do
local moved_coin = transposer.transferItem(from, to, need_silver, coin.findFirstStack(from, ID_COIN_SILVER))
local moved_coin = transposer.transferItem(from, to, need_silver, coin.findFirstStack(from, ID_COIN_SILVER)--[[@as number]] )
if (moved_coin == 0) then
break
else
@@ -108,7 +140,7 @@ function coin.moveCoin(amount, from, to)
end
end
while (moved_gold < need_gold) do
local moved_coin = transposer.transferItem(from, to, need_gold, coin.findFirstStack(from, ID_COIN_GOLD))
local moved_coin = transposer.transferItem(from, to, need_gold, coin.findFirstStack(from, ID_COIN_GOLD)--[[@as number]] )
if (moved_coin == 0) then
break
else
@@ -116,7 +148,7 @@ function coin.moveCoin(amount, from, to)
end
end
while (moved_platinum < need_platinum) do
local moved_coin = transposer.transferItem(from, to, need_platinum, coin.findFirstStack(from, ID_COIN_PLATINUM))
local moved_coin = transposer.transferItem(from, to, need_platinum, coin.findFirstStack(from, ID_COIN_PLATINUM)--[[@as number]] )
if (moved_coin == 0) then
break
else

View File

@@ -2,133 +2,147 @@ local gpu = require("component").gpu
local string = require("string")
local event = require("event")
local Keypad = require("libClass").newClass("Keypad",require("libGUI/widget/Widget"))
local Keypad = require("libClass").newClass("Keypad", require("libGUI/widget/Widget"))
--Rectangle is not used because of it's constructor. Keypad have fixed height and width
function Keypad.setWidth(self,width) return nil end
function Keypad.setHeight(self,height) return nil end
function Keypad.setSize(self,width,height) return nil end
function Keypad.setWidth(self, width) return nil end
function Keypad.setHeight(self, height) return nil end
function Keypad.setSize(self, width, height) return nil end
function Keypad.getWidth(self) return 9 end --fixed
function Keypad.getHeight(self) return 11 end --fixed
function Keypad.getSize(self) return self:getWidth(), self:getHeight() end
Keypad.private.color = 0 --background color
function Keypad.getColor(self) return self.private.color end
function Keypad.setColor(self,color) self.private.color = color or self:getColor() end
function Keypad.setColor(self, color) self.private.color = color or self:getColor() end
Keypad.private.event = -1 --event listener id
Keypad.private.input = ""
function Keypad.getInput(self) return self.private.input end
function Keypad.clearInput(self) self.private.input = "" end
Keypad.private.hide = false --should the input be replaced with '*'
function Keypad.isInputHidden(self) return self.private.hide end
function Keypad.hideInput(self,hide) if(type(hide) == "boolean") then self.private.hide = hide end end
function Keypad.hideInput(self, hide) if (type(hide) == "boolean") then self.private.hide = hide end end
Keypad.private.maxInputLen = -1 --maximum input length
function Keypad.getMaxInputLen(self) return self.private.maxInputLen end
function Keypad.setMaxInputLen(self,len) self.private.maxInputLen = len or self.private.maxInputLen end
function Keypad.setMaxInputLen(self, len) self.private.maxInputLen = len or self.private.maxInputLen end
function Keypad.private.validateCallback(self) end
function Keypad.setValidateCallback(self,fct) if(type(fct) == "function") then self.private.validateCallback = fct end end
function Keypad.enable(self,enable)
function Keypad.setValidateCallback(self, fct) if (type(fct) == "function") then self.private.validateCallback = fct end end
function Keypad.enable(self, enable)
self.private.enabled = enable
if(self.private.event ~= -1) then --if a event listener is present
if (self.private.event ~= -1) then --if a event listener is present
event.cancel(self.private.event) --cancel the event listener
self.private.event = -1 --set event to -1 (no listener)
end
if(enable) then
self.private.event = event.listen("key_down",function(...) self:onKeyboard(...) end) --register a new event listerner
if (enable) then
self.private.event = event.listen("key_down", function(...) self:onKeyboard(...) end) --register a new event listerner
end
end
function Keypad.constructor(self,x,y,color,hide,maxInputLen)
function Keypad.constructor(self, x, y, color, hide, maxInputLen)
self:setColor(color) --background color
self:enable(true) --Keypad.enable register the keyboard event listener
self:hideInput(hide) --should the input be replaced with '*'
self:setMaxInputLen(maxInputLen) --max input length
end
function Keypad.collide(self,x,y)
local wx1,wy1 = self:getPos()
local wx2 = self:getX()+self:getWidth()-1
local wy2 = self:getY()+self:getHeight()-1
return ((x-wx1)*(wx2-x) >= 0 and (y-wy1)*(wy2-y) >= 0)
function Keypad.collide(self, x, y)
local wx1, wy1 = self:getPos()
local wx2 = self:getX() + self:getWidth() - 1
local wy2 = self:getY() + self:getHeight() - 1
return ((x - wx1) * (wx2 - x) >= 0 and (y - wy1) * (wy2 - y) >= 0)
end
function Keypad.private.keyboardHandler(self,eventName,keyboardUUID,char,key,playerName)
if(48<=char and char<=57)then
self.private.input = self.private.input..string.char(char)
elseif(char==8)then
self.private.input = self:getInput():sub(1,#self:getInput()-1)
elseif(char==13) then --\n
function Keypad.private.keyboardHandler(self, eventName, keyboardUUID, char, key, playerName)
if (48 <= char and char <= 57) then
self.private.input = self.private.input .. string.char(char)
elseif (char == 8) then
self.private.input = self:getInput():sub(1, #self:getInput() - 1)
elseif (char == 13) then --\n
self.private.validateCallback(self)
end
self.private.input = self.private.input:sub(1,self:getMaxInputLen())
self.private.input = self.private.input:sub(1, self:getMaxInputLen())
end
function Keypad.onKeyboard(self,...)
function Keypad.onKeyboard(self, ...)
--event.listen("key_up",function(...) keypad:onKeyboard(...) end)
self.private.keyboardHandler(self,...)
self.private.keyboardHandler(self, ...)
self.private.drawInput(self) --redraw the text field
end
function Keypad.private.screenHandler(self,eventName,ScreenUUID,x,y,button,playerName)
function Keypad.private.screenHandler(self, eventName, ScreenUUID, x, y, button, playerName)
local keys = {
{'7','8','9'},
{'4','5','6'},
{'1','2','3'},
{'X','0','V'}
{'7', '8', '9'},
{'4', '5', '6'},
{'1', '2', '3'},
{'X', '0', 'V'}
} --keyboard layout
--convert the screen coordinates to coord in the keys array
x = (x - self:getX())/2
y = (y - self:getY()-1)/2
x = (x - self:getX()) / 2
y = (y - self:getY() - 1) / 2
if(x>=1 and x<=3 and y>=1 and y<=4) then --keys[y][x] might be null if the event is not on a key
if(keys[y][x] == 'X') then --if X got pressed
self.private.input = self:getInput():sub(1,#self:getInput()-1) --remove the last char from the input
elseif(keys[y][x] == 'V') then --if V got pressed
if (x >= 1 and x <= 3 and y >= 1 and y <= 4) then --keys[y][x] might be null if the event is not on a key
if (keys[y][x] == 'X') then --if X got pressed
self.private.input = self:getInput():sub(1, #self:getInput() - 1) --remove the last char from the input
elseif (keys[y][x] == 'V') then --if V got pressed
self.private.validateCallback(self)
else --a number got pressed
self.private.input = self.private.input..(keys[y][x])
self.private.input = self.private.input .. (keys[y][x])
end
end
self.private.input = self.private.input:sub(1,self:getMaxInputLen()) --cut the string to the max input length
self.private.input = self.private.input:sub(1, self:getMaxInputLen()) --cut the string to the max input length
end
function Keypad.private.callback(self,...) --could have been named onKeyboard
self.private.screenHandler(self,...)
function Keypad.private.callback(self, ...) --could have been named onKeyboard
self.private.screenHandler(self, ...)
self.private.drawInput(self) --redraw the text field
end
function Keypad.private.drawInput(self)
if(not self:isVisible()) then return nil end --do nothing if the widget is not visible
if (not self:isVisible()) then return nil end --do nothing if the widget is not visible
local oldBgColor = gpu.setBackground(0) --change the background color and save the old one to restore it later
local oldFgColor = gpu.setForeground(0xffffff) --change the foreground color and save the old one to restore it later
--draw the text field
gpu.setBackground(0)
gpu.fill(self:getX()+1,self:getY()+1,self:getWidth()-2,1," ")
gpu.fill(self:getX() + 1, self:getY() + 1, self:getWidth() - 2, 1, " ")
--fill the text field
local displayText = self:getInput():sub(-1*(self:getWidth()-2))
if(self:isInputHidden()) then
displayText = displayText:gsub('.','*') --replace each char with '*'
local displayText = self:getInput():sub(-1 * (self:getWidth() - 2))
if (self:isInputHidden()) then
displayText = displayText:gsub('.', '*') --replace each char with '*'
end
if(#self:getInput() > self:getWidth()-2) then --if the input if longer than the text field
displayText = "<"..displayText:sub(-1*(self:getWidth()-3)) --replace the first character of the displayed text with "<" to indicate a trucated string
if (#self:getInput() > self:getWidth() - 2) then --if the input if longer than the text field
displayText = "<" .. displayText:sub(-1 * (self:getWidth() - 3)) --replace the first character of the displayed text with "<" to indicate a trucated string
end
gpu.set(self:getX()+1,self:getY()+1,displayText)
gpu.set(self:getX() + 1, self:getY() + 1, displayText)
gpu.setBackground(oldBgColor) --restore the background color to the old one
gpu.setForeground(oldFgColor) --restore the foreground color to the old one
end
function Keypad.draw(self)
if(not self:isVisible()) then return nil end --do nothing if the widget is not visible
if (not self:isVisible()) then return nil end --do nothing if the widget is not visible
local oldBgColor = gpu.setBackground(self:getColor()) --change the background color and save the old one to restore it later
local oldFgColor = gpu.setForeground(0xffffff) --change the foreground color and save the old one to restore it later
gpu.fill(self:getX(),self:getY(),self:getWidth(),self:getHeight()," ") --draw background
gpu.fill(self:getX(), self:getY(), self:getWidth(), self:getHeight(), " ") --draw background
--draw the text field
self.private.drawInput(self)
@@ -136,22 +150,21 @@ function Keypad.draw(self)
--add the buttons
gpu.setBackground(0)
gpu.set(self:getX()+2,self:getY()+3,self:isEnabled() and "7" or " ")
gpu.set(self:getX()+4,self:getY()+3,self:isEnabled() and "8" or " ")
gpu.set(self:getX()+6,self:getY()+3,self:isEnabled() and "9" or " ")
gpu.set(self:getX() + 2, self:getY() + 3, self:isEnabled() and "7" or " ")
gpu.set(self:getX() + 4, self:getY() + 3, self:isEnabled() and "8" or " ")
gpu.set(self:getX() + 6, self:getY() + 3, self:isEnabled() and "9" or " ")
gpu.set(self:getX()+2,self:getY()+5,self:isEnabled() and "4" or " ")
gpu.set(self:getX()+4,self:getY()+5,self:isEnabled() and "5" or " ")
gpu.set(self:getX()+6,self:getY()+5,self:isEnabled() and "6" or " ")
gpu.set(self:getX() + 2, self:getY() + 5, self:isEnabled() and "4" or " ")
gpu.set(self:getX() + 4, self:getY() + 5, self:isEnabled() and "5" or " ")
gpu.set(self:getX() + 6, self:getY() + 5, self:isEnabled() and "6" or " ")
gpu.set(self:getX()+2,self:getY()+7,self:isEnabled() and "1" or " ")
gpu.set(self:getX()+4,self:getY()+7,self:isEnabled() and "2" or " ")
gpu.set(self:getX()+6,self:getY()+7,self:isEnabled() and "3" or " ")
gpu.set(self:getX()+2,self:getY()+9,self:isEnabled() and "X" or " ")
gpu.set(self:getX()+4,self:getY()+9,self:isEnabled() and "0" or " ")
gpu.set(self:getX()+6,self:getY()+9,self:isEnabled() and "V" or " ")
gpu.set(self:getX() + 2, self:getY() + 7, self:isEnabled() and "1" or " ")
gpu.set(self:getX() + 4, self:getY() + 7, self:isEnabled() and "2" or " ")
gpu.set(self:getX() + 6, self:getY() + 7, self:isEnabled() and "3" or " ")
gpu.set(self:getX() + 2, self:getY() + 9, self:isEnabled() and "X" or " ")
gpu.set(self:getX() + 4, self:getY() + 9, self:isEnabled() and "0" or " ")
gpu.set(self:getX() + 6, self:getY() + 9, self:isEnabled() and "V" or " ")
gpu.setBackground(oldBgColor) --restore the background color to the old one
gpu.setForeground(oldFgColor) --restore the foreground color to the old one

View File

@@ -21,7 +21,6 @@ if (fs.exists(args[1]) and not fs.isDirectory(args[1])) then
gpu.setResolution(img:getWidth(), img:getHeight())
screen:addChild(img)
screen:draw()
---@diagnostic disable-next-line: undefined-field
os.sleep(1)
require("event").pull("key_down")
gpu.setBackground(bk)

View File

@@ -40,7 +40,6 @@ local function openPAM(path)
end
local i = 0
repeat
---@diagnostic disable-next-line: undefined-field
if (i % 1000 == 0) then os.sleep() end
local rgb = {}
local pixel = ""
@@ -108,7 +107,6 @@ local function openPPM(path)
-- read pixel data
local i = 0
repeat
---@diagnostic disable-next-line: undefined-field
if (i % 1000 == 0) then os.sleep() end
local rgb = {}
local pixel = ""

View File

@@ -34,7 +34,6 @@ while (run) do
--the widgets are drawn in the same order they were added to the screen
screen:draw()
--sleep so the events can be processed
---@diagnostic disable-next-line: undefined-field
os.sleep()
end
--stop processing touch events

View File

@@ -35,6 +35,7 @@ local function do_mount()
os.exit(1)
end
assert(proxy)
local result, mount_failure = filesystem.mount(proxy, shell.resolve(args[2]))
if not result then
io.stderr:write(mount_failure, "\n")
@@ -53,7 +54,3 @@ else
io.stderr:write("wrong number of arguments: ", #args, "\n")
usage()
end
local proxy = lnfs.LnfsProxy.new("7b51804b-ca59-4103-9a24-dc19d449bd09", 21, false)
filesystem.mount(proxy, "/mnt/7b5")

View File

@@ -14,12 +14,19 @@ local lnfs = {}
local TIMEOUT = 5
local MTU = math.floor(tonumber(require("computer").getDeviceInfo()[modem.address].capacity) * 0.9)
---return the path of the directory the file is in
---@param path string file path
---@return string path directory path
local function dirName(path)
local dir = filesystem.segments(path)
table.remove(dir, #dir)
return filesystem.concat(table.unpack(dir))
end
---split a string into smaller chunks
---@param text string
---@param chunkSize number
---@return table chunkedText
local function splitByChunk(text, chunkSize)
local s = {}
for i = 1, #text, chunkSize do
@@ -28,7 +35,15 @@ local function splitByChunk(text, chunkSize)
return s
end
---@class LnfsFilesystemProxy : ComponentFilesystem
lnfs.LnfsProxy = {}
---Create a new lnfs filesystem proxy
---@param remoteAddr string
---@param remotePort? number
---@param readOnly? boolean
---@return LnfsFilesystemProxy|nil proxy, string|nil reason Explaination of the proxy creation failure
function lnfs.LnfsProxy.new(remoteAddr, remotePort, readOnly)
checkArg(1, remoteAddr, "string")
checkArg(2, remotePort, "number", "nil")

View File

@@ -139,7 +139,9 @@ end
---@diagnostic disable-next-line: lowercase-global
function start(msg)
---@diagnostic disable-next-line: lowercase-global
if (not args) then args = {root = ROOT, ro = false, port = 21} end
---@diagnostic disable-next-line: lowercase-global
if (type(args) == "string") then args = {root = args, ro = false, port = 21} end
ROOT = args.root or "/"
RO = false or args.ro

View File

@@ -55,7 +55,6 @@ local function parseFolders(pack, repo, info)
error(reason, 2)
end
repeat
---@diagnostic disable-next-line: undefined-field
os.sleep(0)
local s, c, reason = pcall(result.finishConnect)
if (not s) then
@@ -77,7 +76,6 @@ local function parseFolders(pack, repo, info)
elseif (#data > 0) then
sContent = sContent .. data
end
---@diagnostic disable-next-line: undefined-field
os.sleep(0)
until data == nil --eof
return sContent, status, headers
@@ -93,7 +91,6 @@ local function parseFolders(pack, repo, info)
if (tonumber(headers["X-RateLimit-Remaining"][1]) == 0) then
print(string.format("No more API request available. More call will be possible at %s", os.date("%H:%M:%S", headers["X-RateLimit-Reset"])))
print("Waiting 1 minute")
---@diagnostic disable-next-line: undefined-field
os.sleep(60)
end
until tonumber(headers["X-RateLimit-Remaining"][1]) > 0

View File

@@ -815,7 +815,6 @@ else stargate.openIris() end
--main loop
while (run) do
root:draw()
---@diagnostic disable-next-line: undefined-field
os.sleep() --sleep to handle events
end
closeApp()

View File

@@ -5,7 +5,6 @@ local serialization = require("serialization")
local text = require("text")
local event = require("event")
local term = require("term")
---@diagnostic disable-next-line: undefined-field
local sleep = require("os").sleep
local component = require("component")
local transposer = component.transposer