diff --git a/symmetricds/Makefile b/symmetricds/Makefile index f940e273..99488c86 100644 --- a/symmetricds/Makefile +++ b/symmetricds/Makefile @@ -1,5 +1,10 @@ +SHELL=/bin/bash SYMD_DOWNLOAD_URL=https://sourceforge.net/projects/symmetricds/files/symmetricds/symmetricds-3.8/symmetric-server-3.8.43.zip/download +PROPERTIES=\ + symmetricds/engines/engine0.properties \ + symmetricds/engines/engine1.properties \ + symmetricds.zip: $(if $(shell command -v wget 2> /dev/null),\ wget -O symmetricds.zip ${SYMD_DOWNLOAD_URL},\ @@ -13,8 +18,29 @@ symmetricds: symmetricds.zip touch $@ # https://stackoverflow.com/a/37197276/1556838 -install: symmetricds +install: symmetricds ${PROPERTIES} $(if $(shell command -v java 2> /dev/null),$(info Found `java`),$(error Please install `java`)) -clean: - rm -rf symmetricds.zip symmetricds +symmetricds/engines/engine%.properties: symmetricds + cp template/$(@F) $(@D)/$(@F) + +check-properties: ${PROPERTIES} + @for prop in $+ ; do \ + ./check-properties.py $$prop || exit 1 ; \ + done + +SYMD_BIN=symmetricds/bin +configure: check-properties + ${SYMD_BIN}/dbsql -e engine0 --sql "" || (echo "Failed to connect to engine0."; exit 1) + ${SYMD_BIN}/dbsql -e engine1 --sql "" || (echo "Failed to connect to engine1."; exit 1) + ${SYMD_BIN}/dbimport -e engine0 configure.sql + + +clean-symd-table: + -${SYMD_BIN}/symadmin -e engine0 uninstall + -${SYMD_BIN}/symadmin -e engine1 uninstall + +clean: clean-symd-table + -rm -rf symmetricds.zip symmetricds + +.PHONY: clean clean-symd-table configure install check-properties diff --git a/symmetricds/check-properties.py b/symmetricds/check-properties.py new file mode 100755 index 00000000..bcb55b7f --- /dev/null +++ b/symmetricds/check-properties.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +import sys + + +def check(file): + print(f"Check {file.name}") + dic = {} + for line in file.readlines(): + line = line.strip() + if line.startswith("#"): + continue + if "=" not in line: + continue + comp = line.split("=") + dic[comp[0]] = comp[1] + + for key in ["registration.url", "db.user", "db.password", "db.url"]: + if not assert_key(dic, key): + print(f"{key} is not set in {file.name}", file=sys.stderr) + exit(1) + + for key in ["sync.url"]: + if not assert_key_not_empty(dic, key): + print(f"{key} is empty in {file.name}", file=sys.stderr) + exit(1) + + +def assert_key_not_empty(dic, key): + if key not in dic: + return True + if not dic[key].strip(): + return False + return True + + +def assert_key(dic, key): + if key not in dic: + return False + if not dic[key].strip(): + return False + return True + + +if __name__ == "__main__": + if len(sys.argv) < 2: + exit(1) + with open(sys.argv[1]) as f: + check(f) diff --git a/symmetricds/configure.sql b/symmetricds/configure.sql new file mode 100644 index 00000000..5324df4c --- /dev/null +++ b/symmetricds/configure.sql @@ -0,0 +1,74 @@ +------------------------------------------------------------------------------ +-- Clear and load SymmetricDS Configuration +------------------------------------------------------------------------------ + +delete from sym_trigger_router; +delete from sym_trigger; +delete from sym_router; +delete from sym_channel where channel_id in ('main_channel'); +delete from sym_node_group_link; +delete from sym_node_group; +delete from sym_node_host; +delete from sym_node_identity; +delete from sym_node_security; +delete from sym_node; + +------------------------------------------------------------------------------ +-- Channels +------------------------------------------------------------------------------ + +-- Channel "sensor_data" for tables related to items for purchase +insert into sym_channel +(channel_id, processing_order, max_batch_size, enabled, description) +values('main_channel', 1, 100000, 1, 'Main channel for mercury'); + +------------------------------------------------------------------------------ +-- Node Groups +------------------------------------------------------------------------------ + +insert into sym_node_group (node_group_id) values ('group0'); +insert into sym_node_group (node_group_id) values ('group1'); + +------------------------------------------------------------------------------ +-- Node Group Links +------------------------------------------------------------------------------ + +-- Corp sends changes to Store when Store pulls from Corp +insert into sym_node_group_link (source_node_group_id, target_node_group_id, data_event_action) values ('group0', 'group1', 'P'); + +-- Store sends changes to Corp when Store pushes to Corp +insert into sym_node_group_link (source_node_group_id, target_node_group_id, data_event_action) values ('group1', 'group0', 'P'); + +------------------------------------------------------------------------------ +-- Triggers +------------------------------------------------------------------------------ + +insert into sym_trigger +(trigger_id,source_table_name,channel_id,last_update_time,create_time) +values('all_mercury_table_trigger','ag_*','main_channel',current_timestamp,current_timestamp); + +------------------------------------------------------------------------------ +-- Routers +------------------------------------------------------------------------------ + +-- Default router sends all data from corp to store +insert into sym_router +(router_id,source_node_group_id,target_node_group_id,router_type,create_time,last_update_time) +values('group0_to_1', 'group0', 'group1', 'default',current_timestamp, current_timestamp); + +-- Default router sends all data from store to corp +insert into sym_router +(router_id,source_node_group_id,target_node_group_id,router_type,create_time,last_update_time) +values('group1_to_0', 'group1', 'group0', 'default',current_timestamp, current_timestamp); + +------------------------------------------------------------------------------ +-- Trigger Routers +------------------------------------------------------------------------------ + +insert into sym_trigger_router +(trigger_id,router_id,initial_load_order,last_update_time,create_time) +values('all_mercury_table_trigger','group0_to_1', 100, current_timestamp, current_timestamp); + +insert into sym_trigger_router +(trigger_id,router_id,initial_load_order,last_update_time,create_time) +values('all_mercury_table_trigger','group1_to_0', 100, current_timestamp, current_timestamp); diff --git a/symmetricds/template/engine0.properties b/symmetricds/template/engine0.properties new file mode 100644 index 00000000..8e192462 --- /dev/null +++ b/symmetricds/template/engine0.properties @@ -0,0 +1,59 @@ +# Sync URL where other nodes can contact this node to push/pull data or register. +# http://{hostname}:31415/sync/engine0 +# sync.url=http://localhost:31415/sync/engine0 +sync.url= + +# Put the same value with sync.url here +registration.url= + +db.user= +db.password= + +# https://jdbc.postgresql.org/documentation/80/connect.html +# db.url=jdbc:postgresql://localhost:5432/mercury +db.url=jdbc:postgresql://localhost:5432/mercury + + + + + + + + + + +########################################################################### +# Do not change anything below this line +########################################################################### + +db.driver=org.postgresql.Driver + +# Friendly name to refer to this node from command line +engine.name=engine0 + +# Node group this node belongs to, which defines what it will sync with who. +# Must match the sym_node_group configuration in database. +group.id=group0 + +# External ID for this node, which is any unique identifier you want to use. +external.id=000 + +# How often to run purge job, +job.purge.period.time.ms=7200000 + +# How to run routing (in millis), which puts changes into batches. +# job.routing.period.time.ms=5000 +job.routing.period.time.ms=1000 + +# How often to run push (in millis), which sends changes to other nodes. +job.push.period.time.ms=1000 + +# How often to run pull (in millis), which receives changes from other nodes. +job.pull.period.time.ms=1000 + +# Automatically register new nodes when they request it +# If this is false, accept the registration requests using "symadmin open-registration" command. +auto.registration=true + +# When this node sends an initial load of data to another node, first send table create scripts. +initial.load.create.first=true diff --git a/symmetricds/template/engine1.properties b/symmetricds/template/engine1.properties new file mode 100644 index 00000000..a92885d2 --- /dev/null +++ b/symmetricds/template/engine1.properties @@ -0,0 +1,65 @@ +# Put engine0's sync.url here. +# registration.url=http://localhost:31415/sync/engine0 +registration.url= + +# How to get db.user/db.password/db.url for a postgres running on heroku +# +# 1. Run +# heroku config:get DATABASE_URL --app +# +# 2. The output would be the following format: +# postgres://:@ +# +# 3. Your configuration would be: +# db.user= +# db.password= +# db.url=jdbc:postgresql://?sslmode=require + +# Please make sure your db.url starts with "jdbc:postgresql://" and you appended "?sslmode=require" at the end. + +db.user= +db.password= +db.url= + + + + + + + + + + +########################################################################### +# Do not change anything below this line +########################################################################### + +db.driver=org.postgresql.Driver + +# Friendly name to refer to this node from command line +engine.name=engine1 + +# Node group this node belongs to, which defines what it will sync with who. +# Must match the sym_node_group configuration in database. +group.id=group1 + +# External ID for this node, which is any unique identifier you want to use. +external.id=001 + +# Sync URL where other nodes can contact this node to push/pull data or register. +# http://{hostname}:{port}/sync/{engine.name} +# sync.url=http://localhost:31415/sync/engine1 + + +# How to run routing (in millis), which puts changes into batches. +job.routing.period.time.ms=1000 + +# How often to run push (in millis), which sends changes to other nodes. +job.push.period.time.ms=1000 + +# How often to run pull (in millis), which receives changes from other nodes. +job.pull.period.time.ms=1000 + + +# seems it doesn't work +# auto.reload=true