init
This commit is contained in:
commit
642f90db1e
148
.gitignore
vendored
Normal file
148
.gitignore
vendored
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Node template
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
### macOS template
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Elastic Beanstalk Files
|
||||||
|
.elasticbeanstalk/*
|
||||||
|
!.elasticbeanstalk/*.cfg.yml
|
||||||
|
!.elasticbeanstalk/*.global.yml
|
||||||
|
/src/bundle.js
|
||||||
|
/src/bundle.js.map
|
||||||
|
/setup/web/live/
|
||||||
|
/work/
|
50
docker-compose.yml
Normal file
50
docker-compose.yml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
PostgreSQL:
|
||||||
|
image: postgres:alpine
|
||||||
|
container_name: PostgreSQL
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
restart: always
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/postgresql:/var/lib/postgresql/data"
|
||||||
|
- "./setup/clustering/setup/postgres/start.sh:/docker-entrypoint-initdb.d/start.sh"
|
||||||
|
- ./setup/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
|
||||||
|
adminer:
|
||||||
|
image: adminer
|
||||||
|
container_name: adminer
|
||||||
|
restart: always
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
- PostgreSQL
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: redis
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- "$ROOT/redis:/data"
|
||||||
|
|
||||||
|
web:
|
||||||
|
build: ./setup/web/.
|
||||||
|
container_name: web
|
||||||
|
command: npm run start
|
||||||
|
volumes:
|
||||||
|
- /user/app
|
||||||
|
ports:
|
||||||
|
- 9000:9000
|
||||||
|
depends_on:
|
||||||
|
- PostgreSQL
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- HOST=${HOST}
|
||||||
|
- DATABASE=${POSTGRES_DB}
|
||||||
|
- USER=${POSTGRES_USER}
|
||||||
|
- PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
60
setup/clustering/docker-compose.yml
Normal file
60
setup/clustering/docker-compose.yml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
primary:
|
||||||
|
hostname: 'primary'
|
||||||
|
image: crunchydata/crunchy-postgres:centos7-10.3-1.8.2
|
||||||
|
ports:
|
||||||
|
- 5432
|
||||||
|
restart: always
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- pg-primary-vol:/var/lib/postgresql/data
|
||||||
|
- ./setup/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=comcardeuser
|
||||||
|
- POSTGRES_PASSWORD=example
|
||||||
|
- POSTGRES_DB=comcarde
|
||||||
|
- PGHOST=/tmp
|
||||||
|
- MAX_CONNECTIONS=10
|
||||||
|
- MAX_WAL_SENDERS=5
|
||||||
|
- PG_MODE=primary
|
||||||
|
- PG_PRIMARY_USER=primaryuser
|
||||||
|
- PG_PRIMARY_PASSWORD=password
|
||||||
|
- PG_DATABASE=testdb
|
||||||
|
- PG_USER=testuser
|
||||||
|
- PG_PASSWORD=password
|
||||||
|
- PG_ROOT_PASSWORD=password
|
||||||
|
- PG_PRIMARY_PORT=5432
|
||||||
|
networks:
|
||||||
|
- replication
|
||||||
|
- front
|
||||||
|
deploy:
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- node.labels.type == primary
|
||||||
|
- node.role == worker
|
||||||
|
|
||||||
|
|
||||||
|
adminer:
|
||||||
|
image: adminer
|
||||||
|
container_name: adminer
|
||||||
|
restart: always
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
- primary
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
- front
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
replication:
|
||||||
|
front:
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pg-primary-vol:
|
||||||
|
pg-replica-vol:
|
13
setup/clustering/setup/postgres/start.sh
Normal file
13
setup/clustering/setup/postgres/start.sh
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
|
||||||
|
env_check_err "POSTGRES_PASSWORD"
|
||||||
|
|
||||||
|
file_env 'POSTGRES_PASSWORD'
|
||||||
|
|
||||||
|
echo "$POSTGRES_PASSWORD"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
152
setup/clustorgres/Dockerfile
Normal file
152
setup/clustorgres/Dockerfile
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# vim:set ft=dockerfile:
|
||||||
|
FROM alpine:3.7
|
||||||
|
|
||||||
|
# alpine includes "postgres" user/group in base install
|
||||||
|
# /etc/passwd:22:postgres:x:70:70::/var/lib/postgresql:/bin/sh
|
||||||
|
# /etc/group:34:postgres:x:70:
|
||||||
|
# the home directory for the postgres user, however, is not created by default
|
||||||
|
# see https://github.com/docker-library/postgres/issues/274
|
||||||
|
LABEL name="martind2000/clustergres"
|
||||||
|
|
||||||
|
RUN set -ex; \
|
||||||
|
postgresHome="$(getent passwd postgres)"; \
|
||||||
|
postgresHome="$(echo "$postgresHome" | cut -d: -f6)"; \
|
||||||
|
[ "$postgresHome" = '/var/lib/postgresql' ]; \
|
||||||
|
mkdir -p "$postgresHome"; \
|
||||||
|
chown -R postgres:postgres "$postgresHome"
|
||||||
|
|
||||||
|
# su-exec (gosu-compatible) is installed further down
|
||||||
|
|
||||||
|
# make the "en_US.UTF-8" locale so postgres will be utf-8 enabled by default
|
||||||
|
# alpine doesn't require explicit locale-file generation
|
||||||
|
ENV LANG en_US.utf8
|
||||||
|
|
||||||
|
RUN mkdir /docker-entrypoint-initdb.d
|
||||||
|
|
||||||
|
ENV PG_MAJOR 10
|
||||||
|
ENV PG_VERSION 10.4
|
||||||
|
ENV PG_SHA256 1b60812310bd5756c62d93a9f93de8c28ea63b0df254f428cd1cf1a4d9020048
|
||||||
|
|
||||||
|
RUN set -ex \
|
||||||
|
\
|
||||||
|
&& apk add --no-cache --virtual .fetch-deps \
|
||||||
|
ca-certificates \
|
||||||
|
openssl \
|
||||||
|
tar \
|
||||||
|
\
|
||||||
|
&& wget -O postgresql.tar.bz2 "https://ftp.postgresql.org/pub/source/v$PG_VERSION/postgresql-$PG_VERSION.tar.bz2" \
|
||||||
|
&& echo "$PG_SHA256 *postgresql.tar.bz2" | sha256sum -c - \
|
||||||
|
&& mkdir -p /usr/src/postgresql \
|
||||||
|
&& tar \
|
||||||
|
--extract \
|
||||||
|
--file postgresql.tar.bz2 \
|
||||||
|
--directory /usr/src/postgresql \
|
||||||
|
--strip-components 1 \
|
||||||
|
&& rm postgresql.tar.bz2 \
|
||||||
|
\
|
||||||
|
&& apk add --no-cache --virtual .build-deps \
|
||||||
|
bison \
|
||||||
|
coreutils \
|
||||||
|
dpkg-dev dpkg \
|
||||||
|
flex \
|
||||||
|
gcc \
|
||||||
|
# krb5-dev \
|
||||||
|
libc-dev \
|
||||||
|
libedit-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libxslt-dev \
|
||||||
|
make \
|
||||||
|
# openldap-dev \
|
||||||
|
openssl-dev \
|
||||||
|
# configure: error: prove not found
|
||||||
|
perl-utils \
|
||||||
|
# configure: error: Perl module IPC::Run is required to run TAP tests
|
||||||
|
perl-ipc-run \
|
||||||
|
# perl-dev \
|
||||||
|
# python-dev \
|
||||||
|
# python3-dev \
|
||||||
|
# tcl-dev \
|
||||||
|
util-linux-dev \
|
||||||
|
zlib-dev \
|
||||||
|
\
|
||||||
|
&& cd /usr/src/postgresql \
|
||||||
|
# update "DEFAULT_PGSOCKET_DIR" to "/var/run/postgresql" (matching Debian)
|
||||||
|
# see https://anonscm.debian.org/git/pkg-postgresql/postgresql.git/tree/debian/patches/51-default-sockets-in-var.patch?id=8b539fcb3e093a521c095e70bdfa76887217b89f
|
||||||
|
&& awk '$1 == "#define" && $2 == "DEFAULT_PGSOCKET_DIR" && $3 == "\"/tmp\"" { $3 = "\"/var/run/postgresql\""; print; next } { print }' src/include/pg_config_manual.h > src/include/pg_config_manual.h.new \
|
||||||
|
&& grep '/var/run/postgresql' src/include/pg_config_manual.h.new \
|
||||||
|
&& mv src/include/pg_config_manual.h.new src/include/pg_config_manual.h \
|
||||||
|
&& gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \
|
||||||
|
# explicitly update autoconf config.guess and config.sub so they support more arches/libcs
|
||||||
|
&& wget -O config/config.guess 'https://git.savannah.gnu.org/cgit/config.git/plain/config.guess?id=7d3d27baf8107b630586c962c057e22149653deb' \
|
||||||
|
&& wget -O config/config.sub 'https://git.savannah.gnu.org/cgit/config.git/plain/config.sub?id=7d3d27baf8107b630586c962c057e22149653deb' \
|
||||||
|
# configure options taken from:
|
||||||
|
# https://anonscm.debian.org/cgit/pkg-postgresql/postgresql.git/tree/debian/rules?h=9.5
|
||||||
|
&& ./configure \
|
||||||
|
--build="$gnuArch" \
|
||||||
|
# "/usr/src/postgresql/src/backend/access/common/tupconvert.c:105: undefined reference to `libintl_gettext'"
|
||||||
|
# --enable-nls \
|
||||||
|
--enable-integer-datetimes \
|
||||||
|
--enable-thread-safety \
|
||||||
|
--enable-tap-tests \
|
||||||
|
# skip debugging info -- we want tiny size instead
|
||||||
|
# --enable-debug \
|
||||||
|
--disable-rpath \
|
||||||
|
--with-uuid=e2fs \
|
||||||
|
--with-gnu-ld \
|
||||||
|
--with-pgport=5432 \
|
||||||
|
--with-system-tzdata=/usr/share/zoneinfo \
|
||||||
|
--prefix=/usr/local \
|
||||||
|
--with-includes=/usr/local/include \
|
||||||
|
--with-libraries=/usr/local/lib \
|
||||||
|
\
|
||||||
|
# these make our image abnormally large (at least 100MB larger), which seems uncouth for an "Alpine" (ie, "small") variant :)
|
||||||
|
# --with-krb5 \
|
||||||
|
# --with-gssapi \
|
||||||
|
# --with-ldap \
|
||||||
|
# --with-tcl \
|
||||||
|
# --with-perl \
|
||||||
|
# --with-python \
|
||||||
|
# --with-pam \
|
||||||
|
--with-openssl \
|
||||||
|
--with-libxml \
|
||||||
|
--with-libxslt \
|
||||||
|
&& make -j "$(nproc)" world \
|
||||||
|
&& make install-world \
|
||||||
|
&& make -C contrib install \
|
||||||
|
\
|
||||||
|
&& runDeps="$( \
|
||||||
|
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
|
||||||
|
| tr ',' '\n' \
|
||||||
|
| sort -u \
|
||||||
|
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
||||||
|
)" \
|
||||||
|
&& apk add --no-cache --virtual .postgresql-rundeps \
|
||||||
|
$runDeps \
|
||||||
|
bash \
|
||||||
|
su-exec \
|
||||||
|
# tzdata is optional, but only adds around 1Mb to image size and is recommended by Django documentation:
|
||||||
|
# https://docs.djangoproject.com/en/1.10/ref/databases/#optimizing-postgresql-s-configuration
|
||||||
|
tzdata \
|
||||||
|
&& apk del .fetch-deps .build-deps \
|
||||||
|
&& cd / \
|
||||||
|
&& rm -rf \
|
||||||
|
/usr/src/postgresql \
|
||||||
|
/usr/local/share/doc \
|
||||||
|
/usr/local/share/man \
|
||||||
|
&& find /usr/local -name '*.a' -delete
|
||||||
|
|
||||||
|
# make the sample config easier to munge (and "correct by default")
|
||||||
|
RUN sed -ri "s!^#?(listen_addresses)\s*=\s*\S+.*!\1 = '*'!" /usr/local/share/postgresql/postgresql.conf.sample
|
||||||
|
|
||||||
|
RUN mkdir -p /var/run/postgresql && chown -R postgres:postgres /var/run/postgresql && chmod 2777 /var/run/postgresql
|
||||||
|
|
||||||
|
ENV PGDATA /var/lib/postgresql/data
|
||||||
|
RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" # this 777 will be replaced by 700 at runtime (allows semi-arbitrary "--user" values)
|
||||||
|
VOLUME /var/lib/postgresql/data
|
||||||
|
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/
|
||||||
|
RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat
|
||||||
|
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||||
|
|
||||||
|
EXPOSE 5432
|
||||||
|
CMD ["postgres"]
|
162
setup/clustorgres/docker-entrypoint.sh
Normal file
162
setup/clustorgres/docker-entrypoint.sh
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeo pipefail
|
||||||
|
# TODO swap to -Eeuo pipefail above (after handling all potentially-unset variables)
|
||||||
|
|
||||||
|
# usage: file_env VAR [DEFAULT]
|
||||||
|
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
||||||
|
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
||||||
|
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
||||||
|
file_env() {
|
||||||
|
local var="$1"
|
||||||
|
local fileVar="${var}_FILE"
|
||||||
|
local def="${2:-}"
|
||||||
|
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
||||||
|
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
local val="$def"
|
||||||
|
if [ "${!var:-}" ]; then
|
||||||
|
val="${!var}"
|
||||||
|
elif [ "${!fileVar:-}" ]; then
|
||||||
|
val="$(< "${!fileVar}")"
|
||||||
|
fi
|
||||||
|
export "$var"="$val"
|
||||||
|
unset "$fileVar"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${1:0:1}" = '-' ]; then
|
||||||
|
set -- postgres "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# allow the container to be started with `--user`
|
||||||
|
if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
|
||||||
|
mkdir -p "$PGDATA"
|
||||||
|
chown -R postgres "$PGDATA"
|
||||||
|
chmod 700 "$PGDATA"
|
||||||
|
|
||||||
|
mkdir -p /var/run/postgresql
|
||||||
|
chown -R postgres /var/run/postgresql
|
||||||
|
chmod 775 /var/run/postgresql
|
||||||
|
|
||||||
|
# Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
|
||||||
|
if [ "$POSTGRES_INITDB_WALDIR" ]; then
|
||||||
|
mkdir -p "$POSTGRES_INITDB_WALDIR"
|
||||||
|
chown -R postgres "$POSTGRES_INITDB_WALDIR"
|
||||||
|
chmod 700 "$POSTGRES_INITDB_WALDIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec su-exec postgres "$BASH_SOURCE" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = 'postgres' ]; then
|
||||||
|
mkdir -p "$PGDATA"
|
||||||
|
chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
|
||||||
|
chmod 700 "$PGDATA" 2>/dev/null || :
|
||||||
|
|
||||||
|
# look specifically for PG_VERSION, as it is expected in the DB dir
|
||||||
|
if [ ! -s "$PGDATA/PG_VERSION" ]; then
|
||||||
|
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
|
||||||
|
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
|
||||||
|
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
|
||||||
|
export LD_PRELOAD='/usr/lib/libnss_wrapper.so'
|
||||||
|
export NSS_WRAPPER_PASSWD="$(mktemp)"
|
||||||
|
export NSS_WRAPPER_GROUP="$(mktemp)"
|
||||||
|
echo "postgres:x:$(id -u):$(id -g):PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD"
|
||||||
|
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
file_env 'POSTGRES_INITDB_ARGS'
|
||||||
|
if [ "$POSTGRES_INITDB_WALDIR" ]; then
|
||||||
|
export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
|
||||||
|
fi
|
||||||
|
eval "initdb --username=postgres $POSTGRES_INITDB_ARGS"
|
||||||
|
|
||||||
|
# unset/cleanup "nss_wrapper" bits
|
||||||
|
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
|
||||||
|
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
|
||||||
|
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check password first so we can output the warning before postgres
|
||||||
|
# messes it up
|
||||||
|
file_env 'POSTGRES_PASSWORD'
|
||||||
|
if [ "$POSTGRES_PASSWORD" ]; then
|
||||||
|
pass="PASSWORD '$POSTGRES_PASSWORD'"
|
||||||
|
authMethod=md5
|
||||||
|
else
|
||||||
|
# The - option suppresses leading tabs but *not* spaces. :)
|
||||||
|
cat >&2 <<-'EOWARN'
|
||||||
|
****************************************************
|
||||||
|
WARNING: No password has been set for the database.
|
||||||
|
This will allow anyone with access to the
|
||||||
|
Postgres port to access your database. In
|
||||||
|
Docker's default configuration, this is
|
||||||
|
effectively any other container on the same
|
||||||
|
system.
|
||||||
|
|
||||||
|
Use "-e POSTGRES_PASSWORD=password" to set
|
||||||
|
it in "docker run".
|
||||||
|
****************************************************
|
||||||
|
EOWARN
|
||||||
|
|
||||||
|
pass=
|
||||||
|
authMethod=trust
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
echo
|
||||||
|
echo "host all all all $authMethod"
|
||||||
|
} >> "$PGDATA/pg_hba.conf"
|
||||||
|
|
||||||
|
# internal start of server in order to allow set-up using psql-client
|
||||||
|
# does not listen on external TCP/IP and waits until start finishes
|
||||||
|
PGUSER="${PGUSER:-postgres}" \
|
||||||
|
pg_ctl -D "$PGDATA" \
|
||||||
|
-o "-c listen_addresses=''" \
|
||||||
|
-w start
|
||||||
|
|
||||||
|
file_env 'POSTGRES_USER' 'postgres'
|
||||||
|
file_env 'POSTGRES_DB' "$POSTGRES_USER"
|
||||||
|
|
||||||
|
psql=( psql -v ON_ERROR_STOP=1 )
|
||||||
|
|
||||||
|
if [ "$POSTGRES_DB" != 'postgres' ]; then
|
||||||
|
"${psql[@]}" --username postgres <<-EOSQL
|
||||||
|
CREATE DATABASE "$POSTGRES_DB" ;
|
||||||
|
EOSQL
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$POSTGRES_USER" = 'postgres' ]; then
|
||||||
|
op='ALTER'
|
||||||
|
else
|
||||||
|
op='CREATE'
|
||||||
|
fi
|
||||||
|
"${psql[@]}" --username postgres <<-EOSQL
|
||||||
|
$op USER "$POSTGRES_USER" WITH SUPERUSER $pass ;
|
||||||
|
EOSQL
|
||||||
|
echo
|
||||||
|
|
||||||
|
psql+=( --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" )
|
||||||
|
|
||||||
|
echo
|
||||||
|
for f in /docker-entrypoint-initdb.d/*; do
|
||||||
|
case "$f" in
|
||||||
|
*.sh) echo "$0: running $f"; . "$f" ;;
|
||||||
|
*.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
|
||||||
|
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
|
||||||
|
*) echo "$0: ignoring $f" ;;
|
||||||
|
esac
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
PGUSER="${PGUSER:-postgres}" \
|
||||||
|
pg_ctl -D "$PGDATA" -m fast -w stop
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo 'PostgreSQL init process complete; ready for start up.'
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
1
setup/mountain/Dockerfile
Normal file
1
setup/mountain/Dockerfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
FROM alpine
|
0
setup/postgres/Dockerfile
Normal file
0
setup/postgres/Dockerfile
Normal file
54
setup/postgres/init.sql
Normal file
54
setup/postgres/init.sql
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
-- SEQUENCE: public.test_id_seq
|
||||||
|
|
||||||
|
-- DROP SEQUENCE public.test_id_seq;
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.test_id_seq;
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.test_id_seq
|
||||||
|
OWNER TO comcardeuser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Table: public.test
|
||||||
|
|
||||||
|
-- DROP TABLE public.test;
|
||||||
|
|
||||||
|
CREATE TABLE public.test
|
||||||
|
(
|
||||||
|
id integer NOT NULL DEFAULT nextval('test_id_seq'::regclass),
|
||||||
|
company_name character varying(100) COLLATE pg_catalog."default",
|
||||||
|
CONSTRAINT test_pkey PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
WITH (
|
||||||
|
OIDS = FALSE
|
||||||
|
)
|
||||||
|
TABLESPACE pg_default;
|
||||||
|
|
||||||
|
ALTER TABLE public.test
|
||||||
|
OWNER to comcardeuser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- FUNCTION: public.insert_company(character varying)
|
||||||
|
|
||||||
|
-- DROP FUNCTION public.insert_company(character varying);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.insert_company(
|
||||||
|
_name character varying)
|
||||||
|
RETURNS void
|
||||||
|
LANGUAGE 'plpgsql'
|
||||||
|
|
||||||
|
COST 100
|
||||||
|
VOLATILE
|
||||||
|
AS $BODY$
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
INSERT into test(company_name) Values(_name);
|
||||||
|
END;
|
||||||
|
|
||||||
|
$BODY$;
|
||||||
|
|
||||||
|
ALTER FUNCTION public.insert_company(character varying)
|
||||||
|
OWNER TO comcardeuser;
|
4
setup/postgres/setup.sh
Normal file
4
setup/postgres/setup.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Build Postgres"
|
0
setup/redis/redis.conf
Normal file
0
setup/redis/redis.conf
Normal file
7
setup/web/Dockerfile
Normal file
7
setup/web/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM node:alpine
|
||||||
|
|
||||||
|
WORKDIR /usr/app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm install --unsafe-perm
|
33
setup/web/ecosystem.json
Normal file
33
setup/web/ecosystem.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
/**
|
||||||
|
* Application configuration section
|
||||||
|
* http://pm2.keymetrics.io/docs/usage/application-declaration/
|
||||||
|
*/
|
||||||
|
apps: [
|
||||||
|
// First application
|
||||||
|
{
|
||||||
|
"name": "Jubilee",
|
||||||
|
"script": "server.js",
|
||||||
|
"cwd": "/home/martind2000/dev/jubilee",
|
||||||
|
"watch": false,
|
||||||
|
"ignore_watch" : ["node_modules"],
|
||||||
|
"merge_logs" : true,
|
||||||
|
"autorestart" : true,
|
||||||
|
"restart_delay" : 3500,
|
||||||
|
"max_memory_restart" : "300M",
|
||||||
|
env: {
|
||||||
|
COMMON_VARIABLE: "true"
|
||||||
|
},
|
||||||
|
env_production: {
|
||||||
|
NODE_ENV: "production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* Deployment section
|
||||||
|
* http://pm2.keymetrics.io/docs/usage/deployment/
|
||||||
|
*/
|
||||||
|
deploy: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
38
setup/web/gulp/backbone.js
Normal file
38
setup/web/gulp/backbone.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const browserify = require('browserify');
|
||||||
|
const gulp = require('gulp');
|
||||||
|
const source = require('vinyl-source-stream');
|
||||||
|
const buffer = require('vinyl-buffer');
|
||||||
|
const uglify = require('gulp-uglify-es').default;
|
||||||
|
const sourcemaps = require('gulp-sourcemaps');
|
||||||
|
const gutil = require('gulp-util');
|
||||||
|
const rename = require('gulp-rename');
|
||||||
|
const stripDebug = require('gulp-strip-debug');
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('bundleBackbone', function () {
|
||||||
|
// set up the browserify instance on a task basis
|
||||||
|
const b = browserify({
|
||||||
|
'debug': true,
|
||||||
|
'entries': './src/js/app.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
return b.bundle()
|
||||||
|
.pipe(source('app.js'))
|
||||||
|
.pipe(buffer())
|
||||||
|
// .pipe(stripDebug())
|
||||||
|
.pipe(rename('bundle.js'))
|
||||||
|
|
||||||
|
.pipe(sourcemaps.init({ 'loadMaps': true }))
|
||||||
|
// Add transformation tasks to the pipeline here.
|
||||||
|
// .pipe(uglify())
|
||||||
|
.on('error', gutil.log)
|
||||||
|
.pipe(sourcemaps.write('.'))
|
||||||
|
.pipe(gulp.dest('./live/js'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('buildBackbone', [ 'bundleBackbone'], function() {
|
||||||
|
gulp.watch('src/js/**/*.js', [ 'bundleBackbone']);
|
||||||
|
});
|
||||||
|
|
59
setup/web/gulp/build.js
Normal file
59
setup/web/gulp/build.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const gulp = require('gulp'),
|
||||||
|
|
||||||
|
autoprefixer = require('gulp-autoprefixer'),
|
||||||
|
cssnano = require('gulp-cssnano'),
|
||||||
|
uglify = require('gulp-uglify'),
|
||||||
|
|
||||||
|
rename = require('gulp-rename'),
|
||||||
|
concat = require('gulp-concat'),
|
||||||
|
cache = require('gulp-cache'),
|
||||||
|
htmlmin = require('gulp-htmlmin'),
|
||||||
|
inject = require('gulp-inject'),
|
||||||
|
del = require('del'),
|
||||||
|
htmlreplace = require('gulp-html-replace');
|
||||||
|
|
||||||
|
const scss = require('gulp-scss');
|
||||||
|
const sass = require('gulp-sass');
|
||||||
|
const googleWebFonts = require('gulp-google-webfonts');
|
||||||
|
|
||||||
|
const fontOptions = { };
|
||||||
|
|
||||||
|
gulp.task('styles', function() {
|
||||||
|
return gulp.src(['node_modules/backbone.modal/backbone.modal.css', 'node_modules/backbone.modal/backbone.modal.theme.css'])
|
||||||
|
.pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
|
||||||
|
|
||||||
|
/* .pipe(gulp.dest('dist/css'))*/
|
||||||
|
/* .pipe(rename({suffix: '.min'}))*/
|
||||||
|
.pipe(concat('style.min.css'))
|
||||||
|
.pipe(cssnano())
|
||||||
|
.pipe(gulp.dest('live/css'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('copy', function() {
|
||||||
|
gulp.src(['src/img/**/*']).pipe(gulp.dest('live/img'));
|
||||||
|
gulp.src(['src/gfx/**/*']).pipe(gulp.dest('live/gfx'));
|
||||||
|
gulp.src(['src/index.html']).pipe(gulp.dest('live'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('clean', function() {
|
||||||
|
return del(['live']);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('customMUI', function() {
|
||||||
|
return gulp.src(['src/css/custom.scss'])
|
||||||
|
.pipe(sass({ 'outputStyle': 'compressed' }).on('error', sass.logError))
|
||||||
|
// .pipe(cssnano())
|
||||||
|
.pipe(rename('mui.custom.css'))
|
||||||
|
// .pipe(gulp.dest(`${dest}/css`));
|
||||||
|
.pipe(gulp.dest('live/css'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('vendor', function() {
|
||||||
|
return gulp.src([
|
||||||
|
'node_modules/muicss/dist/js/mui.min.js'
|
||||||
|
])
|
||||||
|
.pipe(concat('vendor.js'))
|
||||||
|
|
||||||
|
/* .pipe(uglify({ 'mangle': false }))*/
|
||||||
|
.pipe(gulp.dest(`live/js`));
|
||||||
|
});
|
7
setup/web/gulpfile.js
Normal file
7
setup/web/gulpfile.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
|
||||||
|
const requireDir = require('require-dir');
|
||||||
|
|
||||||
|
requireDir('./gulp');
|
||||||
|
|
||||||
|
gulp.task('default', ['bundleBackbone', 'styles', 'copy', 'customMUI', 'vendor']);
|
63
setup/web/package.json
Normal file
63
setup/web/package.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"name": "pgtest",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha",
|
||||||
|
"postinstall": "gulp default",
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"backbone": "^1.3.3",
|
||||||
|
"browserify": "^16.1.0",
|
||||||
|
"eslint": "^4.19.0",
|
||||||
|
"express": "^4.16.3",
|
||||||
|
"hh-mm-ss": "^1.2.0",
|
||||||
|
"jquery": "^3.3.1",
|
||||||
|
"lodash": "^4.17.5",
|
||||||
|
"log4js": "^2.5.3",
|
||||||
|
"memory-cache": "^0.2.0",
|
||||||
|
"moment": "^2.21.0",
|
||||||
|
"muicss": "^0.9.38",
|
||||||
|
"pg-promise": "^8.4.4",
|
||||||
|
"request-json": "^0.6.3",
|
||||||
|
"strict-uri-encode": "^2.0.0",
|
||||||
|
"string": "^3.3.3",
|
||||||
|
"sugar": "^2.0.4",
|
||||||
|
"uglifyify": "^4.0.5",
|
||||||
|
"underscore": "^1.9.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"expect.js": "^0.3.1",
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-google-webfonts": "^1.0.0",
|
||||||
|
"gulp-rename": "^1.2.2",
|
||||||
|
"gulp-sass": "^3.1.0",
|
||||||
|
"gulp-scss": "^1.4.0",
|
||||||
|
"gulp-sourcemaps": "^2.6.4",
|
||||||
|
"gulp-strip-debug": "^3.0.0",
|
||||||
|
"gulp-uglify-es": "^1.0.1",
|
||||||
|
"lodash.assign": "^4.2.0",
|
||||||
|
"mocha": "^5.0.4",
|
||||||
|
"node-fetch": "^2.1.1",
|
||||||
|
"require-dir": "^1.0.0",
|
||||||
|
"requirejs": "^2.3.5",
|
||||||
|
"sinon": "^4.4.6",
|
||||||
|
"vinyl-buffer": "^1.0.1",
|
||||||
|
"vinyl-source-stream": "^2.0.0",
|
||||||
|
"watchify": "^3.11.0",
|
||||||
|
"whatwg-fetch": "^2.0.4",
|
||||||
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
|
"gulp-bump": "^3.1.0",
|
||||||
|
"gulp-cache": "^1.0.2",
|
||||||
|
"gulp-concat": "^2.6.1",
|
||||||
|
"gulp-cssnano": "^2.1.2",
|
||||||
|
"gulp-html-replace": "^1.6.2",
|
||||||
|
"gulp-htmlmin": "^4.0.0",
|
||||||
|
"gulp-inject": "^4.3.1",
|
||||||
|
"gulp-uglify": "^3.0.0"
|
||||||
|
}
|
||||||
|
}
|
49
setup/web/server.js
Normal file
49
setup/web/server.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const logger = require('log4js').getLogger('Server');
|
||||||
|
|
||||||
|
|
||||||
|
const db = require('./server/db-connector').dbConnection;
|
||||||
|
const dbTestdata = require('./server/db-testdata')(db);
|
||||||
|
|
||||||
|
const nameGen = require('./server/name-gen');
|
||||||
|
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 9000;
|
||||||
|
|
||||||
|
const sitePath = 'live';
|
||||||
|
|
||||||
|
app.use(express.static(path.join(__dirname, sitePath)));
|
||||||
|
|
||||||
|
// app.get('/weather', cache('15 minutes'), (req, res) => {
|
||||||
|
|
||||||
|
const asyncMiddleware = fn =>
|
||||||
|
(req, res, next) => {
|
||||||
|
Promise.resolve(fn(req, res, next))
|
||||||
|
.catch(next);
|
||||||
|
};
|
||||||
|
|
||||||
|
app.get('/data', (req, res) => {
|
||||||
|
dbTestdata.sqlGetSimpleList().then((d) => {
|
||||||
|
res.send(d);
|
||||||
|
}).catch((e) => {
|
||||||
|
logger.error(e);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, (err) => {
|
||||||
|
if (err)
|
||||||
|
return logger.error('Server error:', err);
|
||||||
|
|
||||||
|
logger.info(`Test Server is listening on ${port}`);
|
||||||
|
|
||||||
|
const i = setInterval(()=>{
|
||||||
|
dbTestdata.sqlInsertData(nameGen.gen()).then((d) => {
|
||||||
|
logger.debug(d);
|
||||||
|
}).catch((e) => {
|
||||||
|
logger.error(e);
|
||||||
|
});
|
||||||
|
}, 15000)
|
||||||
|
});
|
22
setup/web/server/db-connector.js
Normal file
22
setup/web/server/db-connector.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const pgp = require('pg-promise')();
|
||||||
|
|
||||||
|
const connectionString = process.env.DATABASE_URL;
|
||||||
|
|
||||||
|
|
||||||
|
/*const cn = {
|
||||||
|
connectionString:connectionString
|
||||||
|
};*/
|
||||||
|
|
||||||
|
const cn = {
|
||||||
|
host: process.env.HOST,
|
||||||
|
port: 5432,
|
||||||
|
database: process.env.DATABASE,
|
||||||
|
user: process.env.USER,
|
||||||
|
password: process.env.PASSWORD
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log('>> connectionString', cn);
|
||||||
|
exports.dbConnection = pgp(cn);
|
||||||
|
|
40
setup/web/server/db-testdata.js
Normal file
40
setup/web/server/db-testdata.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const logger = require('log4js').getLogger('db-testdata');
|
||||||
|
logger.level = 'debug';
|
||||||
|
module.exports = function(db) {
|
||||||
|
const module = {};
|
||||||
|
|
||||||
|
module.sqlGetSimpleList = function(id) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
|
||||||
|
db.manyOrNone('select * from "test";', [id])
|
||||||
|
|
||||||
|
.then(function(d) {
|
||||||
|
// console.log(d);
|
||||||
|
return resolve(d);
|
||||||
|
})
|
||||||
|
.catch((err)=> {
|
||||||
|
// console.log(err);
|
||||||
|
return reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.sqlInsertData = function(name) {
|
||||||
|
|
||||||
|
logger.info('Insert ', name);
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
db.func('insert_company',
|
||||||
|
[name])
|
||||||
|
.then(()=> {
|
||||||
|
return resolve('ok');
|
||||||
|
})
|
||||||
|
.catch((err)=> {
|
||||||
|
return reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return module;
|
||||||
|
};
|
61
setup/web/server/name-gen.js
Normal file
61
setup/web/server/name-gen.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Created by mdonnel on 20/04/2017.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Array.prototype.random = function () {
|
||||||
|
return this[Math.floor((Math.random() * this.length))];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const left = ['Alabama',
|
||||||
|
'Alaska',
|
||||||
|
'Arizona',
|
||||||
|
'Maryland',
|
||||||
|
'Nevada',
|
||||||
|
'Mexico',
|
||||||
|
'Texas',
|
||||||
|
'Utah',
|
||||||
|
'Glasgow',
|
||||||
|
'Inverness',
|
||||||
|
'Edinburgh',
|
||||||
|
'Dumbarton',
|
||||||
|
'Balloch',
|
||||||
|
'Renton',
|
||||||
|
'Cardross',
|
||||||
|
'Dundee',
|
||||||
|
'Paisley',
|
||||||
|
'Hamilton',
|
||||||
|
'Greenock',
|
||||||
|
'Falkirk',
|
||||||
|
'Irvine',
|
||||||
|
'Renfrew',
|
||||||
|
'Erskine',
|
||||||
|
'London',
|
||||||
|
'Hammersmith',
|
||||||
|
'Islington',
|
||||||
|
'Silver', 'Black', 'Yellow', 'Purple', 'White', 'Pink', 'Red', 'Orange', 'Brown', 'Green', 'Blue',
|
||||||
|
'Amber', 'Aqua', 'Azure', 'Bronze', 'Coral', 'Copper', 'Crimson', 'Cyan', 'Ginger', 'Gold', 'Indigo', 'Jade'
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
const right = ['Aganju', 'Cygni', 'Akeron', 'Antares', 'Aragoth', 'Ardus', 'Carpenter',
|
||||||
|
'Cooper', 'Dahin', 'Capella', 'Endriago', 'Gallina', 'Fenris', 'Freya', 'Glenn', 'Grissom',
|
||||||
|
'Jotunheim', 'Kailaasa', 'Lagarto', 'Muspelheim', 'Nifleheim', 'Primus', 'Vega', 'Ragnarok',
|
||||||
|
'Shepard', 'Slayton', 'Tarsis', 'Mercury', 'Venus', 'Mars', 'Earth', 'Terra', 'Jupiter',
|
||||||
|
'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Europa', 'Ganymede', 'Callisto', 'Titan', 'Juno',
|
||||||
|
'Eridanus', 'Scorpius', 'Crux', 'Cancer', 'Taurus', 'Lyra', 'Andromeda', 'Virgo', 'Aquarius',
|
||||||
|
'Cygnus', 'Corvus', 'Taurus', 'Draco', 'Perseus', 'Pegasus', 'Gemini', 'Columbia', 'Bootes',
|
||||||
|
'Orion', 'Deneb', 'Merope', 'Agate', 'Amber', 'Beryl', 'Calcite', 'Citrine', 'Coral', 'Diamond',
|
||||||
|
'Emerald', 'Garnet', 'Jade', 'Lapis', 'Moonstone', 'Obsidian', 'Onyx', 'Opal', 'Pearl', 'Quartz',
|
||||||
|
'Ruby', 'Sapphire', 'Topaz', 'Iron', 'Lead', 'Nickel', 'Copper', 'Zinc', 'Tin', 'Manes', 'Argon',
|
||||||
|
'Neon', 'Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliett',
|
||||||
|
'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform',
|
||||||
|
'Victor', 'Whisky', 'Xray', 'Yankee', 'Zulu'];
|
||||||
|
|
||||||
|
|
||||||
|
function gen(){
|
||||||
|
return (`${left.random() } ${ right.random() }`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {gen};
|
137
setup/web/src/css/custom.scss
Normal file
137
setup/web/src/css/custom.scss
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// import MUI colors
|
||||||
|
@import "./node_modules/muicss/lib/sass/mui/colors";
|
||||||
|
|
||||||
|
// customize MUI variables
|
||||||
|
$mui-primary-color: mui-color('pink', '500');
|
||||||
|
$mui-primary-color-dark: mui-color('blue-grey', '700');
|
||||||
|
$mui-primary-color-light: mui-color('blue-grey', '100');
|
||||||
|
|
||||||
|
$mui-accent-color: mui-color('deep-purple', '900');
|
||||||
|
$mui-accent-color-dark: mui-color('indigo', 'A100');
|
||||||
|
$mui-accent-color-light: mui-color('indigo', 'A400');
|
||||||
|
|
||||||
|
$mui-base-font-family: 'Roboto', "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS";
|
||||||
|
$mui-base-font-weight: 400;
|
||||||
|
|
||||||
|
$mui-appbar-font-color: mui-color('black') !default;
|
||||||
|
|
||||||
|
$mui-link-font-color: mui-color('pink', '900') !default;
|
||||||
|
|
||||||
|
// import MUI SASS
|
||||||
|
@import "./node_modules/muicss/lib/sass/mui";
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: mui-color('grey', '100');
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
transition: left 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dates {
|
||||||
|
padding: 2px;
|
||||||
|
border: solid 1px #80007e;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btc, #fx, #trend {
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.up, .ontime, .trendUp {
|
||||||
|
color: mui-color('green') !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.down, .delayed, .trendDown {
|
||||||
|
color: $mui-text-danger !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nochange {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password {
|
||||||
|
border: 1px solid mui-color('grey', '400');
|
||||||
|
background-color: mui-color('grey', '200');
|
||||||
|
font-family: monospace;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trendUp:before {
|
||||||
|
content: "▲";
|
||||||
|
}
|
||||||
|
|
||||||
|
.trendDown:before {
|
||||||
|
content: '▼'
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
min-height: 48px;
|
||||||
|
margin: 8px;
|
||||||
|
border-bottom-color: #666666;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemRow {
|
||||||
|
background-color: #fff;
|
||||||
|
min-height: 48px;
|
||||||
|
border-bottom-color: mui-color('grey', '200');
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardTitle {
|
||||||
|
border-bottom-color: mui-color('grey', '200');
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry {
|
||||||
|
height: 36px;
|
||||||
|
margin: 6px 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleBar {
|
||||||
|
font-family: 'Gotham Light';
|
||||||
|
font-size: 125%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tableBody {
|
||||||
|
transition: all 0.5s;
|
||||||
|
-webkit-transition: all 0.5s;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.unsliced {
|
||||||
|
height: 455px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliced {
|
||||||
|
height: 300px;
|
||||||
|
|
||||||
|
}
|
44
setup/web/src/index.html
Normal file
44
setup/web/src/index.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>PG TEST</title>
|
||||||
|
|
||||||
|
<link href="/css/mui.custom.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="appPanel" data-id="main">
|
||||||
|
<div class="mui-container">
|
||||||
|
<div id="greet"></div>
|
||||||
|
|
||||||
|
<div id="location" class="mui-row" style="display: none;">PG TEST</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-container" id="viewFrame">
|
||||||
|
<div id="dataShell" class="mui-panel" style="display: ;">
|
||||||
|
<div id="dataTitle" class="mui--text-title cardTitle">Data</div>
|
||||||
|
<div id="data"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="js/vendor.js" async></script>
|
||||||
|
<script type='module' src="js/bundle.js" async></script>
|
||||||
|
|
||||||
|
<noscript>
|
||||||
|
<!-- anchor linking to external file -->
|
||||||
|
<h1>Javascript disabled</h1>
|
||||||
|
<p>This really requires javascript to work</p>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
97
setup/web/src/js/DataList.js
Normal file
97
setup/web/src/js/DataList.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
const $ = require('jquery');
|
||||||
|
const _ = require('underscore');
|
||||||
|
const Backbone = require('backbone');
|
||||||
|
const request = require('request');
|
||||||
|
|
||||||
|
const DataItem = Backbone.Model.extend({
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const DataCollection = Backbone.Collection.extend({
|
||||||
|
'model': DataItem
|
||||||
|
});
|
||||||
|
|
||||||
|
// const dataCollection = new dataCollection();
|
||||||
|
|
||||||
|
const DataItemView = Backbone.View.extend({
|
||||||
|
'tagName': 'div',
|
||||||
|
'className' : 'mui-row',
|
||||||
|
'template': _.template(`
|
||||||
|
<div class="mui-col-xs-4 mui-col-md-4"><%=id%></div>
|
||||||
|
<div class="mui-col-xs-8 mui-col-md-8"><%=company_name%></div>
|
||||||
|
`),
|
||||||
|
'initialize': function() {
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
'render': function() {
|
||||||
|
this.$el.html(this.template(this.model.toJSON()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const DataListModel = Backbone.Model.extend({
|
||||||
|
'defaults' : function (obj) {
|
||||||
|
// return a new object
|
||||||
|
return {
|
||||||
|
'update' : new Date().getTime()
|
||||||
|
};
|
||||||
|
}, 'initialize': function() {
|
||||||
|
this.dataCollection = new DataCollection();
|
||||||
|
this.listenTo(this, 'change:update', this.onChange);
|
||||||
|
this.getData();
|
||||||
|
},
|
||||||
|
'onChange': function() {
|
||||||
|
this.getData();
|
||||||
|
},
|
||||||
|
'getData': function() {
|
||||||
|
request({
|
||||||
|
'url': `${window.loc.origin}/data`,
|
||||||
|
'method': 'GET', 'qs': {
|
||||||
|
|
||||||
|
}
|
||||||
|
}, function(err, res, body) {
|
||||||
|
if (err)
|
||||||
|
console.error(err);
|
||||||
|
else {
|
||||||
|
const fsJSON = JSON.parse(body);
|
||||||
|
|
||||||
|
this.dataCollection.reset(fsJSON);
|
||||||
|
|
||||||
|
this.logUpdate();
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
}, 'logUpdate': function() {
|
||||||
|
const time = new Date().getTime() ;
|
||||||
|
|
||||||
|
this.set('time', time);
|
||||||
|
|
||||||
|
this.timerID = setTimeout(
|
||||||
|
() => this.tick(),
|
||||||
|
30 * 1000
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'tick': function() {
|
||||||
|
this.set('update', new Date().getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const DataListView = Backbone.View.extend({
|
||||||
|
'initialize': function(options) {
|
||||||
|
this.model.dataCollection.bind('reset', this.render, this);
|
||||||
|
|
||||||
|
},
|
||||||
|
'render' : function() {
|
||||||
|
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
this.model.dataCollection.each(function(item) {
|
||||||
|
const niView = new DataItemView({ 'model': item });
|
||||||
|
|
||||||
|
this.$el.append(niView.el);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { DataListModel, DataListView };
|
19
setup/web/src/js/app.js
Normal file
19
setup/web/src/js/app.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require('muicss');
|
||||||
|
const $ = require('jquery');
|
||||||
|
const _ = require('underscore');
|
||||||
|
const Backbone = require('backbone');
|
||||||
|
|
||||||
|
const { DataListModel, DataListView } = require('./DataList');
|
||||||
|
|
||||||
|
var app = app || {};
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
window.loc = new URL(window.location);
|
||||||
|
|
||||||
|
app.dataList = new DataListView({ 'model': new DataListModel(), 'el':'#data' });
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user