<commit_before>#!/usr/bin/python

# =========================== adjust path =====================================

import sys
import os

if __name__ == "__main__":
    here = sys.path[0]
    sys.path.insert(0, os.path.join(here, '..', 'sol'))

# =========================== imports =========================================

# from default Python
import pickle
import time
import json
import subprocess
import threading
import traceback
import datetime
from   optparse                 import OptionParser
from   ConfigParser             import SafeConfigParser
import logging
import logging.config

# third-party packages
import bottle
import influxdb

# project-specific
import OpenCli
from solobjectlib import Sol, SolVersion
import solserver_version
import sites

#============================ logging =========================================

logging.config.fileConfig('logging.conf')
log = logging.getLogger('solserver')
log.setLevel(logging.DEBUG)

#============================ defines =========================================

DEFAULT_TCPPORT              = 8081
DEFAULT_SOLSERVERHOST        = '0.0.0.0' # listen on all interfaces

DEFAULT_CONFIGFILE           = 'solserver.config'
DEFAULT_CRASHLOG             = 'solserver.crashlog'
DEFAULT_BACKUPFILE           = 'solserver.backup'

# config file

DEFAULT_SOLMANAGERTOKEN      = 'DEFAULT_SOLMANAGERTOKEN'
DEFAULT_SOLSERVERCERT        = 'solserver.cert'
DEFAULT_SOLSERVERPRIVKEY     = 'solserver.ppk'

# stats

STAT_NUM_JSON_REQ            = 'NUM_JSON_REQ'
STAT_NUM_JSON_UNAUTHORIZED   = 'NUM_JSON_UNAUTHORIZED'
STAT_NUM_CRASHES             = 'NUM_CRASHES'
STAT_NUM_OBJECTS_DB_OK       = 'STAT_NUM_OBJECTS_DB_OK'
STAT_NUM_OBJECTS_DB_FAIL     = 'STAT_NUM_OBJECTS_DB_FAIL'
STAT_NUM_SET_ACTION_REQ      = 'NUM_SET_ACTION_REQ'

#============================ helpers =========================================

def logCrash(threadName,err):
    output  = []
    output += ["============================================================="]
    output += [time.strftime("%m/%d/%Y %H:%M:%S UTC",time.gmtime())]
    output += [""]
    output += ["CRASH in Thread {0}!".format(threadName)]
    output += [""]
    output += ["=== exception type ==="]
    output += [str(type(err))]
    output += [""]
    output += ["=== traceback ==="]
    output += [traceback.format_exc()]
    output  = '\n'.join(output)
    # update stats
    AppData().incrStats(STAT_NUM_CRASHES)
    print output
    log.critical(output)

#============================ classes =========================================

class AppData(object):
    _instance = None
    _init     = False
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(AppData,cls).__new__(cls, *args, **kwargs)
        return cls._instance
    def __init__(self):
        if self._init:
            return
        self._init      = True
        self.dataLock   = threading.RLock()
        try:
            with open(DEFAULT_BACKUPFILE,'r') as f:
                self.data = pickle.load(f)
        except (EnvironmentError, pickle.PickleError):
            self.data = {
                'stats' : {},
                'config' : {
                    'solmanagertoken':         DEFAULT_SOLMANAGERTOKEN,
                },
            }
            self._backupData()
    def incrStats(self,statName,step=1):
        with self.dataLock:
            if statName not in self.data['stats']:
                self.data['stats'][statName] = 0
            self.data['stats'][statName] += step
    def getStats(self):
        with self.dataLock:
            return self.data['stats'].copy()
    def getConfig(self,key):
        with self.dataLock:
            return self.data['config'][key]
    def getAllConfig(self):
        with self.dataLock:
            return self.data['config'].copy()
    def setConfig(self,key,value):
        with self.dataLock:
            self.data['config'][key] = value
        self._backupData()
    def _backupData(self):
        with self.dataLock:
            with open(DEFAULT_BACKUPFILE,'w') as f:
                pickle.dump(self.data,f)

class CherryPySSL(bottle.ServerAdapter):
    def run(self, handler):
        from cherrypy import wsgiserver
        from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
        server = wsgiserver.CherryPyWSGIServer((self.host, self.port), handler)
        server.ssl_adapter = pyOpenSSLAdapter(
            certificate           = DEFAULT_SOLSERVERCERT,
            private_key           = DEFAULT_SOLSERVERPRIVKEY,
        )
        try:
            server.start()
            log.info("Server started")
        finally:
            server.stop()

class Server(threading.Thread):

    def __init__(self,tcpport):

        # store params
        self.tcpport    = tcpport

        # local variables
        AppData()
        self.sol                  = Sol.Sol()
        self.solmanagertoken      = DEFAULT_SOLMANAGERTOKEN
        self.influxClient         = influxdb.client.InfluxDBClient(
            host        = 'localhost',
            port        = '8086',
            database    = 'realms'
        )
        self.actions    = []

        # initialize web server
        self.web        = bottle.Bottle()
        self.web.route(path=["/<filename>"],
                       method='GET',
                       callback=self._cb_root_GET,
                       name='static')
        self.web.route(path=['/map/<sitename>/<filename>', '/map/<sitename>/'],
                       method='GET',
                       callback=self._cb_map_GET,
                       name='static')
        self.web.route(path=['/api/v1/jsonp/<site>/<sol_type>/time/<utc_time>'],
                       method='GET',
                       callback=self._cb_jsonp_GET)
        self.web.route(path=['/api/v1/getactions/'],
                       method='GET',<commit_msg>#56 adding map route<commit_after>#!/usr/bin/python

# =========================== adjust path =====================================

import sys
import os

if __name__ == "__main__":
    here = sys.path[0]
    sys.path.insert(0, os.path.join(here, '..', 'sol'))

# =========================== imports =========================================

# from default Python
import pickle
import time
import json
import subprocess
import threading
import traceback
import datetime
from   optparse                 import OptionParser
from   ConfigParser             import SafeConfigParser
import logging
import logging.config

# third-party packages
import bottle
import influxdb

# project-specific
import OpenCli
from solobjectlib import Sol, SolVersion
import solserver_version
import sites

#============================ logging =========================================

logging.config.fileConfig('logging.conf')
log = logging.getLogger('solserver')
log.setLevel(logging.DEBUG)

#============================ defines =========================================

DEFAULT_TCPPORT              = 8081
DEFAULT_SOLSERVERHOST        = '0.0.0.0' # listen on all interfaces

DEFAULT_CONFIGFILE           = 'solserver.config'
DEFAULT_CRASHLOG             = 'solserver.crashlog'
DEFAULT_BACKUPFILE           = 'solserver.backup'

# config file

DEFAULT_SOLMANAGERTOKEN      = 'DEFAULT_SOLMANAGERTOKEN'
DEFAULT_SOLSERVERCERT        = 'solserver.cert'
DEFAULT_SOLSERVERPRIVKEY     = 'solserver.ppk'

# stats

STAT_NUM_JSON_REQ            = 'NUM_JSON_REQ'
STAT_NUM_JSON_UNAUTHORIZED   = 'NUM_JSON_UNAUTHORIZED'
STAT_NUM_CRASHES             = 'NUM_CRASHES'
STAT_NUM_OBJECTS_DB_OK       = 'STAT_NUM_OBJECTS_DB_OK'
STAT_NUM_OBJECTS_DB_FAIL     = 'STAT_NUM_OBJECTS_DB_FAIL'
STAT_NUM_SET_ACTION_REQ      = 'NUM_SET_ACTION_REQ'

#============================ helpers =========================================

def logCrash(threadName,err):
    output  = []
    output += ["============================================================="]
    output += [time.strftime("%m/%d/%Y %H:%M:%S UTC",time.gmtime())]
    output += [""]
    output += ["CRASH in Thread {0}!".format(threadName)]
    output += [""]
    output += ["=== exception type ==="]
    output += [str(type(err))]
    output += [""]
    output += ["=== traceback ==="]
    output += [traceback.format_exc()]
    output  = '\n'.join(output)
    # update stats
    AppData().incrStats(STAT_NUM_CRASHES)
    print output
    log.critical(output)

#============================ classes =========================================

class AppData(object):
    _instance = None
    _init     = False
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(AppData,cls).__new__(cls, *args, **kwargs)
        return cls._instance
    def __init__(self):
        if self._init:
            return
        self._init      = True
        self.dataLock   = threading.RLock()
        try:
            with open(DEFAULT_BACKUPFILE,'r') as f:
                self.data = pickle.load(f)
        except (EnvironmentError, pickle.PickleError):
            self.data = {
                'stats' : {},
                'config' : {
                    'solmanagertoken':         DEFAULT_SOLMANAGERTOKEN,
                },
            }
            self._backupData()
    def incrStats(self,statName,step=1):
        with self.dataLock:
            if statName not in self.data['stats']:
                self.data['stats'][statName] = 0
            self.data['stats'][statName] += step
    def getStats(self):
        with self.dataLock:
            return self.data['stats'].copy()
    def getConfig(self,key):
        with self.dataLock:
            return self.data['config'][key]
    def getAllConfig(self):
        with self.dataLock:
            return self.data['config'].copy()
    def setConfig(self,key,value):
        with self.dataLock:
            self.data['config'][key] = value
        self._backupData()
    def _backupData(self):
        with self.dataLock:
            with open(DEFAULT_BACKUPFILE,'w') as f:
                pickle.dump(self.data,f)

class CherryPySSL(bottle.ServerAdapter):
    def run(self, handler):
        from cherrypy import wsgiserver
        from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
        server = wsgiserver.CherryPyWSGIServer((self.host, self.port), handler)
        server.ssl_adapter = pyOpenSSLAdapter(
            certificate           = DEFAULT_SOLSERVERCERT,
            private_key           = DEFAULT_SOLSERVERPRIVKEY,
        )
        try:
            server.start()
            log.info("Server started")
        finally:
            server.stop()

class Server(threading.Thread):

    def __init__(self,tcpport):

        # store params
        self.tcpport    = tcpport

        # local variables
        AppData()
        self.sol                  = Sol.Sol()
        self.solmanagertoken      = DEFAULT_SOLMANAGERTOKEN
        self.influxClient         = influxdb.client.InfluxDBClient(
            host        = 'localhost',
            port        = '8086',
            database    = 'realms'
        )
        self.actions    = []

        # initialize web server
        self.web        = bottle.Bottle()
        self.web.route(path=["/<filename>"],
                       method='GET',
                       callback=self._cb_root_GET,
                       name='static')
        self.web.route(path=['/map/<sitename>/<filename>',
                            '/map/<sitename>/',
                            '/map/<sitename>'],
                       method='GET',
                       callback=self._cb_map_GET,
                       name='static')
        self.web.route(path=['/api/v1/jsonp/<site>/<sol_type>/time/<utc_time>'],
                       method='GET',
                       callback=self._cb_jsonp_GET)
        self.web.route(path=['/api/v1/getactions/'],
                       method='GET',
{'fraction_non_alphanumeric': 0.18355285376561972, 'fraction_numerical': 0.003377237419790611, 'mean_word_length': 2.2966880044531033, 'pattern_counts': {'":': 2, '<': 18, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4280759', 'n_tokens_mistral': 3421, 'n_tokens_neox': 3332, 'n_words': 607}