/** * Copyright 2018-2028 WindChat Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.windchat.im.boot.main; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Base64; import java.util.Map; import com.windchat.im.boot.spring.OpenzalySpringBoot; import com.windchat.im.boot.utils.BootLog; import com.windchat.im.boot.utils.Helper; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Level; import com.windchat.common.command.Command; import com.windchat.common.command.CommandResponse; import com.windchat.common.constant.HttpUriAction; import com.windchat.common.constant.RequestAction; import com.windchat.common.executor.AbstracteExecutor; import com.windchat.common.logs.AkxLog4jManager; import com.windchat.common.utils.StringHelper; import com.akaxin.proto.core.FileProto.FileType; import com.windchat.im.boot.config.WindProject; import com.windchat.im.boot.config.ConfigHelper; import com.windchat.im.boot.config.ConfigKey; import com.windchat.im.boot.config.ConfigListener; import com.windchat.im.boot.config.SiteDefaultIcon; import com.windchat.im.business.utils.FilePathUtils; import com.windchat.im.business.utils.FileServerUtils; import com.windchat.im.connector.exception.HttpServerException; import com.windchat.im.connector.exception.TcpServerException; import com.windchat.im.connector.handler.ApiRequestHandler; import com.windchat.im.connector.handler.HttpRequestHandler; import com.windchat.im.connector.handler.ImMessageHandler; import com.windchat.im.connector.handler.ImSiteAuthHandler; import com.windchat.im.connector.handler.WSRequestHandler; import com.windchat.im.connector.http.HttpServer; import com.windchat.im.connector.netty.NettyServer; import com.windchat.im.connector.ws.WsServer; import com.windchat.im.storage.DataSourceManager; import com.windchat.im.storage.dao.config.DBConfig; import com.windchat.im.storage.dao.sqlite.manager.PluginArgs; import com.windchat.im.storage.exception.InitDatabaseException; import com.windchat.im.storage.exception.NeedInitMysqlException; import com.windchat.im.storage.exception.UpgradeDatabaseException; /** *
* Openzaly是Akaxin聊天软件的服务端开源项目,当你第一次从github上下载源码至本地后,可以通过 * Bootstrap中的main方法启动Openzaly服务器代码。Openzaly-server配合Akaxin客户端协同使用, * Akaxin客户端可以在苹果的Appstore以及Akaxin官方下载 * * Openzaly-boot是Openzaly项目中的启动模块,主要负责项目的初始化,事件监听,日志等级变更,帮 * 助文档,标准化输出,服务启动: * * 1.帮助文档 * Openzaly启动支持自定义参数,这些参数通过用户启动命令中增加[-h|-help]获取,具体执行如下: * java -jar openzaly-server.jar -h * java -jar openzaly-server.jar -help * * 2.初始化工作 * 项目启动前期,需要初始化服务端数据,当前需要初始化的数据包括: * a.初始化数据库,自动创建SQLite中需要的table * b.站点服务的默认配置或者用户自定义的配置信息 * c.默认后台管理与用户广场的ICON设置 * * 3.日志等级变更 * Openzaly项目中使用的日志框架为Log4j+SLF4J,默认的日志等级为INFO级别,在后台管理中,支持 * 用户通过配置信息修改,来实时变更项目中的日志级别,从而达到在不停止服务情况下,修改日志级别。 * * 4.服务启动 * Openzaly项目启动的主要部分,包含三个服务的启动分别如下: * a.提供扩展使用的Netty-Http服务 * 使用Netty框架启动Http服务,当开发者开发站点的扩展功能,可以调用此Http接口实现与站点之 * 间的交互。 * * b.提供客户端访问Netty-Tcp服务 * Akaxin的客户端【Andorid与IOS】通过tcp连接保持与站点之间的长连接,实现用户与Openzaly * 之间的IM功能以及部分API访问请求。 * * c.提供WEBIM使用的WebSocket服务 * 暂时此功能未上线 * * 5.标准化输出 * 在标准输出界面输出Openzaly的启动情况【log日志信息中支持更详细的启动记录】 * * * Begin from here,start the Openzaly server for clients * ...... * ** * @author Sam{@link an.guoyue254@gmail.com} * @since 2018.01.01 11:23:42 */ public class Bootstrap { public static void main(String[] args) { // set root dir try { setBaseDir(); } catch (IOException ioe) { BootLog.error("openzaly set base dir error"); System.exit(-100); } // 增加 -h|-help 启动参数 输出帮助文档 // use java -jar -h|-help ,get more help message if (Helper.startHelper(args)) { return; } PrintWriter pwriter = new PrintWriter(System.out); Helper.showAkaxinBanner(pwriter); Helper.buildEnvToSystemOut(pwriter); String nettyTcpHost = "0.0.0.0"; int nettyTcpPort = 2021; String pluginAPiAddress = "0.0.0.0"; int pluginAPiPort = 8280; try { setDefaultSystemLogLevel(); // client tcp address from openzaly.properties nettyTcpHost = ConfigHelper.getStringConfig(ConfigKey.SITE_ADDRESS); nettyTcpPort = ConfigHelper.getIntConfig(ConfigKey.SITE_PORT); // plugin http address from openzaly.properties pluginAPiAddress = ConfigHelper.getStringConfig(ConfigKey.PLUGIN_API_ADDRESS); pluginAPiPort = ConfigHelper.getIntConfig(ConfigKey.PLUGIN_API_PORT); // add site config to database initDataSource(); // use thread to update site-config cached in memory addConfigListener(); // start server startNettyHttpServer(pluginAPiAddress, pluginAPiPort);// 0.0.0.0:8280 startNettyTcpServer(nettyTcpHost, nettyTcpPort);// 0.0.0.0:2021 // disable websocket server // startWebSocketServer("0.0.0.0", 9090);// 0.0.0.0:9090 // start spring boot for openzaly-admin initSpringBoot(args); Helper.startSuccess(pwriter); BootLog.info("start openzaly-server successfully"); } catch (Exception e) { Helper.startFail(pwriter); BootLog.error("start Openzaly-server error", e); BootLog.error("Openzaly-server exit..."); System.exit(-1);// system exit } catch (TcpServerException e) { String errMessage = StringHelper.format("openzaly tcp-server {}:{} {}", nettyTcpHost, nettyTcpPort, e.getCause().getMessage()); Helper.startFailWithError(pwriter, errMessage); BootLog.error("start Openzaly with tcp server error", e); BootLog.error("Openzaly-server exit..."); System.exit(-2);// system exit } catch (HttpServerException e) { String errMessage = StringHelper.format("openzaly http-server {}:{} {}", pluginAPiAddress, pluginAPiPort, e.getCause().getMessage()); Helper.startFailWithError(pwriter, errMessage); BootLog.error("start Openzaly with http server error", e); BootLog.error("Openzaly-server exit..."); System.exit(-3);// system exit } catch (InitDatabaseException e) { String errMessage = StringHelper.format("openzaly init database error {}", e.getCause().getMessage()); Helper.startFailWithError(pwriter, errMessage); BootLog.error("start Openzaly with init database error", e); BootLog.error("Openzaly-server exit..."); System.exit(-4);// system exit } catch (UpgradeDatabaseException e) { Helper.printUpgradeWarn(pwriter); BootLog.error("Openzaly-server current is an old version ,we need to upgrade.", e); System.exit(-5);// system exit } catch (NeedInitMysqlException e) { Helper.printInitMysqlWarn(pwriter); BootLog.error("Openzaly-server need to init mysql.", e); System.exit(-6);// system exit } finally { if (pwriter != null) { pwriter.close(); } } } private static void setBaseDir() throws IOException { String baseDir = ConfigHelper.getStringConfig(ConfigKey.SITE_BASE_DIR); if (StringUtils.isNotBlank(baseDir)) { File file = new File(baseDir); if (!file.isDirectory()) { file.mkdirs(); } System.setProperty("user.dir", file.getCanonicalPath()); } } private static void setDefaultSystemLogLevel() { // 更新日志级别 AkxLog4jManager.setLogLevel(Level.INFO); BootLog.info("{} set system log level={}", WindProject.PLN, Level.INFO); } /** * 初始化数据源 * * @throws InitDatabaseException * @throws UpgradeDatabaseException * @throws NeedInitMysqlException */ private static void initDataSource() throws InitDatabaseException, UpgradeDatabaseException, NeedInitMysqlException { String adminHost = ConfigHelper.getStringConfig(ConfigKey.SITE_ADMIN_ADDRESS); int adminPort = ConfigHelper.getIntConfig(ConfigKey.SITE_ADMIN_PORT); String dbDir = System.getProperty("user.dir"); String adminUic = ConfigHelper.getStringConfig(ConfigKey.SITE_ADMIN_UIC); Map