<filename>src/WebServer/SqCoreWeb/PreDebugWatchDev.py
import os
import platform
import subprocess
from threading import Thread
import time
import sys
import random
import socket

print("SqBuild: Python ver: " + platform.python_version() + " (" + platform.architecture()[0] + "), CWD:'" + os. getcwd() + "'")
if (os.getcwd().endswith("SqCore")) : # VsCode's context menu 'Run Python file in Terminal' runs it from the workspace folder. VsCode F5 runs it from the project folder. We change it to the project folder
    os.chdir(os.getcwd() + "/src/WebServer/SqCoreWeb")

# 1. Basic checks: Ensure Node.js is installed. If node_modules folder is empty, it should restore Npm packages.
nodeTouchFile = os.getcwd() + "/node_modules/.install-stamp"
if os.path.isfile(nodeTouchFile):
    print ("SqBuild: /node_modules/ exist")
else:
    nodeRetCode = os.system("node --version")   # don't want to run 'node --version' all the times. If stamp file exists, assume node.exe is installed
    if (nodeRetCode != 0) :
        sys.exit("Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/")
    sys.exit("SqBuild: PreDebugBuildDev.py checks /node_modules in parallel. And we don't want that both processes start to download that huge folder. Exit now. It only happens once per year.")
    angularRetCode = os.system("ng --version")
    if (angularRetCode != 0) :
        sys.exit("SqBuild: NodeJs's AngularCLI is required to build and run this project. To continue, please install 'npm install -g @angular/cli@9.0.0-rc.10' on (2020-01-29) ")
    # os.system("npm install")
    # Path(nodeTouchFile).touch()


# 2. What can Debug user watch: wwwrootGeneral (NonWebpack), ExampleCsServerPushInRealtime (Webpack), HealthMonitor (Angular), MarketDashboard (Angular)
def threaded_function(commandStr):
     print("SqBuild: Executing in separate thread: " + commandStr)
     os.system(commandStr)    # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. 
     #processObj = subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE)  # This will run the command and return any output into process.output

def startShellCallingThread(pCommandStr):
    thread = Thread(target = threaded_function, args = (pCommandStr,))
    thread.setDaemon(True)  # daemon = true didn't help. Main thread exited, but watchers were left alive.
    thread.start()  #thread1.join()

# 2.1 Non-Webpack webapps in ./wwwroot/webapps should be transpiled from TS to JS
# os.system("tsc --watch")    # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. 
# subprocess.run(["tsc", "--watch"], stdout=subprocess.PIPE) # This will run the command and return any output
# subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE)
# subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # This will run the command and return any output
# thread1 = Thread(target = threaded_function, args = ("tsc --watch",))
# thread1.setDaemon(True)  # daemon = true didn't help. Main thread exited, but watchers were left alive.
# thread1.start()  #thread1.join()
startShellCallingThread("tsc --watch")


# 2.2 Webpack webapps in ./webapps should be packed (TS, CSS, HTML)
# Webpack: 'Multiple output files' are not possible and out of scope of webpack. You can use a build system.
# thread2 = Thread(target = threaded_function, args = ("npx webpack --config webapps/ExampleCsServerPushInRealtime/webpack.config.js --mode=development --watch",))
# thread2.setDaemon(True)
# thread2.start()  #thread2.join()
startShellCallingThread("npx webpack --config webapps/ExampleCsServerPushInRealtime/webpack.config.js --mode=development --watch")

# 2.3 Angular webapps in the project folder should be served on different ports. If an Angular app is not developed any more, comment it out to save resources
# ng serve doesn't create anything into --output-path=wwwroot/webapps/ (it keeps its files temp, maybe in RAM)
# to create files into wwwroot/weapps, at publish run 'ng build HealthMonitor --prod --output-path=wwwroot/webapps/HealthMonitor --base-href ./'
startShellCallingThread("ng serve --proxy-config angular.watch.proxy.conf.js HealthMonitor --port 4201")
startShellCallingThread("ng serve --proxy-config angular.watch.proxy.conf.js MarketDashboard --port 4202")

# 3. Wait for Python message to terminate all threads.
print("SqBuild: User can break (Control-C, or closing CMD) here manually. Or Wait for socket (TCP port) communication from another Python thread to end this thread.")
# Named pipes are nothing but mechanisms that allow IPC communication through the use of file descriptors associated with special files
# Let's use the be basic socket, because it is platform-independent. (and it is not file based), and we can use it easily in C# interop to Python (even under Linux).
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # versus AF_LOCAL, reliable, bidirectional
serversocket.bind(('localhost', 8389)) # bind the server socket to 'localhost'. On most platforms, this will take a shortcut around a couple of layers of network code and be quite a bit faster.
serversocket.listen(5) # become a server socket, maximum 5 connections, queue up as many as 5 connect requests (the normal max) before refusing outside connections. 
while True:
    connection, address = serversocket.accept()
    buf = connection.recv(64)
    if len(buf) > 0:
        print("SqBuild: Socket received message: " + str(buf))
        break


# 4. Terminate all threads. It not only terminates threads, but 'taskkill current process' will close the CMD window as well, which is perfect.
print("SqBuild: Main thread exits now as it kill the the CMD/terminal window")
# quit(), sys.exit() # they don't kill the started child-threads, even though they are daemons
uniqueCmdTitle = "PreDebugWatch.py." + str(random.randint(0,99999))
os.system("title " + uniqueCmdTitle)   # set the title of the CMD
os.system('taskkill /F /FI "WindowTitle eq ' + uniqueCmdTitle + '" /T')  #kill the task which has the title that was just set.

<filename>src/WebServer/SqCoreWeb/PreDebugWatchDev.py
import os
import platform
import subprocess
from threading import Thread
import time
import sys
import random
import socket

print("SqBuild: Python ver: " + platform.python_version() + " (" + platform.architecture()[0] + "), CWD:'" + os. getcwd() + "'")
if (os.getcwd().endswith("SqCore")) : # VsCode's context menu 'Run Python file in Terminal' runs it from the workspace folder. VsCode F5 runs it from the project folder. We change it to the project folder
    os.chdir(os.getcwd() + "/src/WebServer/SqCoreWeb")

# 1. Basic checks: Ensure Node.js is installed. If node_modules folder is empty, it should restore Npm packages.
nodeTouchFile = os.getcwd() + "/node_modules/.install-stamp"
if os.path.isfile(nodeTouchFile):
    print ("SqBuild: /node_modules/ exist")
else:
    nodeRetCode = os.system("node --version")   # don't want to run 'node --version' all the times. If stamp file exists, assume node.exe is installed
    if (nodeRetCode != 0) :
        sys.exit("Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/")
    sys.exit("SqBuild: PreDebugBuildDev.py checks /node_modules in parallel. And we don't want that both processes start to download that huge folder. Exit now. It only happens once per year.")
    angularRetCode = os.system("ng --version")
    if (angularRetCode != 0) :
        sys.exit("SqBuild: NodeJs's AngularCLI is required to build and run this project. To continue, please install 'npm install -g @angular/cli@9.0.0-rc.10' on (2020-01-29) ")
    # os.system("npm install")
    # Path(nodeTouchFile).touch()


# 2. What can Debug user watch: wwwrootGeneral (NonWebpack), ExampleCsServerPushInRealtime (Webpack), HealthMonitor (Angular), MarketDashboard (Angular)
def threaded_function(commandStr):
     print("SqBuild: Executing in separate thread: " + commandStr)
     os.system(commandStr)    # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. 
     #processObj = subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE)  # This will run the command and return any output into process.output

def startShellCallingThread(pCommandStr):
    thread = Thread(target = threaded_function, args = (pCommandStr,))
    thread.setDaemon(True)  # daemon = true didn't help. Main thread exited, but watchers were left alive.
    thread.start()  #thread1.join()

# 2.1 Non-Webpack webapps in ./wwwroot/webapps should be transpiled from TS to JS
# os.system("tsc --watch")    # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. 
# subprocess.run(["tsc", "--watch"], stdout=subprocess.PIPE) # This will run the command and return any output
# subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE)
# subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # This will run the command and return any output
# thread1 = Thread(target = threaded_function, args = ("tsc --watch",))
# thread1.setDaemon(True)  # daemon = true didn't help. Main thread exited, but watchers were left alive.
# thread1.start()  #thread1.join()
startShellCallingThread("tsc --watch")


# 2.2 Webpack webapps in ./webapps should be packed (TS, CSS, HTML)
# Webpack: 'Multiple output files' are not possible and out of scope of webpack. You can use a build system.
# thread2 = Thread(target = threaded_function, args = ("npx webpack --config webapps/ExampleCsServerPushInRealtime/webpack.config.js --mode=development --watch",))
# thread2.setDaemon(True)
# thread2.start()  #thread2.join()
startShellCallingThread("npx webpack --config webapps/ExampleCsServerPushInRealtime/webpack.config.js --mode=development --watch")

# 2.3 Angular webapps in the project folder should be served on different ports. If an Angular app is not developed any more, comment it out to save resources
# ng serve doesn't create anything into --output-path=wwwroot/webapps/ (it keeps its files temp, maybe in RAM)
# to create files into wwwroot/weapps, at publish run 'ng build HealthMonitor --prod --output-path=wwwroot/webapps/HealthMonitor --base-href ./'
startShellCallingThread("ng serve --proxy-config angular.watch.proxy.conf.js HealthMonitor --port 4201")
startShellCallingThread("ng serve --proxy-config angular.watch.proxy.conf.js MarketDashboard --port 4202")

