Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

Molinko

Members
  • Content Count

    451
  • Joined

  • Last visited

  • Days Won

    35

Posts posted by Molinko

  1. I would agree with your first statement. Daemons/services are probably the route to go, but don't forget OpenOS has threads which can be handy too. Services are pretty dang simple though.. The only real requirement is that you have a start and stop method, any other method is optional. You can check out the example service in /etc/rc.d/example.lua but note that there is only a start method and the 'service' isn't very compelling as to possible uses. I think an easy mix is with services that spawn threads. i.e. A service that can manage other processes by launching and killing them with service methods. Here's a (hopefully) simple and understandable service..

    /etc/rc.d/testservice.lua

    local event = require "event"
    local shell = require "shell"
    local thread = require "thread"
    
    local threads = {}
    
    -- # Service methods (notice they aren't local variables. That makes them service methods)
    
    function start(prog, ...)
      -- # start a program as a thread process.
      local proc = thread.create(shell.execute, prog, os.getenv("shell"), ...)
      -- # detach it from current process so rc doesn't block the main thread when we start.
      proc:detach()
      -- # keep track of started processes
      table.insert(threads, proc)
    end
    
    function stop()
      -- # kill all not 'dead' threads service started
      for i, proc in ipairs(threads) do
        if proc.status and proc:status() ~= "dead" then
          proc:kill() -- # stabby stab...
        end
      end
    end

    Use like so..  `rc testservice start myprogram args...`

    Hope this gives you some ideas. Feel free to ask questions :3

  2. This is a cool idea. I believe there are a few libs out there that might help a lot in making this. Just my thoughts.. I think you have the difficulties reversed. Keeping a terminal responsive and in sync over a network is probably the trickier part. Sending files is pretty simple all around. Adding authentication (for validating if you want this or that machine reading or writing that particular file), or encryption if you're on a server or you want to control your base from outside of MC. Those last two may be unnecessary if you're playing single player or just don't care that much about network security.

    Here is a simple example of sending a file between two computers on the same network. Crude but should demonstrate that it's pretty simple in principle.

    client

    -- # fget.lua
    local args, opts = require("shell").parse(...)
    local uptime = require("computer").uptime
    local modem = require("component").modem
    local pull = require("event").pull
    
    local filename = assert(args[1], "Usage: fget filename [port] [timeout]")
    local port = 22
    local timeout = 5
    
    if opts.port then
      local pnum = assert(tonumber(opts.port), "option 'port' must be a number!")
      port = assert(pnum > 0 and pnum <= 65535)
    end
    
    if opts.timeout then
      timeout = assert(tonumber(opts.timeout),"option 'timeout(seconds)' must be number. [~3 sec recommended]")
    end
    
    modem.open(port)
    
    modem.broadcast(port, "F_REQUEST", filename) -- crude and will allow just about anybody to fulfill this request :/
    
    local response, key
    local stime = uptime()
    
    repeat
      local ev = {pull((stime + timeout - uptime()), "(modem_message)(interrupted)")}
    
      if ev[1] == "interrupted" then
      	print(ev[1])
      	os.exit()
      elseif ev[1] == "modem_message" and ev[6] == "F_RESPONSE" then
        key = ev[7]
        response = true
        break
      end
    until uptime() >= (stime + timeout)
    
    if not response then
      print "timed out. no response"
      os.exit()
    end
    
    local _error
    stime = uptime() -- # refresh timeout
    
    repeat
      local ev = {pull((stime + timeout - uptime()), "(modem_message)(interrupted)")}
    
      if ev[1] == "interrupted" then
      	print(ev[1])
      	os.exit()
      elseif ev[1] == "modem_message" and ev[6] == key then
        stime = uptime() -- # refresh the timeout
        
        if not ev[7] then
          if ev[8] and ev[8] == "error" then
            _error = true
            io.stderr:write("error occured. '*drops pizza on the floor*'")
          end
          
          break
        end
        
        io.stdout:write(ev[7])
      end
    until uptime() >= (stime + timeout)
    
    if _error then
      os.exit(1)
    end
    
    -- # Disclaimer: this hasn't been tested :3

    server

    -- # fserv.lua
    local shell = require("shell")
    local uptime = require("computer").uptime
    local modem = require("component").modem
    local pull = require("event").pull
    local uuid = require("uuid")
    local fs = require("filesystem")
    
    local args, opts = shell.parse(...)
    local port = 22
    
    -- # handle port options
    
    local srvdir
    if args[1] then
      assert(fs.exists(args[1]))
      assert(fs.isDirectory(args[1]))
      srvdir = args[1]
    else
      srvdir = shell.getWorkingDirectory()
    end
    
    modem.open(port)
    
    while true do
      local ev = {pull("(modem_message)(interrupted)")}
      
      if ev[1] == "interrupted" then
        print "quitting.."
        os.exit()
      elseif ev[1] == "modem_message" and ev[6] == "F_REQUEST" and ev[7] ~= nil then
        local path = srvdir..ev[7]
        
        if fs.exists(path) and (not fs.isDirectory(path)) then
          local chunkSize = modem.maxPacketSize() - 1024
          local res = {pcall(io.open, path, "r")}
          
          if not res[1] then
            io.stderr:write("service error: " .. res[2])
          else
            local fd = res[1]
            local chunk = fd:read(chunkSize)
    
            if chunk then
              local key = uuid.next()
              
              modem.send(ev[3], ev[4], "F_RESPONSE", key)
    
              repeat
                modem.send(ev[3], ev[4], key, chunk)
                
                res = {pcall(function()
                    chunk = fd:read(chunkSize)
                  end)}
    
                if not res[1] then
                  modem.send(ev[3], ev[4], key, nil, 'error') -- # nil, 'error' signals srv failure on client
                  break
                end
              until not chunk
    
              if res[1] then -- ok
                modem.send(ev[3], ev[4], key, nil) -- # eof on client
              else
                io.stderr:write(res[2] or "bad salsa")
              end
            end
          end
        end
      end
    end
    
    -- # Disclaimer!! Also untested.. :3

    Hope this is helpful, if at least to get those wheels turning :3 

  3. The issue with your adaptation is that is doesn't yield. As in coroutine.yield()

    Threads from the thread lib are fancy objects based around coroutines. Coroutines, basically, are functions you can pause(yield). This means they do a little something and before they return, they yield.

    Yielding is basically a way to generate values before a final value is returned. More importantly threads(coroutines) pause(yield) so other routines(functions) can run(and presumably yield or return quickly), but lets not forget they resume as well, to finish their doings...

    In my example I use the os.sleep(1) call to yield the running thread(fancy coroutine). 

    There are other issues with your program, but just to be clear, threads are a little more than just plug and play and my example shouldn't be adapted to achieve your goals.

  4. Basically the api is more flexible.. 

    local function counter(num)
        local i = num or 0
        while i < 25 do
          print(i)
          os.sleep(1)
          i = i + 1
        end
    end
    
    local threadA = thread.create(counter, 1)
    local threadB = thread.create(counter, 5)
    
    --# Normally these will start and continue running asap. However, you
    --# can block the program from exiting early by using the 'waitForAll' and 'waitForAny' methods i.e
    
    thread.waitForAny({threadA, threadB})

     

  5. Your program has an infinite loop. You'll need to yield either with sleep or by pulling an event. Here is a simple solution.

    repeat
      energy = toMRf(cube.getEnergyStored())
      energyMax = toMRf(cube.getMaxEnergyStored())
      energyJ = toJ(cube.getEnergyStored())
      energyMaxJ = toJ(cube.getMaxEnergyStored())
     
      label(1, 1, "%.2f MRf / %.2f MJ (Energia Acumulada)", colors.red, energy, energyJ )
      label(1, 3, "%.2f MRf / %.2f MJ (Capacidade da bateria)", colors.lime, energyMax, energyMaxJ)
    until event.pull(1) == "interrupted" -- # change 1 to something smaller to refresh faster

     

  6. 20 minutes ago, Piorjade said:

    Again, my methods involving having these pixels in a table lead to the whole redrawing process being really slow, as it would call a gpu method for every pixel.

    I think this is why I think a 'grouping' algorithm(if thats what it's called..) would be useful. Yes, you have to iterate every 'pixel' for its data, but you dont have to draw every pixel one by one independently. If you've heard of MineOS, it has  a pretty beefy double buffering library. If you inspect the draw method you can get an idea of how it does grouping for gpu draw calls from its internal buffer. Just a suggestion in case i haven't been clear.. 

  7. From what I understand term.bind just binds the window instance to a given gpu proxy. The window instance is just size info, cursor state and some other metadata. If you keep digging in the OS you might notice term.internal.open isn't used anywhere other than in the term library and windows aren't exposed anywhere to the user. That's because it's not an explicit OS feature. This is why we have to manually bind a window instance to a process' metadata ourself. As for why it's not present in the process info already has to do with that metatable trickery I warned about earlier. There is one term window, it is on the init it shell process.... I forget. Child processes inherit this window or 'term'. Hope that's not too muddy to understand.

  8. I would definitely keep looking into how OpenOS gets things done, some of it is pretty clever. The buffer API is mostly for byte streams like files and such, maybe socket streams.

    An idea I had was creating a double buffer API and a virtual gpu component proxy interface that could then be bound to the term library with term.bind(gpuProxy, windowInstance)

    I think this would be workable and easily injected. Just my thoughts.. happy coding

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.