-
-
Save washort/48c109e843b0411d5d64de7d788a534c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from rpython.rlib.objectmodel import specialize | |
from rpython.rlib.rarithmetic import intmask | |
from rpython.rtyper.lltypesystem.lltype import scoped_alloc | |
from rpython.rtyper.lltypesystem.rffi import charpsize2str | |
from typhon import log, rsodium, ruv | |
from typhon.atoms import getAtom | |
from typhon.autohelp import autohelp, method | |
from typhon.errors import userError | |
from typhon.futures import FutureCtx, FutureCallback, resolve, Ok, Err, Break, Continue, LOOP_BREAK, LOOP_CONTINUE | |
from typhon.macros import macros | |
from typhon.objects.constants import NullObject | |
from typhon.objects.data import BytesObject, StrObject, unwrapStr | |
from typhon.objects.refs import LocalResolver, makePromise | |
from typhon.objects.root import Object, runnable | |
from typhon.vats import currentVat, scopedVat | |
ABORTFLOW_0 = getAtom(u'abortFlow', 0) | |
FLOWABORTED_1 = getAtom(u'flowAborted', 1) | |
FLOWSTOPPED_1 = getAtom(u'flowStopped', 1) | |
RECEIVE_1 = getAtom(u'receive', 1) | |
RUN_1 = getAtom(u'run', 1) | |
@autohelp | |
class FileUnpauser(Object): | |
'\n A pause on a file fount.\n ' | |
def __init__(self, fount): | |
self.fount = fount | |
@method('Void') | |
def unpause(self): | |
if (self.fount is not None): | |
self.fount.unpause() | |
self.fount = None | |
def renameCB(fs): | |
try: | |
success = intmask(fs.c_result) | |
(vat, r) = ruv.unstashFS(fs) | |
if (success < 0): | |
msg = ruv.formatError(success).decode('utf-8') | |
r.smash(StrObject((u"Couldn't rename file: %s" % msg))) | |
else: | |
r.resolve(NullObject) | |
ruv.fsDiscard(fs) | |
except: | |
print 'Exception in renameCB' | |
class SetContents(Object): | |
pos = 0 | |
def __init__(self, vat, data, resolver, src, dest): | |
self.vat = vat | |
self.data = data | |
self.resolver = resolver | |
self.src = src | |
self.dest = dest | |
def fail(self, reason): | |
self.resolver.smash(StrObject(reason)) | |
def queueWrite(self): | |
fs = ruv.alloc_fs() | |
sb = ruv.scopedBufs([self.data], self) | |
bufs = sb.allocate() | |
ruv.stashFS(fs, (self.vat, sb)) | |
ruv.fsWrite(self.vat.uv_loop, fs, self.fd, bufs, 1, (-1), writeSetContentsCB) | |
def startWriting(self, fd): | |
self.fd = fd | |
self.queueWrite() | |
def written(self, size): | |
self.pos += size | |
self.data = self.data[size:] | |
if self.data: | |
self.queueWrite() | |
else: | |
fs = ruv.alloc_fs() | |
ruv.stashFS(fs, (self.vat, self)) | |
ruv.fsClose(self.vat.uv_loop, fs, self.fd, closeSetContentsCB) | |
def rename(self): | |
p = self.src.rename(self.dest.asBytes()) | |
self.resolver.resolve(p) | |
def openSetContentsCB(fs): | |
try: | |
fd = intmask(fs.c_result) | |
(vat, sc) = ruv.unstashFS(fs) | |
assert isinstance(sc, SetContents) | |
if (fd < 0): | |
msg = ruv.formatError(fd).decode('utf-8') | |
sc.fail((u"Couldn't open file fount: %s" % msg)) | |
else: | |
sc.startWriting(fd) | |
ruv.fsDiscard(fs) | |
except: | |
print 'Exception in openSetContentsCB' | |
def writeSetContentsCB(fs): | |
try: | |
(vat, sb) = ruv.unstashFS(fs) | |
sc = sb.obj | |
assert isinstance(sc, SetContents) | |
size = intmask(fs.c_result) | |
if (size >= 0): | |
sc.written(size) | |
else: | |
msg = ruv.formatError(size).decode('utf-8') | |
sc.fail((u'libuv error: %s' % msg)) | |
ruv.fsDiscard(fs) | |
sb.deallocate() | |
except: | |
print 'Exception in writeSetContentsCB' | |
def closeSetContentsCB(fs): | |
try: | |
(vat, sc) = ruv.unstashFS(fs) | |
with scopedVat(vat): | |
assert isinstance(sc, SetContents) | |
size = intmask(fs.c_result) | |
if (size < 0): | |
msg = ruv.formatError(size).decode('utf-8') | |
sc.fail((u'libuv error: %s' % msg)) | |
else: | |
sc.rename() | |
ruv.fsDiscard(fs) | |
except: | |
print 'Exception in closeSetContentsCB' | |
def readLoopCore(state, data): | |
if (data == ''): | |
return Break(''.join(state.pieces)) | |
else: | |
state.pieces.append(data) | |
state.pos += len(data) | |
return Continue() | |
class _State1(FutureCtx): | |
def __init__(_1, vat, future, buf, pieces, pos, outerState, k): | |
_1.vat = vat | |
_1.future = future | |
_1.buf = buf | |
_1.pieces = pieces | |
_1.pos = pos | |
_1.outerState = outerState | |
_1.k = k | |
class ReadLoop_K0(ruv.FSReadFutureCallback): | |
def do(self, state, result): | |
(inStatus, data, inErr) = result | |
(status, output, err) = readLoopCore(state, data) | |
if (status == LOOP_CONTINUE): | |
state.future.run(state, readLoop_k0) | |
elif (status == LOOP_BREAK): | |
state.k.do(state.outerState, Ok(output)) | |
else: | |
raise ValueError(status) | |
readLoop_k0 = ReadLoop_K0() | |
class readLoop(ruv.FSReadFutureCallback): | |
callbackType = ruv.FSReadFutureCallback | |
def __init__(self, f, buf): | |
self.f = f | |
self.buf = buf | |
def run(self, state, k): | |
ruv.magic_fsRead(state.vat, self.f, self.buf).run(_State1(state.vat, self, self.buf, [], 0, state, k), readLoop_k0) | |
@autohelp | |
class FileResource(Object): | |
'\n A Resource which provides access to the file system of the current\n process.\n ' | |
_immutable_fields_ = ('segments[*]',) | |
def __init__(self, segments): | |
self.segments = segments | |
def toString(self): | |
return (u'<file resource %s>' % self.asBytes().decode('utf-8')) | |
def asBytes(self): | |
return '/'.join(self.segments) | |
def rename(self, dest): | |
(p, r) = makePromise() | |
vat = currentVat.get() | |
uv_loop = vat.uv_loop | |
fs = ruv.alloc_fs() | |
src = self.asBytes() | |
ruv.stashFS(fs, (vat, r)) | |
ruv.fsRename(uv_loop, fs, src, dest, renameCB) | |
return p | |
def sibling(self, segment): | |
return FileResource((self.segments[:(-1)] + [segment])) | |
def temporarySibling(self, suffix): | |
fileName = (rsodium.randomHex() + suffix) | |
return self.sibling(fileName) | |
@method('Any') | |
def getContents(self): | |
(p, r) = makePromise() | |
vat = currentVat.get() | |
buf = ruv.allocBuf(16384) | |
path = self.asBytes() | |
log.log(['fs'], (u"makeFileResource: Opening file '%s'" % path.decode('utf-8'))) | |
iostart_callback.do(State(vat, path, buf, r), (Ok1, None, None)) | |
return p | |
@method('Any', 'Bytes') | |
def setContents(self, data): | |
sibling = self.temporarySibling('.setContents') | |
(p, r) = makePromise() | |
vat = currentVat.get() | |
uv_loop = vat.uv_loop | |
fs = ruv.alloc_fs() | |
path = sibling.asBytes() | |
flags = ((os.O_WRONLY | os.O_CREAT) | os.O_EXCL) | |
sc = SetContents(vat, data, r, sibling, self) | |
ruv.stashFS(fs, (vat, sc)) | |
ruv.fsOpen(uv_loop, fs, path, flags, 511, openSetContentsCB) | |
return p | |
@method('Any', 'Any', _verb='rename') | |
def _rename(self, fr): | |
if (not isinstance(fr, FileResource)): | |
raise userError(u'rename/1: Must be file resource') | |
return self.rename(fr.asBytes()) | |
@method('Any', 'Str', _verb='sibling') | |
def _sibling(self, name): | |
if (u'/' in name): | |
raise userError((u"sibling/1: Illegal file name '%s'" % name)) | |
return self.sibling(name.encode('utf-8')) | |
@method('Any', _verb='temporarySibling') | |
def _temporarySibling(self): | |
return self.temporarySibling('.new') | |
@runnable(RUN_1) | |
def makeFileResource(path): | |
'\n Make a file Resource.\n ' | |
path = unwrapStr(path) | |
segments = [segment.encode('utf-8') for segment in path.split(u'/')] | |
if (not path.startswith(u'/')): | |
segments = (os.getcwd().split('/') + segments) | |
log.log(['fs'], (u"makeFileResource.run/1: Relative path '%s'" % path)) | |
return FileResource(segments) | |
from typhon.futures import FutureCtx as FutureCtx1, Ok as Ok1, Err as Err1 | |
class iostart_callback_Class(object): | |
def do(self1, state1, result1): | |
ruv.magic_fsOpen(state1.vat, state1.path, os.O_RDONLY, 0).run(state1, io1) | |
iostart_callback = iostart_callback_Class() | |
class io1_Class(ruv.magic_fsOpen.callbackType): | |
def do(self2, state2, result2): | |
(status1, f, err1) = result2 | |
state2.f = f | |
readLoop(state2.f, state2.buf).run(state2, readLoop1) | |
io1 = io1_Class() | |
class readLoop1_Class(readLoop.callbackType): | |
def do(self3, state3, result3): | |
(status2, contents, err2) = result3 | |
state3.contents = contents | |
ruv.magic_fsClose(state3.vat, state3.f).run(state3, io2) | |
readLoop1 = readLoop1_Class() | |
class io2_Class(ruv.magic_fsClose.callbackType): | |
def do(self4, state4, result4): | |
resolve(state4.r, BytesObject(state4.contents)).run(state4, None) | |
io2 = io2_Class() | |
class State(FutureCtx1): | |
def __init__(self4, vat, path, buf, r): | |
self4.vat = vat | |
self4.path = path | |
self4.buf = buf | |
self4.r = r | |
self4.f = 0 | |
self4.contents = None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment