copy / v86

x86 PC emulator and x86-to-wasm JIT, running in the browser
https://copy.sh/v86/
BSD 2-Clause "Simplified" License
19.61k stars 1.37k forks source link

V86.prototype.update_file(..) ? #1140

Closed coderofsalvation closed 3 days ago

coderofsalvation commented 2 weeks ago

I've noticed that this (awesome) project has V86.prototype.read_file() and V86.prototype.write_file(). However, calling write_file twice will not persist the inode (I want to update a file from javascript which is being monitored by tail -f). Is this a usecase for adding V86.prototype.update_file()? Or is there another way I can write from javascript to the filesystem (stream to a named pipe?)

As a (slow) workaround for now, I'm monitoring a file in the background (shellscript) and write changes to a named pipe (monitored by tail -f

Anyways, FOSS FTW & keep up the good work ❤

coderofsalvation commented 2 weeks ago

fwiw, the clunky v86pipe shellscript I wrote which allows tailing files (updated by write_file()) indirectly via a (tailable) named pipe:

#!/bin/sh
#
# this daemon allows 'tail -f' on v86 files (which don't persist inode when updated
# via javascript)
# more info see: https://github.com/copy/v86/issues/1140
#
# Hopefully as V86 (or my understanding of it) matures, this will be no longer needed

test -z $2 && { echo "usage: v86pipe <logfile> <namedpipe>"; exit 0; }

# Start reading from the last line in the log file
last_size=0
LOG_FILE=$1
LOG_PIPE=$2

test -f $LOG_FILE || touch $LOG_FILE
test -p $LOG_PIPE || mkfifo $LOG_PIPE

while true; do
    current_size=$(wc -c < $LOG_FILE)
    test $current_size = $last_size || {
      cat $LOG_FILE > $LOG_PIPE
      truncate --size=0 $LOG_FILE
    }
    last_size=$current_size
    # Sleep for a moment to avoid excessive CPU usage
    sleep 0.2
done

Example

$ v86pipe /mnt/log.txt log &
$ tail -f log

Now write_file('log.txt', ....) will make tail -f work as expected.

SuperMaxusa commented 1 week ago

Did you look at #530? This uses a hook with the emulator.fs9p.Read() function.

P.S. about writing to the file: I don't understand about V86.prototype.write_file() you mentioned, in src/browser/starter.js I only find create_file() and read_file().

I guess you can try use emulator.fs9p.Write() function for appending data to an existing file (offset should be current size + 1, id - inode of your pipe file): https://github.com/copy/v86/blob/3c77b98bc4bc7a5d51a2056ea73d7666ca50fc9d/lib/filesystem.js#L856

coderofsalvation commented 1 week ago

Thank you! I started to fiddle (unsuccesfully) with .Read() too, and gave up. Seeing your (referenced) issue is exactly what I wanted.

On Thu, Sep 5, 2024 at 8:30 AM SuperMaxusa @.***> wrote:

Did you look at #530 https://github.com/copy/v86/issues/530? This uses a hook with the emulator.fs9p.Read() function.

— Reply to this email directly, view it on GitHub https://github.com/copy/v86/issues/1140#issuecomment-2330706372, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABL6ZD7X7DPJBX3VGJNZYDZU73BJAVCNFSM6AAAAABNKAYTSGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMZQG4YDMMZXGI . You are receiving this because you authored the thread.Message ID: @.***>

-- L Ξ Ο N V Λ N Κ Λ Μ Μ Ξ N

Creative technologist & researcher #FOSS #commons ▹ @@. @.> (fediverse) ▹ http://leon.freshrss.isvery.ninja (aggregated RSS feed of activities) ▹ https://2wa.isvery.ninjahttps://x.com/coderofsalvatiohttps://www.linkedin.com/in/leonvankammen

coderofsalvation commented 1 week ago

btw. write_file was indeed a typo..I mean create_file. fwiw, meanwhile I was also able to write to a file which is being tailed (tail -f /mnt/foo) via this function, which persist the inode:

emulator.fs9p.update_file = async function(file,data){

      const p = this.SearchPath(file);

      if(p.id === -1)
      {
          return Promise.resolve(null);
      }

      let toUint8Array = function(str) {
        str = String(str) || String("")
        // Create a new Uint8Array with the same length as the input string
        const uint8Array = new Uint8Array(str.length);

        // Iterate over the string and populate the Uint8Array
        for (let i = 0; i < str.length; i++) {
            uint8Array[i] = str.charCodeAt(i);
        }
        return uint8Array;
      }

      const inode = this.GetInode(p.id);
      const buf   = typeof data == 'string' ? toUint8Array(data) : data
      await this.Write(p.id,0, buf.length, buf )
      // update inode
      inode.size = buf.length
      const now = Math.round(Date.now() / 1000);
      inode.atime = inode.mtime = now;
      return new Promise( (resolve,reject) => resolve(buf) )

  }
copy commented 3 days ago

I think this feature request is reasonable, but I don't like adding update_file to the public API of v86 (and thus committing to maintaining and not breaking the API).

Since there are several workarounds (such as using emulator.fs9p directly), I will close this issue.