Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local event = require("event")
- local serialization = require("serialization")
- local computer = require("computer")
- local modem = component.modem
- local fs = require("filesystem")
- -- Configuration
- local sg = component.stargate
- local valid_addresses = {}
- local range_to_process = nil
- local symbols = {}
- local processed_ranges = {} -- Table to store successfully processed ranges
- local worker_data_file = "/worker_name.json"
- local worker_name = nil
- local worker_port = nil
- local master_address = nil
- master_port = 1234
- debugoption = 0
- -- Function to send an error back to the master
- local function send_error(message, range, worker_name, valid_addresses, last_successful_index)
- local processed_range = {
- start = range.start,
- finish = last_successful_index
- }
- local error_data = {
- worker_id = worker_name,
- valid_addresses = valid_addresses,
- error = message,
- processed_ranges = processed_range, -- Send only the summarized processed range
- gate_type = gate_type, -- Use the dynamic gate_type
- port = worker_port
- }
- print("Sending processed_ranges:", serialization.serialize(processed_range))
- modem.open(master_port)
- modem.send(master_address, master_port, "error", serialization.serialize(error_data))
- modem.close(master_port)
- print("Worker:", worker_name, "sent error message to master:", message)
- valid_addresses = {}
- end
- -- Function to recursively generate addresses and return the one at the desired index
- local function generate_address_at_index(target_index, symbols, address_length)
- local current_index = 0 -- Counter to track progress
- local result_address = nil -- To store the target address
- -- Recursive function to generate addresses
- local function generate(current_address, available_symbols, depth, used_symbols)
- if result_address then return end -- Stop recursion if we found the target
- -- Base case: full address generated
- if depth > address_length then
- current_index = current_index + 1 -- Increment the counter
- if current_index == target_index then
- -- Target index reached; copy the current address
- result_address = {}
- for i = 1, address_length do
- table.insert(result_address, current_address[i])
- end
- end
- return
- end
- -- Recursive case: iterate through all available symbols
- for _, symbol in ipairs(available_symbols) do
- if not used_symbols[symbol] then
- used_symbols[symbol] = true
- current_address[depth] = symbol
- -- Recurse deeper
- generate(current_address, available_symbols, depth + 1, used_symbols)
- -- Cleanup for the next iteration
- used_symbols[symbol] = nil
- current_address[depth] = nil
- end
- end
- end
- -- Initialize recursion
- local current_address = {}
- local used_symbols = {}
- generate(current_address, symbols, 1, used_symbols)
- -- Return the result
- if result_address then
- return result_address
- else
- error("Error: Target index exceeds total combinations.")
- end
- end
- -- Function to validate a Stargate address
- local function validate_address(address)
- local success, result = pcall(function()
- return sg.getEnergyRequiredToDial(address)
- end)
- table.remove(address) -- Remove Point of Origin after validation
- if not success then
- return nil, "Disconnected from Stargate component"
- end
- -- Check if the 'open' energy value exists and is greater than 0
- if type(result) == "table" and result.open and result.open > 0 then
- return true
- end
- return false
- end
- -- Function to process a batch of addresses
- local function process_range(range, symbols, point_of_origin, address_length, worker_name)
- local start = range.start
- local finish = range.finish
- print(worker_name, "processing range:", start, "-", finish)
- for index = start, finish do
- local address = generate_address_at_index(index, symbols, address_length)
- table.insert(address, point_of_origin) -- Add the Point of Origin dynamically
- if debugoption == 1 then
- print(table.concat(address, ", "))
- end
- local is_valid, error_message = validate_address(address)
- if error_message then
- print("Error:", error_message)
- send_error("Disconnected from Stargate component", range, worker_name, valid_addresses, index - 1)
- return false -- Stop processing and signal error
- end
- if is_valid then
- table.insert(valid_addresses, address)
- end
- end
- return true
- end
- -- Function to send results back to the master
- local function send_results(range, gate_type, worker_name)
- local mac = computer.address()
- local results = {
- worker_id = worker_name,
- valid_addresses = valid_addresses,
- range = range,
- gate_type = gate_type, -- Use the dynamic gate_type
- mac = mac,
- worker_port = worker_port
- }
- modem.open(master_port)
- modem.send(master_address, master_port, "result", serialization.serialize(results))
- modem.close(master_port)
- print("Worker:", worker_name, "sent results for range:", range.start, "-", range.finish)
- valid_addresses = {} -- Reset valid addresses for the next batch
- processed_ranges = {}
- end
- -- Notify the master that the worker is ready
- local function send_ready_message(worker_name, worker_port)
- local mac = computer.address()
- local ready_data = {
- name = worker_name,
- port = worker_port,
- mac = mac
- }
- modem.open(master_port)
- modem.send(master_address, master_port, "ready", serialization.serialize(ready_data))
- modem.close(master_port)
- print("Sent ready message to master:", worker_name, "| Port:", worker_port)
- end
- local function send_goodbye_message()
- local goodbye_data = {
- name = worker_name,
- address = modem.address, -- Add worker's network address
- mac = computer.address()
- }
- modem.open(master_port)
- modem.send(master_address, master_port, "goodbye", serialization.serialize(goodbye_data))
- modem.close(master_port)
- end
- -- Save worker name and port
- local function save_worker_data(name, port, master_address)
- local file = io.open(worker_data_file, "w")
- if file then
- file:write(serialization.serialize({ name = name, port = port, master_address = master_address }))
- file:close()
- print("Worker data saved:", name, port, master_address)
- else
- print("Error: Unable to save worker data.")
- end
- end
- -- Request name and port from the master node
- local function request_worker_data()
- print("Requesting name and port from master...")
- local id = computer.address()
- local modemid = modem.address
- local data = { id = id, modemid = modemid }
- modem.open(master_port)
- modem.broadcast(master_port, "request_name_port", serialization.serialize(data))
- local master_address, assigned_name, assigned_port
- while true do
- local _, _, from, _, _, command, name, worker_port = event.pull("modem_message")
- if command == "assigned_name_port" then
- master_address = from -- The master's address
- assigned_name = name -- The worker name
- assigned_port = worker_port -- The assigned port
- print("Name and port received from master:", name, assigned_port)
- save_worker_data(name, assigned_port, master_address)
- modem.close(master_port)
- return name, assigned_port, master_address
- elseif command == "error_name_port" then
- master_address = from -- The master's address
- assigned_name = name
- assigned_port = worker_port
- print("Error: Master reassigned existing name and port:", name, assigned_port)
- save_worker_data(name, assigned_port, master_address)
- modem.close(master_port)
- return name, assigned_port, master_address
- end
- end
- end
- -- Load worker name if available
- local function load_worker_data()
- if fs.exists(worker_data_file) then
- local file = io.open(worker_data_file, "r")
- local data = file:read("*all")
- file:close()
- local success, loaded_data = pcall(serialization.unserialize, data)
- if success and loaded_data and loaded_data.name and loaded_data.port and loaded_data.master_address then
- return loaded_data.name, loaded_data.port, loaded_data.master_address
- end
- end
- return nil, nil, nil -- No valid data found
- end
- -- Main worker loop
- local function main(worker_name, worker_port, master_address)
- send_ready_message(worker_name, worker_port)
- modem.open(worker_port)
- while true do
- print(worker_name, "listening for tasks on port", worker_port)
- local _, _, from, port, _, command, data = event.pull("modem_message")
- if port == worker_port then -- Ensure messages are received only on assigned port
- if command == "task" then
- local task = serialization.unserialize(data)
- local task_worker_id = task.worker_id
- -- Validate the worker ID
- if task_worker_id ~= computer.address() then
- print("Mismatch in worker ID! Requesting new worker ID and port...")
- -- Send the range back to the master for reassignment
- modem.open(master_port)
- modem.send(from, master_port, "reassign_range", serialization.serialize({
- range = range_to_process,
- worker_id = worker_name
- }))
- modem.close(master_port)
- worker_name, worker_port, master_address = request_worker_data()
- modem.open(worker_port) -- Re-open the new port
- break -- Restart main loop after getting new ID and port
- end
- modem.open(master_port)
- modem.send(from, master_port, "ok", "") -- Sending "ok" as message1, empty for message2
- print("Sent ok to:", from, master_port)
- modem.close(master_port)
- -- Process the task as normal
- range_to_process = task.range
- symbols = task.symbols
- address_length = task.address_length
- local gate_type = task.gate_type
- local point_of_origin = task.point_of_origin
- -- Process the assigned range
- local success = process_range(range_to_process, symbols, point_of_origin, address_length, worker_name)
- if success then
- -- Send results back to the master node
- send_results(range_to_process, gate_type, worker_name)
- print ("Sent results to:", master_address, master_port)
- else
- print("Worker encountered an issue, halting execution.")
- end
- elseif command == "shutdown" then
- send_goodbye_message()
- print(worker_name, "shutting down as instructed.")
- break
- elseif command == "resync" then
- print("Master has old data, resyncing.")
- worker_name, worker_port, master_address = request_worker_data()
- send_ready_message(worker_name, worker_port)
- end
- end
- end
- end
- -- Worker startup logic
- worker_name, worker_port, master_address = load_worker_data()
- if not worker_name or not worker_port or not master_address then
- worker_name, worker_port, master_address = request_worker_data()
- end
- print("Worker is ready. Name:", worker_name, "Port:", worker_port)
- -- Start the worker
- main(worker_name, worker_port, master_address)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement