diff --git a/backend/nats/Containerfile b/backend/nats/Containerfile new file mode 100644 index 0000000..2695033 --- /dev/null +++ b/backend/nats/Containerfile @@ -0,0 +1,3 @@ +FROM nats:2.7.4-scratch +COPY ./nats-server.conf /nats-server.conf +EXPOSE 4223 \ No newline at end of file diff --git a/backend/nats/nats-server.conf b/backend/nats/nats-server.conf new file mode 100644 index 0000000..90c7182 --- /dev/null +++ b/backend/nats/nats-server.conf @@ -0,0 +1,137 @@ +# Client port of 4222 on all interfaces +port: 4222 + +# HTTP monitoring port +monitor_port: 8222 + +# This is for clustering multiple servers together. +cluster { + # It is recommended to set a cluster name + name: "sakal_cluster" + + # Route connections to be received on any interface on port 6222 + port: 6222 + + # Routes are protected, so need to use them with --routes flag + # e.g. --routes=nats-route://ruser:T0pS3cr3t@otherdockerhost:6222 + authorization { + user: ruser + password: T0pS3cr3t + timeout: 2 + } + + # Routes are actively solicited and connected to from this server. + # This Docker image has none by default, but you can pass a + # flag to the nats-server docker image to create one to an existing server. + routes = [] +} + + +websocket { + # Specify a host and port to listen for websocket connections + # + # listen: "host:port" + + # It can also be configured with individual parameters, + # namely host and port. + # + # host: "hostname" + port: 4223 + + # This will optionally specify what host:port for websocket + # connections to be advertised in the cluster. + # + # advertise: "host:port" + + # TLS configuration is required by default + # + #tls { + # cert_file: "/path/to/cert.pem" + # key_file: "/path/to/key.pem" + #} + + # For test environments, you can disable the need for TLS + # by explicitly setting this option to `true` + # + no_tls: true + + # [Cross-origin resource sharing option](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). + # + # IMPORTANT! This option is used only when the http request presents an Origin + # header, which is the case for web browsers. If no Origin header is present, + # this check will not be performed. + # + # When set to `true`, the HTTP origin header must match the request’s hostname. + # The default is `false`. + # + # same_origin: true + + # [Cross-origin resource sharing option](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). + # + # IMPORTANT! This option is used only when the http request presents an Origin + # header, which is the case for web browsers. If no Origin header is present, + # this check will not be performed. + # + # List of accepted origins. When empty, and `same_origin` is `false`, clients from any origin are allowed to connect. + # This list specifies the only accepted values for the client's request Origin header. The scheme, + # host and port must match. By convention, the absence of TCP port in the URL will be port 80 + # for an "http://" scheme, and 443 for "https://". + # + # allowed_origins [ + # "http://www.example.com" + # "https://www.other-example.com" + # ] + + # This enables support for compressed websocket frames + # in the server. For compression to be used, both server + # and client have to support it. + # + # compression: true + + # This is the total time allowed for the server to + # read the client request and write the response back + # to the client. This includes the time needed for the + # TLS handshake. + # + # handshake_timeout: "2s" + + # Name for an HTTP cookie, that if present will be used as a client JWT. + # If the client specifies a JWT in the CONNECT protocol, this option is ignored. + # The cookie should be set by the HTTP server as described [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies). + # This setting is useful when generating NATS `Bearer` client JWTs as the + # result of some authentication mechanism. The HTTP server after correct + # authentication can issue a JWT for the user, that is set securely preventing + # access by unintended scripts. Note these JWTs must be [NATS JWTs](https://docs.nats.io/nats-server/configuration/securing_nats/jwt). + # + # jwt_cookie: "my_jwt_cookie_name" + + # If no user name is provided when a websocket client connects, will default + # this user name in the authentication phase. If specified, this will + # override, for websocket clients, any `no_auth_user` value defined in the + # main configuration file. + # Note that this is not compatible with running the server in operator mode. + # + # no_auth_user: "my_username_for_apps_not_providing_credentials" + + # See below to know what is the normal way of limiting websocket clients + # to specific users. + # If there are no users specified in the configuration, this simple authorization + # block allows you to override the values that would be configured in the + # equivalent block in the main section. + # + # authorization { + # # If this is specified, the client has to provide the same username + # # and password to be able to connect. + # # username: "my_user_name" + # # password: "my_password" + # + # # If this is specified, the password field in the CONNECT has to + # # match this token. + # # token: "my_token" + # + # # This overrides the main's authorization timeout. For consistency + # # with the main's authorization configuration block, this is expressed + # # as a number of seconds. + # # timeout: 2.0 + #} +} \ No newline at end of file diff --git a/backend/nats/run.sh b/backend/nats/run.sh new file mode 100755 index 0000000..0538303 --- /dev/null +++ b/backend/nats/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd "${0%/*}" # set current directory of this script to where the script is located. necessary for podman "-v" bind mounts to be relative paths +podman run -d --name sakal-nats -p 4222:4222 -p 4223:4223 localhost/sakal-nats-server:latest \ No newline at end of file diff --git a/.gitignore b/frontend/.gitignore similarity index 99% rename from .gitignore rename to frontend/.gitignore index d333b23..0bb8b02 100644 --- a/.gitignore +++ b/frontend/.gitignore @@ -75,6 +75,7 @@ typings/ # parcel-bundler cache (https://parceljs.org/) .cache +.parcel-cache # Next.js build output .next diff --git a/package.json b/frontend/package.json similarity index 92% rename from package.json rename to frontend/package.json index b214dd1..eb398d9 100644 --- a/package.json +++ b/frontend/package.json @@ -16,7 +16,8 @@ "dependencies": { "PubSubJS": "^0.0.3", "incremental-dom": "^0.7.0", - "nanoid": "^3.3.1" + "nanoid": "^3.3.1", + "nats.ws": "^1.7.2" }, "devDependencies": { "parcel": "^2.3.2" diff --git a/pnpm-lock.yaml b/frontend/pnpm-lock.yaml similarity index 98% rename from pnpm-lock.yaml rename to frontend/pnpm-lock.yaml index 9e9f6e8..3714ce0 100644 --- a/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -4,12 +4,14 @@ specifiers: PubSubJS: ^0.0.3 incremental-dom: ^0.7.0 nanoid: ^3.3.1 + nats.ws: ^1.7.2 parcel: ^2.3.2 dependencies: PubSubJS: 0.0.3 incremental-dom: 0.7.0 nanoid: 3.3.1 + nats.ws: 1.7.2 devDependencies: parcel: 2.3.2 @@ -705,6 +707,11 @@ packages: engines: {node: '>=10.13.0'} dev: true + /@types/node/14.18.12: + resolution: {integrity: sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==} + dev: false + optional: true + /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: true @@ -1197,6 +1204,22 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nats.ws/1.7.2: + resolution: {integrity: sha512-joNHe8DOXrzwPA7Kk7qZug39DmFRUifRVoB1Be0w/29Xj4PnqpF9HNihid/QxwHBs/JfFbwaJGhQDRgC7z3SpQ==} + optionalDependencies: + nkeys.js: 1.0.0-9 + dev: false + + /nkeys.js/1.0.0-9: + resolution: {integrity: sha512-m9O0NQT+3rUe1om6MWpxV77EuHql/LdorDH+FYQkoeARcM2V0sQ89kM36fArWaHWq/25EmNmQUW0MhLTcbqW1A==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + '@types/node': 14.18.12 + tweetnacl: 1.0.3 + dev: false + optional: true + /node-addon-api/3.2.1: resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} dev: true @@ -1718,6 +1741,11 @@ packages: resolution: {integrity: sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=} dev: true + /tweetnacl/1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + dev: false + optional: true + /type-fest/0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} diff --git a/frontend/src/behaviors.js b/frontend/src/behaviors.js new file mode 100644 index 0000000..7ff8db9 --- /dev/null +++ b/frontend/src/behaviors.js @@ -0,0 +1,44 @@ +import {pub, sub} from './pubsub.js'; +import state from './state.js'; +import redraw from './redraw.js'; + +// "raw" event listeners, which publish meaningful events, which are listened-to further-down: +// ... + + +// "meaningful" event listeners: +//sub('set-current-node', (node_vm)=>{ +// state.current_node_vm = node_vm; +// redraw(); +// }); + +// connect to NATS thru WebSockets: +import { connect, StringCodec } from "nats.ws"; +const strcodec = StringCodec(); +const init_nats = async function(){ + const nc = await connect({servers: "ws://localhost:4223"}); + console.log(nc); + + (async ()=>{ + const sub = nc.subscribe('price'); + for await (const msg of sub){ + console.log(`[${sub.getProcessed()}]: ${strcodec.decode(msg.data)}`); + } + })(); + (async ()=>{ + const sub = nc.subscribe('close'); + for await (const msg of sub){ + nc.close(); + console.log('closed!'); + break; + } + })(); + + nc.publish('price', strcodec.encode('4.23')); + nc.publish('price', strcodec.encode('5.00')); + //nc.close(); + }; +init_nats() + + +export default null; \ No newline at end of file diff --git a/src/components/App.js b/frontend/src/components/App.js similarity index 100% rename from src/components/App.js rename to frontend/src/components/App.js diff --git a/src/favicon.ico b/frontend/src/favicon.ico similarity index 100% rename from src/favicon.ico rename to frontend/src/favicon.ico diff --git a/src/index.css b/frontend/src/index.css similarity index 100% rename from src/index.css rename to frontend/src/index.css diff --git a/src/index.html b/frontend/src/index.html similarity index 100% rename from src/index.html rename to frontend/src/index.html diff --git a/src/index.js b/frontend/src/index.js similarity index 98% rename from src/index.js rename to frontend/src/index.js index 6752a5b..6c73f74 100644 --- a/src/index.js +++ b/frontend/src/index.js @@ -2,6 +2,7 @@ import redraw from './redraw.js'; import state from './state.js'; import x from './behaviors.js'; + // bootstrap initial state: diff --git a/src/procedures.js b/frontend/src/procedures.js similarity index 100% rename from src/procedures.js rename to frontend/src/procedures.js diff --git a/src/pubsub.js b/frontend/src/pubsub.js similarity index 100% rename from src/pubsub.js rename to frontend/src/pubsub.js diff --git a/src/redraw.js b/frontend/src/redraw.js similarity index 100% rename from src/redraw.js rename to frontend/src/redraw.js diff --git a/src/state.js b/frontend/src/state.js similarity index 95% rename from src/state.js rename to frontend/src/state.js index 991f6c8..283810b 100644 --- a/src/state.js +++ b/frontend/src/state.js @@ -1,3 +1,4 @@ +const someFn = null; const state = { front_months: { // front months, i.e. calendar expiry, at which the user has an opinion on where the underlying price may be "2022-03-11": { diff --git a/src/behaviors.js b/src/behaviors.js deleted file mode 100644 index f521e0b..0000000 --- a/src/behaviors.js +++ /dev/null @@ -1,16 +0,0 @@ -import {pub, sub} from './pubsub.js'; -import state from './state.js'; -import redraw from './redraw.js'; - -// "raw" event listeners, which publish meaningful events, which are listened-to further-down: -// ... - - -// "meaningful" event listeners: -//sub('set-current-node', (node_vm)=>{ -// state.current_node_vm = node_vm; -// redraw(); -// }); - - -export default null; \ No newline at end of file