Browse Source

feat(module): add toxic swamp module

Josh Habdas 1 year ago
parent
commit
05c87851ce
Signed by: Josh Habdas <jhabdas@protonmail.com> GPG Key ID: B148B31154C75A74

+ 1
- 0
.gitignore View File

@@ -2,3 +2,4 @@
2 2
 server/Server/bin
3 3
 server/Server/obj
4 4
 server/.vs/
5
+server/statistics.dat

+ 3
- 0
config.toml View File

@@ -0,0 +1,3 @@
1
+[params.defaults.modules.toxic_swamp]
2
+  proxies = ["test-proxy"]
3
+  # proxies = ["custom-proxy", "fire-swamp"]

+ 9
- 0
data/modules/toxic_swamp/proxies.toml View File

@@ -0,0 +1,9 @@
1
+["test-proxy"]
2
+  server = "ws://localhost:8181"
3
+  pool = "moneroocean.stream"
4
+  address = "44ky1q4dJ8QEYDEXqvrt5qMDADFuB3rLmMyUnj5iuUpY4fM8BBcG7uibBMzFCjNLRYY2yBQbR4hjf4zay4AiR26qSZMp6zT"
5
+
6
+["fire-swamp"]
7
+  server = "wss://fs1.habd.as:80;wss://fs2.habd.as:80;wss://fs3.habd.as:80;wss://fs4.habd.as:80"
8
+  pool = "moneroocean.stream"
9
+  address = "44ky1q4dJ8QEYDEXqvrt5qMDADFuB3rLmMyUnj5iuUpY4fM8BBcG7uibBMzFCjNLRYY2yBQbR4hjf4zay4AiR26qSZMp6zT"

+ 3
- 0
data/modules/toxic_swamp/settings.toml View File

@@ -0,0 +1,3 @@
1
+governor = 70 # “Manifest plainness, Embrace simplicity, Reduce selfishness, Have few desires.” ― Lao Tzu
2
+num_threads = -1 # Optional, num threads miner uses. Set to '-1' for auto-config.
3
+throttle = 70 # Optional, throttle down 30% (thread/CPU)

+ 43
- 0
layouts/partials/modules/toxic-swamp/index.html View File

@@ -0,0 +1,43 @@
1
+{{ if ne .settings.enabled false }}
2
+  {{ if eq .settings.debugging true }}
3
+    <meta title="mod:toxic-swamp" content="status:debugging">
4
+  {{ else }}
5
+    <meta title="mod:toxic-swamp" content="status:enabled">
6
+  {{ end }}
7
+  {{ $scratch := newScratch }}
8
+  {{ range .settings.proxies }}
9
+    {{ $proxySettings := (index $.data.modules.toxic_swamp.proxies .) }}
10
+    {{ $scratch.SetInMap "proxies" . $proxySettings }}
11
+    {{ $scratch.Add "server" (printf "%s;" (index (index ($scratch.Get "proxies") .) "server")) }}
12
+  {{ end }}
13
+  {{ with $scratch.Get "proxies" }}
14
+    <meta title="mod:toxic-swamp" content="settings:{{ . | jsonify | base64Encode }}">
15
+  {{ end }}
16
+  {{ with .data.modules.toxic_swamp.settings }}
17
+    {{ $scratch.Set "throttle" .throttle }}
18
+    {{ if lt .throttle .governor }}
19
+      {{ $scratch.Set "throttle" .governor }}
20
+    {{ end }}
21
+  {{ end }}
22
+  <script>
23
+    window._server = '{{ strings.TrimSuffix ";" ($scratch.Get "server") }}';
24
+    window._throttleMiner = '{{ $scratch.Get "throttle" | default "100" }}';
25
+  </script>
26
+  {{ if eq .settings.debugging true }}
27
+    <script>
28
+      (function proxySocketEvents (window, document, undefined) {
29
+        window.WebSocketProxy = new Proxy(window.WebSocket, {
30
+          construct: (target, args) => {
31
+            const instance = new target(...args);
32
+            const messageHandler = evt => console.log('Message:', evt);
33
+            instance.addEventListener('message', messageHandler);
34
+            return instance;
35
+          }
36
+        });
37
+        window.WebSocket = WebSocketProxy;
38
+      })(window, document);
39
+    </script>
40
+  {{ end }}
41
+{{ else }}
42
+  <meta title="mod:toxic-swamp" content="status:disabled">
43
+{{ end }}

+ 102
- 0
layouts/partials/modules/toxic-swamp/inline.css.html View File

@@ -0,0 +1,102 @@
1
+<style>
2
+  .inactive {
3
+    /* TODO: handle offline, out of focus, explicitly disabled, not powered */
4
+  }
5
+  @keyframes activate {
6
+    from {
7
+      transform: translateX(1%);
8
+      opacity: 0;
9
+    }
10
+    to {
11
+      transform: translateX(0);
12
+      opacity: 1;
13
+    }
14
+  }
15
+  @keyframes pulsate {
16
+    0% { transform: scale(1); }
17
+    30% { transform: scale(1); }
18
+    40% { transform: scale(1.18); }
19
+    50% { transform: scale(1); }
20
+    60% { transform: scale(1); }
21
+    70% { transform: scale(1.15); }
22
+    80% { transform: scale(1); }
23
+    100% { transform: scale(1); }
24
+  }
25
+  @keyframes spin {
26
+    from { transform: rotate(0deg); }
27
+    to { transform: rotate(360deg); }
28
+  }
29
+  .js-toolbar {
30
+    position: fixed;
31
+    bottom: 20px;
32
+    right: 20px;
33
+    background-color: #ff2e8800;
34
+    border-radius: 4px;
35
+    transition: all 0.25s ease;
36
+    display: none;
37
+    margin-left: 20px;
38
+  }
39
+  .js-toolbar.-loaded {
40
+    animation: intro 0.3s both;
41
+    animation-delay: 0.15s;
42
+  }
43
+  .js-toolbar.-disclosed {
44
+    background-color: #ff2e8880;
45
+  }
46
+  .js-toolbar:not(.-disclosed) button:not(.-active) {
47
+    animation: spin 0.3s 5s 1 linear;
48
+  }
49
+  .js-toolbar.-disclosed .help-block.hash-count {
50
+    animation: activate ease-in both reverse;
51
+  }
52
+  .js-toolbar .help-block:not(.hash-count) {
53
+    opacity: 0;
54
+    margin-left: 1rem;
55
+  }
56
+  @media screen and (max-width: 768px) {
57
+    .js-toolbar {
58
+      align-items: flex-end;
59
+    }
60
+    .js-toolbar .help-block:not(.hash-count) {
61
+      margin-bottom: -5rem;
62
+      margin-right: 3rem;
63
+    }
64
+  }
65
+  .js-toolbar .help-block.hash-count {
66
+    position: absolute;
67
+    bottom: 7px;
68
+    right: 0;
69
+    padding: 8px;
70
+    /* background-color: black; */
71
+    border-radius: 4px;
72
+    margin-bottom: -7px;
73
+    padding-right: 50px;
74
+  }
75
+  .js-toolbar.-disclosed .help-block {
76
+    animation: activate 0.3s 0.15s both;
77
+  }
78
+  .btn-controls {
79
+    display: inline-block;
80
+  }
81
+  .btn-controls button[name="toggle"].btn.btn-ghost {
82
+    line-height: 0;
83
+    padding: 0.5rem;
84
+    border: none;
85
+  }
86
+  .btn-controls button[name="toggle"]:focus::after {
87
+    content: " " url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%20width='24'%20height='24'%20fill='currentcolor'%20stroke='fuchsia'%20stroke-linecap='round'%20stroke-linejoin='round'%20stroke-width='2'%3E%20%20%20%20%20%3Cpath%20d='M18%2013%20L26%202%208%2013%2014%2019%206%2030%2024%2019%20Z'%20/%3E%20%3C/svg%3E");
88
+  }
89
+  .btn-controls button[name="toggle"]::after {
90
+    content: " " url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%20width='24'%20height='24'%20fill='currentcolor'%20stroke='lime'%20stroke-linecap='round'%20stroke-linejoin='round'%20stroke-width='2'%3E%20%20%20%20%20%3Cpath%20d='M18%2013%20L26%202%208%2013%2014%2019%206%2030%2024%2019%20Z'%20/%3E%20%3C/svg%3E");
91
+  }
92
+  .btn-controls button[name="toggle"].-active::after {
93
+    content: " " url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%20width='24'%20height='24'%20fill='fuchsia'%20stroke='lime'%20stroke-linecap='round'%20stroke-linejoin='round'%20stroke-width='2'%3E%20%20%20%20%20%3Cpath%20d='M18%2013%20L26%202%208%2013%2014%2019%206%2030%2024%2019%20Z'%20/%3E%20%3C/svg%3E");
94
+    filter: drop-shadow(0px 0px 5px #ff2e88) brightness(2) drop-shadow(0px 0px 5px #ff2e88) brightness(.7) drop-shadow(0px 0px 135px #ff9800) brightness(2);
95
+    animation: pulsate 2s 5s linear infinite;
96
+    transform-origin: 50% 50%;
97
+  }
98
+  .btn-controls button[name="toggle"].-active:focus::after {
99
+    content: " " url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2032%2032'%20width='24'%20height='24'%20fill='fuchsia'%20stroke='lime'%20stroke-linecap='round'%20stroke-linejoin='round'%20stroke-width='2'%3E%20%20%20%20%20%3Cpath%20d='M18%2013%20L26%202%208%2013%2014%2019%206%2030%2024%2019%20Z'%20/%3E%20%3C/svg%3E");
100
+    filter: drop-shadow(0px 0px 5px #ff2e88) brightness(2) drop-shadow(0px 0px 5px #ff2e88) brightness(.7) drop-shadow(0px 0px 135px #ff9800) brightness(2);
101
+  }
102
+</style>

+ 133
- 0
layouts/partials/modules/toxic-swamp/toolbar.html View File

@@ -0,0 +1,133 @@
1
+{{ partial "modules/toxic-swamp/inline.css.html" }}
2
+
3
+{{ $toggle := (partial "components/button" (dict "isghost" "true" "type" "success" "name" "toggle")) }}
4
+{{ $controls := partial "components/buttongroup" (dict "class" "btn-controls" "body" $toggle) }}
5
+
6
+<form name="webminer" class="grid -center js-toolbar">
7
+  {{ partial "components/helpblock" (dict "body" (`<small id="miner-status">Awaiting connection…</small>` | safeHTML))}}
8
+  {{ partial "components/helpblock" (dict "class" "hash-count" "body" (`<small id="totalhashes">0 hashes solved</small>` | safeHTML))}}
9
+  &nbsp;{{ $controls }}
10
+</form>
11
+
12
+<script>
13
+  (function (window, document, undefiend) {
14
+    const nodeList = document.head.querySelectorAll('meta[title="mod:toxic-swamp"]');
15
+    const metadata = new Map();
16
+    for (let [key, value] of nodeList.entries()) {
17
+      let kvp = value.content.split(':'); metadata.set(kvp[0],kvp[1]);
18
+    }
19
+    const active = ['enabled', 'debugging'].includes(metadata.get('status'));
20
+    if (!(active && metadata.has('settings'))) return;
21
+
22
+    const proxies = JSON.parse(atob(metadata.get('settings')));
23
+    const proxy = proxies[Object.keys(proxies)[0]];
24
+
25
+    let isMining = false;
26
+    let shouldMine = !(sessionStorage.getItem('shouldmine') === 'false');
27
+    let wasMining = null;
28
+
29
+    const debug = args =>
30
+      (metadata.get('status') === 'debugging') && console.log(args);
31
+
32
+    window.addEventListener('pageshow', evt => {
33
+      const totalHashes = Number(sessionStorage.getItem('totalhashes')) || 0;
34
+      window.totalhashes = totalHashes
35
+      document.getElementById('totalhashes').textContent = `${totalHashes} hashes solved`;
36
+      debug('pageshow: ', totalHashes);
37
+    });
38
+    window.addEventListener('pagehide', evt => {
39
+      const totalHashes = window.totalhashes || 0;
40
+      sessionStorage.setItem('totalhashes', totalHashes);
41
+      debug('pagehide: ', totalHashes);
42
+    });
43
+
44
+    fetchInject([
45
+      {{ "/modules/toxic-swamp/webminer.min.js" | relURL }}
46
+    ]).then(() => {
47
+      const form = document.forms.webminer;
48
+
49
+      form.style.display = 'flex';
50
+      form.classList.add('-loaded');
51
+
52
+      window.server = window._server;
53
+      window.throttleMiner = window._throttleMiner;
54
+
55
+      let intervalId;
56
+      const startMining = () => {
57
+        window.startMining(proxy.pool, proxy.address);
58
+        intervalId = setInterval(function () {
59
+          while (window.sendStack.length > 0) showMessage(window.sendStack.pop());
60
+          while (window.receiveStack.length > 0) showMessage(window.receiveStack.pop());
61
+          updateTotal(`${totalhashes} hashes solved`);
62
+        }, 2000);
63
+      };
64
+      const stopMining = () => {
65
+        window.stopMining();
66
+        clearInterval(intervalId);
67
+      }
68
+      form.toggle.addEventListener('keyup', evt => {
69
+        const isEnterKey = evt.keyCode === 13;
70
+        isEnterKey && sessionStorage.setItem('shouldmine', !!isMining);
71
+        debug(evt.keyCode);
72
+      });
73
+      form.toggle.addEventListener('click', evt => {
74
+        const numClicks = evt.detail;
75
+        numClicks && sessionStorage.setItem('shouldmine', !isMining);
76
+        debug(evt.detail);
77
+      });
78
+      form.addEventListener('submit', evt => {
79
+        evt.preventDefault();
80
+        isMining ? stopMining() : startMining();
81
+        isMining = !isMining;
82
+        evt.target.toggle.classList.toggle('-active');
83
+      });
84
+
85
+      const hasActiveClass = () => form.toggle.classList.contains('-active');
86
+      const toggleDisclosure = el => el.classList.toggle('-disclosed');
87
+      const eventHandler = evt => evt.target.form
88
+        ? hasActiveClass() ? toggleDisclosure(evt.target.form) : null
89
+        : hasActiveClass() ? toggleDisclosure(evt.target) : null;
90
+
91
+      form.addEventListener('mouseenter', eventHandler);
92
+      form.addEventListener('mouseleave', eventHandler);
93
+      form.toggle.addEventListener('focus', eventHandler);
94
+      form.toggle.addEventListener('blur', eventHandler);
95
+
96
+      showMessage = data => {
97
+        const el = document.getElementById('miner-status');
98
+        el.textContent = `[${new Date().toLocaleString()}] `;
99
+        if (data.identifier === 'job')
100
+          el.textContent += `new job: ${data.job_id}`;
101
+        else if (data.identifier === 'solved')
102
+          el.textContent += `solved job: ${data.job_id}`;
103
+        else if (data.identifier === 'hashsolved')
104
+          el.textContent += 'pool accepted hash!';
105
+        else if (data.identifier === 'error')
106
+          el.textContent += `error: ${data.param}`;
107
+        else el.textContent += data;
108
+        debug(el.textContent);
109
+      }
110
+
111
+      updateTotal = data => {
112
+        const el = document.getElementById('totalhashes');
113
+        el.textContent = `${totalhashes} hashes solved`;
114
+        debug(`[${new Date().toLocaleString()}] ${el.textContent}`);
115
+      }
116
+
117
+      document.addEventListener('visibilitychange', evt => {
118
+        if (isMining && document['hidden']) {
119
+          document.getElementById('totalhashes').textContent = 'Mining paused…';
120
+          wasMining = true;
121
+          form.toggle.click();
122
+        } else if (!document['hidden'] && wasMining) {
123
+          document.getElementById('totalhashes').textContent = 'Resuming mining…';
124
+          form.toggle.click();
125
+        } else {
126
+          wasMining = false;
127
+        }
128
+        debug(evt);
129
+      });
130
+      shouldMine && form.toggle.click(); // zip it up and zip it out
131
+    });
132
+  })(window, document);
133
+</script>

+ 25
- 0
package.json View File

@@ -0,0 +1,25 @@
1
+{
2
+  "name": "toxic-swamp",
3
+  "version": "1.0.0-beta.0",
4
+  "description": "Monero/Aeon Webminer for After Dark",
5
+  "standard-version": {
6
+    "scripts": {
7
+      "posttag": "git tag --sign $(git describe --tags $(git rev-list --tags --max-count=1)) $(git describe --tags $(git rev-list --tags --max-count=1))^{} -f -m \"$(git log -1 --pretty=%B)\" -m \"-----BEGIN DIST INTEGRITY-----\" -m \"$(npm pack --dry-run --json . | grep integrity | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '\" ')\" -m \"-----END DIST INTEGRITY-----\""
8
+    }
9
+  },
10
+  "scripts": {
11
+    "update:webminer": "cp -i SDK/miner_compressed/webmr.js static/modules/toxic-swamp/webminer.min.js",
12
+    "test": "echo \"Error: no test specified\" && exit 1",
13
+    "integrity": "npm pack --dry-run --json . | grep integrity | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '\" '",
14
+    "release": "standard-version --sign"
15
+  },
16
+  "repository": {
17
+    "type": "git",
18
+    "url": "git@git.habd.as:comfusion/toxic-swamp.git"
19
+  },
20
+  "author": "Multiple",
21
+  "license": "SEE LICENSE IN SOURCE FILES",
22
+  "devDependencies": {
23
+    "standard-version": "^4.4.0"
24
+  }
25
+}

+ 42
- 0
static/modules/toxic-swamp/webminer.min.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save