2023年7月7日发(作者:)
Appium源码分析(1)-程序的⼊⼝⼀⽂中我们描述了appium项⽬的⽬录结构,从中我们了解到appium server的源码⽂件为bin和lib两个⽂件夹,但是bin⽬录为可执⾏⽂件,所以我们不研究这个⽂件夹,直接进⼊lib⽬录下就⾏,通过⾥main字段我们了解程序的⼊⼝⽂件为lib/server/,ok我们从这个⽂件开始。我们⼀步⼀步来分析这个⽂件。我采⽤的是来debug我们的程序。
⾸先我们以debug-brk的⽅式启动程序:E:appium>node --debug-brk=9222 .Debugger listening on port 9222ok,这个时候程序会以debug模式启动,监听9222的端⼝,且会停留在源⽂件的第⼀⾏等待调试。ok,这个时候我们在eclipse中启动V8调试点击Debug后,进⼊调试模式:程序停留在⽂件的第⼀⾏,这个时候我们会发现这个⽐我们直接打开多了⼀⾏代码:(function (exports, require, module, __filename, __dirname)这个是nodejs内部的加载机制,它会每⼀个本地⽂件包裹上这么⼀个函数,只要知道这些就⾏,其他的和正常打开该⽂件的代码都是⼀样的。我们现在进⼊正题。严格模式在nodejs中有⼀套规范叫,它是前⼈总结的⼀套nodejs程序编写规范,旨在提⾼代码的可读性以及降低维护成本等。通常在⽂件的开头⽤下⾯语句标识:"use strict";初始化var parser = require('./')() , logFactory = require('./') , logger = null , args = null , fs = require('fs') , path = require('path') , noPermsCheck = false;require('colors');上⾯的语句为初始化模块、变量的语句,以./开头的是本地模块,还有⼀种是核⼼模块,就是不以/标识的模块,⽐如上⾯的fs、path、colors模块。各个变量的意义:变量名parserlogFactoryloggerargsfspathnoPermsCheck意义加载⾃本地模块,是⼀个参数解析器,我们会在中详细介绍log⼯⼚类log器参数集合⽂件模块,核⼼模块路径模块,核⼼模块boolean值,是否省略权限检查,默认为false,需要检查权限解析命令⾏参数(e(__dirname, '../..'));上⾯的代码是将当前运⾏的路径提升到根⽬录,也就是appium的根⽬录。process是⼀个全局变量,所以不需要通过require来加载,()⽅法⽤来改变⼯作⽬录,e()⽅法是将当前⽬录项上倒退2个级别,也就是appium项⽬的根⽬录。if ( === module) { args = rgs(); noPermsCheck = sCheck; (args);}标识的是启动脚本的模块,也就是你在命令⾏中node命令后⾯跟的模块,⽐如我们这个地⽅就是lib/server/。⽽module与⽂件/⽬录是⼀⼀对应的关系,当前⽂件中module⾃然指代该⽂件的结构。这样说法可能有点抽象,我们来看看module的变量:⾥⾯可以看出当前module的filename值为lib/server/,其还含有两个⼦module,⼀个lib/server/和lib/server/。这两个刚好是我们在初始化的时候通过require加载的模块。所以我们应该能够得出这个module⼀定程度上能够反映出各个模块之间的依赖关系。
那么上⾯的==module就是看是否是程序的⼊⼝程序,如果是的话,就需要解析参数。解析参数⽤的就是同级⽬录下的模块来解析的,我们会在下⼀篇的博客中介绍。解析完成后,会给变量args,noPermsCheck 赋值,且初始化log⼯⼚。权限检查logger = ('appium');if (!noPermsCheck) { ...... }⾸先初始化变量logger,我们就拥有了log器。然后判断是否需要进⾏权限的检查,由于我们的noPermsCheck变量为false,所以是需要检查的。那么进⼊到检查代码块:var appiumPermStat = nc(e(__dirname, '../../')); var launchCmd = (_COMMAND || "").toLowerCase(); var isWindows = require('appium-support').ows();上⾯的语句初始化3个局部变量并赋值:appiumPermStat:⾸先获得⽂件对象。launchCmd:判断系统环境下SUDO_COMMAND命令是否为undefined或null,如果不是这两个值,那么该值就为SUDO_COMMAND的值,否则该值就为空字符串(”“),最后再将字符串转化为⼩写的。isWindows:判断是否是windows系统,调⽤的是第三⽅模块appium-support的⽅法。上⾯3个对象赋值以后,就会判断当前环境是否具有⽤户权限,但是该检查只在unix和linux环境下才会做。 if ( !isWindows && // Appium should be run by user who owns files in Appium installation directory !== () && // authorize* commands could be run using sudo !(/authorize/) ) { ("Appium will not work if used or installed with sudo. " + "Please rerun/install as a non-root user. If you had to " + "install Appium using `sudo npm install -g appium`, the " + "solution is to reinstall Node using a method (Homebrew, " + "for example) that doesn't require sudo to install global " + "npm packages."); (1); }1.上⾯的判断条件中isWindows这个很容易理解的,我们上⾯也说⾮windows下才会做这个检查,
2.然后判断⽂件的uid和进程的uid是否相等,如果相等了说明当前⽤户拥有该⽂件的执⾏权限,所以如果既不在window下,⼜不能拥有执⾏权限,就需要继续判断launchCmd了。
3.判断launchCmd:利⽤的正则表达式⽅法match来判断,正斜杠(/)包裹的就是带查找的字符串,上⾯的结果就是判断launchCmd是否包含authorize这个字符串。该判断的⽬的是查看是否以sudo命令启动的该脚本,因为本⾝该脚本不是启动程序的⽤户所能执⾏的,就需要显式的⽤sudo来执⾏。
4.当上⾯的3个条件有⼀个判断失败,就会打印下⾯的信息。说明上⾯的种种判断都是为检查我们是否在安装appium的时候,错误的使⽤sudo命令。重要安装appium的时候千万不要使⽤sudo npm install -g appium 来安装。再次初始化var http = require('http') , express = require('express') , favicon = require('serve-favicon') , bodyParser = require('body-parser') , methodOverride = require('method-override') , morgan = require('morgan') // logger , routing = require('./') , path = require('path') , appium = require('../') , parserWrap = require('./middleware').parserWrap , appiumVer = require('../../').version , appiumRev = null , async = require('async') , helpers = require('./') , logFinalWarning = require('../').logFinalDeprecationWarning , getConfig = require('../').getAppiumConfig , allowCrossDomain = rossDomain , catchAllHandler = llHandler , checkArgs = rgs , configureServer = ureServer , startListening = istening , conditionallyPreLaunch = ionallyPreLaunch , prepareTmpDir = eTmpDir , requestStartLoggingFormat = require('./').requestStartLoggingFormat , requestEndLoggingFormat = require('./').requestEndLoggingFormat , domainMiddleware = require('./').domainMiddleware;变量名httpexpressfaviconbodyParsermethodOverridemorganroutingpathappiumparserWrapappiumVerappiumRevasynchelperslogFinalWarninggetConfigallowCrossDomaincatchAllHandler模块httpexpress意义http模块,不解释.第三⽅模块.⽤于搭建http服务器.第三⽅模块,express中间件组件,改善图⽚缓存性能的.body-parser第三⽅模块.express依赖的中间件组件.第三⽅模块.可以理解为重写了http模块中⼀些⽅法,可能是核⼼模块http中有些⽅法不太好⽤.morgan./.././middleware../../未知第三⽅模块.类似log器,在控制台中,显⽰req请求的信息.本地模块.路由模块.这个模块中定义了uri对应的处理⽅法,我们以后会对其进⾏解释.核⼼模块.⽤于处理⽂件路径相关的操作.本地模块.以后会解释,暂时我也不知道是个啥本地模块.同上.appium的版本null第三⽅模块.是⼀个流程控制⼯具包,提供了直接⽽强⼤的异步功能.././../../../本地模块.以后解释本地模块.模块中logFinalDeprecationWarning模块.本地模块.helpers中的getAppiumConfig模块.保存有appium的配置信息.回调⽅法对象.回调⽅法对象.变量名checkArgsconfigureServerstartListeningconditionallyPreLaunchprepareTmpDirrequestStartLoggingFormatrequestEndLoggingFormatdomainMiddleware模块../../../../../../../../意义回调⽅法对象.回调⽅法对象.回调⽅法对象.回调⽅法对象.回调⽅法对象.本地模块.中的requestStartLoggingFormat模块.本地模块.中的requestEndLoggingFormat模块.本地模块.中的domainMiddleware模块.最后2句代码if ( === module) { main(args);} = main;上⾯的代码为的最后⼀段代码,从上⾯的代码可以看出,该模块中最主要的函数为main函数,提供给外部模块的是run函数。如果当前模块就是启动模块的话,那么会⾃⼰调⽤main函数,所以下⼀篇我们会单独说main函数的内容。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688685226a162468.html
评论列表(0条)