js-dos 0.80.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +43 -0
- package/.gitmodules +4 -0
- package/README.md +24 -0
- package/index.html +106 -0
- package/package.json +48 -0
- package/postcss.config.cjs +8 -0
- package/src/app.css +14 -0
- package/src/base.css +10 -0
- package/src/components/checkbox.tsx +41 -0
- package/src/components/close-button.tsx +17 -0
- package/src/components/components.css +28 -0
- package/src/components/dos-option-checkbox.tsx +72 -0
- package/src/components/dos-option-select.tsx +94 -0
- package/src/components/dos-option-slider.tsx +35 -0
- package/src/components/error.tsx +16 -0
- package/src/components/loading.tsx +26 -0
- package/src/components/lock.tsx +10 -0
- package/src/components/select.tsx +33 -0
- package/src/components/slider.tsx +69 -0
- package/src/download-file.ts +18 -0
- package/src/frame/account-frame.tsx +155 -0
- package/src/frame/editor/defaults.ts +344 -0
- package/src/frame/editor/editor-conf-frame.tsx +42 -0
- package/src/frame/editor/editor-frame.css +55 -0
- package/src/frame/editor/editor-fs-frame.tsx +315 -0
- package/src/frame/frame.css +127 -0
- package/src/frame/frame.tsx +34 -0
- package/src/frame/host-cache-frame.tsx +124 -0
- package/src/frame/image-rendering-frame.tsx +8 -0
- package/src/frame/network-frame.tsx +157 -0
- package/src/frame/quick-save-frame.tsx +95 -0
- package/src/frame/settings-frame.tsx +14 -0
- package/src/frame/stats-frame.tsx +82 -0
- package/src/host/bundle-storage.ts +91 -0
- package/src/host/fullscreen.ts +36 -0
- package/src/host/lcache.ts +203 -0
- package/src/host/lstorage.ts +156 -0
- package/src/i18n.ts +167 -0
- package/src/index.css +7 -0
- package/src/load.ts +139 -0
- package/src/login/login.css +9 -0
- package/src/login/login.tsx +77 -0
- package/src/main.tsx +195 -0
- package/src/non-serializable-store.ts +35 -0
- package/src/public/types.ts +39 -0
- package/src/sidebar/account-button.tsx +32 -0
- package/src/sidebar/cloud-save-button.tsx +89 -0
- package/src/sidebar/diskette-icon.tsx +14 -0
- package/src/sidebar/fullscreen-button.tsx +44 -0
- package/src/sidebar/network-button.tsx +39 -0
- package/src/sidebar/sidebar-button.tsx +243 -0
- package/src/sidebar/sidebar.css +47 -0
- package/src/sidebar/sidebar.tsx +30 -0
- package/src/sockdrive/LICENSE +674 -0
- package/src/sockdrive/README.md +22 -0
- package/src/sockdrive/SDL2/LRUCache11.hpp +240 -0
- package/src/sockdrive/SDL2/sockdrive.cpp +207 -0
- package/src/sockdrive/include/sockdrive.h +23 -0
- package/src/sockdrive/js/.eslintrc.json +43 -0
- package/src/sockdrive/js/README.md +70 -0
- package/src/sockdrive/js/package.json +29 -0
- package/src/sockdrive/js/src/fatfs/chains.js +318 -0
- package/src/sockdrive/js/src/fatfs/dir.js +385 -0
- package/src/sockdrive/js/src/fatfs/helpers.js +210 -0
- package/src/sockdrive/js/src/fatfs/index.js +606 -0
- package/src/sockdrive/js/src/fatfs/structs.js +255 -0
- package/src/sockdrive/js/src/fatfs/vol.js +166 -0
- package/src/sockdrive/js/src/sockdrive/cache.ts +133 -0
- package/src/sockdrive/js/src/sockdrive/drive.ts +364 -0
- package/src/sockdrive/js/src/sockdrive/lru.ts +221 -0
- package/src/sockdrive/js/src/sockdrive/types.ts +10 -0
- package/src/sockdrive/js/src/sockdrive-fat.d.ts +64 -0
- package/src/sockdrive/js/src/sockdrive-fat.ts +228 -0
- package/src/sockdrive/js/src/sockdrive-native.ts +98 -0
- package/src/sockdrive/js/src/test/test.ts +186 -0
- package/src/sockdrive/js/tsconfig.json +11 -0
- package/src/sockdrive/js/webpack.config.js +68 -0
- package/src/sockdrive/js/yarn.lock +1808 -0
- package/src/sockdrive/lz4/lz4.c +2773 -0
- package/src/sockdrive/lz4/lz4.h +862 -0
- package/src/store/auth.ts +104 -0
- package/src/store/dos.ts +284 -0
- package/src/store/editor.ts +59 -0
- package/src/store/storage.ts +30 -0
- package/src/store/ui.ts +183 -0
- package/src/store.ts +27 -0
- package/src/ui.tsx +103 -0
- package/src/v8/changes.ts +56 -0
- package/src/v8/config.ts +18 -0
- package/src/v8/subscriptions.ts +62 -0
- package/src/vite-env.d.ts +2 -0
- package/src/window/dos/controls/keyboard.ts +32 -0
- package/src/window/dos/controls/keys.ts +331 -0
- package/src/window/dos/controls/mouse/mount.ts +99 -0
- package/src/window/dos/controls/mouse/mouse-locked.ts +51 -0
- package/src/window/dos/controls/mouse/mouse-not-locked.ts +84 -0
- package/src/window/dos/controls/mouse/mouse-swipe.ts +57 -0
- package/src/window/dos/controls/mouse/pointer.ts +85 -0
- package/src/window/dos/controls/mouse.ts +21 -0
- package/src/window/dos/dos-dhry2.tsx +191 -0
- package/src/window/dos/dos-runtime.tsx +185 -0
- package/src/window/dos/dos-window.tsx +82 -0
- package/src/window/dos/render/canvas.ts +65 -0
- package/src/window/dos/render/resize.ts +31 -0
- package/src/window/dos/render/webgl.ts +173 -0
- package/src/window/dos/sound/audio-node.ts +148 -0
- package/src/window/error-window.tsx +9 -0
- package/src/window/loading-window.tsx +54 -0
- package/src/window/prerun-window.tsx +98 -0
- package/src/window/select-window.tsx +118 -0
- package/src/window/window.css +78 -0
- package/src/window/window.tsx +49 -0
- package/src/ws/ws-sockdrive.ts +102 -0
- package/src/ws/ws-transport-layer.ts +457 -0
- package/tailwind.config.cjs +48 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +9 -0
- package/vite.config.ts +22 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# sockdrive client api sdk
|
|
2
|
+
|
|
3
|
+
# js
|
|
4
|
+
|
|
5
|
+
Plain js api ready to use in browser.
|
|
6
|
+
|
|
7
|
+
Building:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
cd js
|
|
11
|
+
yarn
|
|
12
|
+
yarn run webpack
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Js api is in `js/dist/sockdriveFat.js`. The api is node-like fs api.
|
|
16
|
+
|
|
17
|
+
Testing:
|
|
18
|
+
|
|
19
|
+
1. Serve dist folder
|
|
20
|
+
2. Open test.html in browser to run tests.
|
|
21
|
+
|
|
22
|
+
# emscripten asyncify
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* LRUCache11 - a templated C++11 based LRU cache class that allows
|
|
3
|
+
* specification of
|
|
4
|
+
* key, value and optionally the map container type (defaults to
|
|
5
|
+
* std::unordered_map)
|
|
6
|
+
* By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete
|
|
7
|
+
* and
|
|
8
|
+
* refresh operations.
|
|
9
|
+
*
|
|
10
|
+
* This is a header-only library and all you need is the LRUCache11.hpp file
|
|
11
|
+
*
|
|
12
|
+
* Github: https://github.com/mohaps/lrucache11
|
|
13
|
+
*
|
|
14
|
+
* This is a follow-up to the LRUCache project -
|
|
15
|
+
* https://github.com/mohaps/lrucache
|
|
16
|
+
*
|
|
17
|
+
* Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>
|
|
18
|
+
*
|
|
19
|
+
* Permission to use, copy, modify, and distribute this software for any
|
|
20
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
21
|
+
* copyright notice and this permission notice appear in all copies.
|
|
22
|
+
*
|
|
23
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
24
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
25
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
26
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
27
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
28
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
29
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
30
|
+
*/
|
|
31
|
+
#pragma once
|
|
32
|
+
#include <algorithm>
|
|
33
|
+
#include <cstdint>
|
|
34
|
+
#include <list>
|
|
35
|
+
#include <mutex>
|
|
36
|
+
#include <stdexcept>
|
|
37
|
+
#include <thread>
|
|
38
|
+
#include <unordered_map>
|
|
39
|
+
|
|
40
|
+
namespace lru11 {
|
|
41
|
+
/*
|
|
42
|
+
* a noop lockable concept that can be used in place of std::mutex
|
|
43
|
+
*/
|
|
44
|
+
class NullLock {
|
|
45
|
+
public:
|
|
46
|
+
void lock() {}
|
|
47
|
+
void unlock() {}
|
|
48
|
+
bool try_lock() { return true; }
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* error raised when a key not in cache is passed to get()
|
|
53
|
+
*/
|
|
54
|
+
class KeyNotFound : public std::invalid_argument {
|
|
55
|
+
public:
|
|
56
|
+
KeyNotFound() : std::invalid_argument("key_not_found") {}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
template <typename K, typename V>
|
|
60
|
+
struct KeyValuePair {
|
|
61
|
+
public:
|
|
62
|
+
K key;
|
|
63
|
+
V value;
|
|
64
|
+
|
|
65
|
+
KeyValuePair(K k, V v) : key(std::move(k)), value(std::move(v)) {}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The LRU Cache class templated by
|
|
70
|
+
* Key - key type
|
|
71
|
+
* Value - value type
|
|
72
|
+
* MapType - an associative container like std::unordered_map
|
|
73
|
+
* LockType - a lock type derived from the Lock class (default:
|
|
74
|
+
*NullLock = no synchronization)
|
|
75
|
+
*
|
|
76
|
+
* The default NullLock based template is not thread-safe, however passing
|
|
77
|
+
*Lock=std::mutex will make it
|
|
78
|
+
* thread-safe
|
|
79
|
+
*/
|
|
80
|
+
template <class Key, class Value, class Lock = NullLock,
|
|
81
|
+
class Map = std::unordered_map<
|
|
82
|
+
Key, typename std::list<KeyValuePair<Key, Value>>::iterator>>
|
|
83
|
+
class Cache {
|
|
84
|
+
public:
|
|
85
|
+
typedef KeyValuePair<Key, Value> node_type;
|
|
86
|
+
typedef std::list<KeyValuePair<Key, Value>> list_type;
|
|
87
|
+
typedef Map map_type;
|
|
88
|
+
typedef Lock lock_type;
|
|
89
|
+
using Guard = std::lock_guard<lock_type>;
|
|
90
|
+
/**
|
|
91
|
+
* the maxSize is the soft limit of keys and (maxSize + elasticity) is the
|
|
92
|
+
* hard limit
|
|
93
|
+
* the cache is allowed to grow till (maxSize + elasticity) and is pruned back
|
|
94
|
+
* to maxSize keys
|
|
95
|
+
* set maxSize = 0 for an unbounded cache (but in that case, you're better off
|
|
96
|
+
* using a std::unordered_map
|
|
97
|
+
* directly anyway! :)
|
|
98
|
+
*/
|
|
99
|
+
explicit Cache(size_t maxSize = 64, size_t elasticity = 10)
|
|
100
|
+
: maxSize_(maxSize), elasticity_(elasticity) {}
|
|
101
|
+
virtual ~Cache() = default;
|
|
102
|
+
size_t size() const {
|
|
103
|
+
Guard g(lock_);
|
|
104
|
+
return cache_.size();
|
|
105
|
+
}
|
|
106
|
+
bool empty() const {
|
|
107
|
+
Guard g(lock_);
|
|
108
|
+
return cache_.empty();
|
|
109
|
+
}
|
|
110
|
+
void clear() {
|
|
111
|
+
Guard g(lock_);
|
|
112
|
+
cache_.clear();
|
|
113
|
+
keys_.clear();
|
|
114
|
+
}
|
|
115
|
+
void insert(const Key& k, uint8_t* ptr) {
|
|
116
|
+
Guard g(lock_);
|
|
117
|
+
const auto iter = cache_.find(k);
|
|
118
|
+
if (iter != cache_.end()) {
|
|
119
|
+
iter->second->value.reset(ptr);
|
|
120
|
+
keys_.splice(keys_.begin(), keys_, iter->second);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
keys_.emplace_front(k, std::unique_ptr<uint8_t>(ptr));
|
|
125
|
+
cache_[k] = keys_.begin();
|
|
126
|
+
prune();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
for backward compatibity. redirects to tryGetCopy()
|
|
130
|
+
*/
|
|
131
|
+
bool tryGet(const Key& kIn, Value& vOut) {
|
|
132
|
+
return tryGetCopy(kIn, vOut);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
bool tryGetCopy(const Key& kIn, Value& vOut) {
|
|
136
|
+
Guard g(lock_);
|
|
137
|
+
Value tmp;
|
|
138
|
+
if (!tryGetRef_nolock(kIn, tmp)) { return false; }
|
|
139
|
+
vOut = tmp;
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
bool tryGetRef(const Key& kIn, Value& vOut) {
|
|
144
|
+
Guard g(lock_);
|
|
145
|
+
return tryGetRef_nolock(kIn, vOut);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The const reference returned here is only
|
|
149
|
+
* guaranteed to be valid till the next insert/delete
|
|
150
|
+
* in multi-threaded apps use getCopy() to be threadsafe
|
|
151
|
+
*/
|
|
152
|
+
const Value& getRef(const Key& k) {
|
|
153
|
+
Guard g(lock_);
|
|
154
|
+
return get_nolock(k);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
added for backward compatibility
|
|
159
|
+
*/
|
|
160
|
+
Value get(const Key& k) {
|
|
161
|
+
return getCopy();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* returns a copy of the stored object (if found)
|
|
165
|
+
* safe to use/recommended in multi-threaded apps
|
|
166
|
+
*/
|
|
167
|
+
Value getCopy(const Key& k) {
|
|
168
|
+
Guard g(lock_);
|
|
169
|
+
return get_nolock(k);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
bool remove(const Key& k) {
|
|
173
|
+
Guard g(lock_);
|
|
174
|
+
auto iter = cache_.find(k);
|
|
175
|
+
if (iter == cache_.end()) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
keys_.erase(iter->second);
|
|
179
|
+
cache_.erase(iter);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
bool contains(const Key& k) const {
|
|
183
|
+
Guard g(lock_);
|
|
184
|
+
return cache_.find(k) != cache_.end();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
size_t getMaxSize() const { return maxSize_; }
|
|
188
|
+
size_t getElasticity() const { return elasticity_; }
|
|
189
|
+
size_t getMaxAllowedSize() const { return maxSize_ + elasticity_; }
|
|
190
|
+
template <typename F>
|
|
191
|
+
void cwalk(F& f) const {
|
|
192
|
+
Guard g(lock_);
|
|
193
|
+
std::for_each(keys_.begin(), keys_.end(), f);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
protected:
|
|
197
|
+
const Value& get_nolock(const Key& k) {
|
|
198
|
+
const auto iter = cache_.find(k);
|
|
199
|
+
if (iter == cache_.end()) {
|
|
200
|
+
abort();
|
|
201
|
+
}
|
|
202
|
+
keys_.splice(keys_.begin(), keys_, iter->second);
|
|
203
|
+
return iter->second->value;
|
|
204
|
+
}
|
|
205
|
+
bool tryGetRef_nolock(const Key& kIn, Value& vOut) {
|
|
206
|
+
const auto iter = cache_.find(kIn);
|
|
207
|
+
if (iter == cache_.end()) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
keys_.splice(keys_.begin(), keys_, iter->second);
|
|
211
|
+
vOut = iter->second->value;
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
size_t prune() {
|
|
215
|
+
size_t maxAllowed = maxSize_ + elasticity_;
|
|
216
|
+
if (maxSize_ == 0 || cache_.size() < maxAllowed) {
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
size_t count = 0;
|
|
220
|
+
while (cache_.size() > maxSize_) {
|
|
221
|
+
cache_.erase(keys_.back().key);
|
|
222
|
+
keys_.pop_back();
|
|
223
|
+
++count;
|
|
224
|
+
}
|
|
225
|
+
return count;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private:
|
|
229
|
+
// Disallow copying.
|
|
230
|
+
Cache(const Cache&) = delete;
|
|
231
|
+
Cache& operator=(const Cache&) = delete;
|
|
232
|
+
|
|
233
|
+
mutable Lock lock_;
|
|
234
|
+
Map cache_;
|
|
235
|
+
list_type keys_;
|
|
236
|
+
size_t maxSize_;
|
|
237
|
+
size_t elasticity_;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
} // namespace LRUCache11
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#include <cstdint>
|
|
2
|
+
#include <cassert>
|
|
3
|
+
#include <unordered_map>
|
|
4
|
+
#include "LRUCache11.hpp"
|
|
5
|
+
|
|
6
|
+
#include "../include/sockdrive.h"
|
|
7
|
+
#include "../lz4/lz4.h"
|
|
8
|
+
#include "SDL_net.h"
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
int SDLNet_TCP_Recv_All(TCPsocket sock, void *data, int maxlen) {
|
|
12
|
+
auto *start = (uint8_t *) data;
|
|
13
|
+
auto restlen = maxlen;
|
|
14
|
+
while (restlen > 0) {
|
|
15
|
+
auto read = SDLNet_TCP_Recv(sock, start, maxlen);
|
|
16
|
+
start += read;
|
|
17
|
+
restlen -= read;
|
|
18
|
+
// TODO: add sleep
|
|
19
|
+
}
|
|
20
|
+
return maxlen;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
int decode_lz4_block(uint32_t compressedSize, uint32_t decodedSize, char *buffer) {
|
|
24
|
+
if (compressedSize == decodedSize) {
|
|
25
|
+
return decodedSize;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 128 * 1024 is for 255 aheadRange (maximum possible)
|
|
29
|
+
constexpr int compressedBuffer = 128 * 1024;
|
|
30
|
+
static char compressed[compressedBuffer];
|
|
31
|
+
|
|
32
|
+
if (compressedBuffer < compressedSize) {
|
|
33
|
+
return -1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
memcpy(compressed, buffer, compressedSize);
|
|
37
|
+
auto result = LZ4_decompress_safe(compressed, buffer, compressedSize, decodedSize);
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class BlockCache {
|
|
42
|
+
const uint32_t sectorSize;
|
|
43
|
+
const uint8_t aheadRange;
|
|
44
|
+
lru11::Cache<uint32_t, std::unique_ptr<uint8_t>> lru;
|
|
45
|
+
|
|
46
|
+
public:
|
|
47
|
+
BlockCache(uint32_t sectorSize, uint8_t aheadRange, uint32_t memoryLimit) :
|
|
48
|
+
sectorSize(sectorSize), aheadRange(aheadRange), lru(memoryLimit / (aheadRange * sectorSize), 0) {
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
uint8_t *read(uint32_t sector) {
|
|
52
|
+
const auto origin = getOrigin(sector);
|
|
53
|
+
if (lru.contains(origin)) {
|
|
54
|
+
return lru.getRef(origin).get() + (sector - origin) * sectorSize;
|
|
55
|
+
}
|
|
56
|
+
return nullptr;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
bool write(uint32_t sector, uint8_t *buffer) {
|
|
60
|
+
const auto origin = getOrigin(sector);
|
|
61
|
+
if (lru.contains(origin)) {
|
|
62
|
+
memcpy(lru.getRef(origin).get() + (sector - origin) * sectorSize, buffer, sectorSize);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void create(uint32_t origin, uint8_t *buffer) {
|
|
69
|
+
if (lru.contains(origin)) {
|
|
70
|
+
memcpy(lru.getRef(origin).get(), buffer, sectorSize * aheadRange);
|
|
71
|
+
} else {
|
|
72
|
+
auto copy = new uint8_t[sectorSize * aheadRange];
|
|
73
|
+
memcpy(copy, buffer, sectorSize * aheadRange);
|
|
74
|
+
lru.insert(origin, copy);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
uint32_t getOrigin(uint32_t sector) const {
|
|
79
|
+
return sector - sector % aheadRange;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
class Drive {
|
|
85
|
+
const uint32_t sectorSize = 512;
|
|
86
|
+
|
|
87
|
+
TCPsocket socket;
|
|
88
|
+
const uint8_t aheadRange;
|
|
89
|
+
uint8_t *readAheadBuffer;
|
|
90
|
+
uint32_t aheadSize;
|
|
91
|
+
|
|
92
|
+
BlockCache cache;
|
|
93
|
+
|
|
94
|
+
public:
|
|
95
|
+
Drive(TCPsocket socket, uint8_t aheadRange = 255, uint32_t memoryLimit = 32 * 1024 * 1024) :
|
|
96
|
+
socket(socket), aheadRange(aheadRange), cache(sectorSize, aheadRange, memoryLimit) {
|
|
97
|
+
|
|
98
|
+
aheadSize = sectorSize * aheadRange;
|
|
99
|
+
readAheadBuffer = new uint8_t[aheadSize];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
~Drive() {
|
|
103
|
+
SDLNet_TCP_Close(socket);
|
|
104
|
+
delete[] readAheadBuffer;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
uint8_t read(uint32_t sector, uint8_t *buffer) {
|
|
108
|
+
auto cached = cache.read(sector);
|
|
109
|
+
if (cached) {
|
|
110
|
+
memcpy(buffer, cached, sectorSize);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static const uint8_t readCommand = 1;
|
|
115
|
+
if (SDLNet_TCP_Send(socket, &readCommand, sizeof(uint8_t)) != sizeof(uint8_t)) {
|
|
116
|
+
return 2;
|
|
117
|
+
}
|
|
118
|
+
auto origin = cache.getOrigin(sector);
|
|
119
|
+
if (SDLNet_TCP_Send(socket, &origin, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
|
120
|
+
return 3;
|
|
121
|
+
}
|
|
122
|
+
if (SDLNet_TCP_Send(socket, &aheadRange, sizeof(uint8_t)) != sizeof(uint8_t)) {
|
|
123
|
+
return 4;
|
|
124
|
+
}
|
|
125
|
+
if (SDLNet_TCP_Recv_All(socket, readAheadBuffer, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
|
126
|
+
return 5;
|
|
127
|
+
}
|
|
128
|
+
uint32_t compressedSize = readAheadBuffer[0] + (readAheadBuffer[1] << 8) + (readAheadBuffer[2] << 16) + (readAheadBuffer[3] << 24);
|
|
129
|
+
if (SDLNet_TCP_Recv_All(socket, readAheadBuffer, compressedSize) != compressedSize) {
|
|
130
|
+
return 6;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
int decodeResult = decode_lz4_block(compressedSize, aheadSize, (char *) readAheadBuffer);
|
|
134
|
+
if (decodeResult != aheadSize) {
|
|
135
|
+
return decodeResult;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
cache.create(origin, readAheadBuffer);
|
|
139
|
+
memcpy(buffer, readAheadBuffer + (sector - origin) * sectorSize, sectorSize);
|
|
140
|
+
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
uint8_t write(uint32_t sector, uint8_t *buffer) {
|
|
145
|
+
cache.write(sector, buffer);
|
|
146
|
+
static const uint8_t writeCommand = 2;
|
|
147
|
+
if (SDLNet_TCP_Send(socket, &writeCommand, sizeof(uint8_t)) != sizeof(uint8_t)) {
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
if (SDLNet_TCP_Send(socket, §or, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
|
151
|
+
return 3;
|
|
152
|
+
}
|
|
153
|
+
if (SDLNet_TCP_Send(socket, buffer, sectorSize) != sectorSize) {
|
|
154
|
+
return 4;
|
|
155
|
+
}
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
size_t sockdrive_open(const char* url, const char* owner, const char* name, const char* token) {
|
|
163
|
+
IPaddress address;
|
|
164
|
+
if (SDLNet_ResolveHost(&address, url, 8001) == 0) {
|
|
165
|
+
return reinterpret_cast<size_t>(new Drive(SDLNet_TCP_Open(&address)));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
uint8_t sockdrive_read(size_t handle, uint32_t sector, uint8_t *buffer) {
|
|
172
|
+
if (!handle) {
|
|
173
|
+
return 1;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return reinterpret_cast<Drive*>(handle)->read(sector, buffer);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
uint8_t sockdrive_write(size_t handle, uint32_t sector, uint8_t *buffer) {
|
|
180
|
+
if (!handle) {
|
|
181
|
+
return 1;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return reinterpret_cast<Drive*>(handle)->write(sector, buffer);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
void sockdrive_close(size_t handle) {
|
|
188
|
+
if (handle) {
|
|
189
|
+
delete reinterpret_cast<Drive*>(handle);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
uint32_t sockdrive_size(size_t handle) {
|
|
194
|
+
return 2097152;
|
|
195
|
+
}
|
|
196
|
+
uint32_t sockdrive_heads(size_t handle) {
|
|
197
|
+
return 128;
|
|
198
|
+
}
|
|
199
|
+
uint32_t sockdrive_sectors(size_t handle) {
|
|
200
|
+
return 63;
|
|
201
|
+
}
|
|
202
|
+
uint32_t sockdrive_cylinders(size_t handle) {
|
|
203
|
+
return 520;
|
|
204
|
+
}
|
|
205
|
+
uint32_t sockdrive_sector_size(size_t handle) {
|
|
206
|
+
return 512;
|
|
207
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by caiii on 30.08.2023.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#ifndef JS_DOS_SOCKDRIVE_H
|
|
6
|
+
#define JS_DOS_SOCKDRIVE_H
|
|
7
|
+
|
|
8
|
+
#include <stddef.h>
|
|
9
|
+
#include <stdint.h>
|
|
10
|
+
|
|
11
|
+
extern "C" {
|
|
12
|
+
size_t sockdrive_open(const char* url, const char* owner, const char* name, const char* token);
|
|
13
|
+
uint8_t sockdrive_read(size_t handle, uint32_t sector, uint8_t * buffer);
|
|
14
|
+
uint8_t sockdrive_write(size_t handle, uint32_t sector, uint8_t* buffer);
|
|
15
|
+
uint32_t sockdrive_size(size_t handle);
|
|
16
|
+
uint32_t sockdrive_heads(size_t handle);
|
|
17
|
+
uint32_t sockdrive_sectors(size_t handle);
|
|
18
|
+
uint32_t sockdrive_cylinders(size_t handle);
|
|
19
|
+
uint32_t sockdrive_sector_size(size_t handle);
|
|
20
|
+
void sockdrive_close(size_t handle);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#endif //JS_DOS_SOCKDRIVE_H
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"extends": [
|
|
7
|
+
"google"
|
|
8
|
+
],
|
|
9
|
+
"parser": "@typescript-eslint/parser",
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 12,
|
|
12
|
+
"sourceType": "module"
|
|
13
|
+
},
|
|
14
|
+
"plugins": [
|
|
15
|
+
"@typescript-eslint"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"object-curly-spacing": [
|
|
19
|
+
"error",
|
|
20
|
+
"always"
|
|
21
|
+
],
|
|
22
|
+
"require-jsdoc": "off",
|
|
23
|
+
"quotes": [
|
|
24
|
+
"error",
|
|
25
|
+
"double"
|
|
26
|
+
],
|
|
27
|
+
"indent": [
|
|
28
|
+
"error",
|
|
29
|
+
4,
|
|
30
|
+
{
|
|
31
|
+
"SwitchCase": 1,
|
|
32
|
+
"FunctionDeclaration": {
|
|
33
|
+
"parameters": "first"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"max-len": [
|
|
38
|
+
"error",
|
|
39
|
+
120
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"ignorePatterns": ["dist/**/*"]
|
|
43
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ffi library for browser
|
|
2
|
+
|
|
3
|
+
## Building
|
|
4
|
+
|
|
5
|
+
Compile it with yarn & webpack:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
yarn
|
|
9
|
+
yarn run webpack
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
You can test by opening dist/test.html, but run dist/test/make-img-linux.sh first.
|
|
13
|
+
|
|
14
|
+
Types information can be found in src/sockdrive-fat.d.ts
|
|
15
|
+
|
|
16
|
+
# 3rdparty code
|
|
17
|
+
|
|
18
|
+
## LZ4
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
/*
|
|
22
|
+
MiniLZ4: Minimal LZ4 block decoding and encoding.
|
|
23
|
+
|
|
24
|
+
based off of node-lz4, https://github.com/pierrec/node-lz4
|
|
25
|
+
|
|
26
|
+
====
|
|
27
|
+
Copyright (c) 2012 Pierre Curto
|
|
28
|
+
|
|
29
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
30
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
31
|
+
in the Software without restriction, including without limitation the rights
|
|
32
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
33
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
34
|
+
furnished to do so, subject to the following conditions:
|
|
35
|
+
|
|
36
|
+
The above copyright notice and this permission notice shall be included in
|
|
37
|
+
all copies or substantial portions of the Software.
|
|
38
|
+
|
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
40
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
41
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
42
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
43
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
44
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
45
|
+
THE SOFTWARE.
|
|
46
|
+
====
|
|
47
|
+
|
|
48
|
+
changes have the same license
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## LRU cache
|
|
52
|
+
|
|
53
|
+
`src/sockdrive/lru.js` is from https://github.com/rsms/js-lru
|
|
54
|
+
Licensed under MIT. Copyright (c) 2010 Rasmus Andersson <http://hunch.se/>
|
|
55
|
+
|
|
56
|
+
## fatfs (fork)
|
|
57
|
+
|
|
58
|
+
`src/fatfs` is a fork of https://github.com/natevw/fatfs
|
|
59
|
+
|
|
60
|
+
License information:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
© 2014 Nathan Vander Wilt.
|
|
64
|
+
Funding for this work was provided by Technical Machine, Inc.
|
|
65
|
+
|
|
66
|
+
Reuse under your choice of:
|
|
67
|
+
|
|
68
|
+
* BSD-2-Clause
|
|
69
|
+
* Apache 2.0
|
|
70
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sockdrive-asyncify",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The sockdrive support for emscripten",
|
|
5
|
+
"license": "GPLv3",
|
|
6
|
+
"private": true,
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"buffer": "^6.0.3",
|
|
9
|
+
"fifolock": "^1.0.0",
|
|
10
|
+
"stream-browserify": "^3.0.0",
|
|
11
|
+
"struct-fu": "^1.2.1",
|
|
12
|
+
"typedarray-to-buffer": "^4.0.0",
|
|
13
|
+
"xok": "^1.0.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/chai": "^4.3.6",
|
|
17
|
+
"@types/mocha": "^10.0.1",
|
|
18
|
+
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
|
19
|
+
"@typescript-eslint/parser": "^6.7.2",
|
|
20
|
+
"eslint": "^8.48.0",
|
|
21
|
+
"eslint-config-google": "^0.14.0",
|
|
22
|
+
"eslint-webpack-plugin": "^4.0.1",
|
|
23
|
+
"process": "^0.11.10",
|
|
24
|
+
"ts-loader": "^9.4.4",
|
|
25
|
+
"typescript": "^5.2.2",
|
|
26
|
+
"webpack": "^5.88.2",
|
|
27
|
+
"webpack-cli": "^5.1.4"
|
|
28
|
+
}
|
|
29
|
+
}
|