Skip to content

Commit f540222

Browse files
committed
emscripten.pyx: Emscripten 1.39.2 has stricted linked again, move aside optional Fetch bindings, drop sleep_with_yield
1 parent bff0fcf commit f540222

File tree

4 files changed

+350
-318
lines changed

4 files changed

+350
-318
lines changed

2.7.10/webprompt.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ BUILD=t
1818
mkdir -p $BUILD
1919

2020
cython -2 ../emscripten.pyx -o $BUILD/emscripten.c
21+
cython -2 ../emscripten_fetch.pyx -o $BUILD/emscripten_fetch.c
2122
# utf_32_be: support Unicode characters e.g. u'é'
2223
PREFIX=$INSTALLDIR OUTDIR=$BUILD ./package-pythonhome.sh \
2324
encodings/utf_32_be.py
@@ -31,7 +32,7 @@ while (( $# )); do
3132
shift
3233
done
3334
emcc -o $BUILD/index.html \
34-
../webprompt-main.c $BUILD/emscripten.c \
35+
../webprompt-main.c $BUILD/emscripten.c $BUILD/emscripten_fetch.c \
3536
$FLAGS \
3637
-I$INSTALLDIR/include/python2.7 -L$INSTALLDIR/lib -lpython2.7 \
3738
-s EMULATE_FUNCTION_POINTER_CASTS=1 \

emscripten.pyx

Lines changed: 6 additions & 316 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ cdef extern from "emscripten.h":
3434
void emscripten_async_call(em_arg_callback_func func, void *arg, int millis)
3535

3636
void emscripten_sleep(unsigned int ms)
37-
void emscripten_sleep_with_yield(unsigned int ms)
3837
void emscripten_wget(const char* url, const char* file)
3938
void emscripten_wget_data(const char* url, void** pbuffer, int* pnum, int *perror)
4039

40+
# Emterpreter-only
41+
#void emscripten_sleep_with_yield(unsigned int ms)
42+
4143
enum:
4244
EM_LOG_CONSOLE
4345
EM_LOG_WARN
@@ -53,75 +55,6 @@ cdef extern from "emscripten.h":
5355
void emscripten_log(int flags, ...)
5456
int emscripten_get_callstack(int flags, char *out, int maxbytes)
5557

56-
cdef extern from "emscripten/html5.h":
57-
ctypedef int EM_BOOL
58-
ctypedef int EMSCRIPTEN_RESULT
59-
enum: EM_TRUE
60-
enum: EM_FALSE
61-
62-
from libc.stdint cimport uint32_t, uint64_t
63-
64-
cdef extern from "emscripten/fetch.h":
65-
ctypedef struct emscripten_fetch_attr_t:
66-
char requestMethod[32]
67-
void *userData
68-
void (*onsuccess)(emscripten_fetch_t *fetch)
69-
void (*onerror)(emscripten_fetch_t *fetch)
70-
void (*onprogress)(emscripten_fetch_t *fetch)
71-
void (*onreadystatechange)(emscripten_fetch_t *fetch)
72-
uint32_t attributes
73-
unsigned long timeoutMSecs
74-
EM_BOOL withCredentials
75-
const char *destinationPath
76-
const char *userName
77-
const char *password
78-
const char * const *requestHeaders
79-
const char *overriddenMimeType
80-
const char *requestData
81-
size_t requestDataSize
82-
83-
ctypedef struct emscripten_fetch_t:
84-
unsigned int id
85-
void *userData
86-
const char *url
87-
const char *data
88-
uint64_t numBytes
89-
uint64_t dataOffset
90-
uint64_t totalBytes
91-
unsigned short readyState
92-
unsigned short status
93-
char statusText[64]
94-
uint32_t __proxyState
95-
emscripten_fetch_attr_t __attributes
96-
97-
enum:
98-
EMSCRIPTEN_FETCH_LOAD_TO_MEMORY
99-
EMSCRIPTEN_FETCH_STREAM_DATA
100-
EMSCRIPTEN_FETCH_PERSIST_FILE
101-
EMSCRIPTEN_FETCH_APPEND
102-
EMSCRIPTEN_FETCH_REPLACE
103-
EMSCRIPTEN_FETCH_NO_DOWNLOAD
104-
EMSCRIPTEN_FETCH_SYNCHRONOUS
105-
EMSCRIPTEN_FETCH_WAITABLE
106-
107-
void emscripten_fetch_attr_init(emscripten_fetch_attr_t *fetch_attr)
108-
emscripten_fetch_t *emscripten_fetch(emscripten_fetch_attr_t *fetch_attr, const char *url)
109-
#EMSCRIPTEN_RESULT emscripten_fetch_wait(emscripten_fetch_t *fetch, double timeoutMSecs)
110-
EMSCRIPTEN_RESULT emscripten_fetch_close(emscripten_fetch_t *fetch)
111-
size_t emscripten_fetch_get_response_headers_length(emscripten_fetch_t *fetch)
112-
size_t emscripten_fetch_get_response_headers(emscripten_fetch_t *fetch, char *dst, size_t dstSizeBytes)
113-
char **emscripten_fetch_unpack_response_headers(const char *headersString)
114-
void emscripten_fetch_free_unpacked_response_headers(char **unpackedHeaders)
115-
116-
FETCH_LOAD_TO_MEMORY = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY
117-
FETCH_STREAM_DATA = EMSCRIPTEN_FETCH_STREAM_DATA
118-
FETCH_PERSIST_FILE = EMSCRIPTEN_FETCH_PERSIST_FILE
119-
FETCH_APPEND = EMSCRIPTEN_FETCH_APPEND
120-
FETCH_REPLACE = EMSCRIPTEN_FETCH_REPLACE
121-
FETCH_NO_DOWNLOAD = EMSCRIPTEN_FETCH_NO_DOWNLOAD
122-
FETCH_SYNCHRONOUS = EMSCRIPTEN_FETCH_SYNCHRONOUS
123-
FETCH_WAITABLE = EMSCRIPTEN_FETCH_WAITABLE
124-
12558
LOG_CONSOLE = EM_LOG_CONSOLE
12659
LOG_WARN = EM_LOG_WARN
12760
LOG_ERROR = EM_LOG_ERROR
@@ -140,8 +73,6 @@ from cpython.ref cimport PyObject, Py_XINCREF, Py_XDECREF
14073

14174
from cpython.buffer cimport PyBuffer_FillInfo
14275

143-
from libc.string cimport strncpy
144-
14576
#cdef extern from "stdio.h":
14677
# int puts(const char *s);
14778

@@ -242,8 +173,9 @@ def exit_with_live_runtime():
242173
def sleep(ms):
243174
emscripten_sleep(ms)
244175

245-
def sleep_with_yield(ms):
246-
emscripten_sleep_with_yield(ms)
176+
# Emterpreter-only
177+
#def sleep_with_yield(ms):
178+
# emscripten_sleep_with_yield(ms)
247179

248180
def run_script(script):
249181
emscripten_run_script(script.encode('UTF-8'));
@@ -302,248 +234,6 @@ def async_wget_data(url, arg, onload, onerror=None):
302234
# emscripten.async_wget_data('https://bank.confidential/', None, None)
303235

304236

305-
306-
# Fetch API
307-
# https://emscripten.org/docs/api_reference/fetch.html
308-
309-
# http://docs.cython.org/en/latest/src/userguide/extension_types.html
310-
cdef class Fetch:
311-
cdef emscripten_fetch_t *fetch
312-
cdef callbacks
313-
314-
def __cinit__(self, url, requestMethod=None, userData=None,
315-
onsuccess=None, onerror=None, onprogress=None, onreadystatechange=None,
316-
attributes=None, timeoutMSecs=None, withCredentials=None,
317-
destinationPath=None, userName=None, password=None,
318-
requestHeaders=None, overriddenMimeType=None, requestData=None):
319-
320-
# Keep track of temporary Python strings we pass emscripten_fetch() for copy
321-
py_str_refs = []
322-
323-
cdef emscripten_fetch_attr_t attr
324-
emscripten_fetch_attr_init(&attr)
325-
326-
Py_XINCREF(<PyObject*>self) # survive until callback
327-
attr.userData = <PyObject*>self
328-
329-
if requestMethod is not None:
330-
strncpy(attr.requestMethod,
331-
requestMethod.encode('UTF-8'),
332-
sizeof(attr.requestMethod) - 1)
333-
334-
self.userData = userData
335-
336-
self.callbacks = {}
337-
attr.onsuccess = callpyfunc_fetch_onsuccess
338-
attr.onerror = callpyfunc_fetch_onerror
339-
if onsuccess is not None:
340-
self.callbacks['onsuccess'] = onsuccess
341-
if onerror is not None:
342-
self.callbacks['onerror'] = onerror
343-
if onprogress is not None:
344-
self.callbacks['onprogress'] = onprogress
345-
attr.onprogress = callpyfunc_fetch_onprogress
346-
if onreadystatechange is not None:
347-
self.callbacks['onreadystatechange'] = onreadystatechange
348-
attr.onreadystatechange = callpyfunc_fetch_onreadystatechange
349-
350-
if attributes is not None:
351-
attr.attributes = attributes
352-
if timeoutMSecs is not None:
353-
attr.timeoutMSecs = timeoutMSecs
354-
if withCredentials is not None:
355-
attr.withCredentials = withCredentials
356-
if destinationPath is not None:
357-
py_str_refs.append(destinationPath.encode('UTF-8'))
358-
attr.destinationPath = py_str_refs[-1]
359-
if userName is not None:
360-
py_str_refs.append(userName.encode('UTF-8'))
361-
attr.userName = py_str_refs[-1]
362-
if password is not None:
363-
py_str_refs.append(password.encode('UTF-8'))
364-
attr.password = py_str_refs[-1]
365-
366-
cdef char** headers
367-
if requestHeaders is not None:
368-
size = (2 * len(requestHeaders) + 1) * sizeof(char*)
369-
headers = <char**>PyMem_Malloc(size)
370-
i = 0
371-
for name,value in requestHeaders.items():
372-
py_str_refs.append(name.encode('UTF-8'))
373-
headers[i] = py_str_refs[-1]
374-
i += 1
375-
py_str_refs.append(value.encode('UTF-8'))
376-
headers[i] = py_str_refs[-1]
377-
i += 1
378-
headers[i] = NULL
379-
attr.requestHeaders = <const char* const *>headers
380-
381-
if overriddenMimeType is not None:
382-
py_str_refs.append(overriddenMimeType.encode('UTF-8'))
383-
attr.overriddenMimeType = py_str_refs[-1]
384-
385-
if requestData is not None:
386-
size = len(requestData)
387-
attr.requestDataSize = size
388-
# direct pointer, no UTF-8 encoding pass:
389-
attr.requestData = requestData
390-
391-
# Fetch
392-
cdef emscripten_fetch_t *fetch = emscripten_fetch(&attr, url.encode('UTF-8'))
393-
self.fetch = fetch
394-
395-
# Explicitely deref temporary Python strings. Test for forgotten refs with e.g.:
396-
# print(attr.overriddenMimeType, attr.destinationPath, attr.userName, attr.password)
397-
del py_str_refs
398-
399-
if requestHeaders is not None:
400-
PyMem_Free(<void*>attr.requestHeaders)
401-
402-
def __dealloc__(self):
403-
emscripten_fetch_close(self.fetch)
404-
405-
# Currently unsafe:
406-
# https://github.com/emscripten-core/emscripten/issues/8234
407-
#def fetch_close(fetch):
408-
# pass
409-
410-
# http://docs.cython.org/en/latest/src/userguide/buffer.html
411-
# https://docs.python.org/3/c-api/typeobj.html#c.PyBufferProcs.bf_getbuffer
412-
# https://docs.python.org/3/c-api/buffer.html#c.PyObject_GetBuffer
413-
# https://docs.python.org/3/c-api/buffer.html#c.PyBuffer_FillInfo
414-
def __getbuffer__(self, Py_buffer *view, int flags):
415-
if self.fetch.data != NULL:
416-
is_readonly = 1
417-
PyBuffer_FillInfo(view, self, <void*>self.fetch.data, self.fetch.numBytes, is_readonly, flags)
418-
else:
419-
view.obj = None
420-
raise BufferError
421-
def __releasebuffer__(self, Py_buffer *view):
422-
pass
423-
424-
def __repr__(self):
425-
return u'<Fetch: id={}, userData={}, url={}, data={}, dataOffset={}, totalBytes={}, readyState={}, status={}, statusText={}>'.format(repr(self.id), repr(self.userData), repr(self.url), repr(self.data), repr(self.dataOffset), repr(self.totalBytes), repr(self.readyState), repr(self.status), repr(self.statusText))
426-
427-
# For testing whether a copy occurred:
428-
#def overwrite(self):
429-
# cdef char* overwrite = <char*>(self.fetch.data)
430-
# overwrite[0] = b'O'
431-
432-
def get_response_headers(self):
433-
cdef char* buf = NULL
434-
# Note: JS crash if applied on a persisted request from IDB cache
435-
# https://github.com/emscripten-core/emscripten/issues/7026#issuecomment-545488132
436-
cdef length = emscripten_fetch_get_response_headers_length(self.fetch)
437-
if length > 0:
438-
headersString = <char*>PyMem_Malloc(length)
439-
emscripten_fetch_get_response_headers(self.fetch, headersString, length+1)
440-
ret = headersString[:length] # copy
441-
PyMem_Free(headersString)
442-
return ret
443-
else:
444-
return None
445-
446-
def get_unpacked_response_headers(self):
447-
cdef char* headersString = NULL
448-
cdef char** unpackedHeaders = NULL
449-
# Note: JS crash if applied on a persisted request from IDB cache
450-
cdef length = emscripten_fetch_get_response_headers_length(self.fetch)
451-
if length > 0:
452-
headersString = <char*>PyMem_Malloc(length)
453-
emscripten_fetch_get_response_headers(self.fetch, headersString, length+1)
454-
unpackedHeaders = emscripten_fetch_unpack_response_headers(headersString)
455-
PyMem_Free(headersString)
456-
d = {}
457-
i = 0
458-
while unpackedHeaders[i] != NULL:
459-
k = unpackedHeaders[i] # c_string_encoding
460-
i += 1
461-
v = unpackedHeaders[i] # c_string_encoding
462-
i += 1
463-
d[k] = v
464-
emscripten_fetch_free_unpacked_response_headers(unpackedHeaders)
465-
return d
466-
else:
467-
return None
468-
469-
@property
470-
def id(self):
471-
return self.fetch.id
472-
cdef readonly userData
473-
@property
474-
def url(self):
475-
#return self.fetch.url.decode('UTF-8')
476-
return self.fetch.url # c_string_encoding
477-
@property
478-
def data(self):
479-
if self.fetch.data != NULL:
480-
return self
481-
else:
482-
return None
483-
@property
484-
def numBytes(self):
485-
return self.fetch.numBytes
486-
@property
487-
def dataOffset(self):
488-
return self.fetch.dataOffset
489-
@property
490-
def totalBytes(self):
491-
return self.fetch.totalBytes # Content-Length
492-
@property
493-
def readyState(self):
494-
return self.fetch.readyState
495-
@property
496-
def status(self):
497-
return self.fetch.status
498-
@property
499-
def statusText(self):
500-
#return self.fetch.statusText.decode('UTF-8')
501-
return self.fetch.statusText # c_string_encoding
502-
503-
cdef void callpyfunc_fetch_callback(emscripten_fetch_t *fetch, char* callback_name):
504-
cdef Fetch py_fetch = <Fetch>fetch.userData
505-
# for theoretical concurrency, if we're called during emscripten_fetch()
506-
py_fetch.fetch = fetch
507-
# call Python function
508-
if py_fetch.callbacks.get(callback_name, None):
509-
py_fetch.callbacks[callback_name](py_fetch)
510-
511-
# one of {onsuccess,onerror} is guaranteed to run, deref Fetch there
512-
cdef void callpyfunc_fetch_onsuccess(emscripten_fetch_t *fetch):
513-
callpyfunc_fetch_callback(fetch, 'onsuccess')
514-
Py_XDECREF(<PyObject*>fetch.userData)
515-
cdef void callpyfunc_fetch_onerror(emscripten_fetch_t *fetch):
516-
callpyfunc_fetch_callback(fetch, 'onerror')
517-
Py_XDECREF(<PyObject*>fetch.userData)
518-
cdef void callpyfunc_fetch_onprogress(emscripten_fetch_t *fetch):
519-
callpyfunc_fetch_callback(fetch, 'onprogress')
520-
cdef void callpyfunc_fetch_onreadystatechange(emscripten_fetch_t *fetch):
521-
callpyfunc_fetch_callback(fetch, 'onreadystatechange')
522-
523-
524-
# import emscripten,sys; f=lambda x:sys.stdout.write(repr(x)+"\n");
525-
# #Module.cwrap('PyRun_SimpleString', 'number', ['string'])("def g(x):\n global a; a=x")
526-
# emscripten.Fetch('/', onsuccess=f)
527-
# emscripten.Fetch(u'/helloé', onsuccess=f)
528-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY, onsuccess=f); del f # output
529-
# fetch_attr={'onsuccess':f}; emscripten.Fetch('/hello', **fetch_attr); del fetch_attr['onsuccess'] # output
530-
# emscripten.Fetch('/non-existent', onerror=lambda x:sys.stdout.write(repr(x)+"\n"))
531-
# emscripten.Fetch('https://bank.confidential/', onerror=lambda x:sys.stdout.write(repr(x)+"\n")) # simulated 404
532-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY|emscripten.FETCH_PERSIST_FILE, onsuccess=f)
533-
# Note: fe.fetch.id changes (in-place) when first caching
534-
# emscripten.Fetch('/hello', requestMethod='EM_IDB_DELETE', onsuccess=f)
535-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY, requestMethod='POST', requestData='AA\xffBB\x00CC', onsuccess=f, onerror=f)
536-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY, requestMethod='12345678901234567890123456789012', onerror=f)
537-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY, onsuccess=f, userData='userData', overriddenMimeType='text/html', userName='userName', password='password', requestHeaders={'Content-Type':'text/plain','Cache-Control':'no-store'})
538-
# emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY|emscripten.FETCH_PERSIST_FILE, onsuccess=f, destinationPath='destinationPath'); emscripten.Fetch('destinationPath', requestMethod='EM_IDB_DELETE', onsuccess=f)
539-
# fe=emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY|emscripten.FETCH_PERSIST_FILE, onsuccess=f, destinationPath='destinationPath'); fe2=emscripten.Fetch('destinationPath', requestMethod='EM_IDB_DELETE', onsuccess=f); print("fe=",fe); print("fe2=",fe2)
540-
# Note: fe2 can occur before fe1
541-
# r=emscripten.Fetch('/hello', attributes=emscripten.FETCH_LOAD_TO_MEMORY)
542-
# open('test.txt','wb').write(r); open('test.txt','rb').read()
543-
# r.data != None
544-
# memoryview(r)[:5].tobytes()
545-
# import cStringIO; cStringIO.StringIO(r).read(5)
546-
547237
# requires -s RETAIN_COMPILER_SETTINGS=1 (otherwise Exception)
548238
def get_compiler_setting(name):
549239
cdef void* amb = <void*>emscripten_get_compiler_setting(name.encode('UTF-8'))

0 commit comments

Comments
 (0)