# 3. Wait for Python message to terminate all threads.
print("SqBuild: User can break (Control-C, or closing CMD) here manually. Or Wait for socket (TCP port) communication from another Python thread to end this thread.")
# Named pipes are nothing but mechanisms that allow IPC communication through the use of file descriptors associated with special files
# Let's use the be basic socket, because it is platform-independent. (and it is not file based), and we can use it easily in C# interop to Python (even under Linux).
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # versus AF_LOCAL, reliable, bidirectional
serversocket.bind(('localhost', 8389)) # bind the server socket to 'localhost'. On most platforms, this will take a shortcut around a couple of layers of network code and be quite a bit faster.
serversocket.listen(5) # become a server socket, maximum 5 connections, queue up as many as 5 connect requests (the normal max) before refusing outside connections. 
while True:
    connection, address = serversocket.accept()
    buf = connection.recv(64)
    if len(buf) > 0:
        print("SqBuild: Socket received message: " + str(buf))
        break


# 4. Terminate all threads. It not only terminates threads, but 'taskkill current process' will close the CMD window as well, which is perfect.
print("SqBuild: Main thread exits now as it kill the the CMD/terminal window")
# quit(), sys.exit() # they don't kill the started child-threads, even though they are daemons
uniqueCmdTitle = "PreDebugWatch.py." + str(random.randint(0,99999))
os.system("title " + uniqueCmdTitle)   # set the title of the CMD
os.system('taskkill /F /FI "WindowTitle eq ' + uniqueCmdTitle + '" /T')  #kill the task which has the title that was just set.

# VsCode's context menu 'Run Python file in Terminal' runs it from the workspace folder. VsCode F5 runs it from the project folder. We change it to the project folder # 1. Basic checks: Ensure Node.js is installed. If node_modules folder is empty, it should restore Npm packages. # don't want to run 'node --version' all the times. If stamp file exists, assume node.exe is installed # os.system("npm install") # Path(nodeTouchFile).touch() # 2. What can Debug user watch: wwwrootGeneral (NonWebpack), ExampleCsServerPushInRealtime (Webpack), HealthMonitor (Angular), MarketDashboard (Angular) # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. #processObj = subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE)  # This will run the command and return any output into process.output # daemon = true didn't help. Main thread exited, but watchers were left alive. #thread1.join() # 2.1 Non-Webpack webapps in ./wwwroot/webapps should be transpiled from TS to JS # os.system("tsc --watch")    # works like normal, loads ./tsconfig.json, which contains "include": ["wwwroot"]. # subprocess.run(["tsc", "--watch"], stdout=subprocess.PIPE) # This will run the command and return any output # subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE) # subprocess.run("tsc --watch", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # This will run the command and return any output # thread1 = Thread(target = threaded_function, args = ("tsc --watch",)) # thread1.setDaemon(True)  # daemon = true didn't help. Main thread exited, but watchers were left alive. # thread1.start()  #thread1.join() # 2.2 Webpack webapps in ./webapps should be packed (TS, CSS, HTML) # Webpack: 'Multiple output files' are not possible and out of scope of webpack. You can use a build system. # thread2 = Thread(target = threaded_function, args = ("npx webpack --config webapps/ExampleCsServerPushInRealtime/webpack.config.js --mode=development --watch",)) # thread2.setDaemon(True) # thread2.start()  #thread2.join() # 2.3 Angular webapps in the project folder should be served on different ports. If an Angular app is not developed any more, comment it out to save resources # ng serve doesn't create anything into --output-path=wwwroot/webapps/ (it keeps its files temp, maybe in RAM) # to create files into wwwroot/weapps, at publish run 'ng build HealthMonitor --prod --output-path=wwwroot/webapps/HealthMonitor --base-href ./' # 3. Wait for Python message to terminate all threads. # Named pipes are nothing but mechanisms that allow IPC communication through the use of file descriptors associated with special files # Let's use the be basic socket, because it is platform-independent. (and it is not file based), and we can use it easily in C# interop to Python (even under Linux). # versus AF_LOCAL, reliable, bidirectional # bind the server socket to 'localhost'. On most platforms, this will take a shortcut around a couple of layers of network code and be quite a bit faster. # become a server socket, maximum 5 connections, queue up as many as 5 connect requests (the normal max) before refusing outside connections. # 4. Terminate all threads. It not only terminates threads, but 'taskkill current process' will close the CMD window as well, which is perfect. # quit(), sys.exit() # they don't kill the started child-threads, even though they are daemons # set the title of the CMD #kill the task which has the title that was just set.